""" Support for 1-Wire environment sensors. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/sensor.onewire/ """ import os import time import logging from glob import glob import voluptuous as vol import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import Entity from homeassistant.const import TEMP_CELSIUS from homeassistant.components.sensor import PLATFORM_SCHEMA _LOGGER = logging.getLogger(__name__) CONF_MOUNT_DIR = 'mount_dir' CONF_NAMES = 'names' DEFAULT_MOUNT_DIR = '/sys/bus/w1/devices/' DEVICE_SENSORS = {'10': {'temperature': 'temperature'}, '12': {'temperature': 'TAI8570/temperature', 'pressure': 'TAI8570/pressure'}, '22': {'temperature': 'temperature'}, '26': {'temperature': 'temperature', 'humidity': 'humidity', 'pressure': 'B1-R1-A/pressure', 'illuminance': 'S3-R1-A/illuminance'}, '28': {'temperature': 'temperature'}, '3B': {'temperature': 'temperature'}, '42': {'temperature': 'temperature'}} SENSOR_TYPES = { 'temperature': ['temperature', TEMP_CELSIUS], 'humidity': ['humidity', '%'], 'pressure': ['pressure', 'mb'], 'illuminance': ['illuminance', 'lux'], } PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Optional(CONF_NAMES): {cv.string: cv.string}, vol.Optional(CONF_MOUNT_DIR, default=DEFAULT_MOUNT_DIR): cv.string, }) def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the one wire Sensors.""" base_dir = config.get(CONF_MOUNT_DIR) devs = [] device_names = {} if 'names' in config: if isinstance(config['names'], dict): device_names = config['names'] if base_dir == DEFAULT_MOUNT_DIR: for device_family in DEVICE_SENSORS: for device_folder in glob(os.path.join(base_dir, device_family + '[.-]*')): sensor_id = os.path.split(device_folder)[1] device_file = os.path.join(device_folder, 'w1_slave') devs.append(OneWireDirect(device_names.get(sensor_id, sensor_id), device_file, 'temperature')) else: for family_file_path in glob(os.path.join(base_dir, '*', 'family')): with open(family_file_path, "r") as family_file: family = family_file.read() if family in DEVICE_SENSORS: for sensor_key, sensor_value in DEVICE_SENSORS[family].items(): sensor_id = os.path.split( os.path.split(family_file_path)[0])[1] device_file = os.path.join( os.path.split(family_file_path)[0], sensor_value) devs.append(OneWireOWFS(device_names.get(sensor_id, sensor_id), device_file, sensor_key)) if devs == []: _LOGGER.error("No onewire sensor found. Check if dtoverlay=w1-gpio " "is in your /boot/config.txt. " "Check the mount_dir parameter if it's defined") return add_entities(devs, True) class OneWire(Entity): """Implementation of an One wire Sensor.""" def __init__(self, name, device_file, sensor_type): """Initialize the sensor.""" self._name = name+' '+sensor_type.capitalize() self._device_file = device_file self._unit_of_measurement = SENSOR_TYPES[sensor_type][1] self._state = None def _read_value_raw(self): """Read the value as it is returned by the sensor.""" with open(self._device_file, 'r') as ds_device_file: lines = ds_device_file.readlines() return lines @property def name(self): """Return the name of the sensor.""" return self._name @property def state(self): """Return the state of the sensor.""" return self._state @property def unit_of_measurement(self): """Return the unit the value is expressed in.""" return self._unit_of_measurement class OneWireDirect(OneWire): """Implementation of an One wire Sensor directly connected to RPI GPIO.""" def update(self): """Get the latest data from the device.""" value = None lines = self._read_value_raw() while lines[0].strip()[-3:] != 'YES': time.sleep(0.2) lines = self._read_value_raw() equals_pos = lines[1].find('t=') if equals_pos != -1: value_string = lines[1][equals_pos + 2:] value = round(float(value_string) / 1000.0, 1) self._state = value class OneWireOWFS(OneWire): """Implementation of an One wire Sensor through owfs.""" def update(self): """Get the latest data from the device.""" value = None try: value_read = self._read_value_raw() if len(value_read) == 1: value = round(float(value_read[0]), 1) except ValueError: _LOGGER.warning("Invalid value read from %s", self._device_file) except FileNotFoundError: _LOGGER.warning("Cannot read from sensor: %s", self._device_file) self._state = value