diff --git a/README.md b/README.md index 379cabe..047c32e 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,15 @@ wolk.publish() wolk.disconnect() ``` +### Debugging + +Display send and received messages with `iot.debug_mode` : + +```python +# Enable debug printing by setting flag to True +iot.debug_mode = False +``` + ---- ## Advanced features diff --git a/WolkCore/WolkCore.py b/WolkCore/WolkCore.py index 7748aa0..1b760e4 100644 --- a/WolkCore/WolkCore.py +++ b/WolkCore/WolkCore.py @@ -298,7 +298,7 @@ def _on_inbound_message(self, message): configuration.command == ConfigurationCommandType.CONFIGURATION_COMMAND_TYPE_SET ): - self.configuration_handler.handle_configuration(configuration.value) + self.configuration_handler.handle_configuration(configuration.values) self.publish_configuration() elif ( diff --git a/examples/Controlled_publish_period/main.py b/examples/Controlled_publish_period/main.py index 2642f53..8f9cd42 100644 --- a/examples/Controlled_publish_period/main.py +++ b/examples/Controlled_publish_period/main.py @@ -15,6 +15,7 @@ import streams from wolkabout.iot import iot from wireless import wifi + # uncomment one of the following lines depending on used board(e.g. Particle Photon, esp8266 or esp32 based board) # from broadcom.bcm43362 import bcm43362 as wifi_driver # from espressif.esp32net import esp32wifi as wifi_driver @@ -34,6 +35,9 @@ publish_period_milliseconds = 5000 streams.serial() +# Enable debug printing by setting flag to True +iot.debug_mode = False + # Connect to WiFi network try: diff --git a/examples/Full_feature_set/main.py b/examples/Full_feature_set/main.py index 1932b52..92ada35 100644 --- a/examples/Full_feature_set/main.py +++ b/examples/Full_feature_set/main.py @@ -36,6 +36,9 @@ publish_period_milliseconds = 5000 streams.serial() +# Enable debug printing by setting flag to True +iot.debug_mode = False + class ActuatorSimulator: def __init__(self, value): @@ -115,16 +118,17 @@ def handle_configuration(self, configuration): print("Something went wrong while creating the device: ", e) try: - wolk = iot.Wolk(device, - host="api-demo.wolkabout.com", - port=1883, - actuation_handler=ActuationHandlerImpl(), - actuator_status_provider=ActuatorStatusProviderImpl(), - outbound_message_queue=iot.ZerynthOutboundMessageQueue(200), - configuration_handler=ConfigurationHandlerImpl(), - configuration_provider=ConfigurationProviderImpl(), - keep_alive_enabled=True - ) + wolk = iot.Wolk( + device, + host="api-demo.wolkabout.com", + port=1883, + actuation_handler=ActuationHandlerImpl(), + actuator_status_provider=ActuatorStatusProviderImpl(), + outbound_message_queue=iot.ZerynthOutboundMessageQueue(200), + configuration_handler=ConfigurationHandlerImpl(), + configuration_provider=ConfigurationProviderImpl(), + keep_alive_enabled=True, + ) except Exception as e: print("Something went wrong while creating the Wolk instance: ", e) @@ -154,11 +158,17 @@ def handle_configuration(self, configuration): else: wolk.add_alarm("HH", False) - print("Publishing readings" + - " T: " + str(temperature) + - " P: " + str(pressure) + - " H: " + str(humidity) + - " ACL: " + str(acceleration)) + print( + "Publishing readings" + + " T: " + + str(temperature) + + " P: " + + str(pressure) + + " H: " + + str(humidity) + + " ACL: " + + str(acceleration) + ) # Adds a sensor reading to the queue wolk.add_sensor_reading("T", temperature) diff --git a/iot.py b/iot.py index b47149e..d359146 100644 --- a/iot.py +++ b/iot.py @@ -57,6 +57,14 @@ def tuple(mlist): pass +debug_mode = False + + +def print_d(*args): + if debug_mode: + print(*args) + + class ZerynthMQTTConnectivityService(ConnectivityService.ConnectivityService): """ @@ -83,6 +91,12 @@ class ZerynthMQTTConnectivityService(ConnectivityService.ConnectivityService): """ def __init__(self, device, host, port, qos=0): + print_d("[D] Connectivity details:") + print_d("[D] Device key - " + str(device.key)) + print_d("[D] Device password - " + str(device.password)) + print_d("[D] Host - " + str(host)) + print_d("[D] Port - " + str(port)) + print_d("[D] Quality of Service - " + str(qos)) self.device = device self.qos = qos self.host = host @@ -113,6 +127,9 @@ def on_mqtt_message(self, client, data): if "message" in data: channel = data["message"].topic payload = data["message"].payload + print_d( + "[D] Received message - Channel: " + channel + " Payload: " + payload + ) message = InboundMessage.InboundMessage(channel, payload) self.inbound_message_listener(message) @@ -128,27 +145,19 @@ def connect(self): if self.connected: return - self.client = mqtt.Client( - client_id=self.device.key, clean_session=True - ) + self.client = mqtt.Client(client_id=self.device.key, clean_session=True) self.client.set_username_pw(self.device.key, self.device.password) - self.client.set_will( - "lastwill/" + self.device.key, "Gone offline", 2, False - ) + self.client.set_will("lastwill/" + self.device.key, "Gone offline", 2, False) try: self.client.connect(self.host, keepalive=60, port=self.port) self.topics = [] - self.topics.append( - ["service/commands/firmware/" + self.device.key, 0] - ) + self.topics.append(["service/commands/firmware/" + self.device.key, 0]) self.topics.append(["service/commands/file/" + self.device.key, 0]) self.topics.append(["service/commands/url/" + self.device.key, 0]) self.topics.append(["service/binary/" + self.device.key, 0]) self.topics.append(["pong/" + self.device.key, 0]) - self.topics.append( - ["configurations/commands/" + self.device.key, 0] - ) + self.topics.append(["configurations/commands/" + self.device.key, 0]) if self.device.actuator_references: for actuator_reference in self.device.actuator_references: topic = [ @@ -192,6 +201,12 @@ def publish(self, outbound_message): Publishes the :samp:`outbound_message` to the WolkAbout IoT Platform """ + print_d( + "[D] Publishing message - Channel: " + + outbound_message.channel + + " Payload: " + + str(outbound_message.payload) + ) self.client.publish( outbound_message.channel, outbound_message.payload, self.qos ) @@ -215,6 +230,7 @@ class ZerynthOutboundMessageQueue(OutboundMessageQueue.OutboundMessageQueue): """ def __init__(self, maxsize): + print_d("[D] Initialized queue with max size of " + str(maxsize)) self.queue = queue.Queue(maxsize=maxsize) def put(self, message): @@ -254,9 +270,7 @@ def peek(self): return self.queue.peek() -class ZerynthOutboundMessageFactory( - OutboundMessageFactory.OutboundMessageFactory -): +class ZerynthOutboundMessageFactory(OutboundMessageFactory.OutboundMessageFactory): """ ------------------------ @@ -293,9 +307,11 @@ def make_from_sensor_reading(self, reading): single_value = "false" if "\n" in str(single_value): single_value = single_value.replace("\n", "\\n") + single_value = single_value.replace("\\\\n", "\\n") single_value = single_value.replace("\r", "") if '"' in str(single_value): single_value = single_value.replace('"', '\\"') + single_value = single_value.replace('\\\\"', '\\"') values_list.append(single_value) string_values = str() @@ -381,8 +397,10 @@ def make_from_actuator_status(self, actuator): if "\n" in str(actuator.value): actuator.value = actuator.value.replace("\n", "\\n") actuator.value = actuator.value.replace("\r", "") + actuator.value = actuator.value.replace("\\\\n", "\\n") if '"' in str(actuator.value): actuator.value = actuator.value.replace('"', '\\"') + actuator.value = actuator.value.replace('\\\\"', '\\"') return OutboundMessage.OutboundMessage( "actuators/status/" + self.device_key + "/" + actuator.reference, @@ -402,39 +420,22 @@ def make_from_firmware_status(self, firmware_status): * :samp:`firmware_status`: Firmware status to be serialized """ - if ( - firmware_status.status - == FirmwareStatusType.FIRMWARE_STATUS_FILE_TRANSFER - ): + if firmware_status.status == FirmwareStatusType.FIRMWARE_STATUS_FILE_TRANSFER: firmware_status.status = "FILE_TRANSFER" - elif ( - firmware_status.status - == FirmwareStatusType.FIRMWARE_STATUS_FILE_READY - ): + elif firmware_status.status == FirmwareStatusType.FIRMWARE_STATUS_FILE_READY: firmware_status.status = "FILE_READY" - elif ( - firmware_status.status - == FirmwareStatusType.FIRMWARE_STATUS_INSTALLATION - ): + elif firmware_status.status == FirmwareStatusType.FIRMWARE_STATUS_INSTALLATION: firmware_status.status = "INSTALLATION" - elif ( - firmware_status.status - == FirmwareStatusType.FIRMWARE_STATUS_COMPLETED - ): + elif firmware_status.status == FirmwareStatusType.FIRMWARE_STATUS_COMPLETED: firmware_status.status = "COMPLETED" - elif ( - firmware_status.status - == FirmwareStatusType.FIRMWARE_STATUS_ABORTED - ): + elif firmware_status.status == FirmwareStatusType.FIRMWARE_STATUS_ABORTED: firmware_status.status = "ABORTED" - elif ( - firmware_status.status == FirmwareStatusType.FIRMWARE_STATUS_ERROR - ): + elif firmware_status.status == FirmwareStatusType.FIRMWARE_STATUS_ERROR: firmware_status.status = "ERROR" if firmware_status.status == "ERROR": @@ -464,8 +465,7 @@ def make_from_firmware_status(self, firmware_status): firmware_status.error = "3" elif ( - firmware_status.error - == FirmwareErrorType.FIRMWARE_ERROR_MALFORMED_URL + firmware_status.error == FirmwareErrorType.FIRMWARE_ERROR_MALFORMED_URL ): firmware_status.error = "4" @@ -535,6 +535,7 @@ def make_from_configuration(self, configuration): single_value = single_value.replace("\r", "") if '"' in str(single_value): single_value = single_value.replace('"', '\\"') + single_value = single_value.replace('\\\\"', '\\"') values_list.append(single_value) @@ -551,9 +552,11 @@ def make_from_configuration(self, configuration): if "\n" in str(value): value = value.replace("\n", "\\n") + value = value.replace("\\\\n", "\\n") value = value.replace("\r", "") if '"' in str(value): value = value.replace('"', '\\"') + value = value.replace('\\\\"', '\\"') if value is True: value = "true" elif value is False: @@ -564,8 +567,7 @@ def make_from_configuration(self, configuration): values = values[:-1] message = OutboundMessage.OutboundMessage( - "configurations/current/" + self.device_key, - '{"values":{' + values + "}}", + "configurations/current/" + self.device_key, '{"values":{' + values + "}}" ) return message @@ -609,21 +611,15 @@ def deserialize_actuator_command(self, message): value = True elif value == "false": value = False - actuation = ActuatorCommand.ActuatorCommand( - reference, command_type, value - ) + actuation = ActuatorCommand.ActuatorCommand(reference, command_type, value) return actuation elif str(command) == "STATUS": command_type = ActuatorCommandType.ACTUATOR_COMMAND_TYPE_STATUS - actuation = ActuatorCommand.ActuatorCommand( - reference, command_type - ) + actuation = ActuatorCommand.ActuatorCommand(reference, command_type) return actuation else: command_type = ActuatorCommandType.ACTUATOR_COMMAND_TYPE_UNKNOWN - actuation = ActuatorCommand.ActuatorCommand( - reference, command_type - ) + actuation = ActuatorCommand.ActuatorCommand(reference, command_type) return actuation def deserialize_configuration_command(self, message): @@ -646,59 +642,67 @@ def deserialize_configuration_command(self, message): command, payload.get("values") ) - for ( - received_reference, - received_value, - ) in configuration.values.items(): - if "\n" in str(received_value): - received_value = received_value.replace("\\n", "\n") - received_value = received_value.replace("\r", "") - if '"' in str(received_value): - received_value = received_value.replace('\\"', '"') + temp_dict = dict() + + for (received_reference, received_value) in configuration.values.items(): + try: + if "." in received_value: + temp_value = float(received_value) + else: + temp_value = int(received_value) + except ValueError: + pass + + if type(received_value) == 4: # PSTRING + if "," in str(received_value): + values_list = received_value.split(",") + for value in values_list: + if "\\n" in str(value): + value = value.replace("\\n", "\n") + value = value.replace("\r", "") + if '\\"' in str(value): + value = value.replace('\\"', '"') + if value == "true": + value = True + elif value == "false": + value = False + try: + if "." in value: + value = float(value) + else: + value = int(value) + except ValueError: + pass + temp_value = tuple(values_list) + else: + if "\n" in str(received_value): + temp_value = received_value.replace("\\n", "\n") + temp_value = received_value.replace("\r", "") + elif '"' in str(received_value): + temp_value = received_value.replace('\\"', '"') + else: + temp_value = received_value + if received_value == "true": - received_value = True + temp_value = True elif received_value == "false": - received_value = False - if "," in received_value: - values_list = received_value.split(",") - for value in values_list: - if "\\n" in str(value): - value = value.replace("\\n", "\n") - value = value.replace("\r", "") - if '\\"' in str(value): - value = value.replace('\\"', '"') - if value == "true": - value = True - elif value == "false": - value = False - try: - if "." in value: - value = float(value) - else: - value = int(value) - except ValueError: - pass - - configuration.values[received_reference] = tuple( - values_list - ) + temp_value = False + + temp_dict[received_reference] = temp_value + configuration.values = temp_dict return configuration elif command == "CURRENT": - command = ( - ConfigurationCommandType.CONFIGURATION_COMMAND_TYPE_CURRENT - ) + command = ConfigurationCommandType.CONFIGURATION_COMMAND_TYPE_CURRENT configuration = ConfigurationCommand.ConfigurationCommand(command) return configuration else: - command = ( - ConfigurationCommandType.CONFIGURATION_COMMAND_TYPE_UNKNOWN - ) + command = ConfigurationCommandType.CONFIGURATION_COMMAND_TYPE_UNKNOWN configuration = ConfigurationCommand.ConfigurationCommand(command) return configuration @@ -721,9 +725,7 @@ class ZerynthKeepAliveService(KeepAliveService.KeepAliveService): * :samp:`interval`: The number of milliseconds between each keep alive message """ - def __init__( - self, connectivity_service, outbound_message_factory, interval - ): + def __init__(self, connectivity_service, outbound_message_factory, interval): self.connectivity_service = connectivity_service self.outbound_message_factory = outbound_message_factory self.interval = interval @@ -744,6 +746,11 @@ def start(self): Sends a keep alive message as soon as the device is connected to the platform and starts a repeating timer to send subsequent keep alive messages every `self.interval` milliseconds """ + print_d( + "[D] Initialized keep alive service with interval of " + + str(self.interval) + + " milliseconds" + ) self.timer = timers.timer() self.timer.interval(self.interval, self.send_keep_alive) self.timer.start() @@ -801,13 +808,9 @@ def __init__( keep_alive_enabled=True, ): self.device = device - self.outbound_message_factory = ZerynthOutboundMessageFactory( - device.key - ) + self.outbound_message_factory = ZerynthOutboundMessageFactory(device.key) self.outbound_message_queue = outbound_message_queue - self.connectivity_service = ZerynthMQTTConnectivityService( - device, host, port - ) + self.connectivity_service = ZerynthMQTTConnectivityService(device, host, port) self.deserializer = ZerynthInboundMessageDeserializer() if device.actuator_references and ( actuation_handler is None or actuator_status_provider is None