From e5d11dd1a5db23f5ab865cbac94c8ca6eb9cba51 Mon Sep 17 00:00:00 2001 From: Eugenio Panadero <eugenio.panadero@gmail.com> Date: Thu, 22 Jun 2017 07:09:08 +0200 Subject: [PATCH] Add new BH1750 light level sensor (#8050) * new sensor platform * requirements_all and .coveragerc update --- .coveragerc | 1 + homeassistant/components/sensor/bh1750.py | 145 ++++++++++++++++++++++ requirements_all.txt | 2 + 3 files changed, 148 insertions(+) create mode 100644 homeassistant/components/sensor/bh1750.py diff --git a/.coveragerc b/.coveragerc index eedb92e9ad9..c57a58ea733 100644 --- a/.coveragerc +++ b/.coveragerc @@ -378,6 +378,7 @@ omit = homeassistant/components/sensor/arest.py homeassistant/components/sensor/arwn.py homeassistant/components/sensor/bbox.py + homeassistant/components/sensor/bh1750.py homeassistant/components/sensor/bitcoin.py homeassistant/components/sensor/blockchain.py homeassistant/components/sensor/bme280.py diff --git a/homeassistant/components/sensor/bh1750.py b/homeassistant/components/sensor/bh1750.py new file mode 100644 index 00000000000..fd6060bfdd9 --- /dev/null +++ b/homeassistant/components/sensor/bh1750.py @@ -0,0 +1,145 @@ +""" +Support for BH1750 light sensor. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/sensor.bh1750/ +""" +import asyncio +from functools import partial +import logging + +import voluptuous as vol + +from homeassistant.components.sensor import PLATFORM_SCHEMA +import homeassistant.helpers.config_validation as cv +from homeassistant.const import CONF_NAME +from homeassistant.helpers.entity import Entity + +REQUIREMENTS = ['i2csense==0.0.3', + 'smbus-cffi==0.5.1'] + +_LOGGER = logging.getLogger(__name__) + +CONF_I2C_ADDRESS = 'i2c_address' +CONF_I2C_BUS = 'i2c_bus' +CONF_OPERATION_MODE = 'operation_mode' +CONF_SENSITIVITY = 'sensitivity' +CONF_DELAY = 'measurement_delay_ms' +CONF_MULTIPLIER = 'multiplier' + +# Operation modes for BH1750 sensor (from the datasheet). Time typically 120ms +# In one time measurements, device is set to Power Down after each sample. +CONTINUOUS_LOW_RES_MODE = "continuous_low_res_mode" +CONTINUOUS_HIGH_RES_MODE_1 = "continuous_high_res_mode_1" +CONTINUOUS_HIGH_RES_MODE_2 = "continuous_high_res_mode_2" +ONE_TIME_LOW_RES_MODE = "one_time_low_res_mode" +ONE_TIME_HIGH_RES_MODE_1 = "one_time_high_res_mode_1" +ONE_TIME_HIGH_RES_MODE_2 = "one_time_high_res_mode_2" +OPERATION_MODES = { + CONTINUOUS_LOW_RES_MODE: (0x13, True), # 4lx resolution + CONTINUOUS_HIGH_RES_MODE_1: (0x10, True), # 1lx resolution. + CONTINUOUS_HIGH_RES_MODE_2: (0X11, True), # 0.5lx resolution. + ONE_TIME_LOW_RES_MODE: (0x23, False), # 4lx resolution. + ONE_TIME_HIGH_RES_MODE_1: (0x20, False), # 1lx resolution. + ONE_TIME_HIGH_RES_MODE_2: (0x21, False), # 0.5lx resolution. +} + +SENSOR_UNIT = 'lx' +DEFAULT_NAME = 'BH1750 Light Sensor' +DEFAULT_I2C_ADDRESS = '0x23' +DEFAULT_I2C_BUS = 1 +DEFAULT_MODE = CONTINUOUS_HIGH_RES_MODE_1 +DEFAULT_DELAY_MS = 120 +DEFAULT_SENSITIVITY = 69 # from 31 to 254 + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, + vol.Optional(CONF_I2C_ADDRESS, default=DEFAULT_I2C_ADDRESS): cv.string, + vol.Optional(CONF_I2C_BUS, default=DEFAULT_I2C_BUS): vol.Coerce(int), + vol.Optional(CONF_OPERATION_MODE, default=DEFAULT_MODE): + vol.In(OPERATION_MODES), + vol.Optional(CONF_SENSITIVITY, default=DEFAULT_SENSITIVITY): + cv.positive_int, + vol.Optional(CONF_DELAY, default=DEFAULT_DELAY_MS): cv.positive_int, + vol.Optional(CONF_MULTIPLIER, default=1.): vol.Range(min=0.1, max=10), +}) + + +# pylint: disable=import-error +@asyncio.coroutine +def async_setup_platform(hass, config, async_add_devices, discovery_info=None): + """Set up the BH1750 sensor.""" + import smbus + from i2csense.bh1750 import BH1750 + + name = config.get(CONF_NAME) + bus_number = config.get(CONF_I2C_BUS) + i2c_address = config.get(CONF_I2C_ADDRESS) + operation_mode = config.get(CONF_OPERATION_MODE) + + bus = smbus.SMBus(bus_number) + + sensor = yield from hass.async_add_job( + partial(BH1750, bus, i2c_address, + operation_mode=operation_mode, + measurement_delay=config.get(CONF_DELAY), + sensitivity=config.get(CONF_SENSITIVITY), + logger=_LOGGER) + ) + if not sensor.sample_ok: + _LOGGER.error("BH1750 sensor not detected at %s", i2c_address) + return False + + dev = [BH1750Sensor(sensor, name, SENSOR_UNIT, + config.get(CONF_MULTIPLIER))] + _LOGGER.info("Setup of BH1750 light sensor at %s in mode %s is complete.", + i2c_address, operation_mode) + + async_add_devices(dev) + + +class BH1750Sensor(Entity): + """Implementation of the BH1750 sensor.""" + + def __init__(self, bh1750_sensor, name, unit, multiplier=1.): + """Initialize the sensor.""" + self._name = name + self._unit_of_measurement = unit + self._multiplier = multiplier + self.bh1750_sensor = bh1750_sensor + if self.bh1750_sensor.light_level >= 0: + self._state = int(round(self.bh1750_sensor.light_level)) + else: + self._state = None + + @property + def name(self) -> str: + """Return the name of the sensor.""" + return self._name + + @property + def state(self) -> int: + """Return the state of the sensor.""" + return self._state + + @property + def unit_of_measurement(self) -> str: + """Return the unit of measurement of the sensor.""" + return self._unit_of_measurement + + @property + def device_class(self) -> str: + """Return the class of this device, from component DEVICE_CLASSES.""" + return 'light' + + @asyncio.coroutine + def async_update(self): + """Get the latest data from the BH1750 and update the states.""" + yield from self.hass.async_add_job(self.bh1750_sensor.update) + if self.bh1750_sensor.sample_ok \ + and self.bh1750_sensor.light_level >= 0: + self._state = int(round(self.bh1750_sensor.light_level + * self._multiplier)) + else: + _LOGGER.warning("Bad Update of sensor.%s: %s", + self.name, self.bh1750_sensor.light_level) diff --git a/requirements_all.txt b/requirements_all.txt index 8fde514cd24..b5e13275602 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -315,6 +315,7 @@ https://github.com/wmalgadey/PyTado/archive/0.1.10.zip#PyTado==0.1.10 # homeassistant.components.media_player.lg_netcast https://github.com/wokar/pylgnetcast/archive/v0.2.0.zip#pylgnetcast==0.2.0 +# homeassistant.components.sensor.bh1750 # homeassistant.components.sensor.bme280 # homeassistant.components.sensor.htu21d # i2csense==0.0.3 @@ -822,6 +823,7 @@ sleekxmpp==1.3.2 # homeassistant.components.sleepiq sleepyq==0.6 +# homeassistant.components.sensor.bh1750 # homeassistant.components.sensor.bme280 # homeassistant.components.sensor.envirophat # homeassistant.components.sensor.htu21d -- GitLab