Esempio n. 1
0
 def __init__(self, credentials):
     self.systemKey = credentials['systemKey']
     self.systemSecret = credentials['systemSecret']
     self.username = credentials['username']
     self.password = credentials['password']
     self.platformURL = credentials['platformURL']
     self.gatewayAddress = self.GetMacAddress()
     #Connect to MQTT
     cbSystem = System(self.systemKey, self.systemSecret, self.platformURL)
     # Device Auth
     if 'active_key' in credentials:
         self.gatewayName = credentials["name"]
         self.active_key = credentials['active_key']
         cbAuth = cbSystem.Device(self.gatewayName,
                                  credentials['active_key'])
     else:
         self.gatewayName = self.gatewayAddress
         cbAuth = cbSystem.User(credentials['username'],
                                credentials['password'])
     # right now override the GatewayName so that portal demos work easier
     self.gatewayName = "thunderboard"
     self.client = cbSystem.Messaging(cbAuth)
     self.client.connect()
     # the on_connect is not working
     self.client.on_message = self.CommandCallback
        return json.JSONEncoder.default(self, obj)

CB_CONFIG = {}

# Parse and Validate all args
parse_env_variables(os.environ)
parse_args(sys.argv)   
check_required_config()

# System credentials
CB_SYSTEM = System(CB_CONFIG['CB_SYSTEM_KEY'], CB_CONFIG['CB_SYSTEM_SECRET'], CB_CONFIG['httpURL'] + ":" + CB_CONFIG["httpPort"] )

uid = None

if 'deviceID' in CB_CONFIG:
    uid = CB_SYSTEM.Device(CB_CONFIG['deviceID'], CB_CONFIG['activeKey'])
elif 'CB_SERVICE_ACCOUNT' in CB_CONFIG:
    uid = CB_SYSTEM.Device(CB_CONFIG['CB_SERVICE_ACCOUNT'], authToken=CB_CONFIG['CB_SERVICE_ACCOUNT_TOKEN'])
else:
    print("Device Name/Active Key or Device Service Account/Token not provided")
    exit(-1)

mqtt = CB_SYSTEM.Messaging(uid, CB_CONFIG["messagingPort"], keepalive=30)


# Set up callback function


def on_connect(client, userdata, flags, rc):
    # When we connect to the broker, start publishing our data to the keelhauled topic
    print("Return Code: ", rc)
