Beispiel #1
0
 def setUp(self) -> None:
     self.fiware_header = FiwareHeader(
         service=settings.FIWARE_SERVICE,
         service_path=settings.FIWARE_SERVICEPATH)
     clear_all(fiware_header=self.fiware_header,
               cb_url=settings.CB_URL,
               iota_url=settings.IOTA_JSON_URL)
     self.service_group1 = ServiceGroup(entity_type='Thing',
                                        resource='/iot/json',
                                        apikey=str(uuid4()))
     self.service_group2 = ServiceGroup(entity_type='OtherThing',
                                        resource='/iot/json',
                                        apikey=str(uuid4()))
     self.device = {
         "device_id": "test_device",
         "service": self.fiware_header.service,
         "service_path": self.fiware_header.service_path,
         "entity_name": "test_entity",
         "entity_type": "test_entity_type",
         "timezone": 'Europe/Berlin',
         "timestamp": None,
         "apikey": "1234",
         "endpoint": None,
         "transport": 'HTTP',
         "expressionLanguage": None
     }
     self.client = IoTAClient(
         url=settings.IOTA_JSON_URL,
         fiware_header=self.fiware_header)
Beispiel #2
0
    def setUp(self) -> None:
        self.fiware_header = FiwareHeader(
            service=settings.FIWARE_SERVICE,
            service_path=settings.FIWARE_SERVICEPATH)
        self.service_group_json = ServiceGroup(
            apikey=settings.FIWARE_SERVICEPATH.strip('/'),
            resource="/iot/json")
        self.service_group_ul = ServiceGroup(
            apikey=settings.FIWARE_SERVICEPATH.strip('/'), resource="/iot/d")

        # create a device configuration
        device_attr = DeviceAttribute(name='temperature',
                                      object_id='t',
                                      type="Number")
        device_command = DeviceCommand(name='heater', type="Boolean")

        self.device_json = Device(device_id='my_json_device',
                                  entity_name='my_json_device',
                                  entity_type='Thing',
                                  protocol='IoTA-JSON',
                                  transport='MQTT',
                                  apikey=self.service_group_json.apikey,
                                  attributes=[device_attr],
                                  commands=[device_command])

        self.device_ul = Device(device_id='my_ul_device',
                                entity_name='my_ul_device',
                                entity_type='Thing',
                                protocol='PDI-IoTA-UltraLight',
                                transport='MQTT',
                                apikey=self.service_group_ul.apikey,
                                attributes=[device_attr],
                                commands=[device_command])

        self.mqttc = IoTAMQTTClient()

        def on_connect(mqttc, obj, flags, rc):
            mqttc.logger.info("rc: " + str(rc))

        def on_connect_fail(mqttc, obj):
            mqttc.logger.info("Connect failed")

        def on_publish(mqttc, obj, mid):
            mqttc.logger.info("mid: " + str(mid))

        def on_subscribe(mqttc, obj, mid, granted_qos):
            mqttc.logger.info("Subscribed: " + str(mid) + " " +
                              str(granted_qos))

        def on_log(mqttc, obj, level, string):
            mqttc.logger.info(string)

        self.mqttc.on_connect = on_connect
        self.mqttc.on_connect_fail = on_connect_fail
        self.mqttc.on_publish = on_publish
        self.mqttc.on_subscribe = on_subscribe
        self.mqttc.on_log = on_log
Beispiel #3
0
    def add_service_group(self, service_group: Union[ServiceGroup, Dict]):
        """
        Registers a device service group with the client

        Args:
            service_group: Service group configuration

        Returns:
            None

        Raises:
            ValueError: if service group already exists
        """
        if isinstance(service_group, dict):
            service_group = ServiceGroup.parse_obj(service_group)
        assert isinstance(service_group, ServiceGroup), \
            "Invalid content for service group!"

        if self.service_groups.get(service_group.apikey, None) is None:
            pass
        else:
            raise ValueError("Service group already exists! %s",
                             service_group.apikey)
        # add service group configuration to the service group list
        self.service_groups[service_group.apikey] = service_group
Beispiel #4
0
 def update_group(self,
                  *,
                  service_group: ServiceGroup,
                  fields: Union[Set[str], List[str]] = None,
                  add: bool = True):
     """
     Modifies the information for a service group configuration, identified
     by the resource and apikey query parameters. Takes a service group body
     as the payload. The body does not have to be complete: for incomplete
     bodies, just the existing attributes will be updated
     
     Args:
         service_group (ServiceGroup): Service to update.
         fields: Fields of the service_group to update. If 'None' all allowed
         fields will be updated
         add:
     Returns:
         None
     """
     if fields:
         if isinstance(fields, list):
             fields = set(fields)
     else:
         fields = None
     url = urljoin(self.base_url, 'iot/services')
     headers = self.headers
     params = service_group.dict(include={'resource', 'apikey'})
     try:
         res = self.put(url=url,
                        headers=headers,
                        params=params,
                        data=service_group.json(
                            include=fields,
                            exclude={'service', 'subservice'},
                            exclude_unset=True))
         if res.ok:
             self.logger.info("ServiceGroup updated!")
         elif (res.status_code == 404) & (add is True):
             self.post_group(service_group=service_group)
         else:
             res.raise_for_status()
     except requests.RequestException as err:
         self.log_error(err=err, msg=None)
         raise
