def test_high_temperature(self): """Test parsing and streaming of DPT2ByteFloat 500.00, 499.84, 500.16. Testing rounding issues.""" assert DPT2ByteFloat.to_knx(500.00) == (0x2E, 0x1A) assert round(abs(DPT2ByteFloat.from_knx((0x2E, 0x1A)) - 499.84), 7) == 0 assert round(abs(DPT2ByteFloat.from_knx((0x2E, 0x1B)) - 500.16), 7) == 0 assert DPT2ByteFloat.to_knx(499.84) == (0x2E, 0x1A) assert DPT2ByteFloat.to_knx(500.16) == (0x2E, 0x1B)
def test_high_temperature(self): """Test parsing and streaming of DPT2ByteFloat 500.00, 499.84, 500.16. Testing rounding issues.""" self.assertEqual(DPT2ByteFloat().to_knx(500.00), (0x2E, 0x1A)) self.assertAlmostEqual(DPT2ByteFloat().from_knx((0x2E, 0x1A)), 499.84) self.assertAlmostEqual(DPT2ByteFloat().from_knx((0x2E, 0x1B)), 500.16) self.assertEqual(DPT2ByteFloat().to_knx(499.84), (0x2E, 0x1A)) self.assertEqual(DPT2ByteFloat().to_knx(500.16), (0x2E, 0x1B))
def test_target_temperature_up(self): """Test increase target temperature.""" # pylint: disable=no-self-use xknx = XKNX(loop=self.loop) climate = Climate(xknx, 'TestClimate', group_address_target_temperature='1/2/2', group_address_setpoint_shift='1/2/3') self.loop.run_until_complete( asyncio.Task(climate.set_setpoint_shift(3))) self.assertEqual(xknx.telegrams.qsize(), 1) self.assertEqual( xknx.telegrams.get_nowait(), # DEFAULT_SETPOINT_SHIFT_STEP is 0.5 -> payload = setpoint_shift * 2 Telegram(GroupAddress('1/2/3'), payload=DPTArray(6))) self.loop.run_until_complete( asyncio.Task(climate.target_temperature.set(23.00))) self.assertEqual(xknx.telegrams.qsize(), 1) self.assertEqual( xknx.telegrams.get_nowait(), Telegram(GroupAddress('1/2/2'), payload=DPTArray(DPT2ByteFloat().to_knx(23.00)))) self.assertEqual(climate.base_temperature, 20) # First change self.loop.run_until_complete( asyncio.Task(climate.set_target_temperature(24.00))) self.assertEqual(xknx.telegrams.qsize(), 2) self.assertEqual(xknx.telegrams.get_nowait(), Telegram(GroupAddress('1/2/3'), payload=DPTArray(8))) self.assertEqual( xknx.telegrams.get_nowait(), Telegram(GroupAddress('1/2/2'), payload=DPTArray(DPT2ByteFloat().to_knx(24.00)))) self.assertEqual(climate.target_temperature.value, 24.00) # Second change self.loop.run_until_complete( asyncio.Task(climate.set_target_temperature(23.50))) self.assertEqual(xknx.telegrams.qsize(), 2) self.assertEqual(xknx.telegrams.get_nowait(), Telegram(GroupAddress('1/2/3'), payload=DPTArray(7))) self.assertEqual( xknx.telegrams.get_nowait(), Telegram(GroupAddress('1/2/2'), payload=DPTArray(DPT2ByteFloat().to_knx(23.50)))) self.assertEqual(climate.target_temperature.value, 23.50) # Test max target temperature # Base (20) - setpoint_shift_max (6) self.assertEqual(climate.target_temperature_max, 26.00) # third change - limit exceeded, setting to max self.loop.run_until_complete( asyncio.Task(climate.set_target_temperature(26.50))) self.assertEqual(climate.target_temperature_max, 26.00) self.assertEqual(climate.setpoint_shift, 6)
def test_very_cold_temperature(self): """ Test parsing and streaming of DPT2ByteFloat -1000.00,-999.68, -1000.32. Testing rounding issues of negative values. """ assert DPT2ByteFloat.to_knx(-1000.00) == (0xB1, 0xE6) assert DPT2ByteFloat.from_knx((0xB1, 0xE6)) == -999.68 assert DPT2ByteFloat.from_knx((0xB1, 0xE5)) == -1000.32 assert DPT2ByteFloat.to_knx(-999.68) == (0xB1, 0xE6) assert DPT2ByteFloat.to_knx(-1000.32) == (0xB1, 0xE5)
def test_very_cold_temperature(self): """ Test parsing and streaming of DPT2ByteFloat -1000.00,-999.68, -1000.32. Testing rounding issues of negative values. """ self.assertEqual(DPT2ByteFloat().to_knx(-1000.00), (0xB1, 0xE6)) self.assertEqual(DPT2ByteFloat().from_knx((0xB1, 0xE6)), -999.68) self.assertEqual(DPT2ByteFloat().from_knx((0xB1, 0xE5)), -1000.32) self.assertEqual(DPT2ByteFloat().to_knx(-999.68), (0xB1, 0xE6)) self.assertEqual(DPT2ByteFloat().to_knx(-1000.32), (0xB1, 0xE5))
def test_parse_transcoder_from_subclass(self): """Test parsing only subclasses of a DPT class.""" assert DPTBase.parse_transcoder("string") == DPTString assert DPTNumeric.parse_transcoder("string") is None assert DPT2ByteFloat.parse_transcoder("string") is None assert DPTBase.parse_transcoder("percent") == DPTScaling assert DPTNumeric.parse_transcoder("percent") == DPTScaling assert DPT2ByteFloat.parse_transcoder("percent") is None assert DPTBase.parse_transcoder("temperature") == DPTTemperature assert DPTNumeric.parse_transcoder("temperature") == DPTTemperature assert DPT2ByteFloat.parse_transcoder("temperature") == DPTTemperature
def test_target_temperature_modified_step(self): """Test increase target temperature with modified step size.""" # pylint: disable=no-self-use xknx = XKNX(loop=self.loop) climate = Climate(xknx, 'TestClimate', group_address_target_temperature='1/2/2', group_address_setpoint_shift='1/2/3', setpoint_shift_step=0.1, setpoint_shift_max=10, setpoint_shift_min=-10) self.loop.run_until_complete( asyncio.Task(climate.set_setpoint_shift(3))) self.assertEqual(xknx.telegrams.qsize(), 1) self.assertEqual( xknx.telegrams.get_nowait(), # setpoint_shift_step is 0.1 -> payload = setpoint_shift * 10 Telegram(GroupAddress('1/2/3'), payload=DPTArray(30))) self.loop.run_until_complete( asyncio.Task(climate.target_temperature.set(23.00))) self.assertEqual(xknx.telegrams.qsize(), 1) self.assertEqual( xknx.telegrams.get_nowait(), Telegram(GroupAddress('1/2/2'), payload=DPTArray(DPT2ByteFloat().to_knx(23.00)))) self.assertEqual(climate.base_temperature, 20.00) self.loop.run_until_complete( asyncio.Task(climate.set_target_temperature(24.00))) self.assertEqual(xknx.telegrams.qsize(), 2) self.assertEqual(xknx.telegrams.get_nowait(), Telegram(GroupAddress('1/2/3'), payload=DPTArray(40))) self.assertEqual( xknx.telegrams.get_nowait(), Telegram(GroupAddress('1/2/2'), payload=DPTArray(DPT2ByteFloat().to_knx(24.00)))) self.assertEqual(climate.target_temperature.value, 24.00) # Test max/min target temperature self.assertEqual(climate.target_temperature_max, 30.00) self.assertEqual(climate.target_temperature_min, 10.00)
async def test_set_value(self): """Test set_value awaitable.""" xknx = XKNX() remote_value = RemoteValue(xknx) remote_value.to_knx = lambda value: DPTArray( DPT2ByteFloat.to_knx(value)) remote_value.after_update_cb = AsyncMock() await remote_value.update_value(3.3) assert remote_value.value == 3.3 remote_value.after_update_cb.assert_called_once() assert xknx.telegrams.qsize() == 0 # invalid value raises ConversionError with pytest.raises(ConversionError): await remote_value.update_value("a") assert remote_value.value == 3.3
def test_base_temperature(self): """Test base temperature.""" # pylint: disable=no-self-use xknx = XKNX(loop=self.loop) climate = Climate(xknx, 'TestClimate', group_address_target_temperature_state='1/2/1', group_address_target_temperature='1/2/2', group_address_setpoint_shift='1/2/3') self.loop.run_until_complete( asyncio.Task(climate.set_target_temperature(21.00))) self.assertEqual(xknx.telegrams.qsize(), 1) self.assertEqual( xknx.telegrams.get_nowait(), Telegram(GroupAddress('1/2/2'), payload=DPTArray(DPT2ByteFloat().to_knx(21.00)))) self.assertFalse(climate.initialized_for_setpoint_shift_calculations) self.assertEqual(climate.base_temperature, None) # setpoint_shift initialized after target_temperature (no temperature change) self.loop.run_until_complete( asyncio.Task(climate.set_setpoint_shift(1))) self.assertEqual(xknx.telegrams.qsize(), 1) self.assertEqual( xknx.telegrams.get_nowait(), # DEFAULT_SETPOINT_SHIFT_STEP is 0.5 -> payload = setpoint_shift * 2 Telegram(GroupAddress('1/2/3'), payload=DPTArray(2))) self.assertTrue(climate.initialized_for_setpoint_shift_calculations) self.assertEqual(climate.base_temperature, 20.00) # setpoint_shift changed after initialisation self.loop.run_until_complete( asyncio.Task(climate.set_setpoint_shift(2))) # setpoint_shift and target_temperature are sent to the bus self.assertEqual(xknx.telegrams.qsize(), 2) self.assertEqual( xknx.telegrams.get_nowait(), # DEFAULT_SETPOINT_SHIFT_STEP is 0.5 -> payload = setpoint_shift * 2 Telegram(GroupAddress('1/2/3'), payload=DPTArray(4))) self.assertTrue(climate.initialized_for_setpoint_shift_calculations) self.assertEqual(climate.base_temperature, 20.00) self.assertEqual(climate.target_temperature.value, 22)
async def test_get_set_value(self): """Test value getter and setter.""" xknx = XKNX() remote_value = RemoteValue(xknx) remote_value.to_knx = lambda value: DPTArray( DPT2ByteFloat.to_knx(value)) remote_value.after_update_cb = AsyncMock() assert remote_value.value is None remote_value.value = 2.2 assert remote_value.value == 2.2 # invalid value raises ConversionError with pytest.raises(ConversionError): remote_value.value = "a" # new value is used in response Telegram test_payload = remote_value.to_knx(2.2) remote_value._send = AsyncMock() await remote_value.respond() remote_value._send.assert_called_with(test_payload, response=True) # callback is not called when setting value programmatically remote_value.after_update_cb.assert_not_called() # no Telegram was sent to the queue assert xknx.telegrams.qsize() == 0
def test_value_taken_from_live_thermostat(self): """Test parsing and streaming of DPT2ByteFloat 19.96.""" assert DPT2ByteFloat.to_knx(16.96) == (0x06, 0xA0) assert DPT2ByteFloat.from_knx((0x06, 0xA0)) == 16.96
def test_value_from_documentation(self): """Test parsing and streaming of DPT2ByteFloat -30.00. Example from the internet[tm].""" assert DPT2ByteFloat.to_knx(-30.00) == (0x8A, 0x24) assert DPT2ByteFloat.from_knx((0x8A, 0x24)) == -30.00
def test_from_knx_wrong_parameter2(self): """Test parsing of DPT2ByteFloat with wrong value (second parameter is a string).""" with pytest.raises(ConversionError): DPT2ByteFloat.from_knx((0xF8, "0x23"))
def test_from_knx_wrong_parameter(self): """Test parsing of DPT2ByteFloat with wrong value (wrong number of bytes).""" with pytest.raises(ConversionError): DPT2ByteFloat.from_knx((0xF8, 0x01, 0x23))
def test_close_to_min(self): """Test parsing and streaming of DPT2ByteFloat with minimum value +1.""" assert DPT2ByteFloat.to_knx(-670760.96) == (0xF8, 0x01) assert DPT2ByteFloat.from_knx((0xF8, 0x01)) == -670760.96
def test_min(self): """Test parsing and streaming of DPT2ByteFloat with minimum value.""" assert DPT2ByteFloat.to_knx(DPT2ByteFloat.value_min) == (0xF8, 0x00) assert DPT2ByteFloat.from_knx((0xF8, 0x00)) == DPT2ByteFloat.value_min
def test_zero_value(self): """Test parsing and streaming of DPT2ByteFloat zero value.""" assert DPT2ByteFloat.to_knx(0.00) == (0x00, 0x00) assert DPT2ByteFloat.from_knx((0x00, 0x00)) == 0.00
def test_minor_negative_temperature(self): """Test parsing and streaming of DPT2ByteFloat -10.00. Testing negative values.""" self.assertEqual(DPT2ByteFloat().to_knx(-10.00), (0x84, 0x18)) self.assertEqual(DPT2ByteFloat().from_knx((0x84, 0x18)), -10.00)
def test_room_temperature(self): """Test parsing and streaming of DPT2ByteFloat 21.00. Room temperature.""" self.assertEqual(DPT2ByteFloat().to_knx(21.00), (0x0C, 0x1A)) self.assertEqual(DPT2ByteFloat().from_knx((0x0C, 0x1A)), 21.00)
def test_zero_value(self): """Test parsing and streaming of DPT2ByteFloat zero value.""" self.assertEqual(DPT2ByteFloat().to_knx(0.00), (0x00, 0x00)) self.assertEqual(DPT2ByteFloat().from_knx((0x00, 0x00)), 0.00)
def test_room_temperature(self): """Test parsing and streaming of DPT2ByteFloat 21.00. Room temperature.""" assert DPT2ByteFloat.to_knx(21.00) == (0x0C, 0x1A) assert DPT2ByteFloat.from_knx((0x0C, 0x1A)) == 21.00
def test_max(self): """Test parsing and streaming of DPT2ByteFloat with maximum value.""" self.assertEqual(DPT2ByteFloat().to_knx(DPT2ByteFloat.value_max), (0x7F, 0xFF)) self.assertEqual(DPT2ByteFloat().from_knx((0x7F, 0xFF)), DPT2ByteFloat.value_max)
def test_minor_negative_temperature(self): """Test parsing and streaming of DPT2ByteFloat -10.00. Testing negative values.""" assert DPT2ByteFloat.to_knx(-10.00) == (0x84, 0x18) assert DPT2ByteFloat.from_knx((0x84, 0x18)) == -10.00
def test_min(self): """Test parsing and streaming of DPT2ByteFloat with minimum value.""" self.assertEqual(DPT2ByteFloat().to_knx(DPT2ByteFloat.value_min), (0xF8, 0x00)) self.assertEqual(DPT2ByteFloat().from_knx((0xF8, 0x00)), DPT2ByteFloat.value_min)
def test_max(self): """Test parsing and streaming of DPT2ByteFloat with maximum value.""" assert DPT2ByteFloat.to_knx(DPT2ByteFloat.value_max) == (0x7F, 0xFF) assert DPT2ByteFloat.from_knx((0x7F, 0xFF)) == DPT2ByteFloat.value_max
def test_close_to_max(self): """Test parsing and streaming of DPT2ByteFloat with maximum value -1.""" self.assertEqual(DPT2ByteFloat().to_knx(670433.28), (0x7F, 0xFE)) self.assertEqual(DPT2ByteFloat().from_knx((0x7F, 0xFE)), 670433.28)
def test_close_to_max(self): """Test parsing and streaming of DPT2ByteFloat with maximum value -1.""" assert DPT2ByteFloat.to_knx(670433.28) == (0x7F, 0xFE) assert DPT2ByteFloat.from_knx((0x7F, 0xFE)) == 670433.28
def test_close_to_min(self): """Test parsing and streaming of DPT2ByteFloat with minimum value +1.""" self.assertEqual(DPT2ByteFloat().to_knx(-670760.96), (0xF8, 0x01)) self.assertEqual(DPT2ByteFloat().from_knx((0xF8, 0x01)), -670760.96)
def test_to_knx_min_exceeded(self): """Test parsing of DPT2ByteFloat with wrong value (underflow).""" with pytest.raises(ConversionError): DPT2ByteFloat.to_knx(DPT2ByteFloat.value_min - 1)
def test_to_knx_wrong_parameter(self): """Test parsing of DPT2ByteFloat with wrong value (string).""" with pytest.raises(ConversionError): DPT2ByteFloat.to_knx("fnord")