1
0
mirror of https://github.com/kidoman/embd synced 2024-12-23 05:10:05 +01:00
embd/sensor/bh1750fvi/bh1750fvi.go

149 lines
3.3 KiB
Go
Raw Normal View History

// Package BH1750FVI allows interfacing with the BH1750FVI ambient light sensor through I2C protocol.
2013-12-21 01:52:36 +05:30
package bh1750fvi
2013-12-17 20:37:58 +05:30
import (
"log"
"sync"
"time"
2014-02-10 05:05:41 +05:30
"github.com/kidoman/embd/i2c"
2013-12-17 20:37:58 +05:30
)
//accuracy = sensorValue/actualValue] (min = 0.96, typ = 1.2, max = 1.44
2013-12-17 20:37:58 +05:30
const (
High = "H"
High2 = "H2"
2013-12-17 20:37:58 +05:30
measurementAcuuracy = 1.2
defReadReg = 0x00
2013-12-17 20:37:58 +05:30
sensorI2cAddr = 0x23
2013-12-17 20:37:58 +05:30
highResOpCode = 0x10
highResMode2OpCode = 0x11
2013-12-17 20:37:58 +05:30
pollDelay = 150
)
2013-12-21 01:52:36 +05:30
// A BH1750FVI interface implements access to the sensor.
type BH1750FVI interface {
// Run starts continuous sensor data acquisition loop.
Run() error
2013-12-17 20:37:58 +05:30
// Lighting returns the ambient lighting in lx.
2013-12-17 20:37:58 +05:30
Lighting() (lighting float64, err error)
// Close.
2013-12-17 20:37:58 +05:30
Close()
// SetPollDelay sets the delay between run of data acquisition loop.
2013-12-17 20:37:58 +05:30
SetPollDelay(delay int)
}
2013-12-21 01:52:36 +05:30
type bh1750fvi struct {
2013-12-17 20:37:58 +05:30
bus i2c.Bus
mu *sync.RWMutex
lightingReadings chan float64
quit chan bool
i2cAddr byte
operationCode byte
2013-12-17 20:37:58 +05:30
poll int
}
// Supports three modes:
// "H" -> High resolution mode (1lx), takes 120ms (recommended).
// "H2" -> High resolution mode 2 (0.5lx), takes 120ms (only use for low light).
2013-12-17 20:37:58 +05:30
// New creates a new BH1750FVI interface according to the mode passed.
2013-12-21 01:52:36 +05:30
func New(mode string, bus i2c.Bus) BH1750FVI {
2013-12-17 20:37:58 +05:30
switch mode {
case High:
2013-12-21 01:52:36 +05:30
return &bh1750fvi{bus: bus, i2cAddr: sensorI2cAddr, operationCode: highResOpCode, mu: new(sync.RWMutex)}
case High2:
2013-12-21 01:52:36 +05:30
return &bh1750fvi{bus: bus, i2cAddr: sensorI2cAddr, operationCode: highResMode2OpCode, mu: new(sync.RWMutex)}
2013-12-17 20:37:58 +05:30
default:
2013-12-21 01:52:36 +05:30
return &bh1750fvi{bus: bus, i2cAddr: sensorI2cAddr, operationCode: highResOpCode, mu: new(sync.RWMutex)}
2013-12-17 20:37:58 +05:30
}
}
// NewHighMode returns a BH1750FVI inteface on high resolution mode (1lx resolution)
2013-12-21 01:52:36 +05:30
func NewHighMode(bus i2c.Bus) BH1750FVI {
return New(High, bus)
}
2013-12-17 20:37:58 +05:30
// NewHighMode returns a BH1750FVI inteface on high resolution mode2 (0.5lx resolution)
2013-12-21 01:52:36 +05:30
func NewHigh2Mode(bus i2c.Bus) BH1750FVI {
return New(High2, bus)
}
2013-12-17 20:37:58 +05:30
2013-12-21 01:52:36 +05:30
func (d *bh1750fvi) measureLighting() (lighting float64, err error) {
err = d.bus.WriteByte(d.i2cAddr, d.operationCode)
2013-12-17 20:37:58 +05:30
if err != nil {
2013-12-21 01:52:36 +05:30
log.Print("bh1750fvi: Failed to initialize sensor")
2013-12-17 20:37:58 +05:30
return
}
time.Sleep(180 * time.Millisecond)
2013-12-17 20:37:58 +05:30
var reading uint16
if reading, err = d.bus.ReadWordFromReg(d.i2cAddr, defReadReg); err != nil {
2013-12-17 20:37:58 +05:30
return
}
lighting = float64(int16(reading)) / measurementAcuuracy
2013-12-17 20:37:58 +05:30
return
}
// Lighting returns the ambient lighting in lx.
2013-12-21 01:52:36 +05:30
func (d *bh1750fvi) Lighting() (lighting float64, err error) {
2013-12-17 20:37:58 +05:30
select {
case lighting = <-d.lightingReadings:
2013-12-17 20:37:58 +05:30
return
default:
return d.measureLighting()
2013-12-17 20:37:58 +05:30
}
}
// Run starts continuous sensor data acquisition loop.
2013-12-21 01:52:36 +05:30
func (d *bh1750fvi) Run() (err error) {
2013-12-17 20:37:58 +05:30
go func() {
d.quit = make(chan bool)
2013-12-17 20:37:58 +05:30
timer := time.Tick(time.Duration(d.poll) * time.Millisecond)
2013-12-17 20:37:58 +05:30
var lighting float64
for {
select {
case d.lightingReadings <- lighting:
2013-12-17 20:37:58 +05:30
case <-timer:
if l, err := d.measureLighting(); err == nil {
2013-12-17 20:37:58 +05:30
lighting = l
}
if err == nil && d.lightingReadings == nil {
d.lightingReadings = make(chan float64)
2013-12-17 20:37:58 +05:30
}
case <-d.quit:
d.lightingReadings = nil
2013-12-17 20:37:58 +05:30
return
}
}
}()
return
}
// Close.
2013-12-21 01:52:36 +05:30
func (d *bh1750fvi) Close() {
if d.quit != nil {
d.quit <- true
2013-12-17 20:37:58 +05:30
}
return
}
// SetPollDelay sets the delay between run of data acquisition loop.
2013-12-21 01:52:36 +05:30
func (d *bh1750fvi) SetPollDelay(delay int) {
d.poll = delay
2013-12-17 20:37:58 +05:30
}