Beispiel #5
0
    def get_group(self, *, resource: str, apikey: str) -> ServiceGroup:
        """
        Retrieves service_group groups from the database based on resource and
        apikey
        Args:
            resource:
            apikey:
        Returns:

        """
        url = urljoin(self.base_url, 'iot/services')
        headers = self.headers
        params = {'resource': resource, 'apikey': apikey}

        try:
            res = self.get(url=url, headers=headers, params=params)
            if res.ok:
                return ServiceGroup(**res.json()['services'][0])
            res.raise_for_status()
        except requests.RequestException as err:
            self.log_error(err=err, msg=None)
            raise
Beispiel #6
0
    def update_service_group(self, service_group: Union[ServiceGroup, Dict]):
        """
        Updates a registered service group configuration. There is no
        opportunity to only partially update the device. Hence, your service
        group model should be complete.

        Args:
            service_group: Service group configuration

        Returns:
            None

        Raises:
            KeyError: if service group not yet registered
        """
        if isinstance(service_group, dict):
            service_group = ServiceGroup.parse_obj(service_group)
        assert isinstance(service_group, ServiceGroup), \
            "Invalid content for service group"

        if self.service_groups.get(service_group.apikey, None) is None:
            raise KeyError("Service group not found! %s", service_group.apikey)
        # add service group configuration to the service group list
        self.service_groups[service_group.apikey] = service_group
Beispiel #7
0
    # them to Fiware is:
    iota_client.patch_device(my_device)
    #
    # ## 3.5 Delete a device
    iota_client.delete_device(device_id=device2.device_id)

    # # 4 Service Groups
    #
    # For some services, there will be no need to provision individual devices,
    # but it will make more sense to provision different service groups,
    # each of one mapped to a different type of entity in the context broker
    # https://iotagent-node-lib.readthedocs.io/en/latest/api/index.html#service-group-api

    # ## 4.1. Create a service group
    service_group1 = ServiceGroup(entity_type='Thing',
                                  resource='/iot/json',
                                  apikey=str(uuid4()))
    iota_client.post_groups(service_groups=[service_group1])

    # ## 4.2 Access a service group
    #
    # All groups:
    retrieved_groups = iota_client.get_group_list()
    # a specific group
    my_group = iota_client.get_group(resource='/iot/json',
                                     apikey=service_group1.apikey)

    # ## 4.3 Delete a service group
    iota_client.delete_group(resource='/iot/json',
                             apikey=service_group1.apikey)
