PyCom WiPy 2.0

Getting acclimated to the WiPy 2.0 and Expansion Board.  My first “hello world” if you will is to get a TSL2591 Light Sensor running.  It is an i2c device.

Initial Notes on WiPy 2.0 Setup:

  • Datasheet for Expansion Board are difficult to understand.  I assumed that the pinouts would closely resemble that of the WiPy 2.0 but they are not even close.  I am still working with the Expansion Board but dread pulling the WiPy 2.0 off of it and having to rework the circuit
  • ATOM w/Pymkr is flakey at best.  Sync Folder setting not working for me.  I find myself having to restart ATOM after a while as it stops responding often.
  • Firmware Upgrade Fails: I think?  Can’t tell what the latest firmware should be so I am not sure what, if anything happened.
  • Connection with ATOM via IP address never worked.  USB connection is working great.

TSL2991 Code:

Stole this from https://github.com/maxlklaxl/python-tsl2591

Out of the box this code did not work with the WiPy 2.0.  After debugging a bit it turns out the pin outs for SDA and SCL needed to be changed.

Code Snippet (line 52ish of tsl2951.py that I changed to work with WiPy 2.0

[sourcecode language=”python” wraplines=”false” collapse=”false”]
from machine import I2C, Pin
class SMBusEmulator:
__slots__ = (‘i2c’,)
def __init__(self):
self.i2c = I2C(pins=("P8", "P23")) #SDA SCL respectively
[/sourcecode]

Full Code:

[sourcecode language=”python” wraplines=”false” collapse=”false”]
# tsl2591 lux sensor interface
import time

VISIBLE = 2
INFRARED = 1
FULLSPECTRUM = 0

ADDR = 0x29
READBIT = 0x01
COMMAND_BIT = 0xA0
CLEAR_BIT = 0x40
WORD_BIT = 0x20
BLOCK_BIT = 0x10
ENABLE_POWERON = 0x01
ENABLE_POWEROFF = 0x00
ENABLE_AEN = 0x02
ENABLE_AIEN = 0x10
CONTROL_RESET = 0x80
LUX_DF = 408.0
LUX_COEFB = 1.64
LUX_COEFC = 0.59
LUX_COEFD = 0.86

REGISTER_ENABLE = 0x00
REGISTER_CONTROL = 0x01
REGISTER_THRESHHOLDL_LOW = 0x02
REGISTER_THRESHHOLDL_HIGH = 0x03
REGISTER_THRESHHOLDH_LOW = 0x04
REGISTER_THRESHHOLDH_HIGH = 0x05
REGISTER_INTERRUPT = 0x06
REGISTER_CRC = 0x08
REGISTER_ID = 0x0A
REGISTER_CHAN0_LOW = 0x14
REGISTER_CHAN0_HIGH = 0x15
REGISTER_CHAN1_LOW = 0x16
REGISTER_CHAN1_HIGH = 0x17
INTEGRATIONTIME_100MS = 0x00
INTEGRATIONTIME_200MS = 0x01
INTEGRATIONTIME_300MS = 0x02
INTEGRATIONTIME_400MS = 0x03
INTEGRATIONTIME_500MS = 0x04
INTEGRATIONTIME_600MS = 0x05

GAIN_LOW = 0x00
GAIN_MED = 0x10
GAIN_HIGH = 0x20
GAIN_MAX = 0x30

def _bytes_to_int(data):
return data[0] + (data[1]<<8)

from machine import I2C, Pin
class SMBusEmulator:
__slots__ = (‘i2c’,)
def __init__(self):
self.i2c = I2C(pins=("P8", "P23"))

def write_byte_data(self, addr, cmd, val):
buf = bytes([cmd, val])
self.i2c.writeto(addr, buf)

def read_word_data(self, addr, cmd):
assert cmd < 256
buf = bytes([cmd])
self.i2c.writeto(addr, buf)
data = self.i2c.readfrom(addr, 4)
return _bytes_to_int(data)

SENSOR_ADDRESS=0x29

class Tsl2591:
def __init__(
self,
sensor_id,
integration=INTEGRATIONTIME_100MS,
gain=GAIN_LOW
):
print(sensor_id)
self.sensor_id = sensor_id
self.bus = SMBusEmulator()
self.integration_time = integration
self.gain = gain
self.set_timing(self.integration_time)
self.set_gain(self.gain)
self.disable()

def set_timing(self, integration):
self.enable()
self.integration_time = integration
self.bus.write_byte_data(
SENSOR_ADDRESS,
COMMAND_BIT | REGISTER_CONTROL,
self.integration_time | self.gain
)
self.disable()

def set_gain(self, gain):
self.enable()
self.gain = gain
self.bus.write_byte_data(
SENSOR_ADDRESS,
COMMAND_BIT | REGISTER_CONTROL,
self.integration_time | self.gain
)
self.disable()

def calculate_lux(self, full, ir):
if (full == 0xFFFF) | (ir == 0xFFFF):
return 0

case_integ = {
INTEGRATIONTIME_100MS: 100.,
INTEGRATIONTIME_200MS: 200.,
INTEGRATIONTIME_300MS: 300.,
INTEGRATIONTIME_400MS: 400.,
INTEGRATIONTIME_500MS: 500.,
INTEGRATIONTIME_600MS: 600.,
}
if self.integration_time in case_integ.keys():
atime = case_integ[self.integration_time]
else:
atime = 100.

case_gain = {
GAIN_LOW: 1.,
GAIN_MED: 25.,
GAIN_HIGH: 428.,
GAIN_MAX: 9876.,
}

if self.gain in case_gain.keys():
again = case_gain[self.gain]
else:
again = 1.

cpl = (atime * again) / LUX_DF
lux1 = (full – (LUX_COEFB * ir)) / cpl

lux2 = ((LUX_COEFC * full) – (LUX_COEFD * ir)) / cpl

return max([lux1, lux2])

def enable(self):
self.bus.write_byte_data(
SENSOR_ADDRESS,
COMMAND_BIT | REGISTER_ENABLE,
ENABLE_POWERON | ENABLE_AEN | ENABLE_AIEN
)

def disable(self):
self.bus.write_byte_data(
SENSOR_ADDRESS,
COMMAND_BIT | REGISTER_ENABLE,
ENABLE_POWEROFF
)

def get_full_luminosity(self):
self.enable()
time.sleep(0.120*self.integration_time+1)
full = self.bus.read_word_data(
SENSOR_ADDRESS, COMMAND_BIT | REGISTER_CHAN0_LOW
)
ir = self.bus.read_word_data(
SENSOR_ADDRESS, COMMAND_BIT | REGISTER_CHAN1_LOW
)
self.disable()
return full, ir

def get_luminosity(self, channel):
full, ir = self.get_full_luminosity()
if channel == FULLSPECTRUM:
return full
elif channel == INFRARED:
return ir
elif channel == VISIBLE:
return full – ir
else:
return 0

def sample(self):
full, ir = self.get_full_luminosity()
return self.calculate_lux(full, ir)

[/sourcecode]

Simple main.py to print out 10 sensor readings. Hello World Complete!
Will work on posting to the cloud/thingspeak or something of that nature next

[sourcecode language=”python” wraplines=”false” collapse=”false”]
# main.py — put your code here!
import time
from machine import Pin
from machine import I2C
import tsl2591

tsl = tsl2591.Tsl2591(0) # initialize tls2591

cnt = 0

while cnt != 10:
time.sleep(2)
full, ir = tsl.get_full_luminosity() # read raw values (full spectrum and ir spectrum)
lux = tsl.calculate_lux(full, ir) # convert raw values to lux
print(lux, full, ir)
cnt = cnt + 1
[/sourcecode]

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.