Add device_info to onewire sensors (#42309)

* Add device info

* Cleanup log
This commit is contained in:
epenet 2020-10-25 18:05:02 +01:00 committed by GitHub
parent 9a970cfe3d
commit c157a582b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 193 additions and 27 deletions

View File

@ -186,10 +186,12 @@ def get_entities(config):
for device in devices: for device in devices:
_LOGGER.debug("Found device: %s", device) _LOGGER.debug("Found device: %s", device)
family = owproxy.read(f"{device}family").decode() family = owproxy.read(f"{device}family").decode()
device_type = owproxy.read(f"{device}type").decode()
sensor_id = os.path.split(os.path.split(device)[0])[1]
dev_type = "std" dev_type = "std"
if "EF" in family: if "EF" in family:
dev_type = "HobbyBoard" dev_type = "HobbyBoard"
family = owproxy.read(f"{device}type").decode() family = device_type
if family not in hb_info_from_type(dev_type): if family not in hb_info_from_type(dev_type):
_LOGGER.warning( _LOGGER.warning(
@ -198,6 +200,12 @@ def get_entities(config):
device, device,
) )
continue continue
device_info = {
"identifiers": {(DOMAIN, sensor_id)},
"manufacturer": "Maxim Integrated",
"model": device_type,
"name": sensor_id,
}
for sensor_key, sensor_value in hb_info_from_type(dev_type)[family].items(): for sensor_key, sensor_value in hb_info_from_type(dev_type)[family].items():
if "moisture" in sensor_key: if "moisture" in sensor_key:
s_id = sensor_key.split("_")[1] s_id = sensor_key.split("_")[1]
@ -206,13 +214,13 @@ def get_entities(config):
) )
if is_leaf: if is_leaf:
sensor_key = f"wetness_{s_id}" sensor_key = f"wetness_{s_id}"
sensor_id = os.path.split(os.path.split(device)[0])[1]
device_file = os.path.join(os.path.split(device)[0], sensor_value) device_file = os.path.join(os.path.split(device)[0], sensor_value)
entities.append( entities.append(
OneWireProxy( OneWireProxy(
device_names.get(sensor_id, sensor_id), device_names.get(sensor_id, sensor_id),
device_file, device_file,
sensor_key, sensor_key,
device_info,
owproxy, owproxy,
) )
) )
@ -232,12 +240,19 @@ def get_entities(config):
) )
continue continue
device_info = {
"identifiers": {(DOMAIN, sensor_id)},
"manufacturer": "Maxim Integrated",
"model": family,
"name": sensor_id,
}
device_file = f"/sys/bus/w1/devices/{sensor_id}/w1_slave" device_file = f"/sys/bus/w1/devices/{sensor_id}/w1_slave"
entities.append( entities.append(
OneWireDirect( OneWireDirect(
device_names.get(sensor_id, sensor_id), device_names.get(sensor_id, sensor_id),
device_file, device_file,
"temperature", "temperature",
device_info,
p1sensor, p1sensor,
) )
) )
@ -286,12 +301,13 @@ def get_entities(config):
class OneWire(Entity): class OneWire(Entity):
"""Implementation of a 1-Wire sensor.""" """Implementation of a 1-Wire sensor."""
def __init__(self, name, device_file, sensor_type): def __init__(self, name, device_file, sensor_type, device_info=None):
"""Initialize the sensor.""" """Initialize the sensor."""
self._name = f"{name} {sensor_type.capitalize()}" self._name = f"{name} {sensor_type.capitalize()}"
self._device_file = device_file self._device_file = device_file
self._device_class = SENSOR_TYPES[sensor_type][2] self._device_class = SENSOR_TYPES[sensor_type][2]
self._unit_of_measurement = SENSOR_TYPES[sensor_type][1] self._unit_of_measurement = SENSOR_TYPES[sensor_type][1]
self._device_info = device_info
self._state = None self._state = None
self._value_raw = None self._value_raw = None
@ -327,13 +343,18 @@ class OneWire(Entity):
"""Return a unique ID.""" """Return a unique ID."""
return self._device_file return self._device_file
@property
def device_info(self) -> Optional[Dict[str, Any]]:
"""Return device specific attributes."""
return self._device_info
class OneWireProxy(OneWire): class OneWireProxy(OneWire):
"""Implementation of a 1-Wire sensor through owserver.""" """Implementation of a 1-Wire sensor through owserver."""
def __init__(self, name, device_file, sensor_type, owproxy): def __init__(self, name, device_file, sensor_type, device_info, owproxy):
"""Initialize the sensor.""" """Initialize the sensor."""
super().__init__(name, device_file, sensor_type) super().__init__(name, device_file, sensor_type, device_info)
self._owproxy = owproxy self._owproxy = owproxy
def _read_value_ownet(self): def _read_value_ownet(self):
@ -358,9 +379,9 @@ class OneWireProxy(OneWire):
class OneWireDirect(OneWire): class OneWireDirect(OneWire):
"""Implementation of a 1-Wire sensor directly connected to RPI GPIO.""" """Implementation of a 1-Wire sensor directly connected to RPI GPIO."""
def __init__(self, name, device_file, sensor_type, owsensor): def __init__(self, name, device_file, sensor_type, device_info, owsensor):
"""Initialize the sensor.""" """Initialize the sensor."""
super().__init__(name, device_file, sensor_type) super().__init__(name, device_file, sensor_type, device_info)
self._owsensor = owsensor self._owsensor = owsensor
def update(self): def update(self):

