diff --git a/homeassistant/components/modbus/const.py b/homeassistant/components/modbus/const.py index e507717b22c..c12c50cdc07 100644 --- a/homeassistant/components/modbus/const.py +++ b/homeassistant/components/modbus/const.py @@ -25,6 +25,7 @@ DATA_TYPE_CUSTOM = "custom" DATA_TYPE_FLOAT = "float" DATA_TYPE_INT = "int" DATA_TYPE_UINT = "uint" +DATA_TYPE_STRING = "string" # call types CALL_TYPE_COIL = "coil" diff --git a/homeassistant/components/modbus/sensor.py b/homeassistant/components/modbus/sensor.py index 8c475a114eb..64fbc466b1c 100644 --- a/homeassistant/components/modbus/sensor.py +++ b/homeassistant/components/modbus/sensor.py @@ -34,6 +34,7 @@ from .const import ( DATA_TYPE_CUSTOM, DATA_TYPE_FLOAT, DATA_TYPE_INT, + DATA_TYPE_STRING, DATA_TYPE_UINT, DEFAULT_HUB, MODBUS_DOMAIN, @@ -69,7 +70,13 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( vol.Required(CONF_REGISTER): cv.positive_int, vol.Optional(CONF_COUNT, default=1): cv.positive_int, vol.Optional(CONF_DATA_TYPE, default=DATA_TYPE_INT): 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_STRING, + DATA_TYPE_CUSTOM, + ] ), vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA, vol.Optional(CONF_HUB, default=DEFAULT_HUB): cv.string, @@ -98,7 +105,9 @@ def setup_platform(hass, config, add_entities, discovery_info=None): for register in config[CONF_REGISTERS]: structure = ">i" - if register[CONF_DATA_TYPE] != DATA_TYPE_CUSTOM: + if register[CONF_DATA_TYPE] == DATA_TYPE_STRING: + structure = str(register[CONF_COUNT] * 2) + "s" + elif register[CONF_DATA_TYPE] != DATA_TYPE_CUSTOM: try: structure = ( f">{data_types[register[CONF_DATA_TYPE]][register[CONF_COUNT]]}" @@ -142,6 +151,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): register[CONF_OFFSET], structure, register[CONF_PRECISION], + register[CONF_DATA_TYPE], register.get(CONF_DEVICE_CLASS), ) ) @@ -168,6 +178,7 @@ class ModbusRegisterSensor(RestoreEntity): offset, structure, precision, + data_type, device_class, ): """Initialize the modbus register sensor.""" @@ -183,6 +194,7 @@ class ModbusRegisterSensor(RestoreEntity): self._offset = offset self._precision = precision self._structure = structure + self._data_type = data_type self._device_class = device_class self._value = None self._available = True @@ -243,13 +255,16 @@ class ModbusRegisterSensor(RestoreEntity): registers.reverse() byte_string = b"".join([x.to_bytes(2, byteorder="big") for x in registers]) - val = struct.unpack(self._structure, byte_string)[0] - val = self._scale * val + self._offset - if isinstance(val, int): - self._value = str(val) - if self._precision > 0: - self._value += "." + "0" * self._precision + if self._data_type != DATA_TYPE_STRING: + val = struct.unpack(self._structure, byte_string)[0] + val = self._scale * val + self._offset + if isinstance(val, int): + self._value = str(val) + if self._precision > 0: + self._value += "." + "0" * self._precision + else: + self._value = f"{val:.{self._precision}f}" else: - self._value = f"{val:.{self._precision}f}" + self._value = byte_string.decode() self._available = True diff --git a/tests/components/modbus/test_modbus_sensor.py b/tests/components/modbus/test_modbus_sensor.py index 6207a363937..ab4d745dc50 100644 --- a/tests/components/modbus/test_modbus_sensor.py +++ b/tests/components/modbus/test_modbus_sensor.py @@ -13,6 +13,7 @@ from homeassistant.components.modbus.const import ( CONF_SCALE, DATA_TYPE_FLOAT, DATA_TYPE_INT, + DATA_TYPE_STRING, DATA_TYPE_UINT, ) from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN @@ -357,3 +358,23 @@ async def test_float_data_type(hass, mock_hub): register_words=[16286, 1617], expected="1.23457", ) + + +async def test_string_data_type(hass, mock_hub): + """Test byte string register data type.""" + register_config = { + CONF_COUNT: 8, + CONF_REGISTER_TYPE: CALL_TYPE_REGISTER_HOLDING, + CONF_DATA_TYPE: DATA_TYPE_STRING, + CONF_SCALE: 1, + CONF_OFFSET: 0, + CONF_PRECISION: 0, + } + await run_test( + hass, + mock_hub, + register_config, + SENSOR_DOMAIN, + register_words=[0x3037, 0x2D30, 0x352D, 0x3230, 0x3230, 0x2031, 0x343A, 0x3335], + expected="07-05-2020 14:35", + )