Add support for specifying hvac_onoff_register value on modbus (#128366)

Co-authored-by: Abílio Costa <abmantis@users.noreply.github.com>
pull/134462/head
Ілля Піскурьов 2025-01-02 17:18:05 +02:00 committed by GitHub
parent 104151d322
commit 3b5455bc49
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 74 additions and 4 deletions

View File

@ -89,6 +89,8 @@ from .const import (
CONF_HVAC_MODE_OFF,
CONF_HVAC_MODE_REGISTER,
CONF_HVAC_MODE_VALUES,
CONF_HVAC_OFF_VALUE,
CONF_HVAC_ON_VALUE,
CONF_HVAC_ONOFF_REGISTER,
CONF_INPUT_TYPE,
CONF_MAX_TEMP,
@ -130,6 +132,8 @@ from .const import (
CONF_WRITE_TYPE,
CONF_ZERO_SUPPRESS,
DEFAULT_HUB,
DEFAULT_HVAC_OFF_VALUE,
DEFAULT_HVAC_ON_VALUE,
DEFAULT_SCAN_INTERVAL,
DEFAULT_TEMP_UNIT,
MODBUS_DOMAIN as DOMAIN,
@ -256,6 +260,12 @@ CLIMATE_SCHEMA = vol.All(
vol.Optional(CONF_STEP, default=0.5): vol.Coerce(float),
vol.Optional(CONF_TEMPERATURE_UNIT, default=DEFAULT_TEMP_UNIT): cv.string,
vol.Optional(CONF_HVAC_ONOFF_REGISTER): cv.positive_int,
vol.Optional(
CONF_HVAC_ON_VALUE, default=DEFAULT_HVAC_ON_VALUE
): cv.positive_int,
vol.Optional(
CONF_HVAC_OFF_VALUE, default=DEFAULT_HVAC_OFF_VALUE
): cv.positive_int,
vol.Optional(CONF_WRITE_REGISTERS, default=False): cv.boolean,
vol.Optional(CONF_HVAC_MODE_REGISTER): vol.Maybe(
{

View File

@ -69,6 +69,8 @@ from .const import (
CONF_HVAC_MODE_OFF,
CONF_HVAC_MODE_REGISTER,
CONF_HVAC_MODE_VALUES,
CONF_HVAC_OFF_VALUE,
CONF_HVAC_ON_VALUE,
CONF_HVAC_ONOFF_REGISTER,
CONF_MAX_TEMP,
CONF_MIN_TEMP,
@ -251,6 +253,8 @@ 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_registers = config[CONF_WRITE_REGISTERS]
self._hvac_on_value = config[CONF_HVAC_ON_VALUE]
self._hvac_off_value = config[CONF_HVAC_OFF_VALUE]
if HVACMode.OFF not in self._attr_hvac_modes:
self._attr_hvac_modes.append(HVACMode.OFF)
else:
@ -266,19 +270,26 @@ class ModbusThermostat(BaseStructPlatform, RestoreEntity, ClimateEntity):
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""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.
# Turn HVAC Off by writing self._hvac_off_value to the On/Off
# register, or self._hvac_on_value otherwise.
if self._hvac_onoff_write_registers:
await self._hub.async_pb_call(
self._slave,
self._hvac_onoff_register,
[0 if hvac_mode == HVACMode.OFF else 1],
[
self._hvac_off_value
if hvac_mode == HVACMode.OFF
else self._hvac_on_value
],
CALL_TYPE_WRITE_REGISTERS,
)
else:
await self._hub.async_pb_call(
self._slave,
self._hvac_onoff_register,
0 if hvac_mode == HVACMode.OFF else 1,
self._hvac_off_value
if hvac_mode == HVACMode.OFF
else self._hvac_on_value,
CALL_TYPE_WRITE_REGISTER,
)
@ -476,7 +487,7 @@ class ModbusThermostat(BaseStructPlatform, RestoreEntity, ClimateEntity):
onoff = await self._async_read_register(
CALL_TYPE_REGISTER_HOLDING, self._hvac_onoff_register, raw=True
)
if onoff == 0:
if onoff == self._hvac_off_value:
self._attr_hvac_mode = HVACMode.OFF
self.async_write_ha_state()

View File

@ -60,6 +60,8 @@ CONF_FAN_MODE_DIFFUSE = "state_fan_diffuse"
CONF_FAN_MODE_VALUES = "values"
CONF_HVAC_MODE_REGISTER = "hvac_mode_register"
CONF_HVAC_ONOFF_REGISTER = "hvac_onoff_register"
CONF_HVAC_ON_VALUE = "hvac_on_value"
CONF_HVAC_OFF_VALUE = "hvac_off_value"
CONF_HVAC_MODE_OFF = "state_off"
CONF_HVAC_MODE_HEAT = "state_heat"
CONF_HVAC_MODE_COOL = "state_cool"
@ -139,6 +141,8 @@ DEFAULT_SCAN_INTERVAL = 15 # seconds
DEFAULT_SLAVE = 1
DEFAULT_STRUCTURE_PREFIX = ">f"
DEFAULT_TEMP_UNIT = "C"
DEFAULT_HVAC_ON_VALUE = 1
DEFAULT_HVAC_OFF_VALUE = 0
MODBUS_DOMAIN = "modbus"
ACTIVE_SCAN_INTERVAL = 2 # limit to force an extra update

View File

@ -24,6 +24,8 @@ from homeassistant.components.climate import (
SERVICE_SET_HVAC_MODE,
SERVICE_SET_SWING_MODE,
SERVICE_SET_TEMPERATURE,
SERVICE_TURN_OFF,
SERVICE_TURN_ON,
SWING_BOTH,
SWING_HORIZONTAL,
SWING_OFF,
@ -54,6 +56,8 @@ from homeassistant.components.modbus.const import (
CONF_HVAC_MODE_OFF,
CONF_HVAC_MODE_REGISTER,
CONF_HVAC_MODE_VALUES,
CONF_HVAC_OFF_VALUE,
CONF_HVAC_ON_VALUE,
CONF_HVAC_ONOFF_REGISTER,
CONF_MAX_TEMP,
CONF_MIN_TEMP,
@ -362,6 +366,47 @@ async def test_config_hvac_onoff_register(hass: HomeAssistant, mock_modbus) -> N
assert HVACMode.AUTO in state.attributes[ATTR_HVAC_MODES]
@pytest.mark.parametrize(
"do_config",
[
{
CONF_CLIMATES: [
{
CONF_NAME: TEST_ENTITY_NAME,
CONF_TARGET_TEMP: 117,
CONF_ADDRESS: 117,
CONF_SLAVE: 10,
CONF_HVAC_ONOFF_REGISTER: 11,
CONF_HVAC_ON_VALUE: 0xAA,
CONF_HVAC_OFF_VALUE: 0xFF,
}
],
},
],
)
async def test_hvac_onoff_values(hass: HomeAssistant, mock_modbus) -> None:
"""Run configuration test for On/Off register values."""
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: ENTITY_ID},
blocking=True,
)
await hass.async_block_till_done()
mock_modbus.write_register.assert_called_with(11, 0xAA, slave=10)
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: ENTITY_ID},
blocking=True,
)
await hass.async_block_till_done()
mock_modbus.write_register.assert_called_with(11, 0xFF, slave=10)
@pytest.mark.parametrize(
"do_config",
[