Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bot SDK as Module implementation #19

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bot_python_sdk/action_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def get_actions(self):
Logger.success(LOCATION, 'Successfully loaded ' + str(len(actions)) + ' cached action(s)')
return actions

def trigger(self, action_id, value=None, alternative_id=None):
def trigger(self, action_id, value=None, alternative_id=None, queue_id=None):
Logger.info(LOCATION, 'Triggering action: ' + action_id)
action = self._get_action(action_id)
self._validate_frequency(action)
Expand Down
3 changes: 2 additions & 1 deletion bot_python_sdk/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def __init__(self):

def on_get(self):
self.configuration_service.resume_configuration()


api = application = falcon.API()
api.add_route(ACTIONS_ENDPOINT, ActionsResource())
Expand All @@ -101,3 +101,4 @@ def on_get(self):
#Initialize the Bluetooth service class to process
#handle BLE specific envents and callbacks
BluetoothService().initialize()
ConfigurationService().resume_configuration()
2 changes: 1 addition & 1 deletion bot_python_sdk/bleno/configure.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,5 +90,5 @@ def onReadRequest(self, offset, callback):
Logger.info(LOCATION,'Connected device configuration complete. ' +
'Start pairing process...')
self.configureData.extend(map(ord, json.dumps(data)))
PairingService().run()
#PairingService().run()
callback(Characteristic.RESULT_SUCCESS, self.configureData[offset:])
219 changes: 219 additions & 0 deletions bot_python_sdk/bot_api_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
"""@package docstring
BOT API service module provides interface for applications to interact with BOT Services.
Applications have to import the module and create object of the BotApiService class.
Then call the corresponding API's and classes to interface with BOT Service
"""
import os
import sys
import json
from bot_python_sdk.store import Store
from bot_python_sdk.action_service import ActionService
from bot_python_sdk.configuration_service import ConfigurationService
from bot_python_sdk.configuration_store import ConfigurationStore
from bot_python_sdk.device_status import DeviceStatus
from bot_python_sdk.logger import Logger

from bot_python_sdk.bluetooth_service import BluetoothService

## Global variables to interface with BOT Services.
LOCATION = 'Controller'
INCOMING_REQUEST = 'Incoming request: '

DEVICE_ID_KEY = 'deviceId'
MAKER_ID_KEY = 'makerId'
PUBLIC_KEY_KEY = 'publicKey'

ACTION_ID = 'actionID'
VALUE_KEY = 'value'
ALTERNATIVER_ID ='alternativeID'

METHOD_GET = 'get'
METHOD_POST = 'set'
ACTIONS_ENDPOINT = 'actions'
PAIRING_ENDPOINT = 'pairing'
ACTIVATION_ENDPOINT = 'activation'

class BoTerror(Exception):

"""BoT API service Exception class, using which all the exceptions are created.
"""
pass

class DeviceForbiddenError(BoTerror):

"""BoT API service Device Forbidden Exception. This shall be triggered when
the device status is not active
"""
def __init__(self, error):
"""The constructor. Stores the error message which the application can access """
self.msg = error

class InvalidRequestError(BoTerror):

"""BoT API service Invalid Request Exception. This shall be triggered when
the actionID or alternateID is missing from the action trigger request.
"""
def __init__(self, error):
"""The constructor. Stores the error message which the application can access """
self.msg = error

class ServiceUnavailableError(BoTerror):

"""BoT API service Service Not Available Exception. This shall be triggered when
the triggered action request is failed from the BOT service.
"""
def __init__(self, error):
"""The constructor. Stores the error message which the application can access """
self.msg = error

class BoTinputError(BoTerror):

"""BoT API service no imput provided Exception. This shall be triggered when
a new device pairing is requested with out maker id being provided.
"""
def __init__(self, error):
"""The constructor. Stores the error message which the application can access """
self.msg = error

class MissingInputError(BoTerror):

"""BoT API service Missing Input Exception. This shall be triggered when
either multipairing is enabled and alternative ID is 0 or invalid.
"""
def __init__(self, error):
"""The constructor. Stores the error message which the application can access """
self.msg = error

class NetworkUnavailableError(BoTerror):

def __init__(self, error):
"""The constructor. Stores the error message which the application can access """
self.msg = error

class ActionsTriggerStoreError(BoTerror):

def __init__(self, error):
"""The constructor. Stores the error message which the application can access """
self.msg = error

class ActionsResource:

""" Action Resource class is responsible for interfacing with Action Service and
either get the actions requested or trigger the actions.
"""
def __init__(self):
""" Constructor. Initializes/creates the action service and configuration store objects"""
"""@var action_service : stores action service object"""
"""@var configuration_store : stores configuration store object"""
self.action_service = ActionService()
self.configuration_store = ConfigurationStore()

## Gets the list of actions from the action service/makerid server.
# @param self The object pointer.
def get_actions(self):
Logger.info(LOCATION, INCOMING_REQUEST + METHOD_GET + ' ' + ACTIONS_ENDPOINT)
response = self.action_service.get_actions()
return response

## Triggers the actions.
# @param self The object pointer.
# @param actions_to_set actions to perform (dictionary).
def trigger_actions(self, actions_to_set):
configuration = self.configuration_store.get()
device_status = configuration.get_device_status()

# if device status is not active/multipair, then its an ivalid state to trigger action.
if device_status is not DeviceStatus.ACTIVE and device_status is not DeviceStatus.MULTIPAIR:
error = 'Not allowed to trigger actions when device is not activated.'
Logger.error(LOCATION, error)
raise DeviceForbiddenError(error)

Logger.info(LOCATION, INCOMING_REQUEST + METHOD_POST + ' ' + ACTIONS_ENDPOINT)
data = actions_to_set

#If actionID is missing then throw an error
if ACTION_ID not in data.keys():
Logger.error(LOCATION, 'Missing parameter `' + ACTION_ID + '` for ' + METHOD_POST + ' ' + ACTIONS_ENDPOINT)
raise InvalidRequestError('Missing parameter')

if device_status is DeviceStatus.MULTIPAIR:
if ALTERNATIVER_ID not in data.keys():
Logger.error(LOCATION, 'Missing parameter `' + ALTERNATIVER_ID + '` for ' + METHOD_POST + ' ' + ACTIONS_ENDPOINT)
raise InvalidRequestError('Missing parameter alternativeID')

action_id = data[ACTION_ID]
value = data[VALUE_KEY] if VALUE_KEY in data.keys() else None
alternative_id = data[ALTERNATIVER_ID] if ALTERNATIVER_ID in data.keys() else None

success = self.action_service.trigger(action_id, value, alternative_id)
response = ''
if success:
response = {'message': 'Action triggered'}
return response
else:
error = 'action service trigger failed, service not available'
raise ServiceUnavailableError(error)


class PairingResource:

""" Pairing Resource class is responsible for interfacing with Pairing Service to
get the pairing status of the device with the FINN application.
"""
def __init__(self):
""" Constructor. Initializes/creates the configuration store and configuration service objects"""
"""@var configuration_service : stores configuration service object"""
"""@var configuration_store : stores configuration store object"""
self.configuration_store = ConfigurationStore()
self.configuration_service = ConfigurationService()

def get_pairing_status(self):
Logger.info(LOCATION, INCOMING_REQUEST + METHOD_GET + ' ' + PAIRING_ENDPOINT)
configuration = self.configuration_store.get()
if configuration.get_device_status() is not DeviceStatus.NEW:
error = 'Device is already paired.'
Logger.error(LOCATION, error)
raise DeviceForbiddenError(error)
device_information = configuration.get_device_information()
response = json.dumps(device_information)
#subprocess.Popen(['make', 'pair'])
self.configuration_service.pair()
return response


class ActivationResource:

def __init__(self):
self.configuration_service = ConfigurationService()

def activate_service(self):
self.configuration_service.resume_configuration()

class BoTApiService():

""" BOT API Service class provides interfaces for BOT SDK. Applications can
import this class and call the api's to talk to BOT service
"""
def __init__(self, makerid, multipairing='no', aid=0):
## Constructor
self.makerID = makerid
self.multipairStatus = multipairing
self.aid = aid

def start(self):
configuration_service = ConfigurationService()
store = Store()

if( (self.multipairStatus == 'yes') and (self.aid == 0)):
raise MissingInputError('Alternate ID is missing')

if not store.has_configuration():
if (self.makerID == ''): # if no maker ID then raise an exception
error = 'Maker ID missing to configure the SDK'
raise BoTinputError(error)
#Module based or Server based. 0:Module based
configuration_service.initialize_configuration(self.makerID, 0, self.multipairStatus, self.aid)

#Initialize the Bluetooth service class to process BLE specific events and callbacks
BluetoothService().initialize()
configuration_service.resume_configuration()
29 changes: 21 additions & 8 deletions bot_python_sdk/configuration_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,31 @@ def __init__(self):
self.configuration = self.configuration_store.get()
self.key_generator = KeyGenerator()

