async def send_to_output(self, message, output_name): """Sends an event/message to the given module output. These are outgoing events and are meant to be "output events" If the connection to the service has not previously been opened by a call to connect, this function will open the connection before sending the event. :param message: message to send to the given output. Anything passed that is not an instance of the Message class will be converted to Message object. :param output_name: Name of the output to send the event to. """ if not isinstance(message, Message): message = Message(message) message.output_name = output_name logger.info("Sending message to output:" + output_name + "...") send_output_event_async = async_adapter.emulate_async( self._pipeline.send_output_event) def sync_callback(): logger.info("Successfully sent message to output: " + output_name) callback = async_adapter.AwaitableCallback(sync_callback) await send_output_event_async(message, callback=callback) await callback.completion()
async def send_message_to_output(self, message, output_name): """Sends an event/message to the given module output. These are outgoing events and are meant to be "output events" If the connection to the service has not previously been opened by a call to connect, this function will open the connection before sending the event. :param message: Message to send to the given output. Anything passed that is not an instance of the Message class will be converted to Message object. :param str output_name: Name of the output to send the event to. :raises: :class:`azure.iot.device.exceptions.CredentialError` if credentials are invalid and a connection cannot be established. :raises: :class:`azure.iot.device.exceptions.ConnectionFailedError` if a establishing a connection results in failure. :raises: :class:`azure.iot.device.exceptions.ConnectionDroppedError` if connection is lost during execution. :raises: :class:`azure.iot.device.exceptions.ClientError` if there is an unexpected failure during execution. """ if not isinstance(message, Message): message = Message(message) message.output_name = output_name logger.info("Sending message to output:" + output_name + "...") send_output_event_async = async_adapter.emulate_async( self._iothub_pipeline.send_output_event) callback = async_adapter.AwaitableCallback() await send_output_event_async(message, callback=callback) await handle_result(callback) logger.info("Successfully sent message to output: " + output_name)
async def send_message(self, message): """Sends a message to the default events endpoint on the Azure IoT Hub or Azure IoT Edge Hub instance. If the connection to the service has not previously been opened by a call to connect, this function will open the connection before sending the event. :param message: The actual message to send. Anything passed that is not an instance of the Message class will be converted to Message object. :type message: :class:`azure.iot.device.Message` or str :raises: :class:`azure.iot.device.exceptions.CredentialError` if credentials are invalid and a connection cannot be established. :raises: :class:`azure.iot.device.exceptions.ConnectionFailedError` if a establishing a connection results in failure. :raises: :class:`azure.iot.device.exceptions.ConnectionDroppedError` if connection is lost during execution. :raises: :class:`azure.iot.device.exceptions.ClientError` if there is an unexpected failure during execution. :raises: ValueError if the message fails size validation. """ if not isinstance(message, Message): message = Message(message) if message.get_size() > device_constant.TELEMETRY_MESSAGE_SIZE_LIMIT: raise ValueError("Size of telemetry message can not exceed 256 KB.") logger.info("Sending message to Hub...") send_message_async = async_adapter.emulate_async(self._mqtt_pipeline.send_message) callback = async_adapter.AwaitableCallback() await send_message_async(message, callback=callback) await handle_result(callback) logger.info("Successfully sent message to Hub")
def test_setting_message_as_security_message(self): s = "After all this time? Always" ctype = "application/json" encoding = "utf-16" msg = Message(s, None, encoding, ctype) assert msg.iothub_interface_id is None msg.set_as_security_message() assert msg.iothub_interface_id == constant.SECURITY_MESSAGE_INTERFACE_ID
def _handle_pipeline_event(self, event): """ Pipeline Event handler function to convert incoming MQTT messages into the appropriate IoTHub events, based on the topic of the message """ # TODO: should we always be decoding the payload? Seems strange to only sometimes do it. # Is there value to the user getting the original bytestring from the wire? if isinstance(event, pipeline_events_mqtt.IncomingMQTTMessageEvent): topic = event.topic device_id = self.nucleus.pipeline_configuration.device_id module_id = self.nucleus.pipeline_configuration.module_id if mqtt_topic_iothub.is_c2d_topic(topic, device_id): message = Message(event.payload) mqtt_topic_iothub.extract_message_properties_from_topic(topic, message) self.send_event_up(pipeline_events_iothub.C2DMessageEvent(message)) elif mqtt_topic_iothub.is_input_topic(topic, device_id, module_id): message = Message(event.payload) mqtt_topic_iothub.extract_message_properties_from_topic(topic, message) message.input_name = mqtt_topic_iothub.get_input_name_from_topic(topic) self.send_event_up(pipeline_events_iothub.InputMessageEvent(message)) elif mqtt_topic_iothub.is_method_topic(topic): request_id = mqtt_topic_iothub.get_method_request_id_from_topic(topic) method_name = mqtt_topic_iothub.get_method_name_from_topic(topic) method_received = MethodRequest( request_id=request_id, name=method_name, payload=json.loads(event.payload.decode("utf-8")), ) self.send_event_up(pipeline_events_iothub.MethodRequestEvent(method_received)) elif mqtt_topic_iothub.is_twin_response_topic(topic): request_id = mqtt_topic_iothub.get_twin_request_id_from_topic(topic) status_code = int(mqtt_topic_iothub.get_twin_status_code_from_topic(topic)) self.send_event_up( pipeline_events_base.ResponseEvent( request_id=request_id, status_code=status_code, response_body=event.payload ) ) elif mqtt_topic_iothub.is_twin_desired_property_patch_topic(topic): self.send_event_up( pipeline_events_iothub.TwinDesiredPropertiesPatchEvent( patch=json.loads(event.payload.decode("utf-8")) ) ) else: logger.debug("Unknown topic: {} passing up to next handler".format(topic)) self.send_event_up(event) else: # all other messages get passed up self.send_event_up(event)
def _handle_pipeline_event(self, event): """ Pipeline Event handler function to convert incoming MQTT messages into the appropriate IoTHub events, based on the topic of the message """ if isinstance(event, pipeline_events_mqtt.IncomingMQTTMessageEvent): topic = event.topic if mqtt_topic_iothub.is_c2d_topic(topic, self.device_id): message = Message(event.payload) mqtt_topic_iothub.extract_properties_from_topic(topic, message) self.send_event_up(pipeline_events_iothub.C2DMessageEvent(message)) elif mqtt_topic_iothub.is_input_topic(topic, self.device_id, self.module_id): message = Message(event.payload) mqtt_topic_iothub.extract_properties_from_topic(topic, message) input_name = mqtt_topic_iothub.get_input_name_from_topic(topic) self.send_event_up(pipeline_events_iothub.InputMessageEvent(input_name, message)) elif mqtt_topic_iothub.is_method_topic(topic): request_id = mqtt_topic_iothub.get_method_request_id_from_topic(topic) method_name = mqtt_topic_iothub.get_method_name_from_topic(topic) method_received = MethodRequest( request_id=request_id, name=method_name, payload=json.loads(event.payload.decode("utf-8")), ) self.send_event_up(pipeline_events_iothub.MethodRequestEvent(method_received)) elif mqtt_topic_iothub.is_twin_response_topic(topic): request_id = mqtt_topic_iothub.get_twin_request_id_from_topic(topic) status_code = int(mqtt_topic_iothub.get_twin_status_code_from_topic(topic)) self.send_event_up( pipeline_events_base.ResponseEvent( request_id=request_id, status_code=status_code, response_body=event.payload ) ) elif mqtt_topic_iothub.is_twin_desired_property_patch_topic(topic): self.send_event_up( pipeline_events_iothub.TwinDesiredPropertiesPatchEvent( patch=json.loads(event.payload.decode("utf-8")) ) ) else: logger.debug("Unknown topic: {} passing up to next handler".format(topic)) self.send_event_up(event) else: # all other messages get passed up super(IoTHubMQTTTranslationStage, self)._handle_pipeline_event(event)
def test_send_to_output_calls_transport(self, client, transport): message = Message("this is a message") output_name = "some_output" client.send_to_output(message, output_name) assert transport.send_output_event.call_count == 1 assert transport.send_output_event.call_args[0][0] is message assert message.output_name == output_name
class TestMessage(object): data_str = "After all this time? Always" data_int = 987 data_obj = Message(data_str) @pytest.mark.parametrize("data", [data_str, data_int, data_obj], ids=["String", "Integer", "Message"]) def test_instantiates_from_data(self, data): msg = Message(data) assert msg.data == data def test_instantiates_with_optional_message_id(self): s = "After all this time? Always" message_id = "Postage12323" msg = Message(s, message_id) assert msg.message_id == message_id def test_instantiates_with_optional_contenttype_encoding(self): s = "After all this time? Always" type = "application/json" encoding = "utf-16" msg = Message(s, None, encoding, type) assert msg.content_encoding == encoding assert msg.content_type == type
def test_instantiates_with_optional_contenttype_encoding(self): s = "After all this time? Always" ctype = "application/json" encoding = "utf-16" msg = Message(s, None, encoding, ctype) assert msg.content_encoding == encoding assert msg.content_type == ctype
async def send_message_to_output(self, message, output_name): """Sends an event/message to the given module output. These are outgoing events and are meant to be "output events" If the connection to the service has not previously been opened by a call to connect, this function will open the connection before sending the event. :param message: Message to send to the given output. Anything passed that is not an instance of the Message class will be converted to Message object. :type message: :class:`azure.iot.device.Message` or str :param str output_name: Name of the output to send the event to. :raises: :class:`azure.iot.device.exceptions.CredentialError` if credentials are invalid and a connection cannot be established. :raises: :class:`azure.iot.device.exceptions.ConnectionFailedError` if a establishing a connection results in failure. :raises: :class:`azure.iot.device.exceptions.ConnectionDroppedError` if connection is lost during execution. :raises: :class:`azure.iot.device.exceptions.OperationTimeout` if connection attempt times out :raises: :class:`azure.iot.device.exceptions.NoConnectionError` if the client is not connected (and there is no auto-connect enabled) :raises: :class:`azure.iot.device.exceptions.ClientError` if there is an unexpected failure during execution. :raises: ValueError if the message fails size validation. """ if not isinstance(message, Message): message = Message(message) if message.get_size() > device_constant.TELEMETRY_MESSAGE_SIZE_LIMIT: raise ValueError("Size of message can not exceed 256 KB.") message.output_name = output_name logger.info("Sending message to output:" + output_name + "...") send_output_message_async = async_adapter.emulate_async( self._mqtt_pipeline.send_output_message ) callback = async_adapter.AwaitableCallback() await send_output_message_async(message, callback=callback) await handle_result(callback) logger.info("Successfully sent message to output: " + output_name)
def test_receive_c2d_message_returns_message_from_c2d_inbox( self, mocker, client): message = Message("this is a message") inbox_mock = mocker.MagicMock(autospec=SyncClientInbox) inbox_mock.get.return_value = message manager_get_inbox_mock = mocker.patch.object(client._inbox_manager, "get_c2d_message_inbox", return_value=inbox_mock) received_message = client.receive_c2d_message() assert manager_get_inbox_mock.call_count == 1 assert inbox_mock.get.call_count == 1 assert received_message is message
def _handle_pipeline_event(self, event): """ Pipeline Event handler function to convert incoming Mqtt messages into the appropriate IotHub events, based on the topic of the message """ if isinstance(event, pipeline_events_mqtt.IncomingMessage): topic = event.topic if mqtt_topic.is_c2d_topic(topic): message = Message(event.payload) mqtt_topic.extract_properties_from_topic(topic, message) self.handle_pipeline_event( pipeline_events_iothub.C2DMessageEvent(message)) elif mqtt_topic.is_input_topic(topic): message = Message(event.payload) mqtt_topic.extract_properties_from_topic(topic, message) input_name = mqtt_topic.get_input_name_from_topic(topic) self.handle_pipeline_event( pipeline_events_iothub.InputMessageEvent( input_name, message)) elif mqtt_topic.is_method_topic(topic): rid = mqtt_topic.get_method_request_id_from_topic(topic) method_name = mqtt_topic.get_method_name_from_topic(topic) method_received = MethodRequest(request_id=rid, name=method_name, payload=json.loads( event.payload)) self._handle_pipeline_event( pipeline_events_iothub.MethodRequest(method_received)) else: logger.warning( "Warning: dropping message with topic {}".format(topic)) else: # all other messages get passed up PipelineStage._handle_pipeline_event(self, event)
class TestMessage(object): data_str = "After all this time? Always" data_int = 987 data_obj = Message(data_str) @pytest.mark.it("Instantiates from data type") @pytest.mark.parametrize( "data", [data_str, data_int, data_obj], ids=["String", "Integer", "Message"] ) def test_instantiates_from_data(self, data): msg = Message(data) assert msg.data == data @pytest.mark.it("Instantiates with optional message id") def test_instantiates_with_optional_message_id(self): s = "After all this time? Always" message_id = "Postage12323" msg = Message(s, message_id) assert msg.message_id == message_id @pytest.mark.it("Instantiates with optional content type encoding") def test_instantiates_with_optional_contenttype_encoding(self): s = "After all this time? Always" ctype = "application/json" encoding = "utf-16" msg = Message(s, None, encoding, ctype) assert msg.content_encoding == encoding assert msg.content_type == ctype @pytest.mark.it("Setting message as security message") def test_setting_message_as_security_message(self): s = "After all this time? Always" ctype = "application/json" encoding = "utf-16" msg = Message(s, None, encoding, ctype) assert msg.iothub_interface_id is None msg.set_as_security_message() assert msg.iothub_interface_id == constant.SECURITY_MESSAGE_INTERFACE_ID @pytest.mark.it( "Uses string representation of data/payload attribute as string representation of Message" ) @pytest.mark.parametrize( "data", [data_str, data_int, data_obj], ids=["String", "Integer", "Message"] ) def test_str_rep(self, data): msg = Message(data) assert str(msg) == str(data)
async def test_receive_input_message_returns_message_from_input_inbox( self, mocker, client): message = Message("this is a message") inbox_mock = mocker.MagicMock(autospec=AsyncClientInbox) inbox_mock.get.return_value = await create_completed_future(message) manager_get_inbox_mock = mocker.patch.object(client._inbox_manager, "get_input_message_inbox", return_value=inbox_mock) input_name = "some_input" received_message = await client.receive_input_message(input_name) assert manager_get_inbox_mock.call_count == 1 assert manager_get_inbox_mock.call_args == mocker.call(input_name) assert inbox_mock.get.call_count == 1 assert received_message is message
async def send_message(self, message): """Sends a message to the default events endpoint on the Azure IoT Hub or Azure IoT Edge Hub instance. If the connection to the service has not previously been opened by a call to connect, this function will open the connection before sending the event. :param message: The actual message to send. Anything passed that is not an instance of the Message class will be converted to Message object. """ if not isinstance(message, Message): message = Message(message) logger.info("Sending message to Hub...") send_message_async = async_adapter.emulate_async(self._iothub_pipeline.send_message) callback = async_adapter.AwaitableCallback() await send_message_async(message, callback=callback) await callback.completion() logger.info("Successfully sent message to Hub")
async def input_listener(module_client): if "ALERT_RULES" in os.environ: alert_rules = json.loads(os.environ.get("ALERT_RULES")) else: with open('./src/rules.json') as f: alert_rules = json.loads(f.read()) for rules in alert_rules: if 'operator' not in rules or rules['operator'] not in [ "eq", "neq", "lt", "lte", "gt", "gte" ]: EdgeLogger.logger.error("Unknown operator {} in rule {}".format( rules['operator'], json.dumps(rules))) while True: try: input_message = await module_client.receive_message_on_input( constantes.INPUT_NAME) # blocking call EdgeLogger().logger.info( "Receive message {}".format(input_message)) alerts = alerting( json.loads(input_message.data)[constantes.DATA_KEY], alert_rules) await module_client.send_message_to_output(input_message, constantes.OUTPUT_NAME) if len(alerts) > 0: message = {"type": "alert", "alerte": alerts} EdgeLogger().logger.info("Send alerts : {}".format( json.dumps(message))) await module_client.send_message_to_output( Message(json.dumps(message)), constantes.OUTPUT_NAME) except Exception as error: EdgeLogger().logger.error(error)
def test_instantiates_with_optional_output_name(self): output_name = "some_output" msg = Message("some message", output_name=output_name) assert msg.output_name == output_name
def test_instantiates_from_data(self, data): msg = Message(data) assert msg.data == data
def test_instantiates_with_optional_message_id(self): s = "After all this time? Always" message_id = "Postage12323" msg = Message(s, message_id) assert msg.message_id == message_id
def message(self): return Message("some message")
class TestMessage(object): data_str = "After all this time? Always" data_int = 987 data_obj = Message(data_str) @pytest.mark.it("Instantiates from data type") @pytest.mark.parametrize("data", [data_str, data_int, data_obj], ids=["String", "Integer", "Message"]) def test_instantiates_from_data(self, data): msg = Message(data) assert msg.data == data @pytest.mark.it("Instantiates with optional provided message id") def test_instantiates_with_optional_message_id(self): s = "After all this time? Always" message_id = "Postage12323" msg = Message(s, message_id) assert msg.message_id == message_id @pytest.mark.it( "Instantiates with optional provided content type and content encoding" ) def test_instantiates_with_optional_contenttype_encoding(self): s = "After all this time? Always" ctype = "application/json" encoding = "utf-16" msg = Message(s, None, encoding, ctype) assert msg.content_encoding == encoding assert msg.content_type == ctype @pytest.mark.it("Instantiates with optional provided output name") def test_instantiates_with_optional_output_name(self): output_name = "some_output" msg = Message("some message", output_name=output_name) assert msg.output_name == output_name @pytest.mark.it("Instantiates with no custom properties set") def test_default_custom_properties(self): msg = Message("some message") assert msg.custom_properties == {} @pytest.mark.it("Instantiates with no set expiry time") def test_default_expiry_time(self): msg = Message("some message") assert msg.expiry_time_utc is None @pytest.mark.it("Instantiates with no set correlation id") def test_default_corr_id(self): msg = Message("some message") assert msg.correlation_id is None @pytest.mark.it("Instantiates with no set user id") def test_default_user_id(self): msg = Message("some message") assert msg.user_id is None @pytest.mark.it("Instantiates with no set input name") def test_default_input_name(self): msg = Message("some message") assert msg.input_name is None @pytest.mark.it( "Instantiates with no set iothub_interface_id (i.e. not as a security message)" ) def test_default_security_msg_status(self): msg = Message("some message") assert msg.iothub_interface_id is None @pytest.mark.it( "Maintains iothub_interface_id (security message) as a read-only property" ) def test_read_only_iothub_interface_id(self): msg = Message("some message") with pytest.raises(AttributeError): msg.iothub_interface_id = "value" @pytest.mark.it( "Uses string representation of data/payload attribute as string representation of Message" ) @pytest.mark.parametrize("data", [data_str, data_int, data_obj], ids=["String", "Integer", "Message"]) def test_str_rep(self, data): msg = Message(data) assert str(msg) == str(data) @pytest.mark.it("Can be set as a security message via API") def test_setting_message_as_security_message(self): s = "After all this time? Always" ctype = "application/json" encoding = "utf-16" msg = Message(s, None, encoding, ctype) assert msg.iothub_interface_id is None msg.set_as_security_message() assert msg.iothub_interface_id == constant.SECURITY_MESSAGE_INTERFACE_ID
def test_read_only_iothub_interface_id(self): msg = Message("some message") with pytest.raises(AttributeError): msg.iothub_interface_id = "value"
def test_default_security_msg_status(self): msg = Message("some message") assert msg.iothub_interface_id is None
def test_default_input_name(self): msg = Message("some message") assert msg.input_name is None
def test_default_user_id(self): msg = Message("some message") assert msg.user_id is None
def test_default_corr_id(self): msg = Message("some message") assert msg.correlation_id is None
def test_str_rep(self, data): msg = Message(data) assert str(msg) == str(data)
def test_default_custom_properties(self): msg = Message("some message") assert msg.custom_properties == {}
def message(): return Message("Wingardium Leviosa")
def test_default_expiry_time(self): msg = Message("some message") assert msg.expiry_time_utc is None