119 lines
4.3 KiB
Python
119 lines
4.3 KiB
Python
# https://github.com/flrrth/pico-bh1750
|
|
|
|
import math
|
|
|
|
from micropython import const
|
|
from utime import sleep_ms
|
|
|
|
|
|
class BH1750:
|
|
"""Class for the BH1750 digital Ambient Light Sensor
|
|
|
|
The datasheet can be found at https://components101.com/sites/default/files/component_datasheet/BH1750.pdf
|
|
"""
|
|
|
|
MEASUREMENT_MODE_CONTINUOUSLY = const(1)
|
|
MEASUREMENT_MODE_ONE_TIME = const(2)
|
|
|
|
RESOLUTION_HIGH = const(0)
|
|
RESOLUTION_HIGH_2 = const(1)
|
|
RESOLUTION_LOW = const(2)
|
|
|
|
MEASUREMENT_TIME_DEFAULT = const(69)
|
|
MEASUREMENT_TIME_MIN = const(31)
|
|
MEASUREMENT_TIME_MAX = const(254)
|
|
|
|
def __init__(self, address, i2c):
|
|
self._address = address
|
|
self._i2c = i2c
|
|
self._measurement_mode = BH1750.MEASUREMENT_MODE_ONE_TIME
|
|
self._resolution = BH1750.RESOLUTION_HIGH
|
|
self._measurement_time = BH1750.MEASUREMENT_TIME_DEFAULT
|
|
|
|
self._write_measurement_time()
|
|
self._write_measurement_mode()
|
|
|
|
def configure(self, measurement_mode: int, resolution: int, measurement_time: int):
|
|
"""Configures the BH1750.
|
|
|
|
Keyword arguments:
|
|
measurement_mode -- measure either continuously or once
|
|
resolution -- return measurements in either high, high2 or low resolution
|
|
measurement_time -- the duration of a single measurement
|
|
"""
|
|
if measurement_time not in range(BH1750.MEASUREMENT_TIME_MIN, BH1750.MEASUREMENT_TIME_MAX + 1):
|
|
raise ValueError("measurement_time must be between {0} and {1}"
|
|
.format(BH1750.MEASUREMENT_TIME_MIN, BH1750.MEASUREMENT_TIME_MAX))
|
|
|
|
self._measurement_mode = measurement_mode
|
|
self._resolution = resolution
|
|
self._measurement_time = measurement_time
|
|
|
|
self._write_measurement_time()
|
|
self._write_measurement_mode()
|
|
|
|
def _write_measurement_time(self):
|
|
buffer = bytearray(1)
|
|
|
|
high_bit = 1 << 6 | self._measurement_time >> 5
|
|
low_bit = 3 << 5 | (self._measurement_time << 3) >> 3
|
|
|
|
buffer[0] = high_bit
|
|
self._i2c.writeto(self._address, buffer)
|
|
|
|
buffer[0] = low_bit
|
|
self._i2c.writeto(self._address, buffer)
|
|
|
|
def _write_measurement_mode(self):
|
|
buffer = bytearray(1)
|
|
|
|
buffer[0] = self._measurement_mode << 4 | self._resolution
|
|
self._i2c.writeto(self._address, buffer)
|
|
sleep_ms(24 if self._measurement_time == BH1750.RESOLUTION_LOW else 180)
|
|
|
|
def reset(self):
|
|
"""Clear the illuminance data register."""
|
|
self._i2c.writeto(self._address, bytearray(b'\x07'))
|
|
|
|
def power_on(self):
|
|
"""Powers on the BH1750."""
|
|
self._i2c.writeto(self._address, bytearray(b'\x01'))
|
|
|
|
def power_off(self):
|
|
"""Powers off the BH1750."""
|
|
self._i2c.writeto(self._address, bytearray(b'\x00'))
|
|
|
|
@property
|
|
def measurement(self) -> float:
|
|
"""Returns the latest measurement."""
|
|
if self._measurement_mode == BH1750.MEASUREMENT_MODE_ONE_TIME:
|
|
self._write_measurement_mode()
|
|
|
|
buffer = bytearray(2)
|
|
self._i2c.readfrom_into(self._address, buffer)
|
|
lux = (buffer[0] << 8 | buffer[1]) / (1.2 * (BH1750.MEASUREMENT_TIME_DEFAULT / self._measurement_time))
|
|
|
|
if self._resolution == BH1750.RESOLUTION_HIGH_2:
|
|
return lux / 2
|
|
else:
|
|
return lux
|
|
|
|
def measurements(self) -> float:
|
|
"""This is a generator function that continues to provide the latest measurement. Because the measurement time
|
|
is greatly affected by resolution and the configured measurement time, this function attemts to calculate the
|
|
appropriate sleep time between measurements.
|
|
|
|
Example usage:
|
|
|
|
for measurement in bh1750.measurements(): # bh1750 is an instance of this class
|
|
print(measurement)
|
|
"""
|
|
while True:
|
|
yield self.measurement
|
|
|
|
if self._measurement_mode == BH1750.MEASUREMENT_MODE_CONTINUOUSLY:
|
|
base_measurement_time = 16 if self._measurement_time == BH1750.RESOLUTION_LOW else 120
|
|
sleep_ms(math.ceil(base_measurement_time * self._measurement_time / BH1750.MEASUREMENT_TIME_DEFAULT))
|
|
|
|
|