def initialize_configuration(self, maker_id):
def initialize_configuration(self, maker_id, sever=1, multipair='no', altId=0):
Logger.info(LOCATION, 'Initializing configuration...')
public_key, private_key = KeyGenerator().generate_key()
device_id = self.key_generator.generate_uuid()
#initialize the alternative id.
aid = 0
# Option for Multi pairing
# If the option is yes, then alternative id needed
print('Enable Multi pair(yes/no)')
status = input()
#If its running as server
if (sever == 1):
# Option for Multi pairing
# If the option is yes, then alternative id needed
print('Enable Multi pair(yes/no)')
status = input()
else:
status = multipair

if(status == 'yes'):
device_status = DeviceStatus.MULTIPAIR.value
print('Enter your alternativeID:')
aid = input()
if (sever == 1):
print('Enter your alternativeID:')
aid = input()
else:
aid = altId
else:
device_status = DeviceStatus.NEW.value

# Added alternative id as an argument to initializing the configuration
self.configuration.initialize(maker_id, device_id, device_status, aid , public_key, private_key)
self.configuration_store.save(self.configuration)
Expand All @@ -43,7 +52,11 @@ def initialize_configuration(self, maker_id):

def resume_configuration(self):
device_status = self.configuration.get_device_status()
Logger.info(LOCATION, 'DeviceStatus = ' + device_status.value)
try:
Logger.info(LOCATION, 'DeviceStatus = ' + device_status.value)
except:
Logger.info(LOCATION, 'DeviceStatus = ' + device_status)

if device_status == DeviceStatus.NEW:
self.pair()
if device_status == DeviceStatus.PAIRED:
Expand Down
91 changes: 91 additions & 0 deletions examples/bot_api_access_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import time
import threading
import bot_python_sdk.bot_api_service as BotSDK
import json
from bot_python_sdk.logger import Logger

import signal
import sys

Component = 'BoT_Application'

bApplicationExit = 0
timeToSleep = 0.2 #200 ms sleep

def handleExitEvent(sig, frame):
msg = 'User Pressed Ctrl+C! ...'
Logger.error(Component, msg)
global bApplicationExit
bApplicationExit = 1
#sys.exit(0)

#print('Press Ctrl+C')
#signal.pause()
signal.signal(signal.SIGINT, handleExitEvent)

'''
def exitHanderThread():
print("THREAD : Handle External Exit Event ... ")
global timeToSleep
global bApplicationExit
while(!bApplicationExit):
time.sleep(timeToSleep) # sleep for 200 ms
print("THREAD : Exiting the Application thread ... ")
'''
if __name__ == "__main__":

makerid = ''
multipairingS = 'no'
aid = 0

if len (sys.argv) == 1:
Logger.info(Component, 'Execute w/o Maker ID ')
elif len (sys.argv) == 2:
# Maker ID provided ..
Logger.info(Component, 'Only Maker ID Provided ')
makerid = sys.argv[1]
elif len (sys.argv) < 4:
msg = 'Please provide all the parameters as \'sudo python3 bot_example01.py <MakerID> <Multipairing Status as yes/no> <Alternate ID>'
Logger.error(Component, msg)
sys.exit(0)
else:
makerid = sys.argv[1]
multipairingS = sys.argv[2]
aid = sys.argv[3]


print(makerid)
print(multipairingS)
print(aid)

#sys.exit(0)
BotSDKHndl = BotSDK.BoTApiService(makerid, multipairingS,aid)
#print("Bot Handle Created ")
Logger.info(Component, 'Bot Handle Created')
# creating thread
#tAppExit = threading.Thread(target=exitHanderThread)

try:
BotSDKHndl.start()
#print("BotSDK API service started successfully ....")
Logger.info(Component, 'BotSDK API service started successfully ....')
except BotSDK.BoTinputError as Error:
#print('Error from BoT API Service : '+Error.msg)
Logger.error(Component, Error.msg)
sys.exit(0)
except BotSDK.MissingInputError as Error:
Logger.error(Component, Error.msg)
sys.exit(0)

msg = 'To Exit the Test Appplication, Press Ctrl+C ...'
Logger.info(Component, msg)

while(bApplicationExit == 0):
time.sleep(timeToSleep) # sleep for 200 ms
msg = 'Application : Exiting the Application (Ctrl+C pressed) ...'
Logger.error(Component, msg)
BotSDKHndl.start()

time.sleep(0.5)
sys.exit(0)

Loading