Beispiel #8
0
    def test_fiware_safe_fields(self):
        """
        Tests all fields of models/ngsi_v2/iot.py that have a regex to
        be FIWARE safe
        Returns:
            None
        """

        from pydantic.error_wrappers import ValidationError

        valid_strings: List[str] = ["name", "test123", "3_:strange-Name!"]
        invalid_strings: List[str] = [
            "my name", "Test?", "#False", "/notvalid"
        ]

        special_strings: List[str] = ["id", "type", "geo:location"]

        # Test if all needed fields, detect all invalid strings
        for string in invalid_strings:
            self.assertRaises(ValidationError,
                              IoTABaseAttribute,
                              name=string,
                              type="name",
                              entity_name="name",
                              entity_type="name")
            self.assertRaises(ValidationError,
                              IoTABaseAttribute,
                              name="name",
                              type=string,
                              entity_name="name",
                              entity_type="name")
            self.assertRaises(ValidationError,
                              IoTABaseAttribute,
                              name="name",
                              type="name",
                              entity_name=string,
                              entity_type="name")
            self.assertRaises(ValidationError,
                              IoTABaseAttribute,
                              name="name",
                              type="name",
                              entity_name="name",
                              entity_type=string)

            self.assertRaises(ValidationError,
                              DeviceCommand,
                              name=string,
                              type="name")
            self.assertRaises(ValidationError,
                              ServiceGroup,
                              entity_type=string,
                              resource="",
                              apikey="")

            self.assertRaises(ValidationError,
                              Device,
                              device_id="",
                              entity_name=string,
                              entity_type="name",
                              transport=TransportProtocol.HTTP)
            self.assertRaises(ValidationError,
                              Device,
                              device_id="",
                              entity_name="name",
                              entity_type=string,
                              transport=TransportProtocol.HTTP)

        # Test if all needed fields, do not trow wrong errors
        for string in valid_strings:
            IoTABaseAttribute(name=string,
                              type=string,
                              entity_name=string,
                              entity_type=string)
            DeviceCommand(name=string, type="name")
            ServiceGroup(entity_type=string, resource="", apikey="")
            Device(device_id="",
                   entity_name=string,
                   entity_type=string,
                   transport=TransportProtocol.HTTP)

        # Test for the special-string protected field if all strings are blocked
        for string in special_strings:
            with self.assertRaises(ValidationError):
                IoTABaseAttribute(name=string,
                                  type="name",
                                  entity_name="name",
                                  entity_type="name")
            with self.assertRaises(ValidationError):
                IoTABaseAttribute(name="name",
                                  type=string,
                                  entity_name="name",
                                  entity_type="name")
            with self.assertRaises(ValidationError):
                DeviceCommand(name=string, type="name")

        # Test for the normal protected field if all strings are allowed
        for string in special_strings:
            IoTABaseAttribute(name="name",
                              type="name",
                              entity_name=string,
                              entity_type=string)
            ServiceGroup(entity_type=string, resource="", apikey="")
            Device(device_id="",
                   entity_name=string,
                   entity_type=string,
                   transport=TransportProtocol.HTTP)
                 device.json(indent=2))

    # ## 2.2 Device Submission
    #
    # Send device configuration to FIWARE via the IoT-Agent. We use the general
    # ngsiv2 httpClient for this.
    # This will automatically create an data entity in the context broker and
    # make the device with it. The name of the entity will be our device_id in
    # this case for more complex configuration you need to set the entity_name
    # and entity_type in the previous Device-Model

    # in order to change the apikey of out devices for incoming data we need to
    # create a service group that our device weill be we attached to
    # NOTE: This is important in order to adjust the apikey for incoming traffic
    service_group = ServiceGroup(service=fiware_header.service,
                                 subservice=fiware_header.service_path,
                                 apikey=SERVICE_GROUP_APIKEY,
                                 resource='/iot/json')

    # create the Http client node that once sent the device cannot be posted
    # again and you need to use the update command
    config = HttpClientConfig(cb_url=CB_URL, iota_url=IOTA_URL)
    client = HttpClient(fiware_header=fiware_header, config=config)
    client.iota.post_group(service_group=service_group, update=True)
    client.iota.post_device(device=device, update=True)

    # ## 2.3 Check for correctness
    # check if the device is correctly configured. You will notice that
    # unfortunately the iot API does not return all the metadata. However,
    # it will still appear in the context-entity
    device = client.iota.get_device(device_id=device.device_id)
    logging.info(f"{device.json(indent=2)}")
logger = logging.getLogger(__name__)

