def __init__(self, Log, Id, InFileName, ModelType, NumberOfDevices):

      self.logger = Log
      self.id_device = Id
      self.in_file_name = InFileName
      self.model_type = ModelType
      self.number_of_devices = NumberOfDevices

      # Load the configuration file
      self.config = {}
      self.load_config()

      # Symmetric Key
      self.symmetrickey = SymmetricKey(self.logger)

      # Secrets
      self.secrets = Secrets(self.logger)
      self.secrets_cache_data = self.secrets.data

      # meta
      self.application_uri = None
      self.namespace = None
      self.device_capability_model_id = None
      self.device_capability_model = []
      self.device_name_prefix = None
      self.ignore_interface_ids = []

      # Devices Cache
      self.devices_cache = DevicesCache(self.logger)
      self.devices_cache_data = self.devices_cache.data
      self.devices_to_provision = []
    def load_devices_cache(self):

        # Load Device Cache
        devices_cache = DevicesCache(self.logger)
        self.devices_cache = devices_cache.data
        return
Example #3
0
    def load_devicescache(self):

        devicescache = DevicesCache(self.logger)
        self.devicescache = devicescache.data
        return
class ProvisionDevices():

    timer = None
    timer_ran = False
    dcm_value = None

    def __init__(self, Log, Id, InFileName, ModelType, NumberOfDevices):

      self.logger = Log
      self.id_device = Id
      self.in_file_name = InFileName
      self.model_type = ModelType
      self.number_of_devices = NumberOfDevices

      # Load the configuration file
      self.config = {}
      self.load_config()

      # Symmetric Key
      self.symmetrickey = SymmetricKey(self.logger)

      # Secrets
      self.secrets = Secrets(self.logger)
      self.secrets_cache_data = self.secrets.data

      # meta
      self.application_uri = None
      self.namespace = None
      self.device_capability_model_id = None
      self.device_capability_model = []
      self.device_name_prefix = None
      self.ignore_interface_ids = []

      # Devices Cache
      self.devices_cache = DevicesCache(self.logger)
      self.devices_cache_data = self.devices_cache.data
      self.devices_to_provision = []


    # -------------------------------------------------------------------------------
    #   Function:   provision_devices
    #   Usage:      Iterates through all of the nodes in config.json and will create
    #               a provisioning call to associated a device template to the node
    #               interface based on the twin, device or gateway pattern
    # -------------------------------------------------------------------------------
    async def provision_devices(self):

      # First up we gather all of the needed provisioning meta-data and secrets
      try:

        for pattern in self.config["IoTCentralPatterns"]:
          if pattern["ModelType"] == self.model_type:
            self.namespace = pattern["NameSpace"]
            self.device_capability_model_id = pattern["DeviceCapabilityModelId"]
            self.device_name_prefix = pattern["DeviceNamePrefix"]
            self.ignore_interface_ids = pattern["IgnoreInterfaceIds"]
            break

        # this is our working cache for things we provision in this session
        self.devices_to_provision = self.create_devices_to_provision()

        # Specific string formatting based on the device-model-type
        if self.model_type == "Twins":
          self.twins_create()
        elif self.model_type == "Gateways":
          self.gateways_create()
        elif self.model_type == "Devices":
          self.devices_create()

        print("********************************")
        print("DEVICES TO PROVISION: %s" % self.devices_to_provision)
        print("********************************")

        # Update or Append new Records to the Devices Cache
        found_device = False
        for device_to_provision in self.devices_to_provision["Devices"]["Devices"]:
          index = 0
          for devices_cache in self.devices_cache_data["Devices"]:
            found_device = False
            if devices_cache["Name"] == device_to_provision["Name"]:
              self.devices_cache_data["Devices"][index] = device_to_provision
              found_device = True
              break
            else:
              index = index + 1
          if found_device == False:
            self.devices_cache_data["Devices"].append(device_to_provision)


        # Update or Append new Records to the Secrets
        found_secret = False
        for device_to_provision in self.devices_to_provision["Secrets"]:

          # Azure IoT Central SDK Call to create the provisioning_device_client
          provisioning_device_client = ProvisioningDeviceClient.create_from_symmetric_key(
            provisioning_host = self.secrets.get_provisioning_host(),
            registration_id = device_to_provision["Name"],
            id_scope = self.secrets.get_scope_id(),
            symmetric_key = device_to_provision["DeviceSymmetricKey"],
            websockets=True
          )

          # Azure IoT Central SDK call to set the DCM payload and provision the device
          provisioning_device_client.provisioning_payload = '{"iotcModelId":"%s"}' % (device_to_provision["DeviceCapabilityModelId"])
          registration_result = await provisioning_device_client.register()
          self.logger.info("[REGISTRATION RESULT] %s" % registration_result)
          self.logger.info("[device_symmetrickey] %s" % device_to_provision["DeviceSymmetricKey"])
          device_to_provision["AssignedHub"] = registration_result.registration_state.assigned_hub

          index = 0
          for secrets_cache in self.secrets_cache_data["Devices"]:
            found_secret = False
            if secrets_cache["Name"] == device_to_provision["Name"]:
              self.secrets_cache_data["Devices"][index] = device_to_provision
              found_secret = True
              break
            else:
              index = index + 1
          if found_secret == False:
            self.secrets_cache_data["Devices"].append(device_to_provision)

        print("********************************")
        print("DEVICES TO PROVISION: %s" % self.devices_to_provision)
        print("********************************")

        self.devices_cache.update_file(self.devices_cache_data)
        self.secrets.update_file_device_secrets(self.secrets_cache_data["Devices"])
        return

      except Exception as ex:
        self.logger.error("[ERROR] %s" % ex)
        self.logger.error("[TERMINATING] We encountered an error in CLASS::ProvisionDevices::provision_devices()" )

    # -------------------------------------------------------------------------------
    #   Function:   load_config
    #   Usage:      Loads the configuration
    # -------------------------------------------------------------------------------
    def load_config(self):

      config = Config(self.logger)
      self.config = config.data
      return

    # -------------------------------------------------------------------------------
    #   Function:   twins_create
    #   Usage:      Returns a a Twin pattern for Devices and Secrets
    # -------------------------------------------------------------------------------
    def twins_create(self):

      try:

        # We will iterate the number of devices we are going to create
        for x in range(self.number_of_devices):

          # Define the Device iteration suffix, it is
          # the base passed number with leading zeros for
          # a legnth of 3 (1-999) devices
          id_number_str = str(int(self.id_device) + x)
          id_number_str = id_number_str.zfill(3)

          device_name = self.device_name_prefix.format(id=id_number_str)

          # The Device Asset scenario appends one interfaces per device id
          device_capability_model = self.create_device_capability_model(device_name, self.device_capability_model_id)

          # Let's Look at the config file and generate
          # our device from the interfaces configuration
          for node in self.config["Nodes"]:

            # check if we are excluding the interface?
            if self.ignore_interface_ids.count(node["InterfacelId"]) == 0:
              device_capability_model["Interfaces"].append(self.create_device_interface(node["Name"], node["InterfacelId"], node["InterfaceInstanceName"]))

          self.devices_to_provision["Devices"]["Devices"].append(device_capability_model)
          self.devices_to_provision["Secrets"].append(self.create_device_connection(device_name, self.device_capability_model_id))

      except Exception as ex:
        self.logger.error("[ERROR] %s" % ex)
        self.logger.error("[TERMINATING] We encountered an error in CLASS::ProvisionDevices::devices_create()" )

      return

    # -------------------------------------------------------------------------------
    #   Function:   gateways_create
    #   Usage:      Returns a a Gateway pattern for Devices and Secrets
    # -------------------------------------------------------------------------------
    def gateways_create(self):

      try:

        # Let's Look at the config file and generate
        # our device from the interfaces configuration
        for node in self.config["Nodes"]:

          device_capability_model_id = self.device_capability_model_id.format(interfaceName=node["Name"])

          # check if we are excluding the interface?
          if self.ignore_interface_ids.count(node["InterfacelId"]) == 0:

            # We will iterate the number of devices we are going to create
            for x in range(self.number_of_devices):

              # Define the Device iteration suffix, it is
              # the base passed number with leading zeros for
              # a legnth of 3 (1-999) devices
              id_number_str = str(int(self.id_device) + x)
              id_number_str = id_number_str.zfill(3)

              device_name = self.device_name_prefix.format(nodeName=node["Name"], id=id_number_str)

              # The Device Asset scenario appends one interfaces per device id
              device_capability_model = self.create_device_capability_model(device_name, device_capability_model_id)
              device_capability_model["Interfaces"].append(self.create_device_interface(node["Name"], node["InterfacelId"], node["InterfaceInstanceName"]))

              self.devices_to_provision["Devices"]["Devices"].append(device_capability_model)
              self.devices_to_provision["Secrets"].append(self.create_device_connection(device_name, device_capability_model_id))

      except Exception as ex:
        self.logger.error("[ERROR] %s" % ex)
        self.logger.error("[TERMINATING] We encountered an error in CLASS::ProvisionDevices::devices_create()" )

      return

    # -------------------------------------------------------------------------------
    #   Function:   devices_create
    #   Usage:      Returns a Device Interface for Interfaces Array
    # -------------------------------------------------------------------------------
    def devices_create(self):

      try:

        # Let's Look at the config file and generate
        # our device from the interfaces configuration
        for node in self.config["Nodes"]:

          device_capability_model_id = self.device_capability_model_id.format(interfaceName=node["Name"])

          # check if we are excluding the interface?
          if self.ignore_interface_ids.count(node["InterfacelId"]) == 0:

            # We will iterate the number of devices we are going to create
            for x in range(self.number_of_devices):

              # Define the Device iteration suffix, it is
              # the base passed number with leading zeros for
              # a legnth of 3 (1-999) devices
              id_number_str = str(int(self.id_device) + x)
              id_number_str = id_number_str.zfill(3)

              device_name = self.device_name_prefix.format(nodeName=node["Name"], id=id_number_str)

              # The Device Asset scenario appends one interfaces per device id
              device_capability_model = self.create_device_capability_model(device_name, device_capability_model_id)
              device_capability_model["Interfaces"].append(self.create_device_interface(node["Name"], node["InterfacelId"], node["InterfaceInstanceName"]))

              self.devices_to_provision["Devices"]["Devices"].append(device_capability_model)
              self.devices_to_provision["Secrets"].append(self.create_device_connection(device_name, device_capability_model_id))

      except Exception as ex:
        self.logger.error("[ERROR] %s" % ex)
        self.logger.error("[TERMINATING] We encountered an error in CLASS::ProvisionDevices::devices_create()" )

      return

    # -------------------------------------------------------------------------------
    #   Function:   create_devices_to_provision
    #   Usage:      Returns a Devices Array
    # -------------------------------------------------------------------------------
    def create_devices_to_provision(self):
      newDeviceToProvisionArray = {
        "Devices": {
          "Devices": [
          ]
        }
        ,
        "Secrets": [
        ]
      }
      return newDeviceToProvisionArray

    # -------------------------------------------------------------------------------
    #   Function:   create_device_capability_model
    #   Usage:      Returns a Device Interface with the  Interfaces Array
    # -------------------------------------------------------------------------------
    def create_device_capability_model(self, DeviceName, DeviceCapabilityModelId):
      newDeviceCapabilityModel = {
        "Name": DeviceName,
        "DeviceType": self.model_type,
        "DeviceCapabilityModelId": DeviceCapabilityModelId,
        "Interfaces": [
        ],
        "LastProvisioned": str(datetime.datetime.now())
      }
      return newDeviceCapabilityModel

    # -------------------------------------------------------------------------------
    #   Function:   create_device_interface
    #   Usage:      Returns a Device Interface for Interfaces Array
    # -------------------------------------------------------------------------------
    def create_device_interface(self, name, Id, instantName):
      newInterface = {
        "Name": name,
        "InterfacelId": Id,
        "InterfaceInstanceName": instantName
      }
      return newInterface

    # -------------------------------------------------------------------------------
    #   Function:   create_device_connection
    #   Usage:      Returns a Device Interface for Interfaces Array
    # -------------------------------------------------------------------------------
    def create_device_connection(self, Name, DeviceCapabilityModelId):

      # Get device symmetric key
      device_symmetric_key = self.symmetrickey.compute_derived_symmetric_key(Name, self.secrets.get_device_secondary_key())

      newDeviceSecret = {
        "Name": Name,
        "DeviceCapabilityModelId": DeviceCapabilityModelId,
        "DeviceType": self.model_type,
        "AssignedHub": "",
        "DeviceSymmetricKey": device_symmetric_key,
        "LastProvisioned": str(datetime.datetime.now())
      }
      return newDeviceSecret
    async def provision_devices(self):

        # Make a working copy of the cache file
        devicescache = DevicesCache(self.logger)
        self.data = devicescache.data
        self.data["Devices"] = [
            x for x in devicescache.data["Devices"]
            if x["DeviceName"] == "Simulated Device"
        ]
        self.logger.info("[DEVICES] self.data Count %s" %
                         len(self.data["Devices"]))

        # load the secrets
        secrets = Secrets(self.logger)
        secrets.init()

        # Symetric Key for handling Device Specific SaS Keys
        symmetrickey = SymmetricKey(self.logger)

        try:

            # Gather the DCM Information
            device_id = self.config["DeviceName"].format(id=self.iddevice)
            dcm_id = self.config["DeviceCapabilityModelId"]
            device_capability_model = self.create_device_capability_model(
                device_id, dcm_id)
            self.logger.info("[DCM ID] %s" % dcm_id)
            self.logger.info("[DEVICE ID] %s" % device_id)
            self.logger.info("[DCM] %s" % device_capability_model)

            # Let's Look at the Config File and Generate
            # our Device from the OPC Server Configuration
            for node in self.nodes:
                device_interface = self.create_device_interface(
                    node["Name"], node["InterfacelId"],
                    node["InterfaceInstanceName"])
                device_capability_model["Interfaces"].append(device_interface)
                self.logger.info("[INTERFACE] %s" % device_interface)

            # Dump the Device Info
            self.logger.info("[DEVICE] MODEL %s" % device_capability_model)

            # Get a Device Specific Symetric Key
            device_symmetrickey = symmetrickey.compute_derived_symmetric_key(
                device_capability_model["DeviceName"],
                secrets.get_device_secondary_key())
            self.logger.info("[SYMETRIC KEY] %s" % device_symmetrickey)

            # Provision the Device
            self.logger.info("[PROVISIONING] %s" %
                             device_capability_model["DeviceName"])

            if not self.whatif:

                self.logger.info("[PROVISIONING HOST]: %s" %
                                 secrets.get_provisioning_host())

                provisioning_device_client = ProvisioningDeviceClient.create_from_symmetric_key(
                    provisioning_host=secrets.get_provisioning_host(),
                    registration_id=device_capability_model["DeviceName"],
                    id_scope=secrets.get_scope_id(),
                    symmetric_key=device_symmetrickey,
                    websockets=True)

                provisioning_device_client.provisioning_payload = '{"iotcModelId":"%s"}' % (
                    device_capability_model["DeviceCapabilityModelId"])
                registration_result = await provisioning_device_client.register(
                )
                device_capability_model["DeviceName"]
                self.device_secrets.append(
                    self.create_device_secret(
                        device_capability_model["DeviceName"],
                        registration_result.registration_state.assigned_hub,
                        device_symmetrickey))
                self.logger.info("[REGISTRATION RESULT] %s" %
                                 registration_result)

            self.data["Devices"].append(device_capability_model)

        except Exception as ex:
            self.logger.error("[ERROR] %s" % ex)
            self.logger.error(
                "[TERMINATING] We encountered an error provisioning device for OPC Server"
            )
            return

        # Update the Cache
        #if not self.whatif:
        self.data["DefaultDeviceName"] = device_capability_model["DeviceName"]
        devicescache.update_file(self.data)
        secrets.update_device_secrets(self.device_secrets)

        return