diff --git a/homeassistant/components/modbus/__init__.py b/homeassistant/components/modbus/__init__.py index e8c53469769..d9e81b74ce9 100644 --- a/homeassistant/components/modbus/__init__.py +++ b/homeassistant/components/modbus/__init__.py @@ -104,6 +104,7 @@ from .const import ( # noqa: F401 CONF_SWAP_WORD, CONF_SWAP_WORD_BYTE, CONF_TARGET_TEMP, + CONF_TARGET_TEMP_WRITE_REGISTERS, CONF_VERIFY, CONF_WRITE_REGISTERS, CONF_WRITE_TYPE, @@ -228,6 +229,7 @@ CLIMATE_SCHEMA = vol.All( BASE_STRUCT_SCHEMA.extend( { vol.Required(CONF_TARGET_TEMP): cv.positive_int, + vol.Optional(CONF_TARGET_TEMP_WRITE_REGISTERS, default=False): cv.boolean, vol.Optional(CONF_MAX_TEMP, default=35): cv.positive_int, vol.Optional(CONF_MIN_TEMP, default=5): cv.positive_int, vol.Optional(CONF_STEP, default=0.5): vol.Coerce(float), diff --git a/homeassistant/components/modbus/climate.py b/homeassistant/components/modbus/climate.py index 0a8b8dabeeb..27a82c7f53b 100644 --- a/homeassistant/components/modbus/climate.py +++ b/homeassistant/components/modbus/climate.py @@ -45,6 +45,7 @@ from .const import ( CONF_MIN_TEMP, CONF_STEP, CONF_TARGET_TEMP, + CONF_TARGET_TEMP_WRITE_REGISTERS, CONF_WRITE_REGISTERS, DataType, ) @@ -84,6 +85,9 @@ class ModbusThermostat(BaseStructPlatform, RestoreEntity, ClimateEntity): """Initialize the modbus thermostat.""" super().__init__(hub, config) self._target_temperature_register = config[CONF_TARGET_TEMP] + self._target_temperature_write_registers = config[ + CONF_TARGET_TEMP_WRITE_REGISTERS + ] self._unit = config[CONF_TEMPERATURE_UNIT] self._attr_current_temperature = None @@ -107,7 +111,7 @@ class ModbusThermostat(BaseStructPlatform, RestoreEntity, ClimateEntity): self._attr_hvac_modes = cast(list[HVACMode], []) self._attr_hvac_mode = None self._hvac_mode_mapping: list[tuple[int, HVACMode]] = [] - self._hvac_mode_write_type = mode_config[CONF_WRITE_REGISTERS] + self._hvac_mode_write_registers = mode_config[CONF_WRITE_REGISTERS] mode_value_config = mode_config[CONF_HVAC_MODE_VALUES] for hvac_mode_kw, hvac_mode in ( @@ -133,7 +137,7 @@ class ModbusThermostat(BaseStructPlatform, RestoreEntity, ClimateEntity): if CONF_HVAC_ONOFF_REGISTER in config: self._hvac_onoff_register = config[CONF_HVAC_ONOFF_REGISTER] - self._hvac_onoff_write_type = config[CONF_WRITE_REGISTERS] + self._hvac_onoff_write_registers = config[CONF_WRITE_REGISTERS] if HVACMode.OFF not in self._attr_hvac_modes: self._attr_hvac_modes.append(HVACMode.OFF) else: @@ -150,7 +154,7 @@ class ModbusThermostat(BaseStructPlatform, RestoreEntity, ClimateEntity): """Set new target hvac mode.""" if self._hvac_onoff_register is not None: # Turn HVAC Off by writing 0 to the On/Off register, or 1 otherwise. - if self._hvac_onoff_write_type: + if self._hvac_onoff_write_registers: await self._hub.async_pymodbus_call( self._slave, self._hvac_onoff_register, @@ -169,7 +173,7 @@ class ModbusThermostat(BaseStructPlatform, RestoreEntity, ClimateEntity): # Write a value to the mode register for the desired mode. for value, mode in self._hvac_mode_mapping: if mode == hvac_mode: - if self._hvac_mode_write_type: + if self._hvac_mode_write_registers: await self._hub.async_pymodbus_call( self._slave, self._hvac_mode_register, @@ -212,12 +216,20 @@ class ModbusThermostat(BaseStructPlatform, RestoreEntity, ClimateEntity): DataType.INT16, DataType.UINT16, ): - result = await self._hub.async_pymodbus_call( - self._slave, - self._target_temperature_register, - int(float(registers[0])), - CALL_TYPE_WRITE_REGISTER, - ) + if self._target_temperature_write_registers: + result = await self._hub.async_pymodbus_call( + self._slave, + self._target_temperature_register, + [int(float(registers[0]))], + CALL_TYPE_WRITE_REGISTERS, + ) + else: + result = await self._hub.async_pymodbus_call( + self._slave, + self._target_temperature_register, + int(float(registers[0])), + CALL_TYPE_WRITE_REGISTER, + ) else: result = await self._hub.async_pymodbus_call( self._slave, diff --git a/homeassistant/components/modbus/const.py b/homeassistant/components/modbus/const.py index 4191e1df56f..264268f323e 100644 --- a/homeassistant/components/modbus/const.py +++ b/homeassistant/components/modbus/const.py @@ -55,6 +55,7 @@ CONF_SWAP_NONE = "none" CONF_SWAP_WORD = "word" CONF_SWAP_WORD_BYTE = "word_byte" CONF_TARGET_TEMP = "target_temp_register" +CONF_TARGET_TEMP_WRITE_REGISTERS = "target_temp_write_registers" CONF_HVAC_MODE_REGISTER = "hvac_mode_register" CONF_HVAC_MODE_VALUES = "values" CONF_HVAC_ONOFF_REGISTER = "hvac_onoff_register" diff --git a/tests/components/modbus/test_climate.py b/tests/components/modbus/test_climate.py index 62b3fb6e7f4..ce43cf7c1d2 100644 --- a/tests/components/modbus/test_climate.py +++ b/tests/components/modbus/test_climate.py @@ -22,6 +22,8 @@ from homeassistant.components.modbus.const import ( CONF_HVAC_ONOFF_REGISTER, CONF_LAZY_ERROR, CONF_TARGET_TEMP, + CONF_TARGET_TEMP_WRITE_REGISTERS, + CONF_WRITE_REGISTERS, MODBUS_DOMAIN, DataType, ) @@ -78,6 +80,19 @@ ENTITY_ID = f"{CLIMATE_DOMAIN}.{TEST_ENTITY_NAME}".replace(" ", "_") } ], }, + { + CONF_CLIMATES: [ + { + CONF_NAME: TEST_ENTITY_NAME, + CONF_TARGET_TEMP: 117, + CONF_ADDRESS: 117, + CONF_SLAVE: 10, + CONF_HVAC_ONOFF_REGISTER: 12, + CONF_TARGET_TEMP_WRITE_REGISTERS: True, + CONF_WRITE_REGISTERS: True, + } + ], + }, { CONF_CLIMATES: [ { @@ -101,6 +116,30 @@ ENTITY_ID = f"{CLIMATE_DOMAIN}.{TEST_ENTITY_NAME}".replace(" ", "_") } ], }, + { + CONF_CLIMATES: [ + { + CONF_NAME: TEST_ENTITY_NAME, + CONF_TARGET_TEMP: 117, + CONF_ADDRESS: 117, + CONF_SLAVE: 10, + CONF_HVAC_ONOFF_REGISTER: 12, + CONF_HVAC_MODE_REGISTER: { + CONF_ADDRESS: 11, + CONF_WRITE_REGISTERS: True, + CONF_HVAC_MODE_VALUES: { + "state_off": 0, + "state_heat": 1, + "state_cool": 2, + "state_heat_cool": 3, + "state_dry": 4, + "state_fan_only": 5, + "state_auto": 6, + }, + }, + } + ], + }, ], ) async def test_config_climate(hass: HomeAssistant, mock_modbus) -> None: @@ -353,6 +392,22 @@ async def test_service_climate_update( ] }, ), + ( + 25, + [0x00], + { + CONF_CLIMATES: [ + { + CONF_NAME: TEST_ENTITY_NAME, + CONF_TARGET_TEMP: 117, + CONF_ADDRESS: 117, + CONF_SLAVE: 10, + CONF_DATA_TYPE: DataType.INT16, + CONF_TARGET_TEMP_WRITE_REGISTERS: True, + } + ] + }, + ), ], ) async def test_service_climate_set_temperature( @@ -417,6 +472,52 @@ async def test_service_climate_set_temperature( ] }, ), + ( + HVACMode.HEAT, + [0x00], + { + CONF_CLIMATES: [ + { + CONF_NAME: TEST_ENTITY_NAME, + CONF_TARGET_TEMP: 117, + CONF_ADDRESS: 117, + CONF_SLAVE: 10, + CONF_HVAC_MODE_REGISTER: { + CONF_ADDRESS: 118, + CONF_HVAC_MODE_VALUES: { + CONF_HVAC_MODE_COOL: 1, + CONF_HVAC_MODE_HEAT: 2, + }, + CONF_WRITE_REGISTERS: True, + }, + CONF_HVAC_ONOFF_REGISTER: 119, + } + ] + }, + ), + ( + HVACMode.OFF, + [0x00], + { + CONF_CLIMATES: [ + { + CONF_NAME: TEST_ENTITY_NAME, + CONF_TARGET_TEMP: 117, + CONF_ADDRESS: 117, + CONF_SLAVE: 10, + CONF_HVAC_MODE_REGISTER: { + CONF_ADDRESS: 118, + CONF_HVAC_MODE_VALUES: { + CONF_HVAC_MODE_COOL: 1, + CONF_HVAC_MODE_HEAT: 2, + }, + }, + CONF_HVAC_ONOFF_REGISTER: 119, + CONF_WRITE_REGISTERS: True, + } + ] + }, + ), ], ) async def test_service_set_mode(