class AdapterLibrary:

    DEFAULT_LOG_LEVEL                       = "info"
    DEFAULT_PLATFORM_URL                    = "http://localhost:9000"
    DEFAULT_MESSAGING_URL                   = "localhost:1883"
    DEFAULT_ADAPTER_CONFIG_COLLECTION_NAME  = "adapter_config"

    SYSTEM_KEY_ARG_KEY                      = "CB_SYSTEM_KEY"
    SYSTEM_SECRET_ARG_KEY                   = "CB_SYSTEM_SECRET"
    DEVICE_NAME_ARG_KEY                     = "device_name"
    ACTIVE_KEY_ARG_KEY                      = "active_key"
    SERVICE_ACCOUNT_ARG_KEY                 = "CB_SERVICE_ACCOUNT"
    SERVICE_ACCOUNT_TOKEN_ARG_KEY           = "CB_SERVICE_ACCOUNT_TOKEN"
    PLATFORM_URL_ARG_KEY                    = "platform_URL"
    MESSAGING_URL_ARG_KEY                   = "messaging_URL"
    ADAPTER_CONFIG_COLLECTION_NAME_ARG_KEY  = "adapter_config_collection_name"
    LOG_LEVEL_ARG_KEY                       = "log_level"

    def __init__(self, adapter_name):
        cbLogs.info("Initializing AdapterLibrary with adapter name: " + adapter_name)
        self.adapter_name = adapter_name
        self._args = {}
        self._cb_system = None
        self._device_client = None
        self._sub_topic = None
        self._cb_message_handler = None

    def parse_arguments(self):
        cbLogs.info("AdapterLibrary - parse_arguments - parsing environment variables and flags")
        self.__parse_env_variables()
        self.__parse_flags()
        self._args[self.LOG_LEVEL_ARG_KEY] = string.upper(self._args[self.LOG_LEVEL_ARG_KEY])
        logging.basicConfig(level=self._args[self.LOG_LEVEL_ARG_KEY])
        if self._args[self.LOG_LEVEL_ARG_KEY] != "DEBUG":
            cbLogs.DEBUG = False
            cbLogs.MQTT_DEBUG = False
        cbLogs.info("AdapterLibrary - parse_arguments - parsed adapter arguments: " + str(self._args))
        cbLogs.info("AdapterLibrary - parse_arguments - Verifying required adapter arguments")
        if self.SYSTEM_KEY_ARG_KEY not in self._args:
            cbLogs.error("System Key is required, can be supplied with --systemKey flag or " + self.SYSTEM_KEY_ARG_KEY + " environment variable")
            exit(-1)
        if self.SYSTEM_SECRET_ARG_KEY not in self._args:
            cbLogs.error("System Secret is required, can be supplied with --systemSecret flag or " + self.SYSTEM_SECRET_ARG_KEY + " environment variable")
            exit(-1)
        if self.ACTIVE_KEY_ARG_KEY not in self._args and self.SERVICE_ACCOUNT_ARG_KEY not in self._args:
            cbLogs.error("Device Password is required when not using a Service Account, can be supplied with --password flag")
            exit(-1)
        if self.SERVICE_ACCOUNT_ARG_KEY in self._args and self.SERVICE_ACCOUNT_TOKEN_ARG_KEY not in self._args:
            cbLogs.error("Service Account Token is required when a Service Account is specified, this should have automatically been supplied. Check for typos then try again")
            exit(-1)
        cbLogs.info("AdapterLibrary - parse_arguments - Adapter arguments parsed and verified!")

    def initialize_clearblade(self):
        cbLogs.info("AdapterLibrary - initialize_clearblade - initializing with ClearBlade")

        self._cb_system = System(self._args[self.SYSTEM_KEY_ARG_KEY], self._args[self.SYSTEM_SECRET_ARG_KEY], self._args[self.PLATFORM_URL_ARG_KEY])
        
        if self.SERVICE_ACCOUNT_ARG_KEY in self._args:
            self.__auth_with_service_account()
        else:
            self.__auth_with_device()

        return self.__fetch_adapter_config()

    def connect_MQTT(self, topic="", cb_message_handler=None):
        cbLogs.info("AdapterLibrary - connect_MQTT - Initializing the ClearBlade MQTT message broker")
        self._cb_message_handler = cb_message_handler
        self._cb_mqtt = self._cb_system.Messaging(self._device_client, client_id=self.adapter_name + "-" + str(random.randint(0, 10000)))
        self._cb_mqtt.on_connect = self.__on_MQTT_connect
        self._cb_mqtt.on_disconnect = self.__on_MQTT_disconnect
        if topic != "":
            self._cb_mqtt.on_subscribe = self.__on_MQTT_subscribe
            self._cb_mqtt.on_message = self.__on_MQTT_message_received
            self._sub_topic = topic
        self._cb_mqtt.connect()

    def publish(self, topic, message):
        cbLogs.info("AdapterLibrary - publish - Publishing MQTT message on topic " + topic)
        self._cb_mqtt.publish(topic, message)
        
    def disconnect_MQTT(self):
        cbLogs.info("AdapterLibrary - disconnect_MQTT - Disconnecting from ClearBlade MQTT message broker")
        self._cb_mqtt.disconnect()

    def __auth_with_service_account(self):
        cbLogs.info("AdapterLibrary - __auth_with_service_account - Authenticating as service account")
        self._device_client = self._cb_system.Device(self._args[self.SERVICE_ACCOUNT_ARG_KEY], authToken=self._args[self.SERVICE_ACCOUNT_TOKEN_ARG_KEY])

    def __auth_with_device(self):
        cbLogs.info("AdapterLibrary - __auth_with_device - Authenticating as device")
        self._device_client = self._cb_system.Device(self._args[self.DEVICE_NAME_ARG_KEY], self._args[self.ACTIVE_KEY_ARG_KEY])

    def __fetch_adapter_config(self):
        cbLogs.info("AdapterLibrary - __fetch_adapter_config - Retrieving adapter config")

        adapter_config = {"topic_root": self.adapter_name, "adapter_settings": ""}

        collection = self._cb_system.Collection(self._device_client, collectionName=self._args[self.ADAPTER_CONFIG_COLLECTION_NAME_ARG_KEY])

        query = Query()
        query.equalTo("adapter_name", self.adapter_name)

        rows = collection.getItems(query)

        if len(rows) == 1:
            if rows[0]["topic_root"] != "":
                adapter_config["topic_root"] = str(rows[0]["topic_root"])
            if rows[0]["adapter_settings"] != "":
                raw_json = json.loads(str(rows[0]["adapter_settings"]))
                adapter_config["adapter_settings"] = self.__byteify(raw_json)
        else:
            cbLogs.warn("No adapter config found for adapter name " + self.adapter_name + ". Using defaults")

        cbLogs.info("AdapterLibrary - __fetch_adapter_config - Using adapter config: " + str(adapter_config))
        return adapter_config

    def __on_MQTT_connect(self, client, userdata, flags, rc):
        cbLogs.info("AdapterLibrary - __on_MQTT_connect - MQTT successfully connected!")
        if self._sub_topic != None:
            self._cb_mqtt.subscribe(self._sub_topic)

    def __on_MQTT_disconnect(self, client, userdata, rc):
        cbLogs.info("AdapterLibrary - __on_MQTT_disconnect - MQTT disconnected with rc " + str(rc))
        if self._sub_topic != None and rc == 1:
            cbLogs.warn("AdapterLibrary - __on_MQTT_disconnect - Verify that your service account has permission to subscribe to the topic: " + self._sub_topic)

    def __on_MQTT_subscribe(self, client, userdata, mid, granted_qos):
        cbLogs.info("AdapterLibrary - __on_MQTT_subscribe - MQTT successfully subcribed to topic " + self._sub_topic)

    def __on_MQTT_message_received(self, client, userdata, message):
        cbLogs.info("AdapterLibrary - __on_MQTT_message_received - MQTT message received on topic " + message.topic)
        if self._cb_message_handler != None:
            cbLogs.info("calling message handler")
            self._cb_message_handler(message)        

    def __parse_env_variables(self):
        """Parse environment variables"""
        env = os.environ
        possible_vars = [self.SYSTEM_KEY_ARG_KEY, self.SYSTEM_SECRET_ARG_KEY, self.SERVICE_ACCOUNT_ARG_KEY, self.SERVICE_ACCOUNT_TOKEN_ARG_KEY]
        
        for var in possible_vars:
            if var in env:
                cbLogs.info("Setting adapter arguments from environment variable: " + var + ": " + str(env[var]))
                self._args[var] = env[var]

    def __parse_flags(self):
        """Parse the command line arguments"""

        parser = argparse.ArgumentParser(description='ClearBlade Adapter')
        parser.add_argument('--systemKey', dest=self.SYSTEM_KEY_ARG_KEY, help='The System Key of the ClearBlade \
                            Plaform "System" the adapter will connect to.')

        parser.add_argument('--systemSecret', dest=self.SYSTEM_SECRET_ARG_KEY, help='The System Secret of the \
                            ClearBlade Plaform "System" the adapter will connect to.')

        parser.add_argument('--deviceName', dest=self.DEVICE_NAME_ARG_KEY, default=self.adapter_name, help='The name of the device that will be used for device \
                            authentication against the ClearBlade Platform or Edge, defined \
                            within the devices table of the ClearBlade platform. The default is ' + self.adapter_name)

        parser.add_argument('--password', dest=self.ACTIVE_KEY_ARG_KEY, help='The password (active key) of the device that will be used for device \
                            authentication against the ClearBlade Platform or Edge, defined within \
                            the devices table of the ClearBlade platform.')

        parser.add_argument('--platformURL', dest=self.PLATFORM_URL_ARG_KEY, default=self.DEFAULT_PLATFORM_URL, \
                            help='The HTTP URL of the ClearBlade Platform or Edge the adapter will \
                            connect to (including port if non-standard). The default is ' + self.DEFAULT_PLATFORM_URL)

        parser.add_argument('--messagingURL', dest=self.MESSAGING_URL_ARG_KEY, default=self.DEFAULT_MESSAGING_URL, \
                            help='The MQTT URL of the ClearBlade Platform or Edge the adapter will \
                            connect to (including port if non-standard). The default is ' + self.DEFAULT_MESSAGING_URL)

        parser.add_argument('--adapterConfigCollection', dest=self.ADAPTER_CONFIG_COLLECTION_NAME_ARG_KEY, \
                            default=self.DEFAULT_ADAPTER_CONFIG_COLLECTION_NAME, \
                            help='The name of the ClearBlade Platform data collection which contains \
                            runtime configuration settings for the adapter. The default is ' + self.DEFAULT_ADAPTER_CONFIG_COLLECTION_NAME)

        parser.add_argument('--logLevel', dest=self.LOG_LEVEL_ARG_KEY, default=self.DEFAULT_LOG_LEVEL, choices=['fatal', 'error', \
                            'warn', 'info', 'debug'], help='The level of logging that \
                            should be utilized by the adapter. The default is ' + self.DEFAULT_LOG_LEVEL)

        args = vars(parser.parse_args(args=sys.argv[1:]))
        for var in args:
            if args[var] != "" and args[var] != None:
                cbLogs.info("Setting adapter arguments from command line argument: " + var + ": " + str(args[var]))
                self._args[var] = args[var]
        
    def __byteify(self, input):
        cbLogs.info("in byteify")
        # helper function for python 2.7 to convert unicode to strings in a dict created with json.loads 
        # https://stackoverflow.com/a/13105359 
        if isinstance(input, dict):
            return {self.__byteify(key): self.__byteify(value)
                    for key, value in input.iteritems()}
        elif isinstance(input, list):
            return [self.__byteify(element) for element in input]
        elif isinstance(input, unicode):
            return input.encode('utf-8')
        else:
            return input
