Add swap to climate and change data_count -> count in modbus (#51668)

pull/51871/head^2
jan iversen 2021-06-16 12:11:23 +02:00 committed by GitHub
parent 61079ab7fa
commit 7ad91fdf71
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 57 additions and 35 deletions

View File

@ -187,7 +187,9 @@ BASE_SWITCH_SCHEMA = BASE_COMPONENT_SCHEMA.extend(
) )
CLIMATE_SCHEMA = BASE_COMPONENT_SCHEMA.extend( CLIMATE_SCHEMA = vol.All(
cv.deprecated(CONF_DATA_COUNT, replacement_key=CONF_COUNT),
BASE_COMPONENT_SCHEMA.extend(
{ {
vol.Optional(CONF_INPUT_TYPE, default=CALL_TYPE_REGISTER_HOLDING): vol.In( vol.Optional(CONF_INPUT_TYPE, default=CALL_TYPE_REGISTER_HOLDING): vol.In(
[ [
@ -196,7 +198,7 @@ CLIMATE_SCHEMA = BASE_COMPONENT_SCHEMA.extend(
] ]
), ),
vol.Required(CONF_TARGET_TEMP): cv.positive_int, vol.Required(CONF_TARGET_TEMP): cv.positive_int,
vol.Optional(CONF_DATA_COUNT, default=2): cv.positive_int, vol.Optional(CONF_COUNT, default=2): cv.positive_int,
vol.Optional(CONF_DATA_TYPE, default=DATA_TYPE_FLOAT): vol.In( vol.Optional(CONF_DATA_TYPE, default=DATA_TYPE_FLOAT): vol.In(
[DATA_TYPE_INT, DATA_TYPE_UINT, DATA_TYPE_FLOAT, DATA_TYPE_CUSTOM] [DATA_TYPE_INT, DATA_TYPE_UINT, DATA_TYPE_FLOAT, DATA_TYPE_CUSTOM]
), ),
@ -208,7 +210,11 @@ CLIMATE_SCHEMA = BASE_COMPONENT_SCHEMA.extend(
vol.Optional(CONF_STEP, default=0.5): vol.Coerce(float), vol.Optional(CONF_STEP, default=0.5): vol.Coerce(float),
vol.Optional(CONF_STRUCTURE, default=DEFAULT_STRUCTURE_PREFIX): cv.string, vol.Optional(CONF_STRUCTURE, default=DEFAULT_STRUCTURE_PREFIX): cv.string,
vol.Optional(CONF_TEMPERATURE_UNIT, default=DEFAULT_TEMP_UNIT): cv.string, vol.Optional(CONF_TEMPERATURE_UNIT, default=DEFAULT_TEMP_UNIT): cv.string,
vol.Optional(CONF_SWAP, default=CONF_SWAP_NONE): vol.In(
[CONF_SWAP_NONE, CONF_SWAP_BYTE, CONF_SWAP_WORD, CONF_SWAP_WORD_BYTE]
),
} }
),
) )
COVERS_SCHEMA = BASE_COMPONENT_SCHEMA.extend( COVERS_SCHEMA = BASE_COMPONENT_SCHEMA.extend(

View File

@ -11,6 +11,7 @@ from homeassistant.components.climate.const import (
SUPPORT_TARGET_TEMPERATURE, SUPPORT_TARGET_TEMPERATURE,
) )
from homeassistant.const import ( from homeassistant.const import (
CONF_COUNT,
CONF_NAME, CONF_NAME,
CONF_OFFSET, CONF_OFFSET,
CONF_STRUCTURE, CONF_STRUCTURE,
@ -28,13 +29,16 @@ from .const import (
CALL_TYPE_REGISTER_HOLDING, CALL_TYPE_REGISTER_HOLDING,
CALL_TYPE_WRITE_REGISTERS, CALL_TYPE_WRITE_REGISTERS,
CONF_CLIMATES, CONF_CLIMATES,
CONF_DATA_COUNT,
CONF_DATA_TYPE, CONF_DATA_TYPE,
CONF_MAX_TEMP, CONF_MAX_TEMP,
CONF_MIN_TEMP, CONF_MIN_TEMP,
CONF_PRECISION, CONF_PRECISION,
CONF_SCALE, CONF_SCALE,
CONF_STEP, CONF_STEP,
CONF_SWAP,
CONF_SWAP_BYTE,
CONF_SWAP_WORD,
CONF_SWAP_WORD_BYTE,
CONF_TARGET_TEMP, CONF_TARGET_TEMP,
DATA_TYPE_CUSTOM, DATA_TYPE_CUSTOM,
DEFAULT_STRUCT_FORMAT, DEFAULT_STRUCT_FORMAT,
@ -59,7 +63,7 @@ async def async_setup_platform(
entities = [] entities = []
for entity in discovery_info[CONF_CLIMATES]: for entity in discovery_info[CONF_CLIMATES]:
hub: ModbusHub = hass.data[MODBUS_DOMAIN][discovery_info[CONF_NAME]] hub: ModbusHub = hass.data[MODBUS_DOMAIN][discovery_info[CONF_NAME]]
count = entity[CONF_DATA_COUNT] count = entity[CONF_COUNT]
data_type = entity[CONF_DATA_TYPE] data_type = entity[CONF_DATA_TYPE]
name = entity[CONF_NAME] name = entity[CONF_NAME]
structure = entity[CONF_STRUCTURE] structure = entity[CONF_STRUCTURE]
@ -110,7 +114,7 @@ class ModbusThermostat(BasePlatform, RestoreEntity, ClimateEntity):
self._current_temperature = None self._current_temperature = None
self._data_type = config[CONF_DATA_TYPE] self._data_type = config[CONF_DATA_TYPE]
self._structure = config[CONF_STRUCTURE] self._structure = config[CONF_STRUCTURE]
self._count = config[CONF_DATA_COUNT] self._count = config[CONF_COUNT]
self._precision = config[CONF_PRECISION] self._precision = config[CONF_PRECISION]
self._scale = config[CONF_SCALE] self._scale = config[CONF_SCALE]
self._offset = config[CONF_OFFSET] self._offset = config[CONF_OFFSET]
@ -118,6 +122,7 @@ class ModbusThermostat(BasePlatform, RestoreEntity, ClimateEntity):
self._max_temp = config[CONF_MAX_TEMP] self._max_temp = config[CONF_MAX_TEMP]
self._min_temp = config[CONF_MIN_TEMP] self._min_temp = config[CONF_MIN_TEMP]
self._temp_step = config[CONF_STEP] self._temp_step = config[CONF_STEP]
self._swap = config[CONF_SWAP]
async def async_added_to_hass(self): async def async_added_to_hass(self):
"""Handle entity which will be added.""" """Handle entity which will be added."""
@ -194,6 +199,21 @@ class ModbusThermostat(BasePlatform, RestoreEntity, ClimateEntity):
self._available = result is not None self._available = result is not None
await self.async_update() await self.async_update()
def _swap_registers(self, registers):
"""Do swap as needed."""
if self._swap in [CONF_SWAP_BYTE, CONF_SWAP_WORD_BYTE]:
# convert [12][34] --> [21][43]
for i, register in enumerate(registers):
registers[i] = int.from_bytes(
register.to_bytes(2, byteorder="little"),
byteorder="big",
signed=False,
)
if self._swap in [CONF_SWAP_WORD, CONF_SWAP_WORD_BYTE]:
# convert [12][34] ==> [34][12]
registers.reverse()
return registers
async def async_update(self, now=None): async def async_update(self, now=None):
"""Update Target & Current Temperature.""" """Update Target & Current Temperature."""
# remark "now" is a dummy parameter to avoid problems with # remark "now" is a dummy parameter to avoid problems with
@ -216,9 +236,8 @@ class ModbusThermostat(BasePlatform, RestoreEntity, ClimateEntity):
self._available = False self._available = False
return -1 return -1
byte_string = b"".join( registers = self._swap_registers(result.registers)
[x.to_bytes(2, byteorder="big") for x in result.registers] byte_string = b"".join([x.to_bytes(2, byteorder="big") for x in registers])
)
val = struct.unpack(self._structure, byte_string) val = struct.unpack(self._structure, byte_string)
if len(val) != 1 or not isinstance(val[0], (float, int)): if len(val) != 1 or not isinstance(val[0], (float, int)):
_LOGGER.error( _LOGGER.error(

View File

@ -3,14 +3,11 @@ 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 ( from homeassistant.components.modbus.const import CONF_CLIMATES, CONF_TARGET_TEMP
CONF_CLIMATES,
CONF_DATA_COUNT,
CONF_TARGET_TEMP,
)
from homeassistant.const import ( from homeassistant.const import (
ATTR_TEMPERATURE, ATTR_TEMPERATURE,
CONF_ADDRESS, CONF_ADDRESS,
CONF_COUNT,
CONF_NAME, CONF_NAME,
CONF_SCAN_INTERVAL, CONF_SCAN_INTERVAL,
CONF_SLAVE, CONF_SLAVE,
@ -28,7 +25,7 @@ from tests.common import mock_restore_cache
{}, {},
{ {
CONF_SCAN_INTERVAL: 20, CONF_SCAN_INTERVAL: 20,
CONF_DATA_COUNT: 2, CONF_COUNT: 2,
}, },
], ],
) )
@ -73,7 +70,7 @@ async def test_temperature_climate(hass, regs, expected):
CONF_SLAVE: 1, CONF_SLAVE: 1,
CONF_TARGET_TEMP: 117, CONF_TARGET_TEMP: 117,
CONF_ADDRESS: 117, CONF_ADDRESS: 117,
CONF_DATA_COUNT: 2, CONF_COUNT: 2,
}, },
climate_name, climate_name,
CLIMATE_DOMAIN, CLIMATE_DOMAIN,