diff --git a/README.md b/README.md index 5a2178f..45672d7 100644 --- a/README.md +++ b/README.md @@ -15,13 +15,13 @@ Use various sensors on the RaspberryPi with Golang (like a ninja!) ## Sensors supported ### BMP085 - + Barometric pressure sensor [Documentation](http://godoc.org/github.com/kid0m4n/go-rpi/sensor/bmp085) [Datasheet](https://www.sparkfun.com/datasheets/Components/General/BST-BMP085-DS000-05.pdf) ### LSM303 - + Accelerometer and magnetometer [Documentation](http://godoc.org/github.com/kid0m4n/go-rpi/sensor/lsm303) [Datasheet](https://www.sparkfun.com/datasheets/Sensors/Magneto/LSM303%20Datasheet.pdf) @@ -30,4 +30,10 @@ Use various sensors on the RaspberryPi with Golang (like a ninja!) Ultrasonic proximity sensor - [Documentation](http://godoc.org/github.com/kid0m4n/go-rpi/sensor/us020) [Product Page](http://www.digibay.in/sensor/object-detection-and-proximity?product_id=239) \ No newline at end of file + [Documentation](http://godoc.org/github.com/kid0m4n/go-rpi/sensor/us020) [Product Page](http://www.digibay.in/sensor/object-detection-and-proximity?product_id=239) + +### BH1750FVI + + Luminosity sensor + + [Documentation](http://godoc.org/github.com/kid0m4n/go-rpi/sensor/us020) [Datasheet](http://www.elechouse.com/elechouse/images/product/Digital%20light%20Sensor/bh1750fvi-e.pdf) diff --git a/samples/bh1750fvi.go b/samples/bh1750fvi.go new file mode 100644 index 0000000..50dc54d --- /dev/null +++ b/samples/bh1750fvi.go @@ -0,0 +1,29 @@ +package main + +import ( + "log" + "time" + + "github.com/kid0m4n/go-rpi/i2c" + "github.com/kid0m4n/go-rpi/sensor/bh1750fvi" +) + +func main() { + bus, err := i2c.NewBus(1) + if err != nil { + log.Panic(err) + } + + lightingSensor := bh1750fvi.New(bh1750fvi.High, bus) + defer lightingSensor.Close() + + for { + lighting, err := lightingSensor.Lighting() + if err != nil { + log.Panic(err) + } + log.Printf("Lighting is %v lx", lighting) + + time.Sleep(500 * time.Millisecond) + } +} diff --git a/sensor/bh1750fvi/bh1750fvi.go b/sensor/bh1750fvi/bh1750fvi.go new file mode 100644 index 0000000..93c8d50 --- /dev/null +++ b/sensor/bh1750fvi/bh1750fvi.go @@ -0,0 +1,171 @@ +// Package BH1750FVI allows interfacing with the BH1750FVI ambient light sensor through I2C protocol. +package bh1750fvi + +import ( + "log" + "sync" + "time" + + "github.com/kid0m4n/go-rpi/i2c" +) + +//accuracy = sensorValue/actualValue] (min = 0.96, typ = 1.2, max = 1.44 +const ( + High = "H" + High2 = "H2" + + measurementAcuuracy = 1.2 + defReadReg = 0x00 + + sensorI2cAddr = 0x23 + + highResOpCode = 0x10 + highResMode2OpCode = 0x11 + + pollDelay = 150 +) + +// A BH1750FVI interface implements access to the sensor. +type BH1750FVI interface { + // Run starts continuous sensor data acquisition loop. + Run() error + + // Lighting returns the ambient lighting in lx. + Lighting() (lighting float64, err error) + + // Close. + Close() + + // SetPollDelay sets the delay between run of data acquisition loop. + SetPollDelay(delay int) +} + +type bh1750fvi struct { + bus i2c.Bus + mu *sync.RWMutex + + lightingReadings chan float64 + quit chan bool + + i2cAddr byte + operationCode byte + + poll int +} + +// Default instance for BH1750FVI sensor +var Default = New(High, i2c.Default) + +// 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). + +// New creates a new BH1750FVI interface according to the mode passed. +func New(mode string, bus i2c.Bus) BH1750FVI { + switch mode { + case High: + return &bh1750fvi{bus: bus, i2cAddr: sensorI2cAddr, operationCode: highResOpCode, mu: new(sync.RWMutex)} + case High2: + return &bh1750fvi{bus: bus, i2cAddr: sensorI2cAddr, operationCode: highResMode2OpCode, mu: new(sync.RWMutex)} + default: + return &bh1750fvi{bus: bus, i2cAddr: sensorI2cAddr, operationCode: highResOpCode, mu: new(sync.RWMutex)} + } +} + +// NewHighMode returns a BH1750FVI inteface on high resolution mode (1lx resolution) +func NewHighMode(bus i2c.Bus) BH1750FVI { + return New(High, bus) +} + +// NewHighMode returns a BH1750FVI inteface on high resolution mode2 (0.5lx resolution) +func NewHigh2Mode(bus i2c.Bus) BH1750FVI { + return New(High2, bus) +} + +func (d *bh1750fvi) measureLighting() (lighting float64, err error) { + err = d.bus.WriteByte(d.i2cAddr, d.operationCode) + if err != nil { + log.Print("bh1750fvi: Failed to initialize sensor") + return + } + time.Sleep(180 * time.Millisecond) + + var sensorReading int + if sensorReading, err = d.bus.ReadInt(d.i2cAddr, defReadReg); err != nil { + return + } + + lighting = float64(sensorReading) / measurementAcuuracy + return +} + +// Lighting returns the ambient lighting in lx. +func (d *bh1750fvi) Lighting() (lighting float64, err error) { + select { + case lighting = <-d.lightingReadings: + return + default: + return d.measureLighting() + } +} + +// Run starts continuous sensor data acquisition loop. +func (d *bh1750fvi) Run() (err error) { + go func() { + d.quit = make(chan bool) + + timer := time.Tick(time.Duration(d.poll) * time.Millisecond) + + var lighting float64 + + for { + select { + case d.lightingReadings <- lighting: + case <-timer: + if l, err := d.measureLighting(); err == nil { + lighting = l + } + if err == nil && d.lightingReadings == nil { + d.lightingReadings = make(chan float64) + } + case <-d.quit: + d.lightingReadings = nil + return + } + } + }() + return +} + +// Close. +func (d *bh1750fvi) Close() { + if d.quit != nil { + d.quit <- true + } + return +} + +// SetPollDelay sets the delay between run of data acquisition loop. +func (d *bh1750fvi) SetPollDelay(delay int) { + d.poll = delay +} + +// SetPollDelay sets the delay between run of data acquisition loop. +func SetPollDelay(delay int) { + Default.SetPollDelay(delay) +} + +// Lighting returns the ambient lighting in lx. +func Lighting() (lighting float64, err error) { + return Default.Lighting() +} + +// Run starts continuous sensor data acquisition loop. +func Run() (err error) { + return Default.Run() +} + +// Close. +func Close() { + Default.Close() +}