from clearblade.ClearBladeCore import System, Query, Developer, registerDev
import urllib.request, json, time

## New system with ClearBlade key and secret
systemKey = "SYSTEMKEY_HERE"
systemSecret = "SYSTEMSECRET_HERE"

mySystem = System(systemKey, systemSecret)

## New device with Clearblade active key and name
deviceName = "DEVICENAME_HERE"
deviceActiveKey = "ACTIVEKEY_HERE"
macDevice = mySystem.Device(deviceName, deviceActiveKey)
token = macDevice.token

## Using device to access messaging client
mqtt = mySystem.Messaging(macDevice, port=1883)

subscribeTopic = "rohith-mac/1/requests"
def on_connect(client, userdata, flags, rc):
	global subscribeTopic
	client.subscribe(subscribeTopic)

incomingRequest = None

def on_message(client, userdata, msg):
	global incomingRequest
	incomingRequest = (msg.payload).decode('utf-8')

mqtt.on_connect = on_connect
mqtt.on_message = on_message
Esempio n. 5
0
                        help='Adapter Device Key')
    parser.add_argument('-tp', '--topic', action='store', type=str, default="device/ble/",
                        help='Adapter Device Key')
    parser.add_argument('-sc', '--schematable', action='store', type=str, default="dev_admin_devicetypes",
                        help='Device Schema Collection')
    parser.add_argument('-dw', '--devicewhitelist', action='store', type=str, default="dev_whitelist",
                        help='Device Whitelist Collection')

    arg = parser.parse_args(sys.argv[1:])
    TOPIC=arg.topic
    logger = setup_custom_logger('BLE Adapter')
    scanner=ScanDelegate()
    exitapp=False
    cbSystem=System(arg.systemkey, arg.systemsecret, arg.systemurl)
