Post your best Lua script examples here

User avatar
By quantalume
#10278 I threw together a quick-and-dirty library for the TSL2591 sensor.

Save the following code to tsl2591.lua.
Code: Select all-- ***************************************************************************
-- TSL2591 module for ESP8266 with nodeMCU firmware
--
-- Written by quantalume
--
-- MIT license, http://opensource.org/licenses/MIT
-- ***************************************************************************
 
local moduleName = ...
local M = {}
_G[moduleName] = M

local i2c_id
local dev_addr = 0x29

TSL2591_GAIN_1X = 0
TSL2591_GAIN_25X = 1
TSL2591_GAIN_428X = 2
TSL2591_GAIN_9876X = 3
TSL2591_INT_TIME_100MS = 0
TSL2591_INT_TIME_200MS = 1
TSL2591_INT_TIME_300MS = 2
TSL2591_INT_TIME_400MS = 3
TSL2591_INT_TIME_500MS = 4
TSL2591_INT_TIME_600MS = 5
local TSL2591_ENABLE_REG = 0
local TSL2591_CONFIG_REG = 1
local TSL2591_STATUS_REG = 0x13
local TSL2591_AEN = 2
local TSL2591_PON = 1
local TSL2591_CH0_LOW = 0x14
local TSL2591_CH0_HIGH = 0x15
local TSL2591_CH1_LOW = 0x16
local TSL2591_CH1_HIGH = 0x17

local function read_reg(reg)
  i2c.start(i2c_id)
  i2c.address(i2c_id, dev_addr, i2c.TRANSMITTER)
  i2c.write(i2c_id, reg + 0xA0)
  i2c.stop(i2c_id)
  i2c.start(i2c_id)
  i2c.address(i2c_id, dev_addr, i2c.RECEIVER)
  c = i2c.read(i2c_id, 1)
  i2c.stop(i2c_id)
  return string.byte(c)
end

local function write_reg(reg, value)
  i2c.start(i2c_id)
  i2c.address(i2c_id, dev_addr, i2c.TRANSMITTER)
  i2c.write(i2c_id, reg + 0xA0)
  i2c.write(i2c_id, value)
  i2c.stop(i2c_id)
  return
end

function M.set_gain(gain, int_time)
  write_reg(TSL2591_CONFIG_REG, gain * 16 + int_time)
end

function M.init(id, sda, scl, speed)
  i2c_id = id
  i2c.setup(i2c_id, sda, scl, speed)

  -- Shut down device until needed
  write_reg(TSL2591_ENABLE_REG, 0)
end

function M.read()

  -- Turn oscillator on and begin conversion
  write_reg(TSL2591_ENABLE_REG, TSL2591_PON + TSL2591_AEN)

  -- Wait until conversion complete 
  -- TODO: establish time-out error trap
  while read_reg(TSL2591_STATUS_REG) % 2 == 0 do end

  -- Conversion complete, shut down device
  write_reg(TSL2591_ENABLE_REG, 0)

  -- Read light values
  -- Device is double-buffered, so make sure we're returning latest values
  for i = 1, 2 do
    ch0 = read_reg(TSL2591_CH0_HIGH)*256 + read_reg(TSL2591_CH0_LOW)
    ch1 = read_reg(TSL2591_CH1_HIGH)*256 + read_reg(TSL2591_CH1_LOW)
  end   
 
  return ch0, ch1  --ch0: visible, ch1: IR
 
end

return M

For the example which follows, I'm using the breakout board from Adafruit for testing. The wiring for this example is (sensor breakout terminal on left):
    Vin -> 3.3V
    Gnd -> Gnd
    SDA -> GPIO13
    SCL -> GPIO12

Here's the code for the example (tested with nodemcu_20150127):
Code: Select alltsl = require("tsl2591")

-- i2c parameters
id = 0
sda = 7
scl = 6

tsl.init(id, sda, scl, i2c.SLOW)

-- set gain and integration time
-- see tsl2591.lua for a list of options
tsl.set_gain(TSL2591_GAIN_25X, TSL2591_INT_TIME_600MS)

vis, ir = tsl.read()
print("CH0 (visible):", vis)
print("CH1 (IR):", ir)

This is only a beginning, and the library needs some error checking and trapping. Also, the device allows you to set high and low light thresholds for generating interrupts, which would be a nice feature to support at some point. I'll probably submit a pull request for the module to nodemcu once it's been tested a bit more.
User avatar
By herrmausf
#55266 Hi,

I have tested your lib, thanks for your work!

To further improve it, I ported the lux calculation based on the python implementation.
Please bear with me since this is my first LUA code ever :shock:
I added some constants that are necessary to the TSL2591 module:

Code: Select all-- ***************************************************************************
-- TSL2591 module for ESP8266 with nodeMCU firmware
--
-- Written by quantalume
-- http://www.esp8266.com/viewtopic.php?f=19&t=1715
-- MIT license, http://opensource.org/licenses/MIT
-- ***************************************************************************
 
local moduleName = ...
local M = {}
_G[moduleName] = M

