async def test_send_on_topic(self): """Test sending the ON command.""" async with async_protocol_manager(): received_topic = "" def expected_topic_received(cmd1, cmd2, user_data, topic=pub.AUTO_TOPIC): nonlocal received_topic received_topic = topic.name address = random_address() on_topic = "send.{}.1.direct".format(ON) topics = [ TopicItem(on_topic, { "address": address, "on_level": 0xFF, "group": 0 }, 0) ] self._last_topic = None expected_topic = "ack.{}.1.on.direct".format(address.id) pub.subscribe(expected_topic_received, expected_topic) send_topics(topics) await asyncio.sleep(0.05) assert received_topic == expected_topic
async def test_send_on_all_link_broadcast_topic(self): """Test sending the broadcast ON command.""" from pyinsteon.handlers.to_device.on_level_all_link_broadcast import ( OnLevelAllLinkBroadcastCommand, ) topic_lock = asyncio.Lock() async with async_protocol_manager(): last_topic = None def topic_received(cmd1, cmd2, user_data, topic=pub.AUTO_TOPIC): """Receive the OFF topic for a device.""" nonlocal last_topic last_topic = topic.name if topic_lock.locked(): topic_lock.release() group = 3 target = Address(bytearray([0x00, 0x00, group])) ack_topic = "ack.{}.on.all_link_broadcast".format(target.id) pub.subscribe(topic_received, ack_topic) cmd = OnLevelAllLinkBroadcastCommand(group=group) await topic_lock.acquire() await cmd.async_send() # Mock transport auto sends ACK/NAK try: await asyncio.wait_for(topic_lock.acquire(), 2) assert last_topic == ack_topic except asyncio.TimeoutError: assert ack_topic is None if topic_lock.locked(): topic_lock.release()
async def test_receive_on_msg(self): """Test receiving an ON message.""" async with async_protocol_manager() as protocol: last_topic = None def topic_received(cmd1, cmd2, target, user_data, hops_left, topic=pub.AUTO_TOPIC): """Receive the OFF topic for a device.""" nonlocal last_topic last_topic = topic.name address = random_address() byte_data = create_std_ext_msg(address, 0x80, 0x11, 0xFF, target=Address("000001")) expected_topic = "{}.{}.on.broadcast".format(address.id, 1) pub.subscribe(topic_received, expected_topic) on_cmd = DataItem(byte_data, 0) data = [on_cmd] send_data(data, protocol.read_queue) await asyncio.sleep(0.05) assert last_topic == expected_topic
async def test_message_to_topic(self): """Test converting a message to a topic.""" async with async_protocol_manager() as protocol: tests = await import_commands() for test_info in tests: self._topic = None address = repr(random_address()) curr_test = tests[test_info] if curr_test.get("address"): curr_test["address"] = address msgs = [create_message(curr_test)] curr_topic = curr_test["topic"].format(address) pub.subscribe(self.capture_topic, curr_topic) send_data(msgs, protocol.read_queue) await sleep(0.07) try: assert self._topic.name == curr_topic except (AssertionError, AttributeError): raise AssertionError( "Failed test {} with message topic {} and test topic {}".format( test_info, self._topic.name, curr_test.get("topic") ) ) finally: pub.unsubscribe(self.capture_topic, curr_topic)
def setUp(self): """Set up the test.""" self.ack_message = "ack.{}".format(START_ALL_LINKING) self.handler = StartAllLinkingCommandHandler() self.received = False pub.subscribe(self.send_listener, START_ALL_LINKING) self._sent = False
def setUp(self): """Set up the test.""" self.ack_message = "ack.send_all_link_command" self.received = False pub.subscribe(self.send_listener, "send_all_link_command") self._sent = False set_log_levels(logger_topics=True)
def setUp(self): """Set up the test.""" self.ack_message = "ack.send_all_link_command" self.handler = SendAllLinkCommandHandler() self.received = False pub.subscribe(self.send_listener, "send_all_link_command") self._sent = False
async def test_x10_all_lights_on(self): """Test X10 message received.""" handler = X10Received() pub.subscribe(self.x10_subscriber, "x10c") handler.subscribe(self.x10_subscriber) # Receive housecode C All Lights On handler.handle_x10_received(0x21, 0x80) assert self._x10_receieved == "x10c.all_lights_on"
async def test_x10_off_received(self): """Test X10 message received.""" handler = X10Received() pub.subscribe(self.x10_subscriber, "x10a03") handler.subscribe(self.x10_subscriber) # Receive housecode A unitcode 3 handler.handle_x10_received(0x62, 0x00) # Receive housecode A command Off handler.handle_x10_received(0x63, 0x80) assert self._x10_receieved == "x10a03.off"
async def test_x10_on_received(self): """Test X10 message received.""" handler = X10Received() pub.subscribe(self.x10_subscriber, "x10g09") handler.subscribe(self.x10_subscriber) # Receive housecode G unitcode 9 handler.handle_x10_received(0x57, 0x00) # Receive housecode G command On handler.handle_x10_received(0x52, 0x80) assert self._x10_receieved == "x10g09.on"
async def test_data_received(self): """Test the data_received method.""" def dummy_nak_listener(*args, **kwargs): """Listen for NAK. This ensures we send the NAK rather than resend the message. """ data = [ { "data": "025003040506070809110b", "topic": "030405.1.on.direct" }, { "data": "02500304050607", "topic": None }, { "data": "0809130b", "topic": "030405.1.off.direct" }, ] with patch("pyinsteon.protocol.protocol.publish_topic", self.mock_publish_topic): async with async_protocol_manager(auto_ack=False) as protocol: for test in data: self.topic = None protocol.data_received(unhexlify(test["data"])) await asyncio.sleep(0.1) try: assert self.topic == test["topic"] except AssertionError: raise AssertionError( f"Failed with data {test['data']}: Topic: {self.topic} Expected: {test['topic']}" ) # Test when the modem only responds with a NAK rather than the original message. nak_topic = "nak.0a0b0c.1.on.direct" pub.subscribe(dummy_nak_listener, nak_topic) protocol.write(unhexlify("02620a0b0c09110b")) await asyncio.sleep(0.1) self.topic = None protocol.data_received(unhexlify("15")) await asyncio.sleep(0.1) assert self.topic == nak_topic # Test that a NAK is resent rather than published as a topic. self.topic = None protocol.data_received(unhexlify("02620d0e0f09110b15")) await asyncio.sleep(0.1) assert self.topic is None
def set_log_levels( logger="info", logger_pyinsteon="info", logger_messages="info", logger_topics=False ): """Set the log levels of the three logs.""" _setup_logger(_LOGGER, logger) _setup_logger(_LOGGER_PYINSTEON, logger_pyinsteon) _setup_logger(_LOGGER_MESSAGES, logger_messages) if logger_topics: _setup_logger(_LOGGER_TOPICS, "info") pub.subscribe(_log_all_topics, pub.ALL_TOPICS) else: _setup_logger(_LOGGER_TOPICS, "fatal") pub.unsubscribe(_log_all_topics, pub.ALL_TOPICS)
async def test_load_empty(self): """Test loading an empty modem ALDB.""" async with LOCK: mgr = pub.getDefaultTopicMgr() mgr.delTopic(ALL_LINK_RECORD_RESPONSE) aldb = ModemALDB(random_address()) pub.subscribe(send_nak_response, SEND_FIRST_TOPIC) response = await aldb.async_load() _LOGGER.debug("Done LOAD function.") _LOGGER.debug("Status: %s", response.name) assert aldb.is_loaded _LOGGER.debug("ALDB Record Count: %d", len(aldb)) assert len(aldb) == 0 pub.unsubscribe(send_nak_response, SEND_FIRST_TOPIC)
async def test_command(self): """Test direct command.""" async with async_protocol_manager() as protocol: msgs = [] def listen_for_ack(): send_data(msgs, protocol.read_queue) tests = await import_commands() pub.subscribe(self.validate_values, pub.ALL_TOPICS) pub.subscribe(listen_for_ack, "ack") for test_info in tests: address = random_address() self._current_test = test_info test_command = tests[test_info] command = test_command.get("command") cmd_class = command.get("class") params = command.get("params") if params.get("address"): params["address"] = address send_params = command.get("send_params") test_response = test_command.get("response") obj = get_class_or_method(commands, cmd_class) cmd = obj(**params) messages = test_command.get("messages") msgs = [] for message in messages: msg_dict = messages[message] msg_dict["address"] = address msgs.append(create_message(msg_dict)) self._assert_tests = test_command.get("assert_tests") # send_data(msgs, self._read_queue) try: response = await cmd.async_send(**send_params) except Exception as ex: raise Exception("Failed test {} with error: {}".format( self._current_test, str(ex))) if test_response: try: assert int(response) == test_response except AssertionError: raise AssertionError( "Failed test: {} command response: {}".format( self._current_test, response)) await sleep(0.1)
async def test_all_lights_on(self): """Test the All Lights On command.""" call_received = False def check_x10_call(raw_x10, x10_flag): """Check the X10 call params.""" nonlocal call_received call_received = True assert raw_x10 == 0x61 assert x10_flag == 0x80 topic = "send.x10_send" pub.subscribe(check_x10_call, topic) await async_x10_all_lights_on(housecode="a") await asyncio.sleep(0.05) assert call_received pub.unsubscribe(check_x10_call, topic)
async def test_load_8_records_eeprom(self): """Test loading 8 records into the modem ALDB.""" async with LOCK: mgr = pub.getDefaultTopicMgr() mgr.delTopic(ALL_LINK_RECORD_RESPONSE) pub.subscribe(self.send_eeprom_response, SEND_READ_EEPROM_TOPIC) aldb = ModemALDB(random_address()) aldb.read_write_mode = ReadWriteMode.EEPROM response = await aldb.async_load() await asyncio.sleep(0.01) _LOGGER.debug("Done LOAD function.") _LOGGER.debug("Status: %s", response.name) assert aldb.is_loaded _LOGGER.debug("ALDB Record Count: %d", len(aldb)) assert len(aldb) == 9 # Includes HWM record pub.unsubscribe(self.send_standard_response, SEND_READ_EEPROM_TOPIC)
async def test_async_send(self): """Test the async_send method.""" self.handler = StartAllLinkingCommandHandler() self.received = False pub.subscribe(self.send_listener, START_ALL_LINKING) topics = [ TopicItem( self.ack_message, { "link_mode": AllLinkMode.CONTROLLER, "group": 0x01 }, 0.5, ) ] send_topics(topics) assert await self.handler.async_send(link_mode=AllLinkMode.CONTROLLER, group=0x01)
def base_setup(self, message_id, bytes_data, **kwargs): """Init the OutboundBase class.""" set_log_levels( logger="info", logger_pyinsteon="debug", logger_messages="debug", logger_topics=False, ) register_outbound_handlers() self.msg = None self.message_id = message_id self.bytes_data = bytes_data pub.subscribe(self.receive_message, "send_message") topic = self.message_id.name.lower() if (topic == "send_standard" and kwargs.get("flags") and kwargs.get("flags").is_extended): topic = "send_extended" pub.sendMessage("send.{}".format(topic), **kwargs)
def set_log_levels(logger="info", logger_pyinsteon="info", logger_messages="info", logger_topics=False): """Set the log levels of the three logs.""" try: assert os.environ["ALLOW_LOGGING"].lower() == "y" except (AssertionError, KeyError): return _setup_logger(_LOGGER, logger) _setup_logger(_LOGGER_PYINSTEON, logger_pyinsteon) _setup_logger(_LOGGER_MESSAGES, logger_messages) if logger_topics: _setup_logger(_LOGGER_TOPICS, "info") pub.subscribe(_log_all_topics, pub.ALL_TOPICS) else: _setup_logger(_LOGGER_TOPICS, "fatal") pub.unsubscribe(_log_all_topics, pub.ALL_TOPICS)
async def test_modem_inbound(self): """Test direct command.""" async with async_protocol_manager(auto_ack=False) as protocol: tests = await import_modem_commands() pub.subscribe(self.validate_values, pub.ALL_TOPICS) for test_info in tests: self._current_test = test_info test_command = tests[test_info] command = test_command.get("command") cmd_class = command.get("class") inbound_message = command.get("inbound_message")["data"] self._assert_tests = test_command.get("assert_tests") obj = get_class_or_method(commands, cmd_class) cmd = obj() inbound_data = unhexlify(f"02{inbound_message}") ack_response_item = DataItem(inbound_data, 0) send_data([ack_response_item], protocol.read_queue) await sleep(0.1)
async def test_receive_on_msg(self): """Test receiving an ON message.""" topic_lock = asyncio.Lock() async with async_protocol_manager() as protocol: last_topic = None def topic_received(cmd1, cmd2, target, user_data, hops_left, topic=pub.AUTO_TOPIC): """Receive the OFF topic for a device.""" nonlocal last_topic last_topic = topic.name if topic_lock.locked(): topic_lock.release() address = random_address() byte_data = create_std_ext_msg(address, 0x80, 0x11, 0xFF, target=Address("000001")) expected_topic = "{}.{}.on.broadcast".format(address.id, 1) pub.subscribe(topic_received, expected_topic) on_cmd = DataItem(byte_data, 0) data = [on_cmd] await topic_lock.acquire() send_data(data, protocol.read_queue) try: await asyncio.wait_for(topic_lock.acquire(), 2) assert last_topic == expected_topic except asyncio.TimeoutError: assert expected_topic is None if topic_lock.locked(): topic_lock.release()
async def test_send_on_topic(self): """Test sending the ON command.""" topic_lock = asyncio.Lock() async with async_protocol_manager(): received_topic = "" def expected_topic_received(cmd1, cmd2, user_data, topic=pub.AUTO_TOPIC): nonlocal received_topic received_topic = topic.name if topic_lock.locked(): topic_lock.release() address = random_address() on_topic = "send.{}.1.direct".format(ON) topics = [ TopicItem(on_topic, { "address": address, "on_level": 0xFF, "group": 0 }, 0) ] self._last_topic = None expected_topic = "ack.{}.1.on.direct".format(address.id) pub.subscribe(expected_topic_received, expected_topic) await topic_lock.acquire() send_topics(topics) try: await asyncio.wait_for(topic_lock.acquire(), 2) assert received_topic == expected_topic except asyncio.TimeoutError: assert expected_topic is None if topic_lock.locked(): topic_lock.release()
async def test_status_request_command(self): """Test an Status Request message.""" status_received = False status_1_received = False state_values = {} def state_updated(value, group, name, address): """Run when the state is updated.""" nonlocal state_values _LOGGER.info("Group %s updated: %s", str(group), str(value)) state_values[group] = value def receive_status(db_version, status): """Run when the state is updated.""" nonlocal status_received _LOGGER.info("Status received") status_received = True def receive_status_1(db_version, status): """Run when the state is updated.""" nonlocal status_1_received _LOGGER.info("Status 1 received") status_1_received = True address = random_address() device = DimmableLightingControl_KeypadLinc_8(address, 0x01, 0x02, 0x03, "Test", "KPL") for button in device.groups: device.groups[button].set_value(0) device.groups[button].subscribe(state_updated) cmd1_status = random.randint(0, 255) cmd2_status = random.randint(0, 255) cmd1_status_1 = random.randint(0, 255) cmd2_status_1 = random.randint(0, 255) cmd1_on = 0x11 cmd2_on = random.randint(0, 255) target = device.address user_data = None ack_status_0 = "ack.{}.{}.direct".format(device.address.id, STATUS_REQUEST) ack_status_1 = "ack.{}.{}.direct".format(device.address.id, STATUS_REQUEST) direct_ack_status = "{}.{}.direct_ack".format(device.address.id, STATUS_REQUEST) ack_on = "ack.{}.1.{}.direct".format(device.address.id, ON) direct_ack_on = "{}.{}.direct_ack".format(device.address.id, ON) status_1_handler_topic = f"handler.{device.address.id}.1.status_request.direct" status_handler_topic = f"handler.{device.address.id}.2.status_request.direct" pub.subscribe(receive_status, status_handler_topic) pub.subscribe(receive_status_1, status_1_handler_topic) responses = [ TopicItem(ack_status_0, cmd_kwargs(0x19, 0x02, user_data), 0.5), TopicItem( direct_ack_status, cmd_kwargs(cmd1_status, cmd2_status, user_data, target), 0.25, ), TopicItem(ack_status_1, cmd_kwargs(0x19, 0x01, user_data), 0.25), TopicItem( direct_ack_status, cmd_kwargs(cmd1_status_1, cmd2_status_1, user_data, target), 0.25, ), TopicItem(ack_on, cmd_kwargs(cmd1_on, cmd2_on, user_data), 0.25), TopicItem(direct_ack_on, cmd_kwargs(cmd1_on, cmd2_on, user_data, target), 0.25), ] send_topics(responses) response = await device.async_status() assert response == ResponseStatus.SUCCESS assert status_received assert status_1_received assert state_values.get(1) == cmd2_status for bit in range(1, 8): bit_set = bit_is_set(cmd2_status_1, bit) button = bit + 1 if bit_set: assert state_values.get(button) else: assert state_values.get(button) is None # Confirm that an ON command does not trigger the status handler again status_received = False status_1_received = False response = await device.async_on(on_level=cmd2_on, fast=False) assert response == ResponseStatus.SUCCESS assert not status_received assert not status_1_received assert state_values.get(1) == cmd2_on for bit in range(1, 8): bit_set = bit_is_set(cmd2_status_1, bit) button = bit + 1 if bit_set: assert state_values.get(button) else: assert state_values.get(button) is None