"""Support for Sensirion SHT31 temperature and humidity sensor.""" from datetime import timedelta import logging import math import voluptuous as vol from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.const import ( TEMP_CELSIUS, CONF_NAME, CONF_MONITORED_CONDITIONS) import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import Entity from homeassistant.helpers.temperature import display_temp from homeassistant.const import PRECISION_TENTHS from homeassistant.util import Throttle _LOGGER = logging.getLogger(__name__) CONF_I2C_ADDRESS = 'i2c_address' DEFAULT_NAME = 'SHT31' DEFAULT_I2C_ADDRESS = 0x44 SENSOR_TEMPERATURE = 'temperature' SENSOR_HUMIDITY = 'humidity' SENSOR_TYPES = (SENSOR_TEMPERATURE, SENSOR_HUMIDITY) MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=10) PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Optional(CONF_I2C_ADDRESS, default=DEFAULT_I2C_ADDRESS): vol.All(vol.Coerce(int), vol.Range(min=0x44, max=0x45)), vol.Optional(CONF_MONITORED_CONDITIONS, default=list(SENSOR_TYPES)): vol.All(cv.ensure_list, [vol.In(SENSOR_TYPES)]), vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, }) def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the sensor platform.""" from Adafruit_SHT31 import SHT31 i2c_address = config.get(CONF_I2C_ADDRESS) sensor = SHT31(address=i2c_address) try: if sensor.read_status() is None: raise ValueError("CRC error while reading SHT31 status") except (OSError, ValueError): _LOGGER.error( "SHT31 sensor not detected at address %s", hex(i2c_address)) return sensor_client = SHTClient(sensor) sensor_classes = { SENSOR_TEMPERATURE: SHTSensorTemperature, SENSOR_HUMIDITY: SHTSensorHumidity } devs = [] for sensor_type, sensor_class in sensor_classes.items(): name = "{} {}".format(config.get(CONF_NAME), sensor_type.capitalize()) devs.append(sensor_class(sensor_client, name)) add_entities(devs) class SHTClient: """Get the latest data from the SHT sensor.""" def __init__(self, adafruit_sht): """Initialize the sensor.""" self.adafruit_sht = adafruit_sht self.temperature = None self.humidity = None @Throttle(MIN_TIME_BETWEEN_UPDATES) def update(self): """Get the latest data from the SHT sensor.""" temperature, humidity = self.adafruit_sht.read_temperature_humidity() if math.isnan(temperature) or math.isnan(humidity): _LOGGER.warning("Bad sample from sensor SHT31") return self.temperature = temperature self.humidity = humidity class SHTSensor(Entity): """An abstract SHTSensor, can be either temperature or humidity.""" def __init__(self, sensor, name): """Initialize the sensor.""" self._sensor = sensor self._name = name self._state = None @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 def update(self): """Fetch temperature and humidity from the sensor.""" self._sensor.update() class SHTSensorTemperature(SHTSensor): """Representation of a temperature sensor.""" @property def unit_of_measurement(self): """Return the unit of measurement.""" return self.hass.config.units.temperature_unit def update(self): """Fetch temperature from the sensor.""" super().update() temp_celsius = self._sensor.temperature if temp_celsius is not None: self._state = display_temp(self.hass, temp_celsius, TEMP_CELSIUS, PRECISION_TENTHS) class SHTSensorHumidity(SHTSensor): """Representation of a humidity sensor.""" @property def unit_of_measurement(self): """Return the unit of measurement.""" return '%' def update(self): """Fetch humidity from the sensor.""" super().update() humidity = self._sensor.humidity if humidity is not None: self._state = round(humidity)