if __name__ == '__main__':

    # # 1 Setup
    #
    # ## 1.1 FiwareHeader
    #
    # Since we want to use the multi-tenancy concept of fiware we always start
    # with create a fiware header
    fiware_header = FiwareHeader(service=SERVICE, service_path=SERVICE_PATH)

    # ## 1.2 Device configuration
    #
    service_group_json = ServiceGroup(apikey=SERVICE_PATH.strip('/'),
                                      resource="/iot/json")
    service_group_ul = ServiceGroup(apikey=SERVICE_PATH.strip('/'),
                                    resource="/iot/d")

    device_attr = DeviceAttribute(name='temperature',
                                  object_id='t',
                                  type="Number")
    device_command = DeviceCommand(name='heater', type="Boolean")

    device_json = Device(device_id='my_json_device',
                         entity_name='my_json_device',
                         entity_type='Thing',
                         protocol='IoTA-JSON',
                         transport='MQTT',
                         apikey=service_group_json.apikey,
                         attributes=[device_attr],
    clear_context_broker(url=CB_URL, fiware_header=fiware_header)
    clear_iot_agent(url=IOTA_URL, fiware_header=fiware_header)

    # instantiate simulation model
    sim_model = SimulationModel(t_start=T_SIM_START,
                                t_end=T_SIM_END,
                                temp_max=TEMPERATURE_MAX,
                                temp_min=TEMPERATURE_MIN,
                                temp_start=TEMPERATURE_ZONE_START)

    # define lists to store historical data
    history_weather_station = []
    history_zone_temperature_sensor = []

    # Create a service group and add it to your
    service_group = ServiceGroup(apikey=APIKEY, resource="/iot/json")

    # ToDo: create two IoTA-MQTT devices for the weather station and the zone
    #  temperature sensor. Also add the simulation time as `active attribute`
    #  to each device!
    #
    # create the weather station device
    # create the simtime attribute and add during device creation
    t_sim = DeviceAttribute(name='simtime', object_id='t_sim', type="Number")

    weather_station = Device(device_id='device:001',
                             entity_name='urn:ngsi-ld:WeatherStation:001',
                             entity_type='WeatherStation',
                             protocol='IoTA-JSON',
                             transport='MQTT',
                             apikey=APIKEY,
Beispiel #12
0
    def test_command_with_mqtt(self):
        """
        Test if a command can be send to a device in FIWARE

        To test this a virtual device is created and provisioned to FIWARE and
        a hosted MQTT Broker

        This test only works if the address of a running MQTT Broker is given in
        the environment ('MQTT_BROKER_URL')

        The main part of this test was taken out of the iot_mqtt_example, see
        there for a complete documentation
        """
        mqtt_broker_url = settings.MQTT_BROKER_URL

        device_attr1 = DeviceAttribute(name='temperature',
                                       object_id='t',
                                       type="Number",
                                       metadata={
                                           "unit":
                                               {"type": "Unit",
                                                "value": {
                                                    "name": {
                                                        "type": "Text",
                                                        "value": "degree "
                                                                 "Celsius"
                                                    }
                                                }}
                                       })

        # creating a static attribute that holds additional information
        static_device_attr = StaticDeviceAttribute(name='info',
                                                   type="Text",
                                                   value="Filip example for "
                                                         "virtual IoT device")
        # creating a command that the IoT device will liston to
        device_command = DeviceCommand(name='heater', type="Boolean")

        device = Device(device_id='MyDevice',
                        entity_name='MyDevice',
                        entity_type='Thing2',
                        protocol='IoTA-JSON',
                        transport='MQTT',
                        apikey=settings.FIWARE_SERVICEPATH.strip('/'),
                        attributes=[device_attr1],
                        static_attributes=[static_device_attr],
                        commands=[device_command])

        device_attr2 = DeviceAttribute(name='humidity',
                                       object_id='h',
                                       type="Number",
                                       metadata={
                                           "unitText":
                                               {"value": "percent",
                                                "type": "Text"}})

        device.add_attribute(attribute=device_attr2)

        # Send device configuration to FIWARE via the IoT-Agent. We use the
        # general ngsiv2 httpClient for this.
        service_group = ServiceGroup(
            service=self.fiware_header.service,
            subservice=self.fiware_header.service_path,
            apikey=settings.FIWARE_SERVICEPATH.strip('/'),
            resource='/iot/json')

        # create the Http client node that once sent the device cannot be posted
        # again and you need to use the update command
        config = HttpClientConfig(cb_url=settings.CB_URL,
                                  iota_url=settings.IOTA_JSON_URL)
        client = HttpClient(fiware_header=self.fiware_header, config=config)
        client.iota.post_group(service_group=service_group, update=True)
        client.iota.post_device(device=device, update=True)

        time.sleep(0.5)

        # check if the device is correctly configured. You will notice that
        # unfortunately the iot API does not return all the metadata. However,
        # it will still appear in the context-entity
        device = client.iota.get_device(device_id=device.device_id)

        # check if the data entity is created in the context broker
        entity = client.cb.get_entity(entity_id=device.device_id,
                                      entity_type=device.entity_type)

        # create a mqtt client that we use as representation of an IoT device
        # following the official documentation of Paho-MQTT.
        # https://www.eclipse.org/paho/index.php?page=clients/python/
        # docs/index.php

        # The callback for when the mqtt client receives a CONNACK response from
        # the server. All callbacks need to have this specific arguments,
        # Otherwise the client will not be able to execute them.
        def on_connect(client, userdata, flags, reasonCode, properties=None):
            client.subscribe(f"/{device.apikey}/{device.device_id}/cmd")

        # Callback when the command topic is succesfully subscribed
        def on_subscribe(client, userdata, mid, granted_qos, properties=None):
            pass

        # NOTE: We need to use the apikey of the service-group to send the
        # message to the platform
        def on_message(client, userdata, msg):
            data = json.loads(msg.payload)
            res = {k: v for k, v in data.items()}
            client.publish(topic=f"/json/{service_group.apikey}"
                                 f"/{device.device_id}/cmdexe",
                           payload=json.dumps(res))

        def on_disconnect(client, userdata, reasonCode, properties=None):
            pass

        mqtt_client = mqtt.Client(client_id="filip-test",
                                  userdata=None,
                                  protocol=mqtt.MQTTv5,
                                  transport="tcp")

        # add our callbacks to the client
        mqtt_client.on_connect = on_connect
        mqtt_client.on_subscribe = on_subscribe
        mqtt_client.on_message = on_message
        mqtt_client.on_disconnect = on_disconnect

        # extract the form the environment
        mqtt_broker_url = urlparse(mqtt_broker_url)

        mqtt_client.connect(host=mqtt_broker_url.hostname,
                            port=mqtt_broker_url.port,
                            keepalive=60,
                            bind_address="",
                            bind_port=0,
                            clean_start=mqtt.MQTT_CLEAN_START_FIRST_ONLY,
                            properties=None)
        # create a non-blocking thread for mqtt communication
        mqtt_client.loop_start()

        for attr in device.attributes:
            mqtt_client.publish(
                topic=f"/json/{service_group.apikey}/{device.device_id}/attrs",
                payload=json.dumps({attr.object_id: random.randint(0, 9)}))

        time.sleep(5)
        entity = client.cb.get_entity(entity_id=device.device_id,
                                      entity_type=device.entity_type)

        # create and send a command via the context broker
        context_command = NamedCommand(name=device_command.name,
                                       value=False)
        client.cb.post_command(entity_id=entity.id,
                               entity_type=entity.type,
                               command=context_command)

        time.sleep(5)
        # check the entity the command attribute should now show OK
        entity = client.cb.get_entity(entity_id=device.device_id,
                                      entity_type=device.entity_type)

        # The main part of this test, for all this setup was done
        self.assertEqual("OK", entity.heater_status.value)

        # close the mqtt listening thread
        mqtt_client.loop_stop()
        # disconnect the mqtt device
        mqtt_client.disconnect()
Beispiel #13
0
class TestMQTTClient(unittest.TestCase):
    """
    Test case for IoTAMQTTClient
    """
    def setUp(self) -> None:
        self.fiware_header = FiwareHeader(
            service=settings.FIWARE_SERVICE,
            service_path=settings.FIWARE_SERVICEPATH)
        self.service_group_json = ServiceGroup(
            apikey=settings.FIWARE_SERVICEPATH.strip('/'),
            resource="/iot/json")
        self.service_group_ul = ServiceGroup(
            apikey=settings.FIWARE_SERVICEPATH.strip('/'), resource="/iot/d")

        # create a device configuration
        device_attr = DeviceAttribute(name='temperature',
                                      object_id='t',
                                      type="Number")
        device_command = DeviceCommand(name='heater', type="Boolean")

        self.device_json = Device(device_id='my_json_device',
                                  entity_name='my_json_device',
                                  entity_type='Thing',
                                  protocol='IoTA-JSON',
                                  transport='MQTT',
                                  apikey=self.service_group_json.apikey,
                                  attributes=[device_attr],
                                  commands=[device_command])

        self.device_ul = Device(device_id='my_ul_device',
                                entity_name='my_ul_device',
                                entity_type='Thing',
                                protocol='PDI-IoTA-UltraLight',
                                transport='MQTT',
                                apikey=self.service_group_ul.apikey,
                                attributes=[device_attr],
                                commands=[device_command])

        self.mqttc = IoTAMQTTClient()

        def on_connect(mqttc, obj, flags, rc):
            mqttc.logger.info("rc: " + str(rc))

        def on_connect_fail(mqttc, obj):
            mqttc.logger.info("Connect failed")

        def on_publish(mqttc, obj, mid):
            mqttc.logger.info("mid: " + str(mid))

        def on_subscribe(mqttc, obj, mid, granted_qos):
            mqttc.logger.info("Subscribed: " + str(mid) + " " +
                              str(granted_qos))

        def on_log(mqttc, obj, level, string):
            mqttc.logger.info(string)

        self.mqttc.on_connect = on_connect
        self.mqttc.on_connect_fail = on_connect_fail
        self.mqttc.on_publish = on_publish
        self.mqttc.on_subscribe = on_subscribe
        self.mqttc.on_log = on_log

    def test_original_functionality(self):
        """
        demonstrate normal client behavior
        For additional examples on how to use the client please check:
        https://github.com/eclipse/paho.mqtt.python/tree/master/examples
        define callbacks methods"""
        first_topic = f"/filip/{settings.FIWARE_SERVICEPATH.strip('/')}/first"
        second_topic = f"/filip/{settings.FIWARE_SERVICEPATH.strip('/')}/second"
        first_payload = "filip_test_1"
        second_payload = "filip_test_2"

        def on_message_first(mqttc, obj, msg, properties=None):
            self.assertEqual(msg.payload.decode('utf-8'), first_payload)

        def on_message_second(mqttc, obj, msg, properties=None):
            self.assertEqual(msg.payload.decode('utf-8'), second_payload)

        self.mqttc.message_callback_add(sub=first_topic,
                                        callback=on_message_first)
        self.mqttc.message_callback_add(sub=second_topic,
                                        callback=on_message_second)
        mqtt_broker_url = urlparse(settings.MQTT_BROKER_URL)

        self.mqttc.connect(host=mqtt_broker_url.hostname,
                           port=mqtt_broker_url.port,
                           keepalive=60,
                           bind_address="",
                           bind_port=0,
                           clean_start=MQTT_CLEAN_START_FIRST_ONLY,
                           properties=None)
        self.mqttc.subscribe(topic=first_topic)

        # create a non blocking loop
        self.mqttc.loop_start()
        self.mqttc.publish(topic=first_topic, payload="filip_test")

        # add additional subscription to connection
        self.mqttc.subscribe(topic=second_topic)
        self.mqttc.publish(topic=second_topic, payload="filip_test")

        # remove subscriptions and callbacks
        self.mqttc.message_callback_remove(first_topic)
        self.mqttc.message_callback_remove(second_topic)
        self.mqttc.unsubscribe(first_topic)
        self.mqttc.unsubscribe(second_topic)

        # stop network loop and disconnect cleanly
        self.mqttc.loop_stop()
        self.mqttc.disconnect()

    def test_init(self):
        devices = [self.device_json, self.device_ul]
        mqttc = IoTAMQTTClient(devices=devices,
                               service_groups=[self.service_group_json])
        self.assertListEqual(mqttc.devices, devices)

    def test_service_groups(self):
        self.mqttc.add_service_group(service_group=self.service_group_json)
        with self.assertRaises(AssertionError):
            self.mqttc.add_service_group(service_group="SomethingRandom")
        with self.assertRaises(ValueError):
            self.mqttc.add_service_group(
                service_group=self.service_group_json.dict())

        self.assertEqual(
            self.service_group_json,
            self.mqttc.get_service_group(self.service_group_json.apikey))

        self.mqttc.update_service_group(service_group=self.service_group_json)

        with self.assertRaises(KeyError):
            self.mqttc.update_service_group(
                service_group=self.service_group_json.copy(
                    update={'apikey': 'someOther'}))

        with self.assertRaises(KeyError):
            self.mqttc.delete_service_group(apikey="SomethingRandom")

        self.mqttc.delete_service_group(apikey=self.service_group_json.apikey)

    def test_devices(self):
        with self.assertRaises(ValueError):
            self.mqttc.devices = [self.device_ul, self.device_ul]

        self.mqttc.add_device(device=self.device_json)
        with self.assertRaises(ValueError):
            self.mqttc.add_device(device=self.device_json)
        self.mqttc.get_device(self.device_json.device_id)

        self.mqttc.update_device(device=self.device_json)
        with self.assertRaises(KeyError):
            self.mqttc.update_device(device=self.device_json.copy(
                update={'device_id': "somethingRandom"}))

        self.mqttc.delete_device(device_id=self.device_json.device_id)

    @clean_test(fiware_service=settings.FIWARE_SERVICE,
                fiware_servicepath=settings.FIWARE_SERVICEPATH,
                cb_url=settings.CB_URL,
                iota_url=settings.IOTA_JSON_URL)
    def test_add_command_callback_json(self):
        """
        Test for receiving commands for a specific device
        Returns:
            None
        """
        for group in self.mqttc.service_groups:
            self.mqttc.delete_service_group(group.apikey)

        for device in self.mqttc.devices:
            self.mqttc.delete_device(device.device_id)

        def on_command(client, obj, msg):
            apikey, device_id, payload = \
                client.get_encoder(PayloadProtocol.IOTA_JSON).decode_message(
                    msg=msg)

            # acknowledge a command. Here command are usually single
            # messages. The first key is equal to the commands name.
            client.publish(device_id=device_id,
                           command_name=next(iter(payload)),
                           payload=payload)

        self.mqttc.add_service_group(self.service_group_json)
        self.mqttc.add_device(self.device_json)
        self.mqttc.add_command_callback(device_id=self.device_json.device_id,
                                        callback=on_command)

        from filip.clients.ngsi_v2 import HttpClient, HttpClientConfig
        httpc_config = HttpClientConfig(cb_url=settings.CB_URL,
                                        iota_url=settings.IOTA_JSON_URL)
        httpc = HttpClient(fiware_header=self.fiware_header,
                           config=httpc_config)
        httpc.iota.post_group(service_group=self.service_group_json,
                              update=True)
        httpc.iota.post_device(device=self.device_json, update=True)

        mqtt_broker_url = urlparse(settings.MQTT_BROKER_URL)

        self.mqttc.connect(host=mqtt_broker_url.hostname,
                           port=mqtt_broker_url.port,
                           keepalive=60,
                           bind_address="",
                           bind_port=0,
                           clean_start=MQTT_CLEAN_START_FIRST_ONLY,
                           properties=None)
        self.mqttc.subscribe()

        entity = httpc.cb.get_entity(entity_id=self.device_json.device_id,
                                     entity_type=self.device_json.entity_type)
        context_command = NamedCommand(name=self.device_json.commands[0].name,
                                       value=False)
        self.mqttc.loop_start()

        httpc.cb.post_command(entity_id=entity.id,
                              entity_type=entity.type,
                              command=context_command)

        time.sleep(2)
        # close the mqtt listening thread
        self.mqttc.loop_stop()
        # disconnect the mqtt device
        self.mqttc.disconnect()

        entity = httpc.cb.get_entity(entity_id=self.device_json.device_id,
                                     entity_type=self.device_json.entity_type)

        # The main part of this test, for all this setup was done
        self.assertEqual("OK", entity.heater_status.value)

    @clean_test(fiware_service=settings.FIWARE_SERVICE,
                fiware_servicepath=settings.FIWARE_SERVICEPATH,
                cb_url=settings.CB_URL,
                iota_url=settings.IOTA_JSON_URL)
    def test_publish_json(self):
        """
        Test for receiving commands for a specific device
        Returns:
            None
        """
        for group in self.mqttc.service_groups:
            self.mqttc.delete_service_group(group.apikey)

        for device in self.mqttc.devices:
            self.mqttc.delete_device(device.device_id)

        self.mqttc.add_service_group(self.service_group_json)
        self.mqttc.add_device(self.device_json)

        from filip.clients.ngsi_v2 import HttpClient, HttpClientConfig
        httpc_config = HttpClientConfig(cb_url=settings.CB_URL,
                                        iota_url=settings.IOTA_JSON_URL)
        httpc = HttpClient(fiware_header=self.fiware_header,
                           config=httpc_config)
        httpc.iota.post_group(service_group=self.service_group_json,
                              update=True)
        httpc.iota.post_device(device=self.device_json, update=True)

        mqtt_broker_url = urlparse(settings.MQTT_BROKER_URL)

        self.mqttc.connect(host=mqtt_broker_url.hostname,
                           port=mqtt_broker_url.port,
                           keepalive=60,
                           bind_address="",
                           bind_port=0,
                           clean_start=MQTT_CLEAN_START_FIRST_ONLY,
                           properties=None)
        self.mqttc.loop_start()

        payload = randrange(0, 100, 1) / 1000
        self.mqttc.publish(
            device_id=self.device_json.device_id,
            payload={self.device_json.attributes[0].object_id: payload})
        time.sleep(1)
        entity = httpc.cb.get_entity(entity_id=self.device_json.device_id,
                                     entity_type=self.device_json.entity_type)
        self.assertEqual(payload, entity.temperature.value)

        payload = randrange(0, 100, 1) / 1000
        self.mqttc.publish(device_id=self.device_json.device_id,
                           attribute_name="temperature",
                           payload=payload)
        time.sleep(1)
        entity = httpc.cb.get_entity(entity_id=self.device_json.device_id,
                                     entity_type=self.device_json.entity_type)
        self.assertEqual(payload, entity.temperature.value)

        # These test do currently not workt due to time stamp parsing
        # self.mqttc.publish(device_id=self.device_json.device_id,
        #                    payload={self.device_json.attributes[
        #                   0].object_id: 50},
        #                    timestamp=True)
        # time.sleep(1)
        # entity = httpc.cb.get_entity(entity_id=self.device_json.device_id,
        #                              entity_type=self.device_json.entity_type)
        # self.assertEqual(50, entity.temperature.value)
        #
        # from datetime import datetime, timedelta
        # timestamp = datetime.now() + timedelta(days=1)
        # timestamp = timestamp.astimezone().isoformat()
        # self.mqttc.publish(device_id=self.device_json.device_id,
        #                    payload={self.device_json.attributes[
        #                   0].object_id: 60,
        #                             'timeInstant': timestamp})
        # time.sleep(1)
        # entity = httpc.cb.get_entity(entity_id=self.device_json.device_id,
        #                              entity_type=self.device_json.entity_type)
        # self.assertEqual(60, entity.temperature.value)
        # self.assertEqual(timestamp, entity.TimeInstant.value)
        #
        # print(entity.json(indent=2))

        # close the mqtt listening thread
        self.mqttc.loop_stop()
        # disconnect the mqtt device
        self.mqttc.disconnect()

    @clean_test(fiware_service=settings.FIWARE_SERVICE,
                fiware_servicepath=settings.FIWARE_SERVICEPATH,
                cb_url=settings.CB_URL,
                iota_url=settings.IOTA_UL_URL)
    def test_add_command_callback_ultralight(self):
        """
        Test for receiving commands for a specific device
        Returns:
            None
        """
        for group in self.mqttc.service_groups:
            self.mqttc.delete_service_group(group.apikey)

        for device in self.mqttc.devices:
            self.mqttc.delete_device(device.device_id)

        def on_command(client, obj, msg):
            apikey, device_id, payload = \
                client.get_encoder(PayloadProtocol.IOTA_UL).decode_message(
                    msg=msg)

            # acknowledge a command. Here command are usually single
            # messages. The first key is equal to the commands name.
            client.publish(device_id=device_id,
                           command_name=next(iter(payload)),
                           payload={'heater': True})

        self.mqttc.add_service_group(self.service_group_ul)
        self.mqttc.add_device(self.device_ul)
        self.mqttc.add_command_callback(device_id=self.device_ul.device_id,
                                        callback=on_command)

        from filip.clients.ngsi_v2 import HttpClient, HttpClientConfig
        httpc_config = HttpClientConfig(cb_url=settings.CB_URL,
                                        iota_url=settings.IOTA_UL_URL)
        httpc = HttpClient(fiware_header=self.fiware_header,
                           config=httpc_config)
        httpc.iota.post_group(service_group=self.service_group_ul)
        httpc.iota.post_device(device=self.device_ul, update=True)

        mqtt_broker_url = urlparse(settings.MQTT_BROKER_URL)

        self.mqttc.connect(host=mqtt_broker_url.hostname,
                           port=mqtt_broker_url.port,
                           keepalive=60,
                           bind_address="",
                           bind_port=0,
                           clean_start=MQTT_CLEAN_START_FIRST_ONLY,
                           properties=None)
        self.mqttc.subscribe()

        entity = httpc.cb.get_entity(entity_id=self.device_ul.device_id,
                                     entity_type=self.device_ul.entity_type)
        context_command = NamedCommand(name=self.device_ul.commands[0].name,
                                       value=False)
        self.mqttc.loop_start()

        httpc.cb.post_command(entity_id=entity.id,
                              entity_type=entity.type,
                              command=context_command)

        time.sleep(5)
        # close the mqtt listening thread
        self.mqttc.loop_stop()
        # disconnect the mqtt device
        self.mqttc.disconnect()

        entity = httpc.cb.get_entity(entity_id=self.device_ul.device_id,
                                     entity_type=self.device_ul.entity_type)

        # The main part of this test, for all this setup was done
        self.assertEqual("OK", entity.heater_status.value)

    @clean_test(fiware_service=settings.FIWARE_SERVICE,
                fiware_servicepath=settings.FIWARE_SERVICEPATH,
                cb_url=settings.CB_URL,
                iota_url=settings.IOTA_UL_URL)
    def test_publish_ultralight(self):
        """
        Test for receiving commands for a specific device
        Returns:
            None
        """
        for group in self.mqttc.service_groups:
            self.mqttc.delete_service_group(group.apikey)

        for device in self.mqttc.devices:
            self.mqttc.delete_device(device.device_id)

        self.mqttc.add_service_group(self.service_group_ul)
        self.mqttc.add_device(self.device_ul)

        from filip.clients.ngsi_v2 import HttpClient, HttpClientConfig
        httpc_config = HttpClientConfig(cb_url=settings.CB_URL,
                                        iota_url=settings.IOTA_UL_URL)
        httpc = HttpClient(fiware_header=self.fiware_header,
                           config=httpc_config)
        httpc.iota.post_group(service_group=self.service_group_ul, update=True)
        httpc.iota.post_device(device=self.device_ul, update=True)

        time.sleep(0.5)

        mqtt_broker_url = urlparse(settings.MQTT_BROKER_URL)

        self.mqttc.connect(host=mqtt_broker_url.hostname,
                           port=mqtt_broker_url.port,
                           keepalive=60,
                           bind_address="",
                           bind_port=0,
                           clean_start=MQTT_CLEAN_START_FIRST_ONLY,
                           properties=None)
        self.mqttc.loop_start()

        payload = randrange(0, 100, 1) / 1000
        self.mqttc.publish(
            device_id=self.device_ul.device_id,
            payload={self.device_ul.attributes[0].object_id: payload})
        time.sleep(1)
        entity = httpc.cb.get_entity(entity_id=self.device_ul.device_id,
                                     entity_type=self.device_ul.entity_type)
        self.assertEqual(payload, entity.temperature.value)

        payload = randrange(0, 100, 1) / 1000
        self.mqttc.publish(device_id=self.device_ul.device_id,
                           attribute_name="temperature",
                           payload=payload)
        time.sleep(1)
        entity = httpc.cb.get_entity(entity_id=self.device_ul.device_id,
                                     entity_type=self.device_ul.entity_type)
        self.assertEqual(payload, entity.temperature.value)

        # These test do currently not workt due to time stamp parsing
        # self.mqttc.publish(device_id=self.device_ul.device_id,
        #                    payload={self.device_ul.attributes[0].object_id:
        #                   50},
        #                    timestamp=True)
        # time.sleep(1)
        # entity = httpc.cb.get_entity(entity_id=self.device_ul.device_id,
        #                              entity_type=self.device_ul.entity_type)
        # self.assertEqual(50, entity.temperature.value)
        #
        # from datetime import datetime, timedelta
        # timestamp = datetime.now() + timedelta(days=1)
        # timestamp = timestamp.astimezone().isoformat()
        # self.mqttc.publish(device_id=self.device_ul.device_id,
        #                    payload={self.device_ul.attributes[0].object_id:
        #                    60,
        #                             'timeInstant': timestamp})
        # time.sleep(1)
        # entity = httpc.cb.get_entity(entity_id=self.device_ul.device_id,
        #                              entity_type=self.device_ul.entity_type)
        # self.assertEqual(60, entity.temperature.value)
        # self.assertEqual(timestamp, entity.TimeInstant.value)
        #
        # print(entity.json(indent=2))

        # close the mqtt listening thread
        self.mqttc.loop_stop()
        # disconnect the mqtt device
        self.mqttc.disconnect()

    def tearDown(self) -> None:
        """
        Cleanup test server
        """
        clear_all(fiware_header=self.fiware_header,
                  cb_url=settings.CB_URL,
                  iota_url=[settings.IOTA_JSON_URL, settings.IOTA_UL_URL])