local i2c_id
local dev_addr = 0x29

TSL2591_GAIN_1X = 0
TSL2591_GAIN_25X = 1
TSL2591_GAIN_428X = 2
TSL2591_GAIN_9876X = 3
TSL2591_INT_TIME_100MS = 0
TSL2591_INT_TIME_200MS = 1
TSL2591_INT_TIME_300MS = 2
TSL2591_INT_TIME_400MS = 3
TSL2591_INT_TIME_500MS = 4
TSL2591_INT_TIME_600MS = 5
local TSL2591_ENABLE_REG = 0
local TSL2591_CONFIG_REG = 1
local TSL2591_STATUS_REG = 0x13
local TSL2591_AEN = 2
local TSL2591_PON = 1
local TSL2591_CH0_LOW = 0x14
local TSL2591_CH0_HIGH = 0x15
local TSL2591_CH1_LOW = 0x16
local TSL2591_CH1_HIGH = 0x17

-- Constants for LUX calculation
LUX_DF = 408.0
LUX_COEFB = 1.64  -- CH0 coefficient
LUX_COEFC = 0.59  -- CH1 coefficient A
LUX_COEFD = 0.86  -- CH2 coefficient B

local function read_reg(reg)
  i2c.start(i2c_id)
  i2c.address(i2c_id, dev_addr, i2c.TRANSMITTER)
  i2c.write(i2c_id, reg + 0xA0)
  i2c.stop(i2c_id)
  i2c.start(i2c_id)
  i2c.address(i2c_id, dev_addr, i2c.RECEIVER)
  c = i2c.read(i2c_id, 1)
  i2c.stop(i2c_id)
  return string.byte(c)
end

local function write_reg(reg, value)
  i2c.start(i2c_id)
  i2c.address(i2c_id, dev_addr, i2c.TRANSMITTER)
  i2c.write(i2c_id, reg + 0xA0)
  i2c.write(i2c_id, value)
  i2c.stop(i2c_id)
  return
end

function M.set_gain(gain, int_time)
  write_reg(TSL2591_CONFIG_REG, gain * 16 + int_time)
end

function M.init(id, sda, scl, speed)
  i2c_id = id
  i2c.setup(i2c_id, sda, scl, speed)

  -- Shut down device until needed
  write_reg(TSL2591_ENABLE_REG, 0)
end

function M.read()

  -- Turn oscillator on and begin conversion
  write_reg(TSL2591_ENABLE_REG, TSL2591_PON + TSL2591_AEN)

  -- Wait until conversion complete 
  -- TODO: establish time-out error trap
  while read_reg(TSL2591_STATUS_REG) % 2 == 0 do end

  -- Conversion complete, shut down device
  write_reg(TSL2591_ENABLE_REG, 0)

  -- Read light values
  -- Device is double-buffered, so make sure we're returning latest values
  for i = 1, 2 do
    ch0 = read_reg(TSL2591_CH0_HIGH)*256 + read_reg(TSL2591_CH0_LOW)
    ch1 = read_reg(TSL2591_CH1_HIGH)*256 + read_reg(TSL2591_CH1_LOW)
  end   
 
  return ch0, ch1  --ch0: visible, ch1: IR
 
end

return M


Then I call it with code similiar to the following (using GPIO D2 for SDA and D1 for SDC):

Code: Select alltsl = require("tsl2591")

-- i2c parameters
id = 0
sda = 2
scl = 1

tsl.init(id, sda, scl, i2c.SLOW)

----------------------------------------
function get_lux(gain, itime, full, ir)
    atime = (itime + 1)*100
   
    if      gain == 0   then again = 1.0   
    elseif  gain == 1   then again = 25.0
    elseif  gain == 2   then again = 428.0
    elseif  gain == 3   then again = 9876.0
    end

    cpl = (atime * again) / LUX_DF
    lux1 = (full - (LUX_COEFB * ir)) / cpl
    lux2 = ((LUX_COEFC * full) - (LUX_COEFD * ir)) / cpl

    return math.max(lux1, lux2)
end

function round(num, len)
  local mult = 10^(len or 0)
  return math.floor(num * mult + 0.5) / mult
end
----------------------------------------


-- set gain and integration time
-- see tsl2591.lua for a list of options
gain = TSL2591_GAIN_25X
itime = TSL2591_INT_TIME_200MS
tsl.set_gain(gain, itime)

full, ir = tsl.read()

while full == 65535 or ir == 65535 do
    if gain > 0 then gain = gain-1
    elseif itime >= 4 then itime = itime-1
    end
    tsl.set_gain(gain, itime)
    full, ir = tsl.read()
end
while full < 10 or ir < 10 do
    if gain == 1 then gain = 2
    elseif itime < 4 then itime = itime+1
    end
    tsl.set_gain(gain, itime)
    full, ir = tsl.read()
end

--print("CH0 (full):  ", full)
--print("CH1 (IR):    ", ir)
--print("Visible (full-IR):   ", full-ir)
print("Lux:     ", round(get_lux(gain,itime,full,ir),2))