From c2e6910c82fc93ca38bb49ff7e1dc48a4fa00794 Mon Sep 17 00:00:00 2001 From: Daniel Esteban Date: Thu, 11 Jan 2018 20:56:23 +0100 Subject: [PATCH 1/2] Added basic driver for BH1750 (light sensor), board GY-302 --- drivers/i2c/bh1750_driver.go | 109 ++++++++++++++++++++++ drivers/i2c/bh1750_driver_test.go | 148 ++++++++++++++++++++++++++++++ 2 files changed, 257 insertions(+) create mode 100644 drivers/i2c/bh1750_driver.go create mode 100644 drivers/i2c/bh1750_driver_test.go diff --git a/drivers/i2c/bh1750_driver.go b/drivers/i2c/bh1750_driver.go new file mode 100644 index 000000000..f7ea1d9fa --- /dev/null +++ b/drivers/i2c/bh1750_driver.go @@ -0,0 +1,109 @@ +package i2c + +import ( + "time" + "errors" + + "gobot.io/x/gobot" +) + +const bh1750Address = 0x23 + +const ( + BH1750_POWER_DOWN = 0x00 + BH1750_POWER_ON = 0x01 + BH1750_RESET = 0x07 + BH1750_CONTINUOUS_HIGH_RES_MODE = 0x10 + BH1750_CONTINUOUS_HIGH_RES_MODE_2 = 0x11 + BH1750_CONTINUOUS_LOW_RES_MODE = 0x13 + BH1750_ONE_TIME_HIGH_RES_MODE = 0x20 + BH1750_ONE_TIME_HIGH_RES_MODE_2 = 0x21 + BH1750_ONE_TIME_LOW_RES_MODE = 0x23 +) + +type BH1750Driver struct { + name string + connector Connector + connection Connection + mode byte + Config +} + +// NewBH1750Driver creates a new driver with specified i2c interface +// Params: +// conn Connector - the Adaptor to use with this Driver +// +// Optional params: +// i2c.WithBus(int): bus to use with this driver +// i2c.WithAddress(int): address to use with this driver +// +func NewBH1750Driver(a Connector, options ...func(Config)) *BH1750Driver { + m := &BH1750Driver{ + name: gobot.DefaultName("BH1750"), + connector: a, + Config: NewConfig(), + mode: BH1750_CONTINUOUS_HIGH_RES_MODE, + } + + for _, option := range options { + option(m) + } + + // TODO: add commands for API + return m +} + +// Name returns the Name for the Driver +func (h *BH1750Driver) Name() string { return h.name } + +// SetName sets the Name for the Driver +func (h *BH1750Driver) SetName(n string) { h.name = n } + +// Connection returns the connection for the Driver +func (h *BH1750Driver) Connection() gobot.Connection { return h.connector.(gobot.Connection) } + +// Start initialized the bh1750 +func (h *BH1750Driver) Start() (err error) { + bus := h.GetBusOrDefault(h.connector.GetDefaultBus()) + address := h.GetAddressOrDefault(bh1750Address) + + h.connection, err = h.connector.GetConnection(address, bus) + if err != nil { + return err + } + + err = h.connection.WriteByte(h.mode) + time.Sleep(10 * time.Microsecond) + if err != nil { + return err + } + + return +} + +// Halt returns true if devices is halted successfully +func (h *BH1750Driver) Halt() (err error) { return } + +func (h *BH1750Driver) RawSensorData() (level int, err error) { + + buf := []byte{0, 0} + bytesRead, err := h.connection.Read(buf) + if bytesRead != 2 { + err = errors.New("wrong number of bytes read") + return + } + if err != nil { + return + } + level = int(buf[0])<<8 | int(buf[1]) + + return +} + +func (h *BH1750Driver) Lux() (lux int, err error) { + + lux, err = h.RawSensorData() + lux = int(float64(lux) / 1.2) + + return +} diff --git a/drivers/i2c/bh1750_driver_test.go b/drivers/i2c/bh1750_driver_test.go new file mode 100644 index 000000000..77f277fc8 --- /dev/null +++ b/drivers/i2c/bh1750_driver_test.go @@ -0,0 +1,148 @@ +package i2c + +import ( + "errors" + "strings" + "testing" + + "bytes" + + "gobot.io/x/gobot" + "gobot.io/x/gobot/gobottest" +) + +var _ gobot.Driver = (*BH1750Driver)(nil) + +// --------- HELPERS +func initTestBH1750Driver() (driver *BH1750Driver) { + driver, _ = initTestBH1750DriverWithStubbedAdaptor() + return +} + +func initTestBH1750DriverWithStubbedAdaptor() (*BH1750Driver, *i2cTestAdaptor) { + adaptor := newI2cTestAdaptor() + return NewBH1750Driver(adaptor), adaptor +} + +// --------- TESTS + +func TestNewBH1750Driver(t *testing.T) { + // Does it return a pointer to an instance of BH1750Driver? + var mma interface{} = NewBH1750Driver(newI2cTestAdaptor()) + _, ok := mma.(*BH1750Driver) + if !ok { + t.Errorf("NewBH1750Driver() should have returned a *BH1750Driver") + } +} + +// Methods +func TestBH1750Driver(t *testing.T) { + mma := initTestBH1750Driver() + + gobottest.Refute(t, mma.Connection(), nil) + gobottest.Assert(t, strings.HasPrefix(mma.Name(), "BH1750"), true) +} + +func TestBH1750DriverSetName(t *testing.T) { + d := initTestBH1750Driver() + d.SetName("TESTME") + gobottest.Assert(t, d.Name(), "TESTME") +} + +func TestBH1750DriverOptions(t *testing.T) { + d := NewBH1750Driver(newI2cTestAdaptor(), WithBus(2)) + gobottest.Assert(t, d.GetBusOrDefault(1), 2) +} + +func TestBH1750DriverStart(t *testing.T) { + d := initTestBH1750Driver() + gobottest.Assert(t, d.Start(), nil) +} + +func TestBH1750StartConnectError(t *testing.T) { + d, adaptor := initTestBH1750DriverWithStubbedAdaptor() + adaptor.Testi2cConnectErr(true) + gobottest.Assert(t, d.Start(), errors.New("Invalid i2c connection")) +} + +func TestBH1750DriverStartWriteError(t *testing.T) { + mma, adaptor := initTestBH1750DriverWithStubbedAdaptor() + adaptor.i2cWriteImpl = func([]byte) (int, error) { + return 0, errors.New("write error") + } + gobottest.Assert(t, mma.Start(), errors.New("write error")) +} + +func TestBH1750DriverHalt(t *testing.T) { + d := initTestBH1750Driver() + gobottest.Assert(t, d.Halt(), nil) +} + +func TestBH1750DriverNullLux(t *testing.T) { + d, _ := initTestBH1750DriverWithStubbedAdaptor() + d.Start() + lux, _ := d.Lux() + gobottest.Assert(t, lux, 0) +} + +func TestBH1750DriverLux(t *testing.T) { + d, adaptor := initTestBH1750DriverWithStubbedAdaptor() + d.Start() + + adaptor.i2cReadImpl = func(b []byte) (int, error) { + buf := new(bytes.Buffer) + buf.Write([]byte{0x05, 0xb0}) + copy(b, buf.Bytes()) + return buf.Len(), nil + } + + lux, _ := d.Lux() + gobottest.Assert(t, lux, 1213) +} + +func TestBH1750DriverNullRawSensorData(t *testing.T) { + d, _ := initTestBH1750DriverWithStubbedAdaptor() + d.Start() + level, _ := d.RawSensorData() + gobottest.Assert(t, level, 0) +} + +func TestBH1750DriverRawSensorData(t *testing.T) { + d, adaptor := initTestBH1750DriverWithStubbedAdaptor() + d.Start() + + adaptor.i2cReadImpl = func(b []byte) (int, error) { + buf := new(bytes.Buffer) + buf.Write([]byte{0x05, 0xb0}) + copy(b, buf.Bytes()) + return buf.Len(), nil + } + + level, _ := d.RawSensorData() + gobottest.Assert(t, level, 1456) +} + +func TestBH1750DriverLuxError(t *testing.T) { + d, adaptor := initTestBH1750DriverWithStubbedAdaptor() + d.Start() + + adaptor.i2cReadImpl = func(b []byte) (int, error) { + return 0, errors.New("wrong number of bytes read") + } + + _, err := d.Lux() + gobottest.Assert(t, err, errors.New("wrong number of bytes read")) +} + +func TestBH1750DriverRawSensorDataError(t *testing.T) { + d, adaptor := initTestBH1750DriverWithStubbedAdaptor() + d.Start() + + adaptor.i2cReadImpl = func(b []byte) (int, error) { + return 0, errors.New("wrong number of bytes read") + } + + _, err := d.RawSensorData() + gobottest.Assert(t, err, errors.New("wrong number of bytes read")) +} + From d4880f808fc7e0e53b199c969d34328690cd603f Mon Sep 17 00:00:00 2001 From: Daniel Esteban Date: Fri, 12 Jan 2018 16:26:21 +0100 Subject: [PATCH 2/2] added comments for godoc added bh1750 to readme --- drivers/i2c/README.md | 1 + drivers/i2c/bh1750_driver.go | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/drivers/i2c/README.md b/drivers/i2c/README.md index 422e59e97..eafeec7a3 100644 --- a/drivers/i2c/README.md +++ b/drivers/i2c/README.md @@ -15,6 +15,7 @@ Gobot has a extensible system for connecting to hardware devices. The following - Adafruit Motor Hat - ADS1015 Analog to Digital Converter - ADS1115 Analog to Digital Converter +- BH1750 Digital Luminosity/Lux/Light Sensor - BlinkM LED - BME280 Barometric Pressure/Temperature/Altitude/Humidity Sensor - BMP180 Barometric Pressure/Temperature/Altitude Sensor diff --git a/drivers/i2c/bh1750_driver.go b/drivers/i2c/bh1750_driver.go index f7ea1d9fa..f9cafae4e 100644 --- a/drivers/i2c/bh1750_driver.go +++ b/drivers/i2c/bh1750_driver.go @@ -21,6 +21,8 @@ const ( BH1750_ONE_TIME_LOW_RES_MODE = 0x23 ) +// BH1750Driver is a driver for the BH1750 digital Ambient Light Sensor IC for I²C bus interface. +// type BH1750Driver struct { name string connector Connector @@ -84,6 +86,7 @@ func (h *BH1750Driver) Start() (err error) { // Halt returns true if devices is halted successfully func (h *BH1750Driver) Halt() (err error) { return } +// RawSensorData returns the raw value from the bh1750 func (h *BH1750Driver) RawSensorData() (level int, err error) { buf := []byte{0, 0} @@ -100,6 +103,7 @@ func (h *BH1750Driver) RawSensorData() (level int, err error) { return } +// Lux returns the adjusted value from the bh1750 func (h *BH1750Driver) Lux() (lux int, err error) { lux, err = h.RawSensorData()