]> vault307.fbx.one Git - SensorLib.git/commitdiff
sensors master
authorjimmy <jimipunk88@gmail.com>
Tue, 25 Jun 2024 01:20:05 +0000 (20:20 -0500)
committerjimmy <jimipunk88@gmail.com>
Tue, 25 Jun 2024 01:20:05 +0000 (20:20 -0500)
bh1750.py [new file with mode: 0644]
si7021.py [new file with mode: 0644]
us100.py [new file with mode: 0644]
veml7700.py [new file with mode: 0644]

diff --git a/bh1750.py b/bh1750.py
new file mode 100644 (file)
index 0000000..6564e94
--- /dev/null
+++ b/bh1750.py
@@ -0,0 +1,116 @@
+# 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))
\ No newline at end of file
diff --git a/si7021.py b/si7021.py
new file mode 100644 (file)
index 0000000..a1bf02c
--- /dev/null
+++ b/si7021.py
@@ -0,0 +1,167 @@
+'''This module implements a driver for the Si7021 humidity and temperature
+sensor.
+
+Datasheet:
+https://www.silabs.com/Support%20Documents%2FTechnicalDocs%2FSi7021-A20.pdf
+
+'''
+
+from time import sleep
+
+class CRCError(Exception):
+    'Data failed a CRC check.'
+    pass
+
+
+class Si7021(object):
+    'Driver for the Si7021 temperature sensor.'
+    SI7021_DEFAULT_ADDRESS = 0x40
+    SI7021_MEASTEMP_NOHOLD_CMD = bytearray([0xF3])
+    SI7021_MEASRH_NOHOLD_CMD = bytearray([0xF5])
+    SI7021_RESET_CMD = bytearray([0xFE])
+    SI7021_ID1_CMD = bytearray([0xFA, 0x0F])
+    SI7021_ID2_CMD = bytearray([0xFC, 0xC9])
+    I2C_WAIT_TIME = 0.025
+
+
+    def __init__(self, i2c, address=SI7021_DEFAULT_ADDRESS):
+        'Initialize an Si7021 sensor object.'
+        self.i2c = i2c
+        self.address = address
+        self.serial, self.identifier = self._get_device_info()
+
+
+    @property
+    def temperature(self):
+        'Return the temperature in Celcius.'
+        temperature = self._get_data(self.SI7021_MEASTEMP_NOHOLD_CMD)
+        celcius = temperature * 175.72 / 65536 - 46.85
+        return celcius
+
+
+    @temperature.setter
+    def temperature(self, value):
+        raise AttributeError('can\'t set attribute')
+
+
+    @property
+    def relative_humidity(self):
+        'Return the relative humidity as a percentage. i.e. 35.59927'
+        relative_humidity = self._get_data(self.SI7021_MEASRH_NOHOLD_CMD)
+        relative_humidity = relative_humidity * 125 / 65536 - 6
+        return relative_humidity
+
+
+    @relative_humidity.setter
+    def relative_humidity(self, value):
+        raise AttributeError('can\'t set attribute')
+
+
+    def reset(self):
+        'Reset the sensor.'
+        self.i2c.writeto(self.address, self.SI7021_RESET_CMD)
+        sleep(self.I2C_WAIT_TIME)
+
+
+    def _get_data(self, command):
+        'Retrieve data from the sensor and verify it with a CRC check.'
+        data = bytearray(3)
+        self.i2c.writeto(self.address, command)
+        sleep(self.I2C_WAIT_TIME)
+
+        self.i2c.readfrom_into(self.address, data)
+        value = self._convert_to_integer(data[:2])
+
+        verified = self._verify_checksum(data)
+        if not verified:
+            raise CRCError('Data read off i2c bus failed CRC check.',
+                           data[:2],
+                           data[-1])
+        return value
+
+
+    def _get_device_info(self):
+        '''Get the serial number and the sensor identifier. The identifier is
+        part of the bytes returned for the serial number.
+
+        '''
+        # Serial 1st half
+        self.i2c.writeto(self.address, self.SI7021_ID1_CMD)
+        id1 = bytearray(8)
+        sleep(self.I2C_WAIT_TIME)
+        self.i2c.readfrom_into(self.address, id1)
+
+        # Serial 2nd half
+        self.i2c.writeto(self.address, self.SI7021_ID2_CMD)
+        id2 = bytearray(6)
+        sleep(self.I2C_WAIT_TIME)
+        self.i2c.readfrom_into(self.address, id2)
+
+        combined_id = bytearray([id1[0], id1[2], id1[4], id1[6],
+                                 id2[0], id2[1], id2[3], id2[4]])
+
+        serial = self._convert_to_integer(combined_id)
+        identifier = self._get_device_identifier(id2[0])
+
+        return serial, identifier
+
+    def _convert_to_integer(self, bytes_to_convert):
+        'Use bitwise operators to convert the bytes into integers.'
+        integer = None
+        for chunk in bytes_to_convert:
+            if not integer:
+                integer = chunk
+            else:
+                integer = integer << 8
+                integer = integer | chunk
+        return integer
+
+
+    def _get_device_identifier(self, identifier_byte):
+        '''Convert the identifier byte to a device identifier. Values are based
+        on the information from page 24 of the datasheet.
+
+        '''
+        if identifier_byte == 0x00 or identifier_byte == 0xFF:
+            return 'engineering sample'
+        elif identifier_byte == 0x0D:
+            return 'Si7013'
+        elif identifier_byte == 0x14:
+            return 'Si7020'
+        elif identifier_byte == 0x15:
+            return 'Si7021'
+        else:
+            return 'unknown'
+
+
+    def _verify_checksum(self, data):
+        ''''Verify the checksum using the polynomial from page 19 of the
+        datasheet.
+
+        x8 + x5 + x4 + 1 = 0x131 = 0b100110001
+
+        Valid Example:
+        byte1: 0x67 [01100111]
+        byte2: 0x8c [10001100]
+        byte3: 0xfc [11111100] (CRC byte)
+
+        '''
+        crc = 0
+        values = data[:2]
+        checksum = int(data[-1])
+        for value in values:
+            crc = crc ^ value
+            for _ in range(8, 0, -1):
+                if crc & 0x80: #10000000
+                    crc <<= 1
+                    crc ^= 0x131 #100110001
+                else:
+                    crc <<= 1
+        if crc != checksum:
+            return False
+        else:
+            return True
+
+def convert_celcius_to_fahrenheit(celcius):
+    'Convert a Celcius measurement into a Fahrenheit measurement.'
+    return celcius * 1.8 + 32
\ No newline at end of file
diff --git a/us100.py b/us100.py
new file mode 100644 (file)
index 0000000..56c8018
--- /dev/null
+++ b/us100.py
@@ -0,0 +1,36 @@
+import utime
+
+class US100UART:
+    """Read the US-100 sonar sensor in UART mode."""
+
+    def __init__(self, uart):
+        self.uart = uart
+        uart.init(baudrate=9600, bits=8, parity=None, stop=1)
+        utime.sleep_ms(100)
+        self.buf = bytearray(2)
+        self.t = 0
+
+    def distance(self):
+        """Read the temperature compensated distance im millimeters."""
+        self.buf[0] = 0
+        self.buf[1] = 0
+        self.uart.write(b'\x55')
+        self.t = utime.ticks_ms()
+        while not self.uart.any():
+            if utime.ticks_diff(utime.ticks_ms(), self.t) > 100:
+                raise Exception('Timeout while reading from US100 sensor!')
+            utime.sleep_us(100)
+        self.uart.readinto(self.buf, 2)
+        return (self.buf[0] * 256) + self.buf[1]
+
+    def temperature(self):
+        """Read the temperature in degree celcius."""
+        self.buf[0] = 0
+        self.uart.write(b'\x50')
+        self.t = utime.ticks_ms()
+        while not self.uart.any():
+            if utime.ticks_diff(utime.ticks_ms(), self.t) > 100:
+                raise Exception('Timeout while reading from US100 sensor!')
+            utime.sleep_us(100)
+        self.uart.readinto(self.buf, 1)
+        return self.buf[0] - 45
\ No newline at end of file
diff --git a/veml7700.py b/veml7700.py
new file mode 100644 (file)
index 0000000..7bbc044
--- /dev/null
@@ -0,0 +1,113 @@
+from machine import I2C, Pin
+import time
+from micropython import const
+
+#start const
+# default address
+addr = const(0x10)
+
+# Write registers
+als_conf_0 = const(0x00)
+als_WH = const(0x01)
+als_WL = const(0x02)
+pow_sav = const(0x03)
+
+# Read registers
+als = const(0x04)
+white = const(0x05)
+interrupt = const(0x06)
+
+#gain            0.125                    0.25                    1                        2                         integration time
+confValues = {  25: {1/8: bytearray([0x00, 0x13]), 1/4: bytearray([0x00,0x1B]), 1: bytearray([0x00, 0x01]), 2: bytearray([0x00, 0x0B])}, #25
+                50: {1/8: bytearray([0x00, 0x12]), 1/4: bytearray([0x00,0x1A]), 1: bytearray([0x00, 0x02]), 2: bytearray([0x00, 0x0A])}, #50
+                100:{1/8: bytearray([0x00, 0x10]), 1/4: bytearray([0x00,0x18]), 1: bytearray([0x00, 0x00]), 2: bytearray([0x00, 0x08])}, #100
+                200:{1/8: bytearray([0x40, 0x10]), 1/4: bytearray([0x40,0x18]), 1: bytearray([0x40, 0x00]), 2: bytearray([0x40, 0x08])}, #200
+                400:{1/8: bytearray([0x80, 0x10]), 1/4: bytearray([0x80,0x18]), 1: bytearray([0x80, 0x00]), 2: bytearray([0x80, 0x08])}, #400
+                800:{1/8: bytearray([0xC0, 0x10]), 1/4: bytearray([0xC0,0x18]), 1: bytearray([0xC0, 0x00]), 2: bytearray([0xC0, 0x08])}} #800
+
+#gain               0.125,  0.25,   1,      2       integration time
+gainValues = {  25: {1/8: 1.8432, 1/4: 0.9216, 1: 0.2304, 2: 0.1152}, #25
+                50: {1/8: 0.9216, 1/4: 0.4608, 1: 0.1152, 2: 0.0576}, #50
+                100:{1/8: 0.4608, 1/4: 0.2304, 1: 0.0288, 2: 0.0144}, #100
+                200:{1/8: 0.2304, 1/4: 0.1152, 1: 0.0288, 2: 0.0144}, #200
+                400:{1/8: 0.1152, 1/4: 0.0576, 1: 0.0144, 2: 0.0072}, #400
+                800:{1/8: 0.0876, 1/4: 0.0288, 1: 0.0072, 2: 0.0036}} #800
+
+
+# fin des constante
+
+# Reference data sheet Table 1 for configuration settings
+
+interrupt_high = bytearray([0x00, 0x00]) # Clear values
+# Reference data sheet Table 2 for High Threshold
+
+interrupt_low = bytearray([0x00, 0x00]) # Clear values
+# Reference data sheet Table 3 for Low Threshold
+
+power_save_mode= bytearray([0x00, 0x00]) # clear values
+# Reference data sheet Table 4 for Power Saving Modes
+
+
+class VEML7700:
+
+    def __init__(self,
+                 address=addr,
+                 i2c=None,
+                 it=25,
+                 gain=1/8,
+                 **kwargs):
+       
+        self.address = address
+        if i2c is None:
+            raise ValueError('An I2C object is required.')
+        self.i2c = i2c
+
+        confValuesForIt = confValues.get(it)
+        gainValuesForIt = gainValues.get(it)
+        if confValuesForIt is not None and gainValuesForIt is not None:
+            confValueForGain = confValuesForIt.get(gain)
+            gainValueForGain = gainValuesForIt.get(gain)
+            if confValueForGain is not None and gainValueForGain is not None:
+                self.confValues = confValueForGain
+                self.gain = gainValueForGain
+            else:
+                raise ValueError('Wrong gain value. Use 1/8, 1/4, 1, 2')
+        else:
+            raise ValueError('Wrong integration time value. Use 25, 50, 100, 200, 400, 800')
+
+        self.init()
+
+    def init(self):
+       
+        # load calibration data
+        #self.i2c.writeto_mem(self.address, als_conf_0, bytearray([0x00,0x13]) )
+        self.i2c.writeto_mem(self.address, als_conf_0, self.confValues )
+        self.i2c.writeto_mem(self.address, als_WH, interrupt_high )
+        self.i2c.writeto_mem(self.address, als_WL, interrupt_low)
+        self.i2c.writeto_mem(self.address, pow_sav, power_save_mode)
+        
+    def detect(self):
+        """ Functions is  verified is  module has detecedself.
+        this function not implemented for this time
+        """
+        None
+        
+    def read_lux(self):
+        """ Reads the data from the sensor and returns the data.
+            
+            Returns:
+               the number of lux detect by this captor.
+        """
+               #The frequency to read the sensor should be set greater than
+        # the integration time (and the power saving delay if set).
+        # Reading at a faster frequency will not cause an error, but
+        # will result in reading the previous data
+
+        self.lux = bytearray(2)
+        
+        time.sleep(.04)  # 40ms
+
+        self.i2c.readfrom_mem_into(self.address, als, self.lux)
+        self.lux= self.lux[0]+self.lux[1]*256
+        self.lux=self.lux*self.gain
+        return(int(round(self.lux,0)))
\ No newline at end of file