async def main(): connection_config = ConnectionConfig( connection_type=ConnectionType.TUNNELING, gateway_ip="10.0.0.197", gateway_port=3671, local_ip="10.0.0.70") xknx = XKNX(connection_config=connection_config) await xknx.start() print(len(xknx.devices)) for device in xknx.devices: print(device) print("Start done") light = Light(xknx, name ='Lamp Pieter', group_address_switch='0/2/18') print(light) await light.set_off() TempSensor = Sensor(xknx, 'TempSensor Bureel Pieter', group_address_state='2/2/11', value_type='temperature') await TempSensor.sync() print(TempSensor) print(TempSensor.resolve_state()) print(TempSensor.unit_of_measurement()) print(TempSensor.sensor_value.value) await xknx.stop()
async def test_always_callback_sensor(self): """Test always callback sensor.""" xknx = XKNX() sensor = Sensor( xknx, "TestSensor", group_address_state="1/2/3", always_callback=False, value_type="volume_liquid_litre", ) after_update_callback = AsyncMock() sensor.register_device_updated_cb(after_update_callback) payload = DPTArray((0x00, 0x00, 0x01, 0x00)) # set initial payload of sensor sensor.sensor_value.value = 256 telegram = Telegram(destination_address=GroupAddress("1/2/3"), payload=GroupValueWrite(payload)) response_telegram = Telegram( destination_address=GroupAddress("1/2/3"), payload=GroupValueResponse(payload), ) # verify not called when always_callback is False await sensor.process(telegram) after_update_callback.assert_not_called() after_update_callback.reset_mock() sensor.always_callback = True # verify called when always_callback is True await sensor.process(telegram) after_update_callback.assert_called_once() after_update_callback.reset_mock() # verify not called when processing read responses await sensor.process(response_telegram) after_update_callback.assert_not_called()
async def test_array_sensor_loop(self, value_type, test_payload, test_value): """Test sensor and expose_sensor with different values.""" xknx = XKNX() xknx.knxip_interface = AsyncMock() xknx.rate_limit = False await xknx.telegram_queue.start() expose = ExposeSensor( xknx, "TestExpose", group_address="1/1/1", value_type=value_type, ) assert expose.resolve_state() is None # set a value from expose - HA sends strings for new values stringified_value = str(test_value) await expose.set(stringified_value) outgoing_telegram = Telegram( destination_address=GroupAddress("1/1/1"), direction=TelegramDirection.OUTGOING, payload=GroupValueWrite(test_payload), ) await xknx.telegrams.join() xknx.knxip_interface.send_telegram.assert_called_with(outgoing_telegram) assert expose.resolve_state() == test_value # init sensor after expose is set - with same group address sensor = Sensor( xknx, "TestSensor", group_address_state="1/1/1", value_type=value_type, ) assert sensor.resolve_state() is None # read sensor state (from expose as it has the same GA) # wait_for_result so we don't have to await self.xknx.telegrams.join() await sensor.sync(wait_for_result=True) read_telegram = Telegram( destination_address=GroupAddress("1/1/1"), direction=TelegramDirection.OUTGOING, payload=GroupValueRead(), ) response_telegram = Telegram( destination_address=GroupAddress("1/1/1"), direction=TelegramDirection.OUTGOING, payload=GroupValueResponse(test_payload), ) xknx.knxip_interface.send_telegram.assert_has_calls( [ call(read_telegram), call(response_telegram), ] ) # test if Sensor has successfully read from ExposeSensor assert sensor.resolve_state() == test_value assert expose.resolve_state() == sensor.resolve_state() await xknx.telegram_queue.stop()
def test_has_group_address(self): """Test sensor has group address.""" xknx = XKNX() sensor = Sensor( xknx, "TestSensor", value_type="temperature", group_address_state="1/2/3" ) assert sensor.has_group_address(GroupAddress("1/2/3")) assert not sensor.has_group_address(GroupAddress("1/2/4"))
def test_state_addresses(self): """Test state addresses of sensor object.""" xknx = XKNX(loop=self.loop) sensor = Sensor(xknx, 'TestSensor', value_type='temperature', group_address_state='1/2/3') self.assertEqual(sensor.state_addresses(), [GroupAddress('1/2/3')])
def test_state_addresses(self): """Test expose sensor returns empty list as state addresses.""" xknx = XKNX(loop=self.loop) sensor = Sensor(xknx, 'TestSensor', value_type='temperature', group_address='1/2/3') self.assertEqual(sensor.state_addresses(), [GroupAddress('1/2/3')])
def test_process(self): """Test process / reading telegrams from telegram queue.""" xknx = XKNX(loop=self.loop) sensor = Sensor(xknx, 'TestSensor', group_address='1/2/3') telegram = Telegram(Address('1/2/3')) telegram.payload = DPTArray((0x01, 0x02, 0x03)) self.loop.run_until_complete(asyncio.Task(sensor.process(telegram))) self.assertEqual(sensor.state, DPTArray((0x01, 0x02, 0x03)))
def test_has_group_address(self): """Test sensor has group address.""" xknx = XKNX(loop=self.loop) sensor = Sensor(xknx, 'TestSensor', value_type='temperature', group_address_state='1/2/3') self.assertTrue(sensor.has_group_address(GroupAddress('1/2/3'))) self.assertFalse(sensor.has_group_address(GroupAddress('1/2/4')))
def test_state_addresses_passive(self): """Test state addresses of passive sensor object.""" xknx = XKNX(loop=self.loop) sensor = Sensor(xknx, 'TestSensor', value_type='temperature', group_address_state='1/2/3', sync_state=False) self.assertEqual(sensor.state_addresses(), [])
def test_state_addresses(self): """Test state addresses of sensor object.""" xknx = XKNX(loop=self.loop) sensor = Sensor( xknx, 'TestSensor', value_type='temperature', group_address_state='1/2/3') self.assertEqual(sensor.state_addresses(), [GroupAddress('1/2/3')])
def test_has_group_address(self): """Test sensor has group address.""" xknx = XKNX(loop=self.loop) sensor = Sensor( xknx, 'TestSensor', value_type='temperature', group_address_state='1/2/3') self.assertTrue(sensor.has_group_address(GroupAddress('1/2/3'))) self.assertFalse(sensor.has_group_address(GroupAddress('1/2/4')))
def test_str_temp(self): """Test resolve state with temperature sensor.""" xknx = XKNX(loop=self.loop) sensor = Sensor(xknx, 'TestSensor', group_address='1/2/3', value_type="temperature") sensor.state = DPTArray((0x0c, 0x1a)) self.assertEqual(sensor.resolve_state(), 21.00) self.assertEqual(sensor.unit_of_measurement(), "°C")
def test_str_humidity(self): """Test resolve state with humidity sensor.""" xknx = XKNX(loop=self.loop) sensor = Sensor(xknx, 'TestSensor', group_address='1/2/3', value_type="humidity") sensor.state = DPTArray((0x0e, 0x73)) self.assertEqual(sensor.resolve_state(), 33.02) self.assertEqual(sensor.unit_of_measurement(), "%")
def test_str_power(self): """Test resolve state with power sensor.""" xknx = XKNX(loop=self.loop) sensor = Sensor(xknx, 'TestSensor', group_address='1/2/3', value_type="power") sensor.sensor_value.payload = DPTArray((0x43, 0xC6, 0x80, 00)) self.assertEqual(sensor.resolve_state(), 397) self.assertEqual(sensor.unit_of_measurement(), "W")
def test_str_electric_potential(self): """Test resolve state with voltage sensor.""" xknx = XKNX(loop=self.loop) sensor = Sensor(xknx, 'TestSensor', group_address_state='1/2/3', value_type="electric_potential") sensor.sensor_value.payload = DPTArray((0x43, 0x65, 0xE3, 0xD7)) self.assertEqual(round(sensor.resolve_state(), 2), 229.89) self.assertEqual(sensor.unit_of_measurement(), "V")
def test_str_scaling(self): """Test resolve state with percent sensor.""" xknx = XKNX(loop=self.loop) sensor = Sensor(xknx, 'TestSensor', group_address='1/2/3', value_type="percent") sensor.state = DPTArray((0x40, )) self.assertEqual(sensor.resolve_state(), "25") self.assertEqual(sensor.unit_of_measurement(), "%")
def test_str_scaling(self): """Test resolve state with percent sensor.""" xknx = XKNX(loop=self.loop) sensor = Sensor(xknx, 'TestSensor', group_address_state='1/2/3', value_type="percent") sensor.sensor_value.payload = DPTArray((0x40, )) self.assertEqual(sensor.resolve_state(), 25) self.assertEqual(sensor.unit_of_measurement(), "%") self.assertEqual(sensor.ha_device_class(), None)
def test_sync(self): """Test sync function / sending group reads to KNX bus.""" xknx = XKNX(loop=self.loop) sensor = Sensor(xknx, 'TestSensor', group_address='1/2/3') self.loop.run_until_complete(asyncio.Task(sensor.sync(False))) self.assertEqual(xknx.telegrams.qsize(), 1) telegram = xknx.telegrams.get_nowait() self.assertEqual(telegram, Telegram(Address('1/2/3'), TelegramType.GROUP_READ))
def test_str_speed_ms(self): """Test resolve state with speed_ms sensor.""" xknx = XKNX(loop=self.loop) sensor = Sensor( xknx, 'TestSensor', group_address='1/2/3', value_type="speed_ms") sensor.sensor_value.payload = DPTArray((0x00, 0x1b,)) self.assertEqual(sensor.resolve_state(), 0.27) self.assertEqual(sensor.unit_of_measurement(), "m/s")
def test_str_electric_potential(self): """Test resolve state with voltage sensor.""" xknx = XKNX(loop=self.loop) sensor = Sensor( xknx, 'TestSensor', group_address_state='1/2/3', value_type="electric_potential") sensor.sensor_value.payload = DPTArray((0x43, 0x65, 0xE3, 0xD7)) self.assertEqual(round(sensor.resolve_state(), 2), 229.89) self.assertEqual(sensor.unit_of_measurement(), "V")
def test_process(self): """Test process / reading telegrams from telegram queue.""" xknx = XKNX(loop=self.loop) sensor = Sensor(xknx, 'TestSensor', value_type='temperature', group_address_state='1/2/3') telegram = Telegram(GroupAddress('1/2/3')) telegram.payload = DPTArray((0x06, 0xa0)) self.loop.run_until_complete(asyncio.Task(sensor.process(telegram))) self.assertEqual(sensor.sensor_value.payload, DPTArray((0x06, 0xa0))) self.assertEqual(sensor.resolve_state(), 16.96)
def test_str_scaling(self): """Test resolve state with percent sensor.""" xknx = XKNX(loop=self.loop) sensor = Sensor( xknx, 'TestSensor', group_address_state='1/2/3', value_type="percent") sensor.sensor_value.payload = DPTArray((0x40,)) self.assertEqual(sensor.resolve_state(), 25) self.assertEqual(sensor.unit_of_measurement(), "%") self.assertEqual(sensor.ha_device_class(), None)
def test_str_speed_ms(self): """Test resolve state with speed_ms sensor.""" xknx = XKNX(loop=self.loop) sensor = Sensor( xknx, 'TestSensor', group_address_state='1/2/3', value_type="speed_ms") sensor.sensor_value.payload = DPTArray((0x00, 0x1b,)) self.assertEqual(sensor.resolve_state(), 0.27) self.assertEqual(sensor.unit_of_measurement(), "m/s") self.assertEqual(sensor.ha_device_class(), None)
def test_str_temp(self): """Test resolve state with temperature sensor.""" xknx = XKNX(loop=self.loop) sensor = Sensor( xknx, 'TestSensor', group_address_state='1/2/3', value_type="temperature") sensor.sensor_value.payload = DPTArray((0x0c, 0x1a)) self.assertEqual(sensor.resolve_state(), 21.00) self.assertEqual(sensor.unit_of_measurement(), "°C") self.assertEqual(sensor.ha_device_class(), "temperature")
def test_str_humidity(self): """Test resolve state with humidity sensor.""" xknx = XKNX(loop=self.loop) sensor = Sensor( xknx, 'TestSensor', group_address_state='1/2/3', value_type="humidity") sensor.sensor_value.payload = DPTArray((0x0e, 0x73)) self.assertEqual(sensor.resolve_state(), 33.02) self.assertEqual(sensor.unit_of_measurement(), "%") self.assertEqual(sensor.ha_device_class(), "humidity")
def test_str_power(self): """Test resolve state with power sensor.""" xknx = XKNX(loop=self.loop) sensor = Sensor( xknx, 'TestSensor', group_address_state='1/2/3', value_type="power") sensor.sensor_value.payload = DPTArray((0x43, 0xC6, 0x80, 00)) self.assertEqual(sensor.resolve_state(), 397) self.assertEqual(sensor.unit_of_measurement(), "W") self.assertEqual(sensor.ha_device_class(), "power")
def test_process(self): """Test process / reading telegrams from telegram queue.""" xknx = XKNX(loop=self.loop) sensor = Sensor( xknx, 'TestSensor', value_type='temperature', group_address_state='1/2/3') telegram = Telegram(GroupAddress('1/2/3')) telegram.payload = DPTArray((0x06, 0xa0)) self.loop.run_until_complete(asyncio.Task(sensor.process(telegram))) self.assertEqual(sensor.sensor_value.payload, DPTArray((0x06, 0xa0))) self.assertEqual(sensor.resolve_state(), 16.96)
def test_sync_passive(self): """Test sync function / not sending group reads to KNX bus.""" xknx = XKNX(loop=self.loop) sensor = Sensor(xknx, 'TestSensor', value_type="temperature", group_address_state='1/2/3', sync_state=False) self.loop.run_until_complete(asyncio.Task(sensor.sync(False))) self.assertEqual(xknx.telegrams.qsize(), 0) with self.assertRaises(asyncio.queues.QueueEmpty): xknx.telegrams.get_nowait()
async def main(): """Connect to KNX/IP device and read the value of a temperature and a motion sensor.""" xknx = XKNX() await xknx.start() sensor1 = BinarySensor( xknx, "DiningRoom.Motion.Sensor", group_address_state="6/0/2", device_class="motion", ) await sensor1.sync() print(sensor1) sensor2 = Sensor( xknx, "DiningRoom.Temperature.Sensor", group_address_state="6/2/1", value_type="temperature", ) await sensor2.sync() print(sensor2) await xknx.stop()
def test_sync(self): """Test sync function / sending group reads to KNX bus.""" xknx = XKNX(loop=self.loop) sensor = Sensor( xknx, 'TestSensor', value_type="temperature", group_address_state='1/2/3') self.loop.run_until_complete(asyncio.Task(sensor.sync(False))) self.assertEqual(xknx.telegrams.qsize(), 1) telegram = xknx.telegrams.get_nowait() self.assertEqual(telegram, Telegram(GroupAddress('1/2/3'), TelegramType.GROUP_READ))
def test_sync_with_wait(self): """Test sync with wait_for_result=True.""" xknx = XKNX() sensor = Sensor( xknx, "Sensor", group_address_state="1/2/3", value_type="wind_speed_ms" ) with patch( "xknx.remote_value.RemoteValue.read_state", new_callable=MagicMock ) as read_state_mock: fut = asyncio.Future() fut.set_result(None) read_state_mock.return_value = fut self.loop.run_until_complete(sensor.sync(wait_for_result=True)) read_state_mock.assert_called_with(wait_for_result=True)
def parse_group_sensor(self, entries): """Parse a sensor section of xknx.yaml.""" for entry in entries: sensor = Sensor.from_config( self.xknx, entry, entries[entry]) self.xknx.devices.add(sensor)
def test_sensor(self): """Test string representation of sensor object.""" xknx = XKNX(loop=self.loop) sensor = Sensor(xknx, name='MeinSensor', group_address='1/2/3', value_type='percent') self.assertEqual( str(sensor), '<Sensor name="MeinSensor" group_address="<Address str="1/2/3" />" state="None" resolve_state="None" />' ) self.loop.run_until_complete( asyncio.Task(sensor._set_internal_state(DPTArray((0x23))))) # pylint: disable=protected-access self.assertEqual( str(sensor), '<Sensor name="MeinSensor" group_address="<Address str="1/2/3" />" state="<DPTArray value="[0x23]" />" resolve_state="14" />' )
async def test_process_callback(self): """Test process / reading telegrams from telegram queue. Test if callback is called.""" xknx = XKNX() sensor = Sensor( xknx, "TestSensor", group_address_state="1/2/3", value_type="temperature" ) after_update_callback = AsyncMock() sensor.register_device_updated_cb(after_update_callback) telegram = Telegram( destination_address=GroupAddress("1/2/3"), payload=GroupValueWrite(DPTArray((0x01, 0x02))), ) await sensor.process(telegram) after_update_callback.assert_called_with(sensor) assert sensor.last_telegram == telegram
def test_unique_id(self): """Test unique id functionality.""" xknx = XKNX() sensor = Sensor(xknx, "TestSensor", group_address_state="1/2/3", value_type="temperature") assert sensor.unique_id == "1/2/3"
async def test_process(self): """Test process / reading telegrams from telegram queue.""" xknx = XKNX() sensor = Sensor(xknx, "TestSensor", value_type="temperature", group_address_state="1/2/3") telegram = Telegram( destination_address=GroupAddress("1/2/3"), payload=GroupValueWrite(DPTArray((0x06, 0xA0))), ) await sensor.process(telegram) assert sensor.sensor_value.value == 16.96 assert sensor.sensor_value.telegram.payload.value == DPTArray( (0x06, 0xA0)) assert sensor.resolve_state() == 16.96
def test_config_sensor_temperature_type(self): """Test reading temperature Sensor from config file.""" self.assertEqual( TestConfig.xknx.devices['Kitchen.Temperature'], Sensor(TestConfig.xknx, 'Kitchen.Temperature', group_address_state='2/0/2', value_type='temperature', device_updated_cb=TestConfig.xknx.devices.device_updated))
def test_config_sensor_percent(self): """Test reading percent Sensor from config file.""" self.assertEqual( TestConfig.xknx.devices['Heating.Valve1'], Sensor(TestConfig.xknx, 'Heating.Valve1', group_address_state='2/0/0', value_type='percent', device_updated_cb=TestConfig.xknx.devices.device_updated))
def test_config_sensor_no_value_type(self): """Test reading Sensor without value_type from config file.""" xknx = XKNX(config='xknx.yaml', loop=self.loop) self.assertEqual( xknx.devices['Some.Other.Value'], Sensor(xknx, 'Some.Other.Value', group_address='2/0/2', device_updated_cb=xknx.devices.device_updated))
def test_config_sensor_percent_passive(self): """Test passive percent Sensor from config file.""" self.assertEqual( TestConfig.xknx.devices['Heating.Valve2'], Sensor(TestConfig.xknx, 'Heating.Valve2', group_address_state='2/0/1', value_type='percent', sync_state=False, device_updated_cb=TestConfig.xknx.devices.device_updated))
def test_process_callback(self): """Test process / reading telegrams from telegram queue. Test if callback is called.""" # pylint: disable=no-self-use xknx = XKNX(loop=self.loop) sensor = Sensor( xknx, 'TestSensor', group_address_state='1/2/3', value_type="temperature") after_update_callback = Mock() async def async_after_update_callback(device): """Async callback.""" after_update_callback(device) sensor.register_device_updated_cb(async_after_update_callback) telegram = Telegram(GroupAddress('1/2/3')) telegram.payload = DPTArray((0x01, 0x02)) self.loop.run_until_complete(asyncio.Task(sensor.process(telegram))) after_update_callback.assert_called_with(sensor)
def test_array_sensor_loop(self): """Test sensor and expose_sensor with different values.""" test_cases = [ ('angle', DPTArray((0x0B)), 16), ('brightness', DPTArray((0x27, 0x10)), 10000), ('color_temperature', DPTArray((0x0D, 0x48)), 3400), ('counter_pulses', DPTArray((0x9F)), -97), ('current', DPTArray((0x00, 0x03)), 3), ('electric_current', DPTArray((0x3D, 0xCC, 0xCC, 0xCD)), 0.1), ('electric_potential', DPTArray((0x43, 0xF0, 0xDE, 0xB8)), 481.74), ('energy', DPTArray((0x43, 0xE4, 0x00, 0x00)), 456), ('enthalpy', DPTArray((0xC1, 0x4E)), -4387.84), ('frequency', DPTArray((0x42, 0x46, 0xCC, 0xCD)), 49.7), ('heatflowrate', DPTArray((0x42, 0xAE, 0x00, 0x00)), 87), ('humidity', DPTArray((0x6C, 0xB6)), 98795.52), ('illuminance', DPTArray((0x2F, 0xE9)), 648), ('luminous_flux', DPTArray((0x43, 0x87, 0x40, 0x00)), 270.5), ('percent', DPTArray((0x26)), 15), ('percentU8', DPTArray((0xCD)), 205), ('percentV8', DPTArray((0x9A)), -102), ('phaseanglerad', DPTArray((0xC1, 0x10, 0x00, 0x00)), -9), ('phaseangledeg', DPTArray((0x43, 0x87, 0x40, 0x00)), 270.5), ('power', DPTArray((0x42, 0xA9, 0xBD, 0x71)), 84.87), ('powerfactor', DPTArray((0x42, 0xA9, 0x6B, 0x85)), 84.71), ('ppm', DPTArray((0x00, 0x03)), 0.03), ('pressure', DPTArray((0x42, 0xA9, 0x6B, 0x85)), 84.71), ('pulse', DPTArray((0x11)), 17), ('scene_number', DPTArray((0x00)), 1), ('speed', DPTArray((0x00, 0x00, 0x00, 0x00)), 0), ('speed_ms', DPTArray((0x0E, 0xA4)), 34), ('string', DPTArray((0x4B, 0x4E, 0x58, 0x20, 0x69, 0x73, 0x20, 0x4F, 0x4B, 0x00, 0x00, 0x00, 0x00, 0x00)), "KNX is OK"), ('temperature', DPTArray((0x03, 0x12)), 7.86), ('voltage', DPTArray((0x07, 0x9A)), 19.46), # Generic DPT Without Min/Max and Unit. ('DPT-5', DPTArray((0x1F)), 31), ('1byte_unsigned', DPTArray((0x08)), 8), ('DPT-7', DPTArray((0xD4, 0x31)), 54321), ('2byte_unsigned', DPTArray((0x30, 0x39)), 12345), ('DPT-9', DPTArray((0x2E, 0xA9)), 545.6), ('DPT-12', DPTArray((0x07, 0x5B, 0xCD, 0x15)), 123456789), ('4byte_unsigned', DPTArray((0x00, 0x00, 0x00, 0x00)), 0), ('DPT-13', DPTArray((0x02, 0xE5, 0x5E, 0xF7)), 48586487), ('4byte_signed', DPTArray((0xFD, 0x1A, 0xA1, 0x09)), -48586487), ('DPT-14', DPTArray((0x47, 0xC0, 0xF7, 0x20)), 98798.25), ('4byte_float', DPTArray((0xC2, 0x09, 0xEE, 0xCC)), -34.4832), ] for value_type, test_payload, test_value in test_cases: with self.subTest(value_type=value_type): xknx = XKNX(loop=self.loop) sensor = Sensor( xknx, 'TestSensor_%s' % value_type, group_address_state='1/1/1', value_type=value_type ) expose = ExposeSensor( xknx, 'TestExpose_%s' % value_type, group_address='2/2/2', value_type=value_type ) incoming_telegram = Telegram(GroupAddress('1/1/1'), TelegramType.GROUP_WRITE, direction=TelegramDirection.INCOMING, payload=test_payload) self.loop.run_until_complete(asyncio.Task(sensor.process(incoming_telegram))) incoming_value = sensor.resolve_state() if isinstance(test_value, float): self.assertEqual(round(incoming_value, 4), test_value) else: self.assertEqual(incoming_value, test_value) # HA sends strings for new values stringified_value = str(test_value) self.loop.run_until_complete(asyncio.Task(expose.set(stringified_value))) self.assertEqual(xknx.telegrams.qsize(), 1) outgoing_telegram = xknx.telegrams.get_nowait() self.assertEqual( outgoing_telegram, Telegram( GroupAddress('2/2/2'), TelegramType.GROUP_WRITE, direction=TelegramDirection.OUTGOING, payload=test_payload))