#    cbAuth=cbSystem.User(CBUSER, CBPASS)
    cbAuth=cbSystem.Device(arg.adaptername, arg.adapterkey)
    mqtt=cbSystem.Messaging(cbAuth)
    
    mqtt.connect() #Connect to the msg broker
    while not exitapp:
        dev={}
        #List of devices to schema and devices monitor
        whitelisttable = cbSystem.Collection(cbAuth, collectionName=arg.devicewhitelist)
        wl_rows = whitelisttable.getItems()   
        schematable = cbSystem.Collection(cbAuth, collectionName=arg.schematable)
        schema_rows = schematable.getItems()
        for row in schema_rows:
            SC[row["item_id"]]=row["schema"]
        for row in wl_rows:
            WL[row["device_id"]]=SC[row["devicetype"]]
            #if "00:0b:57:1a:8f:de" in wl:
        logging.debug("Setting cbLogs.MQTT_DEBUG to False")
        cbLogs.MQTT_DEBUG = False

    logging.info("Intializing ClearBlade device client")
    logging.debug("System Key = %s", CB_CONFIG['systemKey'])
    logging.debug("System Secret = %s", CB_CONFIG['systemSecret'])
    logging.debug("HTTP URL = %s", CB_CONFIG['httpURL'] + ":" + CB_CONFIG['httpPort'])

    CB_SYSTEM = System(CB_CONFIG['systemKey'], CB_CONFIG['systemSecret'], CB_CONFIG['httpURL'] + \
                       ":" + CB_CONFIG['httpPort'])

    logging.info("Authenticating to ClearBlade")
    logging.debug("Device ID = %s", CB_CONFIG['deviceID'])
    logging.debug("Device Active Key = %s", CB_CONFIG['activeKey'])

    CB_AUTH = CB_SYSTEM.Device(CB_CONFIG['deviceID'], CB_CONFIG['activeKey'])

    #Retrieve the adapter configuration
    if CB_CONFIG['adapterSettingsCollectionName'] != "":
        logging.info("Retrieving the adapter configuration settings")
        get_adapter_config()

    #########################
    #BEGIN MQTT SPECIFIC CODE
    #########################

    #Connect to the message broker
    # logging.info("Initializing the ClearBlade message broker")
    # CB_MQTT = CB_SYSTEM.Messaging(CB_AUTH)

    # CB_MQTT.on_log = on_log
