From 5cafca068e7f54126c01037dac98fddfe99bfddf Mon Sep 17 00:00:00 2001 From: SystemsPurge Date: Tue, 24 Sep 2024 12:19:58 +0200 Subject: [PATCH 1/4] Made object_id optional in the mqtt_client publish method --- filip/clients/mqtt/client.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/filip/clients/mqtt/client.py b/filip/clients/mqtt/client.py index 817f4970..3bef69e1 100644 --- a/filip/clients/mqtt/client.py +++ b/filip/clients/mqtt/client.py @@ -751,13 +751,22 @@ def publish(self, msg_payload = payload.copy() for key in payload.keys(): for attr in device.attributes: - if key in attr.object_id or key == 'timeInstant': + key_constraint = key == "timeInstant" + def elif_action(msg): None + + if attr.object_id is not None: + key_constraint = key_constraint or (key in attr.object_id) + def elif_action(msg): msg[attr.object_id] = msg.pop(key) + + #could be made more compact by pulling up the second condition + #but would probably make the code less readable... + if key_constraint: break + elif key == attr.name: - if attr.object_id: - msg_payload[attr.object_id] = \ - msg_payload.pop(key) + elif_action(msg_payload) break + else: err_msg = f"Attribute key '{key}' is not allowed " \ f"in the message payload for this " \ From f99807e6b18d9aff6ee0d5f20aa23621228097bd Mon Sep 17 00:00:00 2001 From: SystemsPurge Date: Tue, 24 Sep 2024 15:27:28 +0200 Subject: [PATCH 2/4] Added test for the optional object_id implementation --- tests/clients/test_mqtt_client.py | 58 +++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/tests/clients/test_mqtt_client.py b/tests/clients/test_mqtt_client.py index 11166ffd..41a6e4bb 100644 --- a/tests/clients/test_mqtt_client.py +++ b/tests/clients/test_mqtt_client.py @@ -1,8 +1,9 @@ import logging import time +import datetime import unittest -from random import randrange -from paho.mqtt.client import MQTT_CLEAN_START_FIRST_ONLY +from random import randrange,Random +from paho.mqtt.client import MQTT_CLEAN_START_FIRST_ONLY,MQTTv5 from filip.custom_types import AnyMqttUrl from filip.models import FiwareHeader from filip.models.ngsi_v2.context import NamedCommand @@ -10,7 +11,8 @@ Device, \ DeviceAttribute, \ DeviceCommand, \ - ServiceGroup, PayloadProtocol + ServiceGroup, PayloadProtocol, \ + TransportProtocol from filip.clients.mqtt import IoTAMQTTClient from filip.utils.cleanup import clean_test, clear_all from tests.config import settings @@ -131,6 +133,56 @@ def on_message_second(mqttc, obj, msg, properties=None): # stop network loop and disconnect cleanly self.mqttc.loop_stop() self.mqttc.disconnect() + + def test_optional_object_id(self): + """ + Test: + Verify the IotaMQTTClient publish function + is not raising when missing an object_id. + The test setup is minimal, we are not concerned + with commands/command callbacks, just that publish + works for a specific device argument + Setup: + publish with: + - attr_name=None + - command_name=None + - Dict payload + - with and without object_id + - with key = attr.name/in object_id + """ + tmp_id="dev_id" + tmp_attrs = [DeviceAttribute(name="temperature", + type="Number"), + DeviceAttribute(name="temperature", + type="Number", + object_id="temp")] + + payloads = [{"temperature":Random().randint(0,50)}, + {"t":Random().randint(0,50)}] + + for p,attr in zip(payloads,tmp_attrs): + tmp_dev = Device(device_id=tmp_id, + attributes=[attr], + entity_name="tmp_entity", + entity_type="tmp_type", + apikey="tmp_key", + transport=TransportProtocol.MQTT, + protocol=PayloadProtocol.IOTA_JSON) + tmp_mqttc = IoTAMQTTClient(protocol=MQTTv5 ,devices=[tmp_dev]) + tmp_mqttc.publish(device_id=tmp_id,payload=p) + tmp_mqttc.delete_device(device_id=tmp_id) + + #checking if raises correctly + with self.assertRaises(KeyError): + tmp_dev = Device(device_id=tmp_id, + attributes=[tmp_attrs[0]], + entity_name="tmp_entity", + entity_type="tmp_type", + apikey="tmp_key", + transport=TransportProtocol.MQTT, + protocol=PayloadProtocol.IOTA_JSON) + tmp_mqttc.publish(device_id=tmp_id,payload={"t":Random().randint(0,50)}) + tmp_mqttc.delete_device(device_id=tmp_id) def test_init(self): devices = [self.device_json, self.device_ul] From f930fe312dc3ebe710369504b6a17daa4edbf72f Mon Sep 17 00:00:00 2001 From: JunsongDu Date: Tue, 1 Oct 2024 15:54:31 +0200 Subject: [PATCH 3/4] chore: use object_id to send data if object_id is defined --- filip/clients/mqtt/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/filip/clients/mqtt/client.py b/filip/clients/mqtt/client.py index 3bef69e1..cda4b4ef 100644 --- a/filip/clients/mqtt/client.py +++ b/filip/clients/mqtt/client.py @@ -778,7 +778,7 @@ def elif_action(msg): msg[attr.object_id] = msg.pop(key) topic_type=IoTAMQTTMessageType.MULTI) payload = self._encoders[device.protocol].encode_msg( device_id=device_id, - payload=payload, + payload=msg_payload, msg_type=IoTAMQTTMessageType.MULTI) # create message for command acknowledgement From 25c5f09b5a6221c7fc88136b56d6fefea8cfffd9 Mon Sep 17 00:00:00 2001 From: JunsongDu Date: Tue, 1 Oct 2024 17:39:08 +0200 Subject: [PATCH 4/4] chore: add test for unregistered attribute name --- tests/clients/test_mqtt_client.py | 34 ++++++++++++++++--------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/tests/clients/test_mqtt_client.py b/tests/clients/test_mqtt_client.py index 41a6e4bb..9bbb602d 100644 --- a/tests/clients/test_mqtt_client.py +++ b/tests/clients/test_mqtt_client.py @@ -154,20 +154,20 @@ def test_optional_object_id(self): tmp_attrs = [DeviceAttribute(name="temperature", type="Number"), DeviceAttribute(name="temperature", - type="Number", - object_id="temp")] + type="Number", + object_id="temp")] payloads = [{"temperature":Random().randint(0,50)}, - {"t":Random().randint(0,50)}] + {"temp":Random().randint(0,50)}] for p,attr in zip(payloads,tmp_attrs): tmp_dev = Device(device_id=tmp_id, - attributes=[attr], - entity_name="tmp_entity", - entity_type="tmp_type", - apikey="tmp_key", - transport=TransportProtocol.MQTT, - protocol=PayloadProtocol.IOTA_JSON) + attributes=[attr], + entity_name="tmp_entity", + entity_type="tmp_type", + apikey="tmp_key", + transport=TransportProtocol.MQTT, + protocol=PayloadProtocol.IOTA_JSON) tmp_mqttc = IoTAMQTTClient(protocol=MQTTv5 ,devices=[tmp_dev]) tmp_mqttc.publish(device_id=tmp_id,payload=p) tmp_mqttc.delete_device(device_id=tmp_id) @@ -175,13 +175,15 @@ def test_optional_object_id(self): #checking if raises correctly with self.assertRaises(KeyError): tmp_dev = Device(device_id=tmp_id, - attributes=[tmp_attrs[0]], - entity_name="tmp_entity", - entity_type="tmp_type", - apikey="tmp_key", - transport=TransportProtocol.MQTT, - protocol=PayloadProtocol.IOTA_JSON) - tmp_mqttc.publish(device_id=tmp_id,payload={"t":Random().randint(0,50)}) + attributes=[tmp_attrs[0]], + entity_name="tmp_entity", + entity_type="tmp_type", + apikey="tmp_key", + transport=TransportProtocol.MQTT, + protocol=PayloadProtocol.IOTA_JSON) + tmp_mqttc = IoTAMQTTClient(protocol=MQTTv5, devices=[tmp_dev]) + tmp_mqttc.publish(device_id=tmp_id, + payload={"t": Random().randint(0,50)}) tmp_mqttc.delete_device(device_id=tmp_id) def test_init(self):