Skip to content

Commit 843c4e2

Browse files
authored
Update Onewire SysBus integration to use a 3rd party library (home-assistant#40943)
1 parent 3bb0e00 commit 843c4e2

File tree

7 files changed

+227
-46
lines changed

7 files changed

+227
-46
lines changed

CODEOWNERS

+1-1
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ homeassistant/components/ohmconnect/* @robbiet480
305305
homeassistant/components/ombi/* @larssont
306306
homeassistant/components/omnilogic/* @oliver84 @djtimca @gentoosu
307307
homeassistant/components/onboarding/* @home-assistant/core
308-
homeassistant/components/onewire/* @garbled1
308+
homeassistant/components/onewire/* @garbled1 @epenet
309309
homeassistant/components/onvif/* @hunterjm
310310
homeassistant/components/openerz/* @misialq
311311
homeassistant/components/opengarage/* @danielhiversen
+7-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
"""Constants for 1-Wire component."""
2+
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
3+
24
CONF_MOUNT_DIR = "mount_dir"
35
CONF_NAMES = "names"
46

7+
CONF_TYPE_OWFS = "OWFS"
8+
CONF_TYPE_OWSERVER = "OWServer"
9+
CONF_TYPE_SYSBUS = "SysBus"
10+
511
DEFAULT_OWSERVER_PORT = 4304
612
DEFAULT_SYSBUS_MOUNT_DIR = "/sys/bus/w1/devices/"
713

814
DOMAIN = "onewire"
915

1016
SUPPORTED_PLATFORMS = [
11-
"sensor",
17+
SENSOR_DOMAIN,
1218
]

homeassistant/components/onewire/manifest.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22
"domain": "onewire",
33
"name": "1-Wire",
44
"documentation": "https://www.home-assistant.io/integrations/onewire",
5-
"requirements": ["pyownet==0.10.0.post1"],
6-
"codeowners": ["@garbled1"]
5+
"requirements": ["pyownet==0.10.0.post1", "pi1wire==0.1.0"],
6+
"codeowners": ["@garbled1", "@epenet"]
77
}

homeassistant/components/onewire/sensor.py

+79-42
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,13 @@
22
from glob import glob
33
import logging
44
import os
5-
import time
65

6+
from pi1wire import (
7+
InvalidCRCException,
8+
NotFoundSensorException,
9+
Pi1Wire,
10+
UnsupportResponseException,
11+
)
712
from pyownet import protocol
813
import voluptuous as vol
914

@@ -23,6 +28,9 @@
2328
from .const import (
2429
CONF_MOUNT_DIR,
2530
CONF_NAMES,
31+
CONF_TYPE_OWFS,
32+
CONF_TYPE_OWSERVER,
33+
CONF_TYPE_SYSBUS,
2634
DEFAULT_OWSERVER_PORT,
2735
DEFAULT_SYSBUS_MOUNT_DIR,
2836
)
@@ -54,6 +62,8 @@
5462
"EF": {"HobbyBoard": "special"},
5563
}
5664

65+
DEVICE_SUPPORT_SYSBUS = ["10", "22", "28", "3B", "42"]
66+
5767
# EF sensors are usually hobbyboards specialized sensors.
5868
# These can only be read by OWFS. Currently this driver only supports them
5969
# via owserver (network protocol)
@@ -120,18 +130,32 @@ def hb_info_from_type(dev_type="std"):
120130

121131
def setup_platform(hass, config, add_entities, discovery_info=None):
122132
"""Set up 1-Wire platform."""
133+
entities = get_entities(config)
134+
add_entities(entities, True)
135+
136+
137+
def get_entities(config):
138+
"""Get a list of entities."""
123139
base_dir = config[CONF_MOUNT_DIR]
124-
owport = config[CONF_PORT]
125140
owhost = config.get(CONF_HOST)
141+
owport = config[CONF_PORT]
126142

127-
devs = []
143+
# Ensure type is configured
144+
if owhost:
145+
conf_type = CONF_TYPE_OWSERVER
146+
elif base_dir == DEFAULT_SYSBUS_MOUNT_DIR:
147+
conf_type = CONF_TYPE_SYSBUS
148+
else:
149+
conf_type = CONF_TYPE_OWFS
150+
151+
entities = []
128152
device_names = {}
129153
if CONF_NAMES in config:
130154
if isinstance(config[CONF_NAMES], dict):
131155
device_names = config[CONF_NAMES]
132156

133157
# We have an owserver on a remote(or local) host/port
134-
if owhost:
158+
if conf_type == CONF_TYPE_OWSERVER:
135159
_LOGGER.debug("Initializing using %s:%s", owhost, owport)
136160
try:
137161
owproxy = protocol.proxy(host=owhost, port=owport)
@@ -166,7 +190,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
166190
sensor_key = f"wetness_{s_id}"
167191
sensor_id = os.path.split(os.path.split(device)[0])[1]
168192
device_file = os.path.join(os.path.split(device)[0], sensor_value)
169-
devs.append(
193+
entities.append(
170194
OneWireProxy(
171195
device_names.get(sensor_id, sensor_id),
172196
device_file,
@@ -176,19 +200,34 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
176200
)
177201

178202
# We have a raw GPIO ow sensor on a Pi
179-
elif base_dir == DEFAULT_SYSBUS_MOUNT_DIR:
180-
_LOGGER.debug("Initializing using SysBus %s", base_dir)
181-
for device_family in DEVICE_SENSORS:
182-
for device_folder in glob(os.path.join(base_dir, f"{device_family}[.-]*")):
183-
sensor_id = os.path.split(device_folder)[1]
184-
device_file = os.path.join(device_folder, "w1_slave")
185-
devs.append(
186-
OneWireDirect(
187-
device_names.get(sensor_id, sensor_id),
188-
device_file,
189-
"temperature",
190-
)
203+
elif conf_type == CONF_TYPE_SYSBUS:
204+
_LOGGER.debug("Initializing using SysBus")
205+
for p1sensor in Pi1Wire().find_all_sensors():
206+
family = p1sensor.mac_address[:2]
207+
sensor_id = f"{family}-{p1sensor.mac_address[2:]}"
208+
if family not in DEVICE_SUPPORT_SYSBUS:
209+
_LOGGER.warning(
210+
"Ignoring unknown family (%s) of sensor found for device: %s",
211+
family,
212+
sensor_id,
191213
)
214+
continue
215+
216+
device_file = f"/sys/bus/w1/devices/{sensor_id}/w1_slave"
217+
entities.append(
218+
OneWireDirect(
219+
device_names.get(sensor_id, sensor_id),
220+
device_file,
221+
"temperature",
222+
p1sensor,
223+
)
224+
)
225+
if not entities:
226+
_LOGGER.error(
227+
"No onewire sensor found. Check if dtoverlay=w1-gpio "
228+
"is in your /boot/config.txt. "
229+
"Check the mount_dir parameter if it's defined"
230+
)
192231

193232
# We have an owfs mounted
194233
else:
@@ -204,23 +243,15 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
204243
device_file = os.path.join(
205244
os.path.split(family_file_path)[0], sensor_value
206245
)
207-
devs.append(
246+
entities.append(
208247
OneWireOWFS(
209248
device_names.get(sensor_id, sensor_id),
210249
device_file,
211250
sensor_key,
212251
)
213252
)
214253

215-
if devs == []:
216-
_LOGGER.error(
217-
"No onewire sensor found. Check if dtoverlay=w1-gpio "
218-
"is in your /boot/config.txt. "
219-
"Check the mount_dir parameter if it's defined"
220-
)
221-
return
222-
223-
add_entities(devs, True)
254+
return entities
224255

225256

226257
class OneWire(Entity):
@@ -234,12 +265,6 @@ def __init__(self, name, device_file, sensor_type):
234265
self._state = None
235266
self._value_raw = None
236267

237-
def _read_value_raw(self):
238-
"""Read the value as it is returned by the sensor."""
239-
with open(self._device_file) as ds_device_file:
240-
lines = ds_device_file.readlines()
241-
return lines
242-
243268
@property
244269
def name(self):
245270
"""Return the name of the sensor."""
@@ -300,24 +325,36 @@ def update(self):
300325
class OneWireDirect(OneWire):
301326
"""Implementation of a 1-Wire sensor directly connected to RPI GPIO."""
302327

328+
def __init__(self, name, device_file, sensor_type, owsensor):
329+
"""Initialize the sensor."""
330+
super().__init__(name, device_file, sensor_type)
331+
self._owsensor = owsensor
332+
303333
def update(self):
304334
"""Get the latest data from the device."""
305335
value = None
306-
lines = self._read_value_raw()
307-
while lines[0].strip()[-3:] != "YES":
308-
time.sleep(0.2)
309-
lines = self._read_value_raw()
310-
equals_pos = lines[1].find("t=")
311-
if equals_pos != -1:
312-
value_string = lines[1][equals_pos + 2 :]
313-
value = round(float(value_string) / 1000.0, 1)
314-
self._value_raw = float(value_string)
336+
try:
337+
self._value_raw = self._owsensor.get_temperature()
338+
value = round(float(self._value_raw), 1)
339+
except (
340+
FileNotFoundError,
341+
InvalidCRCException,
342+
NotFoundSensorException,
343+
UnsupportResponseException,
344+
) as ex:
345+
_LOGGER.warning("Cannot read from sensor %s: %s", self._device_file, ex)
315346
self._state = value
316347

317348

318349
class OneWireOWFS(OneWire):
319350
"""Implementation of a 1-Wire sensor through owfs."""
320351

352+
def _read_value_raw(self):
353+
"""Read the value as it is returned by the sensor."""
354+
with open(self._device_file) as ds_device_file:
355+
lines = ds_device_file.readlines()
356+
return lines
357+
321358
def update(self):
322359
"""Get the latest data from the device."""
323360
value = None

requirements_all.txt

+3
Original file line numberDiff line numberDiff line change
@@ -1087,6 +1087,9 @@ pencompy==0.0.3
10871087
# homeassistant.components.unifi_direct
10881088
pexpect==4.6.0
10891089

1090+
# homeassistant.components.onewire
1091+
pi1wire==0.1.0
1092+
10901093
# homeassistant.components.pi4ioe5v9xxxx
10911094
pi4ioe5v9xxxx==0.0.2
10921095

requirements_test_all.txt

+6
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,9 @@ pdunehd==1.3.2
516516
# homeassistant.components.unifi_direct
517517
pexpect==4.6.0
518518

519+
# homeassistant.components.onewire
520+
pi1wire==0.1.0
521+
519522
# homeassistant.components.pilight
520523
pilight==0.1.1
521524

@@ -773,6 +776,9 @@ pyotp==2.3.0
773776
# homeassistant.components.openweathermap
774777
pyowm==2.10.0
775778

779+
# homeassistant.components.onewire
780+
pyownet==0.10.0.post1
781+
776782
# homeassistant.components.point
777783
pypoint==1.1.2
778784

0 commit comments

Comments
 (0)