View File

@ -25,7 +25,7 @@ from homeassistant.const import (
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
from tests.async_mock import patch from tests.async_mock import patch
from tests.common import mock_registry from tests.common import mock_device_registry, mock_registry
MOCK_CONFIG = { MOCK_CONFIG = {
SENSOR_DOMAIN: { SENSOR_DOMAIN: {
@ -39,8 +39,22 @@ MOCK_CONFIG = {
} }
MOCK_DEVICE_SENSORS = { MOCK_DEVICE_SENSORS = {
"00.111111111111": {"sensors": []}, "00.111111111111": {
"inject_reads": [
b"", # read device type
],
"sensors": [],
},
"10.111111111111": { "10.111111111111": {
"inject_reads": [
b"DS18S20", # read device type
],
"device_info": {
"identifiers": {(DOMAIN, "10.111111111111")},
"manufacturer": "Maxim Integrated",
"model": "DS18S20",
"name": "10.111111111111",
},
"sensors": [ "sensors": [
{ {
"entity_id": "sensor.my_ds18b20_temperature", "entity_id": "sensor.my_ds18b20_temperature",
@ -50,9 +64,18 @@ MOCK_DEVICE_SENSORS = {
"unit": TEMP_CELSIUS, "unit": TEMP_CELSIUS,
"class": DEVICE_CLASS_TEMPERATURE, "class": DEVICE_CLASS_TEMPERATURE,
}, },
] ],
}, },
"12.111111111111": { "12.111111111111": {
"inject_reads": [
b"DS2406", # read device type
],
"device_info": {
"identifiers": {(DOMAIN, "12.111111111111")},
"manufacturer": "Maxim Integrated",
"model": "DS2406",
"name": "12.111111111111",
},
"sensors": [ "sensors": [
{ {
"entity_id": "sensor.12_111111111111_temperature", "entity_id": "sensor.12_111111111111_temperature",
@ -70,9 +93,18 @@ MOCK_DEVICE_SENSORS = {
"unit": PRESSURE_MBAR, "unit": PRESSURE_MBAR,
"class": DEVICE_CLASS_PRESSURE, "class": DEVICE_CLASS_PRESSURE,
}, },
] ],
}, },
"1D.111111111111": { "1D.111111111111": {
"inject_reads": [
b"DS2423", # read device type
],
"device_info": {
"identifiers": {(DOMAIN, "1D.111111111111")},
"manufacturer": "Maxim Integrated",
"model": "DS2423",
"name": "1D.111111111111",
},
"sensors": [ "sensors": [
{ {
"entity_id": "sensor.1d_111111111111_counter_a", "entity_id": "sensor.1d_111111111111_counter_a",
@ -90,9 +122,18 @@ MOCK_DEVICE_SENSORS = {
"unit": "count", "unit": "count",
"class": None, "class": None,
}, },
] ],
}, },
"22.111111111111": { "22.111111111111": {
"inject_reads": [
b"DS1822", # read device type
],
"device_info": {
"identifiers": {(DOMAIN, "22.111111111111")},
"manufacturer": "Maxim Integrated",
"model": "DS1822",
"name": "22.111111111111",
},
"sensors": [ "sensors": [
{ {
"entity_id": "sensor.22_111111111111_temperature", "entity_id": "sensor.22_111111111111_temperature",
@ -102,9 +143,18 @@ MOCK_DEVICE_SENSORS = {
"unit": TEMP_CELSIUS, "unit": TEMP_CELSIUS,
"class": DEVICE_CLASS_TEMPERATURE, "class": DEVICE_CLASS_TEMPERATURE,
}, },
] ],
}, },
"26.111111111111": { "26.111111111111": {
"inject_reads": [
b"DS2438", # read device type
],
"device_info": {
"identifiers": {(DOMAIN, "26.111111111111")},
"manufacturer": "Maxim Integrated",
"model": "DS2438",
"name": "26.111111111111",
},
"sensors": [ "sensors": [
{ {
"entity_id": "sensor.26_111111111111_temperature", "entity_id": "sensor.26_111111111111_temperature",
@ -194,9 +244,18 @@ MOCK_DEVICE_SENSORS = {
"unit": ELECTRICAL_CURRENT_AMPERE, "unit": ELECTRICAL_CURRENT_AMPERE,
"class": DEVICE_CLASS_CURRENT, "class": DEVICE_CLASS_CURRENT,
}, },
] ],
}, },
"28.111111111111": { "28.111111111111": {
"inject_reads": [
b"DS18B20", # read device type
],
"device_info": {
"identifiers": {(DOMAIN, "28.111111111111")},
"manufacturer": "Maxim Integrated",
"model": "DS18B20",
"name": "28.111111111111",
},
"sensors": [ "sensors": [
{ {
"entity_id": "sensor.28_111111111111_temperature", "entity_id": "sensor.28_111111111111_temperature",
@ -206,9 +265,18 @@ MOCK_DEVICE_SENSORS = {
"unit": TEMP_CELSIUS, "unit": TEMP_CELSIUS,
"class": DEVICE_CLASS_TEMPERATURE, "class": DEVICE_CLASS_TEMPERATURE,
}, },
] ],
}, },
"3B.111111111111": { "3B.111111111111": {
"inject_reads": [
b"DS1825", # read device type
],
"device_info": {
"identifiers": {(DOMAIN, "3B.111111111111")},
"manufacturer": "Maxim Integrated",
"model": "DS1825",
"name": "3B.111111111111",
},
"sensors": [ "sensors": [
{ {
"entity_id": "sensor.3b_111111111111_temperature", "entity_id": "sensor.3b_111111111111_temperature",
@ -218,9 +286,18 @@ MOCK_DEVICE_SENSORS = {
"unit": TEMP_CELSIUS, "unit": TEMP_CELSIUS,
"class": DEVICE_CLASS_TEMPERATURE, "class": DEVICE_CLASS_TEMPERATURE,
}, },
] ],
}, },
"42.111111111111": { "42.111111111111": {
"inject_reads": [
b"DS28EA00", # read device type
],
"device_info": {
"identifiers": {(DOMAIN, "42.111111111111")},
"manufacturer": "Maxim Integrated",
"model": "DS28EA00",
"name": "42.111111111111",
},
"sensors": [ "sensors": [
{ {
"entity_id": "sensor.42_111111111111_temperature", "entity_id": "sensor.42_111111111111_temperature",
@ -230,12 +307,18 @@ MOCK_DEVICE_SENSORS = {
"unit": TEMP_CELSIUS, "unit": TEMP_CELSIUS,
"class": DEVICE_CLASS_TEMPERATURE, "class": DEVICE_CLASS_TEMPERATURE,
}, },
] ],
}, },
"EF.111111111111": { "EF.111111111111": {
"inject_reads": [ "inject_reads": [
b"HobbyBoards_EF", # read type b"HobbyBoards_EF", # read type
], ],
"device_info": {
"identifiers": {(DOMAIN, "EF.111111111111")},
"manufacturer": "Maxim Integrated",
"model": "HobbyBoards_EF",
"name": "EF.111111111111",
},
"sensors": [ "sensors": [
{ {
"entity_id": "sensor.ef_111111111111_humidity", "entity_id": "sensor.ef_111111111111_humidity",
@ -271,6 +354,12 @@ MOCK_DEVICE_SENSORS = {
b" 0", # read is_leaf_2 b" 0", # read is_leaf_2
b" 0", # read is_leaf_3 b" 0", # read is_leaf_3
], ],
"device_info": {
"identifiers": {(DOMAIN, "EF.111111111112")},
"manufacturer": "Maxim Integrated",
"model": "HB_MOISTURE_METER",
"name": "EF.111111111112",
},
"sensors": [ "sensors": [
{ {
"entity_id": "sensor.ef_111111111112_wetness_0", "entity_id": "sensor.ef_111111111112_wetness_0",
@ -313,13 +402,16 @@ MOCK_DEVICE_SENSORS = {
async def test_owserver_setup_valid_device(hass, device_id): async def test_owserver_setup_valid_device(hass, device_id):
"""Test for 1-Wire device.""" """Test for 1-Wire device."""
entity_registry = mock_registry(hass) entity_registry = mock_registry(hass)
device_registry = mock_device_registry(hass)
mock_device_sensor = MOCK_DEVICE_SENSORS[device_id]
dir_return_value = [f"/{device_id}/"] dir_return_value = [f"/{device_id}/"]
read_side_effect = [device_id[0:2].encode()] read_side_effect = [device_id[0:2].encode()]
if "inject_reads" in MOCK_DEVICE_SENSORS[device_id]: if "inject_reads" in mock_device_sensor:
read_side_effect += MOCK_DEVICE_SENSORS[device_id]["inject_reads"] read_side_effect += mock_device_sensor["inject_reads"]
expected_sensors = MOCK_DEVICE_SENSORS[device_id]["sensors"] expected_sensors = mock_device_sensor["sensors"]
for expected_sensor in expected_sensors: for expected_sensor in expected_sensors:
read_side_effect.append(expected_sensor["injected_value"]) read_side_effect.append(expected_sensor["injected_value"])
@ -335,6 +427,16 @@ async def test_owserver_setup_valid_device(hass, device_id):
assert len(entity_registry.entities) == len(expected_sensors) assert len(entity_registry.entities) == len(expected_sensors)
if len(expected_sensors) > 0:
device_info = mock_device_sensor["device_info"]
assert len(device_registry.devices) == 1
registry_entry = device_registry.async_get_device({(DOMAIN, device_id)}, set())
assert registry_entry is not None
assert registry_entry.identifiers == {(DOMAIN, device_id)}
assert registry_entry.manufacturer == device_info["manufacturer"]
assert registry_entry.name == device_info["name"]
assert registry_entry.model == device_info["model"]
for expected_sensor in expected_sensors: for expected_sensor in expected_sensors:
entity_id = expected_sensor["entity_id"] entity_id = expected_sensor["entity_id"]
registry_entry = entity_registry.entities.get(entity_id) registry_entry = entity_registry.entities.get(entity_id)

View File

@ -8,7 +8,7 @@ from homeassistant.const import DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
from tests.async_mock import patch from tests.async_mock import patch
from tests.common import mock_registry from tests.common import mock_device_registry, mock_registry
MOCK_CONFIG = { MOCK_CONFIG = {
SENSOR_DOMAIN: { SENSOR_DOMAIN: {
@ -23,6 +23,12 @@ MOCK_CONFIG = {
MOCK_DEVICE_SENSORS = { MOCK_DEVICE_SENSORS = {
"00-111111111111": {"sensors": []}, "00-111111111111": {"sensors": []},
"10-111111111111": { "10-111111111111": {
"device_info": {
"identifiers": {(DOMAIN, "10-111111111111")},
"manufacturer": "Maxim Integrated",
"model": "10",
"name": "10-111111111111",
},
"sensors": [ "sensors": [
{ {
"entity_id": "sensor.my_ds18b20_temperature", "entity_id": "sensor.my_ds18b20_temperature",
@ -32,11 +38,17 @@ MOCK_DEVICE_SENSORS = {
"unit": TEMP_CELSIUS, "unit": TEMP_CELSIUS,
"class": DEVICE_CLASS_TEMPERATURE, "class": DEVICE_CLASS_TEMPERATURE,
}, },
] ],
}, },
"12-111111111111": {"sensors": []}, "12-111111111111": {"sensors": []},
"1D-111111111111": {"sensors": []}, "1D-111111111111": {"sensors": []},
"22-111111111111": { "22-111111111111": {
"device_info": {
"identifiers": {(DOMAIN, "22-111111111111")},
"manufacturer": "Maxim Integrated",
"model": "22",
"name": "22-111111111111",
},
"sensors": [ "sensors": [
{ {
"entity_id": "sensor.22_111111111111_temperature", "entity_id": "sensor.22_111111111111_temperature",
@ -46,10 +58,16 @@ MOCK_DEVICE_SENSORS = {
"unit": TEMP_CELSIUS, "unit": TEMP_CELSIUS,
"class": DEVICE_CLASS_TEMPERATURE, "class": DEVICE_CLASS_TEMPERATURE,
}, },
] ],
}, },
"26-111111111111": {"sensors": []}, "26-111111111111": {"sensors": []},
"28-111111111111": { "28-111111111111": {
"device_info": {
"identifiers": {(DOMAIN, "28-111111111111")},
"manufacturer": "Maxim Integrated",
"model": "28",
"name": "28-111111111111",
},
"sensors": [ "sensors": [
{ {
"entity_id": "sensor.28_111111111111_temperature", "entity_id": "sensor.28_111111111111_temperature",
@ -59,9 +77,15 @@ MOCK_DEVICE_SENSORS = {
"unit": TEMP_CELSIUS, "unit": TEMP_CELSIUS,
"class": DEVICE_CLASS_TEMPERATURE, "class": DEVICE_CLASS_TEMPERATURE,
}, },
] ],
}, },
"3B-111111111111": { "3B-111111111111": {
"device_info": {
"identifiers": {(DOMAIN, "3B-111111111111")},
"manufacturer": "Maxim Integrated",
"model": "3B",
"name": "3B-111111111111",
},
"sensors": [ "sensors": [
{ {
"entity_id": "sensor.3b_111111111111_temperature", "entity_id": "sensor.3b_111111111111_temperature",
@ -71,9 +95,15 @@ MOCK_DEVICE_SENSORS = {
"unit": TEMP_CELSIUS, "unit": TEMP_CELSIUS,
"class": DEVICE_CLASS_TEMPERATURE, "class": DEVICE_CLASS_TEMPERATURE,
}, },
] ],
}, },
"42-111111111111": { "42-111111111111": {
"device_info": {
"identifiers": {(DOMAIN, "42-111111111111")},
"manufacturer": "Maxim Integrated",
"model": "42",
"name": "42-111111111111",
},
"sensors": [ "sensors": [
{ {
"entity_id": "sensor.42_111111111111_temperature", "entity_id": "sensor.42_111111111111_temperature",
@ -83,7 +113,7 @@ MOCK_DEVICE_SENSORS = {
"unit": TEMP_CELSIUS, "unit": TEMP_CELSIUS,
"class": DEVICE_CLASS_TEMPERATURE, "class": DEVICE_CLASS_TEMPERATURE,
}, },
] ],
}, },
"EF-111111111111": { "EF-111111111111": {
"sensors": [], "sensors": [],
@ -98,10 +128,13 @@ MOCK_DEVICE_SENSORS = {
async def test_onewiredirect_setup_valid_device(hass, device_id): async def test_onewiredirect_setup_valid_device(hass, device_id):
"""Test that sysbus config entry works correctly.""" """Test that sysbus config entry works correctly."""
entity_registry = mock_registry(hass) entity_registry = mock_registry(hass)
device_registry = mock_device_registry(hass)
mock_device_sensor = MOCK_DEVICE_SENSORS[device_id]
glob_result = [f"/{DEFAULT_SYSBUS_MOUNT_DIR}/{device_id}"] glob_result = [f"/{DEFAULT_SYSBUS_MOUNT_DIR}/{device_id}"]
read_side_effect = [] read_side_effect = []
expected_sensors = MOCK_DEVICE_SENSORS[device_id]["sensors"] expected_sensors = mock_device_sensor["sensors"]
for expected_sensor in expected_sensors: for expected_sensor in expected_sensors:
read_side_effect.append(expected_sensor["injected_value"]) read_side_effect.append(expected_sensor["injected_value"])
@ -119,6 +152,16 @@ async def test_onewiredirect_setup_valid_device(hass, device_id):
assert len(entity_registry.entities) == len(expected_sensors) assert len(entity_registry.entities) == len(expected_sensors)
if len(expected_sensors) > 0:
device_info = mock_device_sensor["device_info"]
assert len(device_registry.devices) == 1
registry_entry = device_registry.async_get_device({(DOMAIN, device_id)}, set())
assert registry_entry is not None
assert registry_entry.identifiers == {(DOMAIN, device_id)}
assert registry_entry.manufacturer == device_info["manufacturer"]
assert registry_entry.name == device_info["name"]
assert registry_entry.model == device_info["model"]
for expected_sensor in expected_sensors: for expected_sensor in expected_sensors:
entity_id = expected_sensor["entity_id"] entity_id = expected_sensor["entity_id"]
registry_entry = entity_registry.entities.get(entity_id) registry_entry = entity_registry.entities.get(entity_id)