From 200d3ae84527f05c1ee5a25e9645b87b00f0b823 Mon Sep 17 00:00:00 2001 From: GrahamJB1 <26122648+GrahamJB1@users.noreply.github.com> Date: Thu, 19 Jan 2023 10:08:11 +0000 Subject: [PATCH] modbus slave unique ids (#86126) modbus slave unique ids --- .../components/modbus/binary_sensor.py | 4 ++++ homeassistant/components/modbus/sensor.py | 10 ++++++++- tests/components/modbus/test_binary_sensor.py | 21 ++++++++++++------- tests/components/modbus/test_sensor.py | 12 +++++++++++ 4 files changed, 39 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/modbus/binary_sensor.py b/homeassistant/components/modbus/binary_sensor.py index f1f5814fe76..ec923100347 100644 --- a/homeassistant/components/modbus/binary_sensor.py +++ b/homeassistant/components/modbus/binary_sensor.py @@ -10,6 +10,7 @@ from homeassistant.const import ( CONF_BINARY_SENSORS, CONF_DEVICE_CLASS, CONF_NAME, + CONF_UNIQUE_ID, STATE_ON, ) from homeassistant.core import HomeAssistant, callback @@ -138,6 +139,9 @@ class SlaveSensor( idx += 1 self._attr_name = f"{entry[CONF_NAME]} {idx}" self._attr_device_class = entry.get(CONF_DEVICE_CLASS) + self._attr_unique_id = entry.get(CONF_UNIQUE_ID) + if self._attr_unique_id: + self._attr_unique_id = f"{self._attr_unique_id}_{idx}" self._attr_available = False self._result_inx = idx super().__init__(coordinator) diff --git a/homeassistant/components/modbus/sensor.py b/homeassistant/components/modbus/sensor.py index 310f7b0a9cd..7294485365d 100644 --- a/homeassistant/components/modbus/sensor.py +++ b/homeassistant/components/modbus/sensor.py @@ -6,7 +6,12 @@ import logging from typing import Any, Optional from homeassistant.components.sensor import CONF_STATE_CLASS, SensorEntity -from homeassistant.const import CONF_NAME, CONF_SENSORS, CONF_UNIT_OF_MEASUREMENT +from homeassistant.const import ( + CONF_NAME, + CONF_SENSORS, + CONF_UNIQUE_ID, + CONF_UNIT_OF_MEASUREMENT, +) from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.restore_state import RestoreEntity @@ -145,6 +150,9 @@ class SlaveSensor( idx += 1 self._idx = idx self._attr_name = f"{entry[CONF_NAME]} {idx}" + self._attr_unique_id = entry.get(CONF_UNIQUE_ID) + if self._attr_unique_id: + self._attr_unique_id = f"{self._attr_unique_id}_{idx}" self._attr_available = False super().__init__(coordinator) diff --git a/tests/components/modbus/test_binary_sensor.py b/tests/components/modbus/test_binary_sensor.py index 611f558cf1f..652ae7e74af 100644 --- a/tests/components/modbus/test_binary_sensor.py +++ b/tests/components/modbus/test_binary_sensor.py @@ -19,17 +19,20 @@ from homeassistant.const import ( CONF_NAME, CONF_SCAN_INTERVAL, CONF_SLAVE, + CONF_UNIQUE_ID, STATE_OFF, STATE_ON, STATE_UNAVAILABLE, STATE_UNKNOWN, ) from homeassistant.core import State +from homeassistant.helpers import entity_registry as er from homeassistant.setup import async_setup_component from .conftest import TEST_ENTITY_NAME, ReadResult, do_next_cycle ENTITY_ID = f"{SENSOR_DOMAIN}.{TEST_ENTITY_NAME}".replace(" ", "_") +SLAVE_UNIQUE_ID = "ground_floor_sensor" @pytest.mark.parametrize( @@ -341,31 +344,31 @@ async def test_config_slave_binary_sensor(hass, mock_modbus): "config_addon,register_words,expected, slaves", [ ( - {CONF_SLAVE_COUNT: 1}, + {CONF_SLAVE_COUNT: 1, CONF_UNIQUE_ID: SLAVE_UNIQUE_ID}, [False] * 8, STATE_OFF, [STATE_OFF], ), ( - {CONF_SLAVE_COUNT: 1}, + {CONF_SLAVE_COUNT: 1, CONF_UNIQUE_ID: SLAVE_UNIQUE_ID}, [True] + [False] * 7, STATE_ON, [STATE_OFF], ), ( - {CONF_SLAVE_COUNT: 1}, + {CONF_SLAVE_COUNT: 1, CONF_UNIQUE_ID: SLAVE_UNIQUE_ID}, [False, True] + [False] * 6, STATE_OFF, [STATE_ON], ), ( - {CONF_SLAVE_COUNT: 7}, + {CONF_SLAVE_COUNT: 7, CONF_UNIQUE_ID: SLAVE_UNIQUE_ID}, [True, False] * 4, STATE_ON, [STATE_OFF, STATE_ON] * 3 + [STATE_OFF], ), ( - {CONF_SLAVE_COUNT: 31}, + {CONF_SLAVE_COUNT: 31, CONF_UNIQUE_ID: SLAVE_UNIQUE_ID}, [True, False] * 16, STATE_ON, [STATE_OFF, STATE_ON] * 15 + [STATE_OFF], @@ -375,10 +378,14 @@ async def test_config_slave_binary_sensor(hass, mock_modbus): async def test_slave_binary_sensor(hass, expected, slaves, mock_do_cycle): """Run test for given config.""" assert hass.states.get(ENTITY_ID).state == expected + entity_registry = er.async_get(hass) - for i in range(len(slaves)): + for i, slave in enumerate(slaves): entity_id = f"{SENSOR_DOMAIN}.{TEST_ENTITY_NAME}_{i+1}".replace(" ", "_") - assert hass.states.get(entity_id).state == slaves[i] + assert hass.states.get(entity_id).state == slave + unique_id = f"{SLAVE_UNIQUE_ID}_{i+1}" + entry = entity_registry.async_get(entity_id) + assert entry.unique_id == unique_id async def test_no_discovery_info_binary_sensor(hass, caplog): diff --git a/tests/components/modbus/test_sensor.py b/tests/components/modbus/test_sensor.py index bb9e4285c42..4a6495d5b46 100644 --- a/tests/components/modbus/test_sensor.py +++ b/tests/components/modbus/test_sensor.py @@ -33,15 +33,18 @@ from homeassistant.const import ( CONF_SENSORS, CONF_SLAVE, CONF_STRUCTURE, + CONF_UNIQUE_ID, STATE_UNAVAILABLE, STATE_UNKNOWN, ) from homeassistant.core import State +from homeassistant.helpers import entity_registry as er from homeassistant.setup import async_setup_component from .conftest import TEST_ENTITY_NAME, ReadResult, do_next_cycle ENTITY_ID = f"{SENSOR_DOMAIN}.{TEST_ENTITY_NAME}".replace(" ", "_") +SLAVE_UNIQUE_ID = "ground_floor_sensor" @pytest.mark.parametrize( @@ -573,6 +576,7 @@ async def test_all_sensor(hass, mock_do_cycle, expected): ( { CONF_SLAVE_COUNT: 0, + CONF_UNIQUE_ID: SLAVE_UNIQUE_ID, }, [0x0102, 0x0304], False, @@ -581,6 +585,7 @@ async def test_all_sensor(hass, mock_do_cycle, expected): ( { CONF_SLAVE_COUNT: 1, + CONF_UNIQUE_ID: SLAVE_UNIQUE_ID, }, [0x0102, 0x0304, 0x0403, 0x0201], False, @@ -589,6 +594,7 @@ async def test_all_sensor(hass, mock_do_cycle, expected): ( { CONF_SLAVE_COUNT: 3, + CONF_UNIQUE_ID: SLAVE_UNIQUE_ID, }, [ 0x0102, @@ -611,6 +617,7 @@ async def test_all_sensor(hass, mock_do_cycle, expected): ( { CONF_SLAVE_COUNT: 1, + CONF_UNIQUE_ID: SLAVE_UNIQUE_ID, }, [0x0102, 0x0304, 0x0403, 0x0201], True, @@ -619,6 +626,7 @@ async def test_all_sensor(hass, mock_do_cycle, expected): ( { CONF_SLAVE_COUNT: 1, + CONF_UNIQUE_ID: SLAVE_UNIQUE_ID, }, [], False, @@ -629,10 +637,14 @@ async def test_all_sensor(hass, mock_do_cycle, expected): async def test_slave_sensor(hass, mock_do_cycle, expected): """Run test for sensor.""" assert hass.states.get(ENTITY_ID).state == expected[0] + entity_registry = er.async_get(hass) for i in range(1, len(expected)): entity_id = f"{SENSOR_DOMAIN}.{TEST_ENTITY_NAME}_{i}".replace(" ", "_") assert hass.states.get(entity_id).state == expected[i] + unique_id = f"{SLAVE_UNIQUE_ID}_{i}" + entry = entity_registry.async_get(entity_id) + assert entry.unique_id == unique_id @pytest.mark.parametrize(