diff --git a/7_distance_and_light_sensor.py b/7_distance_and_light_sensor.py new file mode 100644 index 0000000..867e39b --- /dev/null +++ b/7_distance_and_light_sensor.py @@ -0,0 +1,26 @@ +# +# Copyright (C) Orange +# +# This software is distributed under the terms and conditions of the 'MIT' +# license which can be found in the file 'LICENSE.md' in this package distribution +import sys +import time +import LiveObjects + +# Create LiveObjects +lo = LiveObjects.Connection() +sensor = LiveObjects.SensorVL6180X() + +MESSAGE_RATE = 5 + +# Main program +lo.connect() # Connect to LiveObjects +last = uptime = time.time() + +while True: + if (time.time()) >= last + MESSAGE_RATE: + lo.add_to_payload("distance", sensor.range) + lo.add_to_payload("ambient_light", sensor.amb_light()) + lo.send_data() # Sending data to cloud + last = time.time() + lo.loop() # Check for incoming messages and if connection is still active diff --git a/LiveObjects/Connection.py b/LiveObjects/Connection.py index 0efa679..8501c71 100644 --- a/LiveObjects/Connection.py +++ b/LiveObjects/Connection.py @@ -212,6 +212,7 @@ def get_parameter(self, name): return 0 def add_to_payload(self, name, val): + self.add_model("Orange") self.__payload[self.__value][name] = val def set_object_as_payload(self, val): diff --git a/LiveObjects/hal.py b/LiveObjects/hal.py index c59e7d6..7277dd5 100644 --- a/LiveObjects/hal.py +++ b/LiveObjects/hal.py @@ -210,10 +210,70 @@ def get_client_id(self): return self.get_lang_str() + ':' + get_mac() -class BoardsFactory: +class RaspberryPi(Linux): + pass + + +def is_raspberrypi(): + try: + with open('/proc/device-tree/model') as f: + return f.read().startswith('Raspberry') + except FileNotFoundError: + return False + +class BoardsFactory: def __new__(cls, net_type): s = sys.platform sn = s[0].upper() + s[1:] # capitalize first letter + if sn == 'Linux': + sn = 'RaspberryPi' if is_raspberrypi() else 'Linux' board = eval(sn)(net_type) # instance of board w/ net type: WiFi, LTE, etc. return board + + +MAX_DEV_NB = 20 + + +def get_i2c(): + import machine + typical_gpio = ([22, 23], [5, 4], [22, 21], [23, 18]) + for gpio in typical_gpio: + scl, sda = gpio + i2c = None + try: # MicroPython 1.19.1 20220618-v1.19.1 + i2c = machine.SoftI2C(scl=machine.Pin(scl), sda=machine.Pin(sda), freq=100000) + if i2c.scan() and len(i2c.scan()) < MAX_DEV_NB: + return i2c + except ValueError: # next sda, scl + pass + except AttributeError: # Pycom MicroPython 1.20.2.r6 [v1.11-c5a0a97] on 2021-10-28 + i2c = machine.I2C(0) + return i2c + del i2c + raise RuntimeError("No I2C devices found. Check SDA and SCL lines and add respective GPIO to 'typical_gpio'.") + + +class SensorVL6180X: + def __new__(cls): + try: # Python@RPi + import busio + import adafruit_vl6180x + import board + + class VL6180X(adafruit_vl6180x.VL6180X): + def amb_light(self): + """Implementing default gain""" + return self.read_lux(gain=0x06) # ALS_GAIN_1 + + i2c = busio.I2C(board.SCL, board.SDA) + return VL6180X(i2c) + + except ImportError: # microPython + import vl6180x_micro + i2c = get_i2c() + return vl6180x_micro.Sensor(i2c) + + except NotImplementedError: # if no I2C device + print("No GPIO present.") + sys.exit() diff --git a/README.md b/README.md index a5d9785..ea06cf0 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Prototype with Orange using Live Objects -### Discover Orange [**Live Objects**](https://liveobjects.orange-business.com) using dedicated SDK for **Python and uPython compatible** boards and systems. +### Discover Orange [**Live Objects**](https://liveobjects.orange-business.com) using dedicated SDK for **Python 3 and uPython compatible** boards and systems. This code wraps all the functions necessary to make your object work with Live Objects. @@ -23,7 +23,7 @@ Code uses MQTT connection to exchange data with Live objects under the hood to k This code needs a few libraries to run: - Python needs [paho-mqtt](https://pypi.org/project/paho-mqtt/) - Python for Windows needs [python-certifi-win32](https://pypi.org/project/python-certifi-win32/) -- uPython needs [umqttsimple, umqttrobust and ssl](https://github.com/micropython/micropython-lib) +- uPython needs [umqttsimple](https://github.com/micropython/micropython-lib/blob/master/micropython/umqtt.simple/umqtt/simple.py) and [umqttrobust](https://github.com/micropython/micropython-lib/blob/master/micropython/umqtt.robust/umqtt/robust.py) ## How to use ## @@ -236,12 +236,55 @@ You need to override specific methods - e.g. `connect` which is depended on type All specific functions are placed in `services.py`. If your board needs function supporting its equipment you need to put it in this file. +## VL6180X Sensor use-case ## + +We can connect sensor using I2C to board supporting Python like **Raspberry Pi**. + +The [VL6180X](https://www.st.com/en/imaging-and-photonics-solutions/vl6180x.html) is the latest product based on ST’s patented FlightSense™technology. +This is a ground-breaking technology allowing absolute distance to be measured independent of target reflectance. +Instead of estimating the distance by measuring the amount of light reflected back from the object (which is significantly influenced by color and surface), +the VL6180X precisely measures the time the light takes to travel to the nearest object and reflect back to the sensor (Time-of-Flight). +Description from st.com. + +### Prerequisites ### + +#### Enabling I2C #### +Enable (if needed) **I2C** interface on your Raspberry Pi using terminal and command: +```bash +sudo raspi-config +``` +and selecting: **3 Interface Options** -> **P5 I2C** -> **\** + +![I2C_Enabling](image/enable_I2C.png) + +#### Wiring #### +![Wiring](https://www.raspberrypi-spy.co.uk/wp-content/uploads/2012/06/Raspberry-Pi-GPIO-Header-with-Photo-768x512.png "Mapping") + +
+ +Example of development module using VL6180X you can find [here](https://kamami.pl/en/kamod-kamami-peripheral-modules/559362-kamodvl6180x-a-module-with-distance-gesture-and-als-sensor.html). Below diagram shows how to connect it to Raspberry Pi. + +![Schematics](image/RPi_VL6180X.png "Schematics") + +#### Adding VL6180X Python module #### +Necessary module by [Adafruit](https://learn.adafruit.com/adafruit-vl6180x-time-of-flight-micro-lidar-distance-sensor-breakout/python-circuitpython) can be installed using `pip` +```bash +pip3 install adafruit-circuitpython-vl6180x +``` + +#### How to use #### +To run you need to use below command: +```bash +python3 7_distance_and_light_sensor.py +``` + +--- # Installation guide for uPython # ## Example for ESP32 / ESP8266 ## ### Requirements ### 1. [ampy](https://learn.adafruit.com/micropython-basics-load-files-and-run-code/install-ampy) -2. [umqttsimple, umqttrobust and ssl](https://github.com/micropython/micropython-lib) +2. [umqttsimple, umqttrobust and ssl](https://github.com/micropython/micropython-lib) (for your convenience they are included in `micropython` folder) 3. [PuTTY](https://www.putty.org/) (for Windows) ### Installation steps ### @@ -264,6 +307,7 @@ You can use one of example ones (`1_send_data.py`, ...) renaming it to `main.py` > ampy -pCOMXX put main.py ``` + 4. Connect to device and check if it's working using PuTTY Ctrl + D soft resets device @@ -274,25 +318,75 @@ You can use one of example ones (`1_send_data.py`, ...) renaming it to `main.py` After all steps content of the device should look like below: ```commandline -> ampy -pCOMXX ls +> ampy --port COMx ls /LiveObjects /boot.py /main.py /umqttrobust.py /simple.py -> ampy -pCOMXX ls LiveObjects +> ampy --port COMx ls LiveObjects /LiveObjects/Connection.py /LiveObjects/__init__.py /LiveObjects/hal.py /LiveObjects/credentials.py /LiveObjects/services.py ``` +where COMx means port on your computer (e.g. COM8) with connected microPython board. ## Example for LoPy / GPy ## You can do the steps as above but better is to use [Pymakr plug-in](https://pycom.io/products/supported-networks/pymakr/) for **Visual Studio Code** or **Atom** delivered by [Pycom](https://pycom.io/). Plug-in supports code development, its upload to the board and communication with board. +## VL6180X Sensor use-case ## + +Sensor described in this [section](#vl6180x-sensor-use-case) can be used on boards supporting microPython. + +### Prerequisites ### + +#### Wiring #### +You need to connect I2C interface (SCL & SDA) and power lines on the board with corresponding pins on the sensor. +You need to be aware that **boards can use different GPIOs for I2C** purposes. Set of typical pairs is placed +in function `get_i2c()` in file `hal.py`. If your board uses other GPIO pins, you need to add them to the tuple `typical_gpio`. +```Python +def get_i2c(): + import machine + typical_gpio = ([22, 23], [5, 4], [22, 21]) +... +``` +![ESP32_sch](image/ESP32_VL6180X_sch.png) + +Example of wiring ESP32 board with GPIO22 and GPIO21 (_source: https://randomnerdtutorials.com/esp32-pinout-reference-gpios/_) + +![ESP32](image/ESP32_VL6180X.jpg) + +#### How to use #### +1. You need to upload additional library for VL6180X support (it is placed in `micropython` folder): +```commandline +> ampy -pCOMXX put vl6180x_micro.py +``` +2. Copy `7_distance_and_light_sensor.py` as `main.py` and upload it into board. + +After above operations you can see: +```commandline +> ampy --port COMx ls +/LiveObjects +/boot.py +/main.py +/umqttrobust.py +/simple.py +/vl6180x_micro.py + +> ampy --port COMx ls LiveObjects +/LiveObjects/Connection.py +/LiveObjects/__init__.py +/LiveObjects/hal.py +/LiveObjects/credentials.py +/LiveObjects/services.py +``` +3. Connect to device and check if it's working using PuTTY. + + ## Troubleshooting ## If you are getting 'MQTT exception: 5' check your api key \ No newline at end of file diff --git a/image/ESP32_VL6180X.jpg b/image/ESP32_VL6180X.jpg new file mode 100644 index 0000000..56d0507 Binary files /dev/null and b/image/ESP32_VL6180X.jpg differ diff --git a/image/ESP32_VL6180X_sch.png b/image/ESP32_VL6180X_sch.png new file mode 100644 index 0000000..f0a4f31 Binary files /dev/null and b/image/ESP32_VL6180X_sch.png differ diff --git a/image/RPi_VL6180X.png b/image/RPi_VL6180X.png new file mode 100644 index 0000000..aa3025c Binary files /dev/null and b/image/RPi_VL6180X.png differ diff --git a/image/enable_I2C.png b/image/enable_I2C.png new file mode 100644 index 0000000..11c6bf3 Binary files /dev/null and b/image/enable_I2C.png differ diff --git a/micropython/simple.py b/micropython/simple.py new file mode 100644 index 0000000..8216fa5 --- /dev/null +++ b/micropython/simple.py @@ -0,0 +1,204 @@ +import usocket as socket +import ustruct as struct +from ubinascii import hexlify + +class MQTTException(Exception): + pass + +class MQTTClient: + + def __init__(self, client_id, server, port=0, user=None, password=None, keepalive=0, + ssl=False, ssl_params={}): + if port == 0: + port = 8883 if ssl else 1883 + self.client_id = client_id + self.sock = None + self.server = server + self.port = port + self.ssl = ssl + self.ssl_params = ssl_params + self.pid = 0 + self.cb = None + self.user = user + self.pswd = password + self.keepalive = keepalive + self.lw_topic = None + self.lw_msg = None + self.lw_qos = 0 + self.lw_retain = False + + def _send_str(self, s): + self.sock.write(struct.pack("!H", len(s))) + self.sock.write(s) + + def _recv_len(self): + n = 0 + sh = 0 + while 1: + b = self.sock.read(1)[0] + n |= (b & 0x7f) << sh + if not b & 0x80: + return n + sh += 7 + + def set_callback(self, f): + self.cb = f + + def set_last_will(self, topic, msg, retain=False, qos=0): + assert 0 <= qos <= 2 + assert topic + self.lw_topic = topic + self.lw_msg = msg + self.lw_qos = qos + self.lw_retain = retain + + def connect(self, clean_session=True): + self.sock = socket.socket() + addr = socket.getaddrinfo(self.server, self.port)[0][-1] + self.sock.connect(addr) + if self.ssl: + import ussl + self.sock = ussl.wrap_socket(self.sock, **self.ssl_params) + premsg = bytearray(b"\x10\0\0\0\0\0") + msg = bytearray(b"\x04MQTT\x04\x02\0\0") + + sz = 10 + 2 + len(self.client_id) + msg[6] = clean_session << 1 + if self.user is not None: + sz += 2 + len(self.user) + 2 + len(self.pswd) + msg[6] |= 0xC0 + if self.keepalive: + assert self.keepalive < 65536 + msg[7] |= self.keepalive >> 8 + msg[8] |= self.keepalive & 0x00FF + if self.lw_topic: + sz += 2 + len(self.lw_topic) + 2 + len(self.lw_msg) + msg[6] |= 0x4 | (self.lw_qos & 0x1) << 3 | (self.lw_qos & 0x2) << 3 + msg[6] |= self.lw_retain << 5 + + i = 1 + while sz > 0x7f: + premsg[i] = (sz & 0x7f) | 0x80 + sz >>= 7 + i += 1 + premsg[i] = sz + + self.sock.write(premsg, i + 2) + self.sock.write(msg) + #print(hex(len(msg)), hexlify(msg, ":")) + self._send_str(self.client_id) + if self.lw_topic: + self._send_str(self.lw_topic) + self._send_str(self.lw_msg) + if self.user is not None: + self._send_str(self.user) + self._send_str(self.pswd) + resp = self.sock.read(4) + assert resp[0] == 0x20 and resp[1] == 0x02 + if resp[3] != 0: + raise MQTTException(resp[3]) + return resp[2] & 1 + + def disconnect(self): + self.sock.write(b"\xe0\0") + self.sock.close() + + def ping(self): + self.sock.write(b"\xc0\0") + + def publish(self, topic, msg, retain=False, qos=0): + pkt = bytearray(b"\x30\0\0\0") + pkt[0] |= qos << 1 | retain + sz = 2 + len(topic) + len(msg) + if qos > 0: + sz += 2 + assert sz < 2097152 + i = 1 + while sz > 0x7f: + pkt[i] = (sz & 0x7f) | 0x80 + sz >>= 7 + i += 1 + pkt[i] = sz + #print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt, i + 1) + self._send_str(topic) + if qos > 0: + self.pid += 1 + pid = self.pid + struct.pack_into("!H", pkt, 0, pid) + self.sock.write(pkt, 2) + self.sock.write(msg) + if qos == 1: + while 1: + op = self.wait_msg() + if op == 0x40: + sz = self.sock.read(1) + assert sz == b"\x02" + rcv_pid = self.sock.read(2) + rcv_pid = rcv_pid[0] << 8 | rcv_pid[1] + if pid == rcv_pid: + return + elif qos == 2: + assert 0 + + def subscribe(self, topic, qos=0): + assert self.cb is not None, "Subscribe callback is not set" + pkt = bytearray(b"\x82\0\0\0") + self.pid += 1 + struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid) + #print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt) + self._send_str(topic) + self.sock.write(qos.to_bytes(1, "little")) + while 1: + op = self.wait_msg() + if op == 0x90: + resp = self.sock.read(4) + #print(resp) + assert resp[1] == pkt[2] and resp[2] == pkt[3] + if resp[3] == 0x80: + raise MQTTException(resp[3]) + return + + # Wait for a single incoming MQTT message and process it. + # Subscribed messages are delivered to a callback previously + # set by .set_callback() method. Other (internal) MQTT + # messages processed internally. + def wait_msg(self): + res = self.sock.read(1) + self.sock.setblocking(True) + if res is None: + return None + if res == b"": + raise OSError(-1) + if res == b"\xd0": # PINGRESP + sz = self.sock.read(1)[0] + assert sz == 0 + return None + op = res[0] + if op & 0xf0 != 0x30: + return op + sz = self._recv_len() + topic_len = self.sock.read(2) + topic_len = (topic_len[0] << 8) | topic_len[1] + topic = self.sock.read(topic_len) + sz -= topic_len + 2 + if op & 6: + pid = self.sock.read(2) + pid = pid[0] << 8 | pid[1] + sz -= 2 + msg = self.sock.read(sz) + self.cb(topic, msg) + if op & 6 == 2: + pkt = bytearray(b"\x40\x02\0\0") + struct.pack_into("!H", pkt, 2, pid) + self.sock.write(pkt) + elif op & 6 == 4: + assert 0 + + # Checks whether a pending message from server is available. + # If not, returns immediately with None. Otherwise, does + # the same processing as wait_msg. + def check_msg(self): + self.sock.setblocking(False) + return self.wait_msg() diff --git a/micropython/umqttrobust.py b/micropython/umqttrobust.py new file mode 100755 index 0000000..a1e91fe --- /dev/null +++ b/micropython/umqttrobust.py @@ -0,0 +1,43 @@ +import utime +import simple + +class MQTTClient(simple.MQTTClient): + + DELAY = 2 + DEBUG = False + + def delay(self, i): + utime.sleep(self.DELAY) + + def log(self, in_reconnect, e): + if self.DEBUG: + if in_reconnect: + print("mqtt reconnect: %r" % e) + else: + print("mqtt: %r" % e) + + def reconnect(self): + i = 0 + while 1: + try: + return super().connect(False) + except OSError as e: + self.log(True, e) + i += 1 + self.delay(i) + + def publish(self, topic, msg, retain=False, qos=0): + while 1: + try: + return super().publish(topic, msg, retain, qos) + except OSError as e: + self.log(False, e) + self.reconnect() + + def wait_msg(self): + while 1: + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() diff --git a/micropython/vl6180x_micro.py b/micropython/vl6180x_micro.py new file mode 100644 index 0000000..1b5e33e --- /dev/null +++ b/micropython/vl6180x_micro.py @@ -0,0 +1,174 @@ +# +# Copyright (C) Orange +# +# This software is distributed under the terms and conditions of the 'MIT' +# license which can be found in the file 'LICENSE.md' in this package distribution +# +# This file incorporates work covered by the following copyright and +# permission notice: +# +# Copyright (c) 2018, Ledbelly2142 +# https://github.com/Ledbelly2142/VL6180X/blob/master/LICENSE +# +# Copyright (c) 2022, Adafruit +# https://github.com/adafruit/Adafruit_CircuitPython_VL6180X/blob/main/LICENSE + +import ustruct +import struct +import time +from machine import I2C + + +class Sensor: + """ + Micropython library for VL6180X sensor measuring distance and ambient light + """ + def __init__(self, i2c, address=0x29): + self.i2c = i2c + self._address = address + self.default_settings() + self.init() + + def _i2c_write(self, register, regValue): + return self.i2c.writeto_mem(self._address, register, bytearray([regValue]), addrsize=16), 'big' + + def _i2c_read(self, register, nb_bytes=1): + value = int.from_bytes( + self.i2c.readfrom_mem(self._address, register, nb_bytes, addrsize=16), + 'big' + ) + return value & 0xFFFF + + def init(self): + if self._i2c_read(0x0016) != 1: + raise RuntimeError("Failure reset") + + # Recommended setup from the datasheet + self._i2c_write(0x0207, 0x01) + self._i2c_write(0x0208, 0x01) + self._i2c_write(0x0096, 0x00) + self._i2c_write(0x0097, 0xfd) + self._i2c_write(0x00e3, 0x00) + self._i2c_write(0x00e4, 0x04) + self._i2c_write(0x00e5, 0x02) + self._i2c_write(0x00e6, 0x01) + self._i2c_write(0x00e7, 0x03) + self._i2c_write(0x00f5, 0x02) + self._i2c_write(0x00d9, 0x05) + self._i2c_write(0x00db, 0xce) + self._i2c_write(0x00dc, 0x03) + self._i2c_write(0x00dd, 0xf8) + self._i2c_write(0x009f, 0x00) + self._i2c_write(0x00a3, 0x3c) + self._i2c_write(0x00b7, 0x00) + self._i2c_write(0x00bb, 0x3c) + self._i2c_write(0x00b2, 0x09) + self._i2c_write(0x00ca, 0x09) + self._i2c_write(0x0198, 0x01) + self._i2c_write(0x01b0, 0x17) + self._i2c_write(0x01ad, 0x00) + self._i2c_write(0x00ff, 0x05) + self._i2c_write(0x0100, 0x05) + self._i2c_write(0x0199, 0x05) + self._i2c_write(0x01a6, 0x1b) + self._i2c_write(0x01ac, 0x3e) + self._i2c_write(0x01a7, 0x1f) + self._i2c_write(0x0030, 0x00) + + def default_settings(self): + # Enables polling for ‘New Sample ready’ when measurement completes + self._i2c_write(0x0011, 0x10) + self._i2c_write(0x010A, 0x30) # Set Avg sample period + self._i2c_write(0x003f, 0x46) # Set the ALS gain + self._i2c_write(0x0031, 0xFF) # Set auto calibration period + # (Max = 255)/(OFF = 0) + self._i2c_write(0x0040, 0x63) # Set ALS integration time to 100ms + # perform a single temperature calibration + self._i2c_write(0x002E, 0x01) + + # Optional settings from datasheet + self._i2c_write(0x001B, 0x09) # Set default ranging inter-measurement + # period to 100ms + self._i2c_write(0x003E, 0x0A) # Set default ALS inter-measurement + # period to 100ms + self._i2c_write(0x0014, 0x24) # Configures interrupt on ‘New Sample + # Ready threshold event’ + + # Additional settings defaults from community + self._i2c_write(0x001C, 0x32) # Max convergence time + self._i2c_write(0x002D, 0x10 | 0x01) # Range check enables + self._i2c_write(0x0022, 0x7B) # Early convergence estimate + self._i2c_write(0x0120, 0x01) # Firmware result scaler + + def _read_range_single(self): + """Measure the distance in millimeters. Takes 0.01s.""" + self._i2c_write(0x0018, 0x01) # Sysrange start + time.sleep(0.01) + return self._i2c_read(0x0062) # Result range value import ustruct + + @property + def range(self): + return self._read_range_single() + + def amb_light(self, gain=0x06): + """Read the lux (light value) from the sensor and return it. Must + specify the gain value to use for the lux reading: + + ================= ===== + Setting Value + ================= ===== + ``ALS_GAIN_1`` 1x + ``ALS_GAIN_1_25`` 1.25x + ``ALS_GAIN_1_67`` 1.67x + ``ALS_GAIN_2_5`` 2.5x + ``ALS_GAIN_5`` 5x + ``ALS_GAIN_10`` 10x + ``ALS_GAIN_20`` 20x + ``ALS_GAIN_40`` 40x + ================= ===== + + :param int gain: The gain value to use + """ + + reg = self._i2c_read(0x0014) + reg &= ~0x38 + reg |= 0x4 << 3 # IRQ on ALS ready + self._i2c_write(0x0014, reg) + # 100 ms integration period + self._i2c_write(0x0040, 0) + self._i2c_write(0x0041, 100) + # analog gain + gain = min(gain, 0x07) + self._i2c_write(0x003F, 0x40 | gain) + # start ALS + self._i2c_write(0x0038, 1) + # Poll until "New Sample Ready threshold event" is set + while ( + (self._i2c_read(0x004F) >> 3) & 0x7 + ) != 4: + pass + # read lux! + lux = self._i2c_read(0x0050, 2) + # clear interrupt + self._i2c_write(0x0015, 0x07) + lux *= 0.32 # calibrated count/lux + + if gain == 0x06: # ALS_GAIN_1: + pass + elif gain == 0x05: # ALS_GAIN_1_25: + lux /= 1.25 + elif gain == 0x04: # ALS_GAIN_1_67: + lux /= 1.67 + elif gain == 0x03: # ALS_GAIN_2_5: + lux /= 2.5 + elif gain == 0x02: # ALS_GAIN_5: + lux /= 5 + elif gain == 0x01: # ALS_GAIN_10: + lux /= 10 + elif gain == 0x00: # ALS_GAIN_20: + lux /= 20 + elif gain == 0x07: # ALS_GAIN_40: + lux /= 40 + lux *= 100 + lux /= 100 # integration time in ms + return lux diff --git a/setup.py b/setup.py index c0e343a..d26e74a 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ include_package_data=True, install_requires=['paho-mqtt'], - version='2.0.2', + version='2.1.0', license='MIT',