def test__mqtt_command_callback_ignore_retained(caplog, topic: bytes, payload: bytes): ActorMock = _mock_actor_class( switchbot_mqtt._ButtonAutomator.MQTT_COMMAND_TOPIC_LEVELS) message = MQTTMessage(topic=topic) message.payload = payload message.retain = True with unittest.mock.patch.object( ActorMock, "__init__", return_value=None) as init_mock, unittest.mock.patch.object( ActorMock, "execute_command") as execute_command_mock, caplog.at_level( logging.DEBUG): ActorMock._mqtt_command_callback( "client_dummy", switchbot_mqtt._MQTTCallbackUserdata(retry_count=4, device_passwords={}), message, ) init_mock.assert_not_called() execute_command_mock.assert_not_called() assert caplog.record_tuples == [ ( "switchbot_mqtt", logging.DEBUG, "received topic={} payload={!r}".format(topic.decode(), payload), ), ("switchbot_mqtt", logging.INFO, "ignoring retained message"), ]
def test__mqtt_command_callback_invalid_mac_address(caplog, mac_address: str, payload: bytes): ActorMock = _mock_actor_class( switchbot_mqtt._ButtonAutomator.MQTT_COMMAND_TOPIC_LEVELS) topic = "homeassistant/switch/switchbot/{}/set".format( mac_address).encode() message = MQTTMessage(topic=topic) message.payload = payload with unittest.mock.patch.object( ActorMock, "__init__", return_value=None) as init_mock, unittest.mock.patch.object( ActorMock, "execute_command") as execute_command_mock, caplog.at_level( logging.DEBUG): ActorMock._mqtt_command_callback( "client_dummy", switchbot_mqtt._MQTTCallbackUserdata(retry_count=3, device_passwords={}), message, ) init_mock.assert_not_called() execute_command_mock.assert_not_called() assert caplog.record_tuples == [ ( "switchbot_mqtt", logging.DEBUG, "received topic={} payload={!r}".format(topic.decode(), payload), ), ( "switchbot_mqtt", logging.WARNING, "invalid mac address {}".format(mac_address), ), ]
def test__mqtt_command_callback_password(mac_address, expected_password): ActorMock = _mock_actor_class([ "switchbot", switchbot_mqtt._MQTTTopicPlaceholder.MAC_ADDRESS, ]) message = MQTTMessage(topic=b"switchbot/" + mac_address.encode()) message.payload = b"whatever" callback_userdata = switchbot_mqtt._MQTTCallbackUserdata( retry_count=3, device_passwords={ "11:22:33:44:55:77": "test", "aa:bb:cc:dd:ee:ff": "secret", "11:22:33:dd:ee:ff": "äöü", }, ) with unittest.mock.patch.object( ActorMock, "__init__", return_value=None) as init_mock, unittest.mock.patch.object( ActorMock, "execute_command") as execute_command_mock: ActorMock._mqtt_command_callback("client_dummy", callback_userdata, message) init_mock.assert_called_once_with(mac_address=mac_address, retry_count=3, password=expected_password) execute_command_mock.assert_called_once_with( mqtt_client="client_dummy", mqtt_message_payload=b"whatever")
def test__mqtt_command_callback( caplog, command_topic_levels: typing.List[switchbot_mqtt._MQTTTopicLevel], topic: bytes, payload: bytes, expected_mac_address: str, retry_count: int, ): ActorMock = _mock_actor_class(command_topic_levels) message = MQTTMessage(topic=topic) message.payload = payload callback_userdata = switchbot_mqtt._MQTTCallbackUserdata( retry_count=retry_count, device_passwords={}) with unittest.mock.patch.object( ActorMock, "__init__", return_value=None) as init_mock, unittest.mock.patch.object( ActorMock, "execute_command") as execute_command_mock, caplog.at_level( logging.DEBUG): ActorMock._mqtt_command_callback("client_dummy", callback_userdata, message) init_mock.assert_called_once_with(mac_address=expected_mac_address, retry_count=retry_count, password=None) execute_command_mock.assert_called_once_with(mqtt_client="client_dummy", mqtt_message_payload=payload) assert caplog.record_tuples == [( "switchbot_mqtt", logging.DEBUG, "received topic={} payload={!r}".format(topic.decode(), payload), )]
def test_mqtt_handle_on_message_save_device_data(app_and_ctx, capsys): device_id = 9999 # not present tid_bi = 'b209eba637a54f1f617cf5a6f925e4eb9fc083e66029061018b369e64b9864d7' # blind_index(hex_to_key("622c23fe2623e54ba103c13b88072ca3fdc5836fc459cb2b5c31d8df3f07ebc2"), "8") payload = b"{'added': 6987, 'num_data': 31164, 'data': 'gAAAAABcTFAz9Wr5ZsnMcVYbQiXlnZCvT36MfDatZNyLwDpm_ixbzkZhM1NA4w7MN2p3CW3gyTA8gYtuKtDTomhulszvLTFfPA==', 'tid': 'encrypted_tid(8)', 'tid_bi': '%b', 'correctness_hash': '$2b$12$9hxKg4pjXbm0kpbItQTd2uMICAGn2ntRw1qQskHIL/7tLa3ISIlmO'}" % tid_bi.encode( ) topic = b"d:%a/server/save_data" % device_id msg = MQTTMessage(topic=topic) msg.payload = payload invalid_topic = b"d:%a/server/invalid" % device_id msg_invalid = MQTTMessage(topic=invalid_topic) msg_invalid.payload = payload from app.mqtt.mqtt import handle_on_message app, ctx = app_and_ctx with app.app_context(): handle_on_message(None, None, msg_invalid, app, db) captured = capsys.readouterr() assert f"Invalid topic: {msg_invalid.topic}" in captured.out handle_on_message(None, None, msg, app, db) captured = capsys.readouterr() assert f"Device with id: {device_id} doesn't exist." in captured.out device_data = db.session.query(DeviceData).filter( and_( DeviceData.tid_bi == tid_bi, DeviceData.device_id == device_id, )).first() assert device_data is None msg.payload = payload # reassign, because `handle_on_message` causes side-effect and converts it to `dict` device_id = 23 topic = b"d:%a/server/save_data" % device_id msg.topic = topic handle_on_message(None, None, msg, app, db) device_data = db.session.query(DeviceData).filter( and_( DeviceData.tid_bi == tid_bi, DeviceData.device_id == device_id, )).first() assert device_data is not None assert device_data.added == 6987 assert device_data.num_data == 31164
def test_mqtt_handle_on_message_invalid_message(app_and_ctx, capsys): msg = MQTTMessage(topic=b"anything") msg.payload = b"invalid" from app.mqtt.mqtt import handle_on_message app, ctx = app_and_ctx with app.app_context(): handle_on_message(None, None, msg, app, db) captured = capsys.readouterr() assert f"Received invalid message '" in captured.out
def setUp(self): self.ddm = DeviceDataManager() self.ddm.actuator.addValue(15) self.mqt = MqttClientConnector() self.sd = SensorData() self.sd.addValue(14) mm = MQTTMessage() mm.payload = "ss" pass
def private_publish(self, topic, payload=None, qos=0, retain=False): """ Queue message internally without distribute to MQTT. """ msg = MQTTMessage(topic=topic.encode()) msg.payload = payload.encode() if payload else None msg.qos = qos msg.retain = retain self._queue.put(msg)
def process_mqtt_message_to_action(command) -> Fsr61Action: message = MQTTMessage() message.payload = command device.packets.clear() device.process_mqtt_message(message) self.assertEqual(len(device.packets), 1) return Fsr61Eep.extract_packet(device.packets[0])
def get_client_with_messages(msgs: dict) -> HomieClient: c = HomieClient() for topic, payload in msgs.items(): msg = MQTTMessage() msg.topic = topic.encode('utf-8') msg.payload = payload.encode('utf-8') c.on_message(None, None, msg) return c
def test_mqtt_handle_zone_control_utf8(mocker): interface = BasicMQTTInterface() interface.alarm = mocker.MagicMock() message = MQTTMessage(topic='paradox/control/zones/Előtér'.encode('utf-8')) message.payload = b'clear_bypass' interface._mqtt_handle_zone_control(None, None, message) interface.alarm.control_zone.assert_called_once_with( "Előtér", "clear_bypass")
def test_mqtt_handle_partition_control(command, expected, mocker): interface = BasicMQTTInterface() interface.alarm = mocker.MagicMock() message = MQTTMessage(topic=b'paradox/control/partition/First_floor') message.payload = command interface._mqtt_handle_partition_control(None, None, message) interface.alarm.control_partition.assert_called_once_with( "First_floor", expected)
def payload(message: MQTTMessage) -> dict: try: payload = json.loads(message.payload) if isinstance(payload, bool): message.payload = payload raise TypeError except (ValueError, TypeError): var = message.topic.split('/')[-1] payload = {var: message.payload} return payload
def send_message(topic=None, payload=None): # Mock an instance of an Eclipse Paho MQTTMessage message = MQTTMessage(mid=42, topic=topic.encode('utf-8')) message.payload = payload.encode('utf-8') # Signal the message to the machinery on_message(None, None, message) # Give the machinery some time to process the message time.sleep(0.05)
def process_mqtt_message_to_command(mqtt_command) -> Fsb61Command: message = MQTTMessage() message.payload = mqtt_command device.packets.clear() device.process_mqtt_message(message) self.assertEqual(len(device.packets), 1) fsb61_command = Fsb61CommandConverter.extract_packet( device.packets[0]) return fsb61_command
def test_construct_message_2(self, fakedevice, interface): topic = "iot-2/type/testproduct123/id/{}/mon" topic = topic.format(fakedevice.id).encode("utf8") paho_message = MQTTMessage(topic=topic) paho_message.payload = b'{"Action": "Disconnect"}' event = Status(paho_message) message_2 = interface.construct_zconnect_message(event) assert message_2.category == "status" assert message_2.body == {"Action": "Disconnect"} assert message_2.device == fakedevice
def test_generate_status_callback(self, fakedevice, interface): mocked = mock.Mock() topic = "iot-2/type/testproduct123/id/{}/mon" topic = topic.format(fakedevice.id).encode("utf8") paho_message = MQTTMessage(topic=topic) paho_message.payload = b'{"Action": "Disconnect"}' event = Status(paho_message) callback = interface.generate_status_callback(mocked) callback(event) assert mocked.call_count == 1
def test_construct_message(self, fakedevice, interface): topic = (TOPIC.format("testproduct123", fakedevice.id, "periodic").encode("utf8")) paho_message = MQTTMessage(topic=topic) paho_message.payload = b'{"foo": "bar"}' event = Event(paho_message, {"json": jsonCodec}) message = interface.construct_zconnect_message(event) assert message.category == "periodic" assert message.body == {"foo": "bar"} assert message.device == fakedevice
def test_mqtt_handle_on_message_receive_pk_user_doesnt_have_this_device( app_and_ctx, capsys): pk = b'-----BEGIN PUBLIC KEY-----\\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE2rD6Bhju8WSEFogdBxZt/N+n7ziUPi5C\\nQU1gSQQDNm57fdDuYNDOR7Wwb1fq5tSl2TC1D6WRTIt1gzzCsApGpZ3PIs7Wdbil\\neJL/ETGa2Sqwav7JDH4r0V30sF4NqDok\\n-----END PUBLIC KEY-----\\n' user_id = 1 device_id = 34 msg = MQTTMessage(topic=b"d:%a/server/" % device_id) msg.payload = b"{'user_id': %a, " \ b"'device_public_key': '%b'}" % (user_id, pk) from app.mqtt.mqtt import handle_on_message app, ctx = app_and_ctx with app.app_context(): handle_on_message(None, None, msg, app, db) captured = capsys.readouterr() assert f"This User can't access device {device_id}" in captured.out
def test__mqtt_on_message( topic: bytes, payload: bytes, expected_mac_address: str, expected_action: switchbot_mqtt._SwitchbotAction, ): message = MQTTMessage(topic=topic) message.payload = payload with unittest.mock.patch("switchbot_mqtt._send_command") as send_command_mock: switchbot_mqtt._mqtt_on_message("client_dummy", None, message) send_command_mock.assert_called_once_with( mqtt_client="client_dummy", switchbot_mac_address=expected_mac_address, action=expected_action, )
def mqtt_pub(self, topic, payload): if isinstance(payload, unicode): local_payload = payload.encode('utf-8') elif isinstance(payload, (bytes, bytearray)): local_payload = payload elif isinstance(payload, (int, float)): local_payload = str(payload).encode('ascii') elif payload is None: local_payload = b'' else: raise Exception( 'payload must be a string, bytearray, int, float or None.') message = MQTTMessage(0, topic.encode('utf-8')) message.payload = local_payload cls.m2i._on_mqtt_message(None, None, message)
async def test_read_write(mqtt, client_id): """Test MQTT transport read and write.""" mqtt_client = mqtt.return_value topic = f"{IN_PREFIX}/0/255/3/1/11" payload = "test" msg = MQTTMessage() msg.topic = topic.encode() msg.payload = payload.encode() messages = [msg] async def mock_messages(): """Mock the messages generator.""" for message in messages: yield message @asynccontextmanager async def filter_messages(): """Mock filter messages.""" yield mock_messages() mqtt_client.unfiltered_messages.side_effect = filter_messages transport = MQTTClient(HOST, PORT, IN_PREFIX, OUT_PREFIX) await transport.connect() assert mqtt.call_count == 1 assert mqtt.call_args == call( HOST, PORT, client_id=client_id, logger=PAHO_MQTT_LOGGER, clean_session=True, ) await asyncio.sleep(0) read = await transport.read() assert read == "0;255;3;1;11;test" await transport.write(read) assert mqtt_client.publish.call_count == 1 assert mqtt_client.publish.call_args == call( f"{OUT_PREFIX}/0/255/3/1/11", qos=1, retain=False, timeout=10, payload=payload ) await transport.disconnect() assert mqtt_client.disconnect.call_count == 1
async def test_mqtt_handle_door_control(mocker): interface = get_interface(mocker) try: await asyncio.sleep(0.01) message = MQTTMessage(topic="paradox/control/doors/Door 1".encode("utf-8")) message.payload = b"unlock" interface._mqtt_handle_door_control(None, None, message) await asyncio.sleep(0.01) interface.alarm.control_door.assert_called_once_with("Door 1", "unlock") finally: interface.stop() interface.join() assert not interface.is_alive()
def test_parse_ibm_event(self, fakedevice, interface): topic = (TOPIC.format("testproduct123", fakedevice.id, "example_category").encode("utf8")) paho_message = MQTTMessage(topic=topic) paho_message.payload = b'{"foo": "bar"}' event = Event(paho_message, {"json": jsonCodec}) zconnect_message = interface.construct_zconnect_message(event) assert zconnect_message.device.id == fakedevice.id assert (zconnect_message.device.product.iot_name == fakedevice.product.iot_name == "testproduct123") assert zconnect_message.category == "example_category" assert zconnect_message.body == {"foo": "bar"}
async def test_mqtt_handle_zone_control_utf8(mocker): interface = get_interface(mocker) try: await asyncio.sleep(0.01) message = MQTTMessage(topic="paradox/control/zones/Előtér".encode("utf-8")) message.payload = b"clear_bypass" interface._mqtt_handle_zone_control(None, None, message) await asyncio.sleep(0.01) interface.alarm.control_zone.assert_called_once_with("Előtér", "clear_bypass") finally: interface.stop() interface.join() assert not interface.is_alive()
async def test_read_failure(mqtt, client_id): """Test MQTT transport read failure.""" mqtt_client = mqtt.return_value topic = f"{IN_PREFIX}/0/0/0/0/0" payload = "test" msg = MQTTMessage() msg.topic = topic.encode() msg.payload = payload.encode() messages = [msg] async def mock_messages(): """Mock the messages generator.""" for message in messages: yield message @asynccontextmanager async def filter_messages(): """Mock filter messages.""" yield mock_messages() raise MqttError("Boom") mqtt_client.unfiltered_messages.side_effect = filter_messages transport = MQTTClient(HOST, PORT, IN_PREFIX, OUT_PREFIX) await transport.connect() assert mqtt.call_count == 1 assert mqtt.call_args == call( HOST, PORT, client_id=client_id, logger=PAHO_MQTT_LOGGER, clean_session=True, ) await asyncio.sleep(0) read = await transport.read() assert read == "0;0;0;0;0;test" with pytest.raises(TransportFailedError): await transport.read() await transport.disconnect() assert mqtt_client.disconnect.call_count == 1
async def test_mqtt_handle_partition_control(command, expected, mocker): interface = get_interface(mocker) try: await asyncio.sleep(0.01) message = MQTTMessage(topic=b"paradox/control/partition/First_floor") message.payload = command interface._mqtt_handle_partition_control(None, None, message) await asyncio.sleep(0.01) interface.alarm.control_partition.assert_called_once_with( "First_floor", expected) finally: interface.stop() interface.join() assert not interface.is_alive()
def resend_command(self): ''' resend commands in self.pending_commands intended to be run 5 seconds or so after command sent to PLM ''' self.log.debug('Running resend_command: {}'.format('no commands pending' if len(self.pending_commands.keys())==0 else self.pending_commands)) for name, value in self.pending_commands.copy().items(): if value[1] <=5: #max 5 retries msg = MQTTMessage(topic=name.encode()) msg.payload = str(value[0]).encode() else: self.log.error('Too many retries on sending command {}, {} - giving up'.format(name, value[0])) del self.pending_commands[name] self.publish_node(self.nodes[name]) return self.log.warning('resending command {}, {} retry: {}'.format(name, value[0], value[1])) self.q.put_nowait(msg)
def test_subscribe(mock_broker, mocker): mqttc = MqttClient(port=1883, callback=callback) mqttc.subscribe(topic="sensor/temperature") # create a fake MQTT message msg = MQTTMessage(mid=MID) msg.topic = b"sensor/temperature" msg.payload = b"22.5" mocker.spy(mqttc, "callback") # trigger 2 messages received on the MQTT bus mqttc._client.on_message(mqttc._client, None, msg) mqttc._client.on_message(mqttc._client, None, msg) mqttc.stop() assert mqttc.callback.call_count == 2
def publishText(self, session: DialogSession) -> Response: message = MQTTMessage() message.payload = json.dumps({ 'sessionId': session.sessionId, 'siteId': session.deviceUid, 'text': session.input }) session.extend(message=message) self.MqttManager.publish(topic=constants.TOPIC_TEXT_CAPTURED, payload={ 'sessionId': session.sessionId, 'text': session.input, 'device': session.deviceUid, 'likelihood': 1, 'seconds': 1 }) return jsonify(success=True, sessionId=session.sessionId)