def test_metadata(self): """ Test for metadata works but the api of iot agent-json seems not working correctly Returns: None """ metadata = {"accuracy": {"type": "Text", "value": "+-5%"}} attr = DeviceAttribute(name="temperature", object_id="temperature", type="Number", metadata=metadata) device = Device(**self.device) device.device_id = "device_with_meta" device.add_attribute(attribute=attr) logger.info(device.json(indent=2)) with IoTAClient( url=settings.IOTA_JSON_URL, fiware_header=self.fiware_header) as client: client.post_device(device=device) logger.info(client.get_device(device_id=device.device_id).json( indent=2, exclude_unset=True)) with ContextBrokerClient( url=settings.CB_URL, fiware_header=self.fiware_header) as client: logger.info(client.get_entity(entity_id=device.entity_name).json( indent=2))
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_device_endpoints(self): """ Test device creation """ with IoTAClient( url=settings.IOTA_JSON_URL, fiware_header=self.fiware_header) as client: client.get_device_list() device = Device(**self.device) attr = DeviceAttribute(name='temperature', object_id='t', type='Number', entity_name='test') attr_command = DeviceCommand(name='open') attr_lazy = LazyDeviceAttribute(name='pressure', object_id='p', type='Text', entity_name='pressure') attr_static = StaticDeviceAttribute(name='hasRoom', type='Relationship', value='my_partner_id') device.add_attribute(attr) device.add_attribute(attr_command) device.add_attribute(attr_lazy) device.add_attribute(attr_static) client.post_device(device=device) device_res = client.get_device(device_id=device.device_id) self.assertEqual(device.dict(exclude={'service', 'service_path', 'timezone'}), device_res.dict(exclude={'service', 'service_path', 'timezone'})) self.assertEqual(self.fiware_header.service, device_res.service) self.assertEqual(self.fiware_header.service_path, device_res.service_path)
# These attributes represent static information (as names) and are # mirrored 1:1 device2.add_attribute( StaticDeviceAttribute(name="address", type=DataType.TEXT, value="Lichtenhof 3")) # ### 2.2.2 DeviceAttribute # # These attributes represent a live information of the device. # The value can be read by accessing the mirrored attribute in the # context entity. # It is differentiated between two kinds: # # DeviceAttributes, always keep the value in the context entity up-to-date # (polling) device2.add_attribute(DeviceAttribute(name="temperature", object_id="t")) # LazyDeviceAttributes, only update the value in the entity if it is # accessed (event based) device2.add_attribute(LazyDeviceAttribute(name="temperature")) # ### 2.2.3 Commands # # Commands can be executed to let the device execute some action device2.add_attribute(DeviceCommand(name="on")) # In the context entity three attributes are added for a command: # - Command (name): used to execute # - Status (name_status): used to inform about execution status # - Info/Result (name_info): used to inform about the final result # # 3 Interact with Fiware #
# # ## 2.1 Device creation # # First we create our device configuration using the models provided for # filip.models.ngsi_v2.iot # creating an attribute for incoming measurements from e.g. a sensor we do # add the metadata for units here using the unit models. You will later # notice that the library automatically will augment the provided # information about units. device_attr1 = DeviceAttribute(name='temperature', object_id='t', type="Number", metadata={ "unit": { "type": "Unit", "value": { "name": "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') # NOTE: You need to know that if you define an apikey for a single device it
def test_patch_device(self): """ Test the methode: patch_device of the iota client """ device = Device(**self.device) device.endpoint = "http://test.com" device.transport = "MQTT" device.add_attribute(DeviceAttribute( name="Att1", object_id="o1", type=DataType.STRUCTUREDVALUE)) device.add_attribute(StaticDeviceAttribute( name="Stat1", value="test", type=DataType.STRUCTUREDVALUE)) device.add_attribute(StaticDeviceAttribute( name="Stat2", value="test", type=DataType.STRUCTUREDVALUE)) device.add_command(DeviceCommand(name="Com1")) # use patch_device to post self.client.patch_device(device=device) cb_client = ContextBrokerClient(url=settings.CB_URL, fiware_header=self.fiware_header) # test if attributes exists correctly live_entity = cb_client.get_entity(entity_id=device.entity_name) live_entity.get_attribute("Att1") live_entity.get_attribute("Com1") live_entity.get_attribute("Com1_info") live_entity.get_attribute("Com1_status") self.assertEqual(live_entity.get_attribute("Stat1").value, "test") # change device attributes and update device.get_attribute("Stat1").value = "new_test" device.delete_attribute(device.get_attribute("Stat2")) device.delete_attribute(device.get_attribute("Att1")) device.delete_attribute(device.get_attribute("Com1")) device.add_attribute(DeviceAttribute( name="Att2", object_id="o1", type=DataType.STRUCTUREDVALUE)) device.add_attribute(StaticDeviceAttribute( name="Stat3", value="test3", type=DataType.STRUCTUREDVALUE)) device.add_command(DeviceCommand(name="Com2")) self.client.patch_device(device=device, cb_url=settings.CB_URL) # test if update does what it should, for the device. It does not # change the entity completely: live_entity = cb_client.get_entity(entity_id=device.entity_name) with self.assertRaises(KeyError): live_entity.get_attribute("Att1") with self.assertRaises(KeyError): live_entity.get_attribute("Com1_info") with self.assertRaises(KeyError): live_entity.get_attribute("Stat2") self.assertEqual(live_entity.get_attribute("Stat1").value, "new_test") live_entity.get_attribute("Stat3") live_entity.get_attribute("Com2_info") live_entity.get_attribute("Att2") # test update where device information were changed device_settings = {"endpoint": "http://localhost:7071", "device_id": "new_id", "entity_name": "new_name", "entity_type": "new_type", "timestamp": False, "apikey": "zuiop", "protocol": "HTTP", "transport": "HTTP"} for key, value in device_settings.items(): device.__setattr__(key, value) self.client.patch_device(device=device) live_device = self.client.get_device(device_id=device.device_id) self.assertEqual(live_device.__getattribute__(key), value) cb_client.close()
def test_update_device(self): """ Test the methode: update_device of the iota client """ device = Device(**self.device) device.endpoint = "http://test.com" device.transport = "MQTT" device.add_attribute(DeviceAttribute( name="Att1", object_id="o1", type=DataType.STRUCTUREDVALUE)) device.add_attribute(StaticDeviceAttribute( name="Stat1", value="test", type=DataType.STRUCTUREDVALUE)) device.add_attribute(StaticDeviceAttribute( name="Stat2", value="test", type=DataType.STRUCTUREDVALUE)) device.add_command(DeviceCommand(name="Com1")) # use update_device to post self.client.update_device(device=device, add=True) cb_client = ContextBrokerClient(url=settings.CB_URL, fiware_header=self.fiware_header) # test if attributes exists correctly live_entity = cb_client.get_entity(entity_id=device.entity_name) live_entity.get_attribute("Att1") live_entity.get_attribute("Com1") live_entity.get_attribute("Com1_info") live_entity.get_attribute("Com1_status") self.assertEqual(live_entity.get_attribute("Stat1").value, "test") # change device attributes and update device.get_attribute("Stat1").value = "new_test" device.delete_attribute(device.get_attribute("Stat2")) device.delete_attribute(device.get_attribute("Att1")) device.delete_attribute(device.get_attribute("Com1")) device.add_attribute(DeviceAttribute( name="Att2", object_id="o1", type=DataType.STRUCTUREDVALUE)) device.add_attribute(StaticDeviceAttribute( name="Stat3", value="test3", type=DataType.STRUCTUREDVALUE)) device.add_command(DeviceCommand(name="Com2")) # device.endpoint = "http://localhost:8080" self.client.update_device(device=device) # test if update does what it should, for the device. It does not # change the entity completely: live_device = self.client.get_device(device_id=device.device_id) with self.assertRaises(KeyError): live_device.get_attribute("Att1") with self.assertRaises(KeyError): live_device.get_attribute("Com1_info") with self.assertRaises(KeyError): live_device.get_attribute("Stat2") self.assertEqual(live_device.get_attribute("Stat1").value, "new_test") live_device.get_attribute("Stat3") live_device.get_command("Com2") live_device.get_attribute("Att2") cb_client.close()
# # ## 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], commands=[device_command]) device_ul = Device(device_id='my_ul_device', entity_name='my_ul_device', entity_type='Thing',
iotac = IoTAClient(url=IOTA_URL, fiware_header=fiware_header) iotac.post_groups(service_groups=groups) iotac.post_devices(devices=devices) # ToDo: Get the device configurations from the server weather_station = iotac.get_device(device_id="device:001") zone_temperature_sensor = iotac.get_device(device_id="device:002") # ToDo: Get the service group configurations from the server group = iotac.get_group(resource="/iot/json", apikey=APIKEY) # ToDo: Create and additional device holding a command attribute and # post it to the IoT-Agent. It should be mapped to the `type` heater # create the simtime attribute and add during device creation t_sim = DeviceAttribute(name='simtime', object_id='t_sim', type="Number") # ToDo: create the command attribute of name `heater_on` (currently it is # not possible to add metadata here) cmd = DeviceCommand(name="heater_on", type=DataType.BOOLEAN) # ToDo: create the device configuration and send it to the server heater = Device(device_id="device:003", entity_name="urn:ngsi-ld:Heater:001", entity_type="Heater", apikey=APIKEY, attributes=[t_sim], commands=[cmd], transport='MQTT',
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, attributes=[t_sim], commands=[]) # create a temperature attribute and add it via the api of the # `device`-model. Use the 't_amb' as `object_id`. `object_id` specifies # what key will be used in the MQTT Message payload t_amb = DeviceAttribute(name='temperature', object_id='t_amb',
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()