Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions homeassistant/components/onewire/sensor.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Support for 1-Wire environment sensors."""
from __future__ import annotations

import asyncio
from glob import glob
import logging
import os
Expand Down Expand Up @@ -426,11 +427,31 @@ def state(self) -> StateType:
"""Return the state of the entity."""
return self._state

def update(self):
async def get_temperature(self):
"""Get the latest data from the device."""
attempts = 1
while True:
try:
return await self.hass.async_add_executor_job(
self._owsensor.get_temperature
)
except UnsupportResponseException as ex:
_LOGGER.debug(
"Cannot read from sensor %s (retry attempt %s): %s",
self._device_file,
attempts,
ex,
)
await asyncio.sleep(0.2)
attempts += 1
if attempts > 10:
raise

async def async_update(self):
"""Get the latest data from the device."""
value = None
try:
self._value_raw = self._owsensor.get_temperature()
self._value_raw = await self.get_temperature()
value = round(float(self._value_raw), 1)
except (
FileNotFoundError,
Expand Down
30 changes: 29 additions & 1 deletion tests/components/onewire/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Tests for 1-Wire integration."""

from typing import Any, List, Tuple
from unittest.mock import patch

from pyownet.protocol import ProtocolError
Expand All @@ -15,7 +16,7 @@
from homeassistant.config_entries import CONN_CLASS_LOCAL_POLL
from homeassistant.const import CONF_HOST, CONF_PORT, CONF_TYPE

from .const import MOCK_OWPROXY_DEVICES
from .const import MOCK_OWPROXY_DEVICES, MOCK_SYSBUS_DEVICES

from tests.common import MockConfigEntry

Expand Down Expand Up @@ -125,3 +126,30 @@ def setup_owproxy_mock_devices(owproxy, domain, device_ids) -> None:
)
owproxy.return_value.dir.return_value = dir_return_value
owproxy.return_value.read.side_effect = read_side_effect


def setup_sysbus_mock_devices(
domain: str, device_ids: List[str]
) -> Tuple[List[str], List[Any]]:
"""Set up mock for sysbus."""
glob_result = []
read_side_effect = []

for device_id in device_ids:
mock_device = MOCK_SYSBUS_DEVICES[device_id]

# Setup directory listing
glob_result += [f"/{DEFAULT_SYSBUS_MOUNT_DIR}/{device_id}"]

# Setup sub-device reads
device_sensors = mock_device.get(domain, [])
for expected_sensor in device_sensors:
if isinstance(expected_sensor["injected_value"], list):
read_side_effect += expected_sensor["injected_value"]
else:
read_side_effect.append(expected_sensor["injected_value"])

# Ensure enough read side effect
read_side_effect.extend([FileNotFoundError("Missing injected value")] * 20)

return (glob_result, read_side_effect)
60 changes: 48 additions & 12 deletions tests/components/onewire/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -778,15 +778,15 @@
}