Esempio n. 7
0
def run_async_server():
    """
    The main loop instantiates one or more PyModbus servers mapped to ClearBlade Modbus proxies based on
    IP address and port defined in a ClearBlade platform Collection
    """
    log = None
    virtual_ifs = []
    err_msg = None
    defer_reactor = False

    try:
        parser = get_parser()
        user_options = parser.parse_args()
        local_ip_address = user_options.ip_address
        local_tcp_port = user_options.tcp_port
        net_if = user_options.net_if
        if user_options.log_level == 'DEBUG':
            _debug = True
        else:
            _debug = False
        HEARTBEAT = user_options.heartbeat

        log = headless.get_wrapping_logger(name=ADAPTER_DEVICE_ID, debug=_debug)
        server_log = headless.get_wrapping_logger(name="pymodbus.server", debug=_debug)

        log.info("Initializing ClearBlade System connection")
        cb_system = System(systemKey=user_options.systemKey, systemSecret=user_options.systemSecret, url=user_options.url)
        cb_auth = cb_system.Device(name=user_options.deviceName, key=user_options.deviceKey)
        cb_slave_config = user_options.slaves_collection
        cb_data = user_options.data_collection

        ip_proxies = []
        proxy_ports = []
        ip_address = None
        collection = cb_system.Collection(cb_auth, collectionName=cb_slave_config)
        query = Query()
        query.notEqualTo(COL_PROXY_IP_ADDRESS, '')
        rows = collection.getItems(query)
        for row in rows:
            # TODO: allow for possibility of multiple IPs with same port or same IP with multiple ports
            ip_address = str(row[COL_PROXY_IP_ADDRESS])
            tcp_port = int(row[COL_PROXY_IP_PORT])
            if ip_address not in ip_proxies:
                log.info("Found slave at {} on ClearBlade adapter config".format(ip_address))
                ip_proxies.append(ip_address)
                proxy_ports.append(tcp_port)
            else:
                log.warning("Duplicate proxy IP address {} found in configuration - ignoring".format(ip_address))

        log.debug("Processing {} slaves".format(len(ip_proxies)))
        for i in range(0, len(ip_proxies)):
            log.debug("Getting server context for {}".format(ip_proxies[i]))
            context = ClearBladeModbusProxyServerContext(cb_system=cb_system, cb_auth=cb_auth,
                                                         cb_slaves_config=cb_slave_config, cb_data=cb_data,
                                                         ip_address=ip_proxies[i], log=log)
            # Create IP aliases
            local_ip_address = ip_proxies[i]
            ip_mask = '255.255.255.0'
            local_tcp_port = proxy_ports[i]
            if sys.platform.startswith('win'):
                log.info("I'm on Windows!")
                local_ip_address = 'localhost'
            elif sys.platform.startswith('linux') or sys.platform.startswith('cygwin'):
                virtual_if = '{nif}:{alias}'.format(nif=net_if, alias=i)
                virtual_ifs.append(virtual_if)
                linux_command = "ifconfig {vif} {ip}".format(vif=virtual_if, ip=local_ip_address)
                if ip_mask is not None:
                    linux_command += " netmask {mask}".format(mask=ip_mask)
                log.info("Creating virtual IP address / alias via $ {}".format(linux_command))
                subprocess.call(linux_command, shell=True)

            # Create Server Identification
            identity = ModbusDeviceIdentification()
            identity.VendorName = 'PyModbus'
            identity.VendorUrl = 'http://github.com/bashwork/pymodbus/'
            identity.ProductName = 'Inmarsat/ClearBlade Modbus Server Adapter'
            identity.ModelName = ip_proxies[i]
            identity.MajorMinorRevision = '1.0'

            # Setup Modbus TCP Server
            log.info("Starting Modbus TCP server on {}:{}".format(local_ip_address, local_tcp_port))
            modbus_server_args = {
                'context': context,
                'identity': identity,
                'address': (local_ip_address, local_tcp_port),
                # 'console': _debug,
                'defer_reactor_run': True,
            }
            if modbus_server_args['defer_reactor_run']:
                defer_reactor = True
            reactor.callInThread(StartTcpServer, **modbus_server_args)

            if local_ip_address == 'localhost':
                log.info("Windows retricted environment prevents IP alias - running localhost for {}"
                         .format(ip_proxies[i]))
                break

        reactor.callInThread(_heartbeat, log, time.time(), HEARTBEAT)
        if defer_reactor:
            reactor.suggestThreadPoolSize(len(ip_proxies))
            reactor.run()

    except KeyboardInterrupt:
        err_msg = "modbus_server_adapter.py halted by Keyboard Interrupt"
        if log is not None:
            log.info(err_msg)
        else:
            print(err_msg)
        sys.exit("modbus_server_adapter.py halted by Keyboard Interrupt")

    except Exception as e:
        err_msg = "EXCEPTION: {}".format(e)
        if log is not None:
            log.info(err_msg)
        else:
            print(err_msg)
        sys.exit("modbus_server_adapter.py halted by exception {}".format(e))

    finally:
        if defer_reactor and reactor.running:
            reactor.stop()
        for vif in virtual_ifs:
            debug_msg = "Taking down virtual interface {}".format(vif)
            if log is not None:
                log.debug(debug_msg)
            else:
                print(debug_msg)
            linux_command = "ifconfig {} down".format(vif)
            subprocess.call(linux_command, shell=True)
        print("Exiting...")