Correct set_temperature in modbus climate (#52923)

This commit is contained in:
jan iversen 2021-07-20 20:19:26 +02:00 committed by GitHub
parent a14bde8187
commit 8c43e5c736
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 74 additions and 9 deletions

View file

@ -33,7 +33,12 @@ from .const import (
CONF_MIN_TEMP, CONF_MIN_TEMP,
CONF_STEP, CONF_STEP,
CONF_TARGET_TEMP, CONF_TARGET_TEMP,
DEFAULT_STRUCT_FORMAT, DATA_TYPE_INT16,
DATA_TYPE_INT32,
DATA_TYPE_INT64,
DATA_TYPE_UINT16,
DATA_TYPE_UINT32,
DATA_TYPE_UINT64,
MODBUS_DOMAIN, MODBUS_DOMAIN,
) )
from .modbus import ModbusHub from .modbus import ModbusHub
@ -145,16 +150,28 @@ class ModbusThermostat(BaseStructPlatform, RestoreEntity, ClimateEntity):
"""Set new target temperature.""" """Set new target temperature."""
if ATTR_TEMPERATURE not in kwargs: if ATTR_TEMPERATURE not in kwargs:
return return
target_temperature = int( target_temperature = (
(kwargs.get(ATTR_TEMPERATURE) - self._offset) / self._scale float(kwargs.get(ATTR_TEMPERATURE)) - self._offset
) ) / self._scale
byte_string = struct.pack(self._structure, target_temperature) if self._data_type in [
struct_string = f">{DEFAULT_STRUCT_FORMAT[self._data_type]}" DATA_TYPE_INT16,
register_value = struct.unpack(struct_string, byte_string)[0] DATA_TYPE_INT32,
DATA_TYPE_INT64,
DATA_TYPE_UINT16,
DATA_TYPE_UINT32,
DATA_TYPE_UINT64,
]:
target_temperature = int(target_temperature)
as_bytes = struct.pack(self._structure, target_temperature)
raw_regs = [
int.from_bytes(as_bytes[i : i + 2], "big")
for i in range(0, len(as_bytes), 2)
]
registers = self._swap_registers(raw_regs)
result = await self._hub.async_pymodbus_call( result = await self._hub.async_pymodbus_call(
self._slave, self._slave,
self._target_temperature_register, self._target_temperature_register,
register_value, registers,
CALL_TYPE_WRITE_REGISTERS, CALL_TYPE_WRITE_REGISTERS,
) )
self._available = result is not None self._available = result is not None

View file

@ -3,7 +3,15 @@ import pytest
from homeassistant.components.climate import DOMAIN as CLIMATE_DOMAIN from homeassistant.components.climate import DOMAIN as CLIMATE_DOMAIN
from homeassistant.components.climate.const import HVAC_MODE_AUTO from homeassistant.components.climate.const import HVAC_MODE_AUTO
from homeassistant.components.modbus.const import CONF_CLIMATES, CONF_TARGET_TEMP from homeassistant.components.modbus.const import (
CONF_CLIMATES,
CONF_DATA_TYPE,
CONF_TARGET_TEMP,
DATA_TYPE_FLOAT32,
DATA_TYPE_FLOAT64,
DATA_TYPE_INT16,
DATA_TYPE_INT32,
)
from homeassistant.const import ( from homeassistant.const import (
ATTR_TEMPERATURE, ATTR_TEMPERATURE,
CONF_ADDRESS, CONF_ADDRESS,
@ -110,6 +118,46 @@ async def test_service_climate_update(hass, mock_pymodbus):
assert hass.states.get(ENTITY_ID).state == "auto" assert hass.states.get(ENTITY_ID).state == "auto"
@pytest.mark.parametrize(
"data_type, temperature, result",
[
(DATA_TYPE_INT16, 35, [0x00]),
(DATA_TYPE_INT32, 36, [0x00, 0x00]),
(DATA_TYPE_FLOAT32, 37.5, [0x00, 0x00]),
(DATA_TYPE_FLOAT64, "39", [0x00, 0x00, 0x00, 0x00]),
],
)
async def test_service_climate_set_temperature(
hass, data_type, temperature, result, mock_pymodbus
):
"""Run test for service homeassistant.update_entity."""
config = {
CONF_CLIMATES: [
{
CONF_NAME: CLIMATE_NAME,
CONF_TARGET_TEMP: 117,
CONF_ADDRESS: 117,
CONF_SLAVE: 10,
CONF_DATA_TYPE: data_type,
}
]
}
mock_pymodbus.read_holding_registers.return_value = ReadResult(result)
await prepare_service_update(
hass,
config,
)
await hass.services.async_call(
CLIMATE_DOMAIN,
"set_temperature",
{
"entity_id": ENTITY_ID,
ATTR_TEMPERATURE: temperature,
},
blocking=True,
)
test_value = State(ENTITY_ID, 35) test_value = State(ENTITY_ID, 35)
test_value.attributes = {ATTR_TEMPERATURE: 37} test_value.attributes = {ATTR_TEMPERATURE: 37}