MOCK_SYSBUS_DEVICES = {
"00-111111111111": {"sensors": []},
"00-111111111111": {SENSOR_DOMAIN: []},
"10-111111111111": {
"device_info": {
"identifiers": {(DOMAIN, "10-111111111111")},
"manufacturer": "Maxim Integrated",
"model": "10",
"name": "10-111111111111",
},
"sensors": [
SENSOR_DOMAIN: [
{
"entity_id": "sensor.my_ds18b20_temperature",
"unique_id": "/sys/bus/w1/devices/10-111111111111/w1_slave",
Expand All @@ -797,16 +797,16 @@
},
],
},
"12-111111111111": {"sensors": []},
"1D-111111111111": {"sensors": []},
"12-111111111111": {SENSOR_DOMAIN: []},
"1D-111111111111": {SENSOR_DOMAIN: []},
"22-111111111111": {
"device_info": {
"identifiers": {(DOMAIN, "22-111111111111")},
"manufacturer": "Maxim Integrated",
"model": "22",
"name": "22-111111111111",
},
"sensors": [
"sensor": [
{
"entity_id": "sensor.22_111111111111_temperature",
"unique_id": "/sys/bus/w1/devices/22-111111111111/w1_slave",
Expand All @@ -817,15 +817,15 @@
},
],
},
"26-111111111111": {"sensors": []},
"26-111111111111": {SENSOR_DOMAIN: []},
"28-111111111111": {
"device_info": {
"identifiers": {(DOMAIN, "28-111111111111")},
"manufacturer": "Maxim Integrated",
"model": "28",
"name": "28-111111111111",
},
"sensors": [
SENSOR_DOMAIN: [
{
"entity_id": "sensor.28_111111111111_temperature",
"unique_id": "/sys/bus/w1/devices/28-111111111111/w1_slave",
Expand All @@ -836,15 +836,15 @@
},
],
},
"29-111111111111": {"sensors": []},
"29-111111111111": {SENSOR_DOMAIN: []},
"3B-111111111111": {
"device_info": {
"identifiers": {(DOMAIN, "3B-111111111111")},
"manufacturer": "Maxim Integrated",
"model": "3B",
"name": "3B-111111111111",
},
"sensors": [
SENSOR_DOMAIN: [
{
"entity_id": "sensor.3b_111111111111_temperature",
"unique_id": "/sys/bus/w1/devices/3B-111111111111/w1_slave",
Expand All @@ -862,7 +862,7 @@
"model": "42",
"name": "42-111111111111",
},
"sensors": [
SENSOR_DOMAIN: [
{
"entity_id": "sensor.42_111111111111_temperature",
"unique_id": "/sys/bus/w1/devices/42-111111111111/w1_slave",
Expand All @@ -873,10 +873,46 @@
},
],
},
"42-111111111112": {
"device_info": {
"identifiers": {(DOMAIN, "42-111111111112")},
"manufacturer": "Maxim Integrated",
"model": "42",
"name": "42-111111111112",
},
SENSOR_DOMAIN: [
{
"entity_id": "sensor.42_111111111112_temperature",
"unique_id": "/sys/bus/w1/devices/42-111111111112/w1_slave",
"injected_value": [UnsupportResponseException] * 9 + ["27.993"],
"result": "28.0",
"unit": TEMP_CELSIUS,
"class": DEVICE_CLASS_TEMPERATURE,
},
],
},
"42-111111111113": {
"device_info": {
"identifiers": {(DOMAIN, "42-111111111113")},
"manufacturer": "Maxim Integrated",
"model": "42",
"name": "42-111111111113",
},
SENSOR_DOMAIN: [
{
"entity_id": "sensor.42_111111111113_temperature",
"unique_id": "/sys/bus/w1/devices/42-111111111113/w1_slave",
"injected_value": [UnsupportResponseException] * 10 + ["27.993"],
"result": "unknown",
"unit": TEMP_CELSIUS,
"class": DEVICE_CLASS_TEMPERATURE,
},
],
},
"EF-111111111111": {
"sensors": [],
SENSOR_DOMAIN: [],
},
"EF-111111111112": {
"sensors": [],
SENSOR_DOMAIN: [],
},
}
29 changes: 15 additions & 14 deletions tests/components/onewire/test_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
from homeassistant.setup import async_setup_component

from . import setup_onewire_patched_owserver_integration, setup_owproxy_mock_devices
from . import (
setup_onewire_patched_owserver_integration,
setup_owproxy_mock_devices,
setup_sysbus_mock_devices,
)
from .const import MOCK_OWPROXY_DEVICES, MOCK_SYSBUS_DEVICES

from tests.common import assert_setup_component, mock_device_registry, mock_registry
Expand Down Expand Up @@ -185,19 +189,16 @@ async def test_owserver_setup_valid_device(owproxy, hass, device_id, platform):
@pytest.mark.parametrize("device_id", MOCK_SYSBUS_DEVICES.keys())
async def test_onewiredirect_setup_valid_device(hass, device_id):
"""Test that sysbus config entry works correctly."""
await async_setup_component(hass, "persistent_notification", {})
entity_registry = mock_registry(hass)
device_registry = mock_device_registry(hass)

mock_device_sensor = MOCK_SYSBUS_DEVICES[device_id]
glob_result, read_side_effect = setup_sysbus_mock_devices(
SENSOR_DOMAIN, [device_id]
)

glob_result = [f"/{DEFAULT_SYSBUS_MOUNT_DIR}/{device_id}"]
read_side_effect = []
expected_sensors = mock_device_sensor["sensors"]
for expected_sensor in expected_sensors:
read_side_effect.append(expected_sensor["injected_value"])

# Ensure enough read side effect
read_side_effect.extend([FileNotFoundError("Missing injected value")] * 20)
mock_device = MOCK_SYSBUS_DEVICES[device_id]
expected_entities = mock_device.get(SENSOR_DOMAIN, [])

with patch(
"homeassistant.components.onewire.onewirehub.os.path.isdir", return_value=True
Expand All @@ -208,10 +209,10 @@ async def test_onewiredirect_setup_valid_device(hass, device_id):
assert await async_setup_component(hass, SENSOR_DOMAIN, MOCK_SYSBUS_CONFIG)
await hass.async_block_till_done()

assert len(entity_registry.entities) == len(expected_sensors)
assert len(entity_registry.entities) == len(expected_entities)

if len(expected_sensors) > 0:
device_info = mock_device_sensor["device_info"]
if len(expected_entities) > 0:
device_info = mock_device["device_info"]
assert len(device_registry.devices) == 1
registry_entry = device_registry.async_get_device({(DOMAIN, device_id)})
assert registry_entry is not None
Expand All @@ -220,7 +221,7 @@ async def test_onewiredirect_setup_valid_device(hass, device_id):
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_entities:
entity_id = expected_sensor["entity_id"]
registry_entry = entity_registry.entities.get(entity_id)
assert registry_entry is not None
Expand Down