Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] add support for VEML7700 #1099

Draft
wants to merge 1 commit into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 143 additions & 0 deletions drivers/i2c/veml7700_driver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package i2c

const (
defaultVEML7700Address = 0x10
)

const (
ALS_GAIN_1 = 0x0
ALS_GAIN_2 = 0x1
ALS_GAIN_1_4 = 0x3
ALS_GAIN_1_8 = 0x2
)

const (
ALS_25MS = 0xC
ALS_50MS = 0x8
ALS_100MS = 0x0
ALS_200MS = 0x1
ALS_400MS = 0x2
ALS_800MS = 0x3
)

type VEML7700Driver struct {
*Driver
gain byte
integrationTime byte
}

func NewVEML7700Driver(c Connector, options ...func(Config)) *VEML7700Driver {
v := &VEML7700Driver{
Driver: NewDriver(c, "VEML7700", defaultVEML7700Address),
}
v.afterStart = v.initialize

for _, option := range options {
option(v)
}

return v
}

func (v *VEML7700Driver) initialize() error {
if err := v.setGain(ALS_GAIN_1_8); err != nil {
return err
}
if err := v.setIntegrationTime(ALS_100MS); err != nil {
return err
}
return v.setShutdown(false)
}

func (v *VEML7700Driver) ReadRawLight() (uint16, error) {
buf := make([]byte, 2)
if err := v.connection.ReadBlockData(0x04, buf); err != nil {
return 0, err
}
return uint16(buf[0]) | (uint16(buf[1]) << 8), nil
}

func (v *VEML7700Driver) ReadRawWhite() (uint16, error) {
buf := make([]byte, 2)
if err := v.connection.ReadBlockData(0x05, buf); err != nil {
return 0, err
}
return uint16(buf[0]) | (uint16(buf[1]) << 8), nil
}

func (v *VEML7700Driver) setShutdown(state bool) error {
var shutdown byte
if state {
shutdown = 1
} else {
shutdown = 0
}
return v.connection.WriteBlockData(0x00, []byte{shutdown})
}

func (v *VEML7700Driver) setGain(gain byte) error {
v.gain = gain
return v.connection.WriteBlockData(0x00, []byte{gain})
}

func (v *VEML7700Driver) setIntegrationTime(integrationTime byte) error {
v.integrationTime = integrationTime
return v.connection.WriteBlockData(0x00, []byte{integrationTime})
}

func (v *VEML7700Driver) GainValue() float64 {
switch v.gain {
case ALS_GAIN_2:
return 2.0
case ALS_GAIN_1:
return 1.0
case ALS_GAIN_1_4:
return 0.25
case ALS_GAIN_1_8:
return 0.125
default:
return 1.0
}
}

// IntegrationTimeValue returns the current integration time in milliseconds
func (v *VEML7700Driver) IntegrationTimeValue() int {
switch v.integrationTime {
case ALS_25MS:
return 25
case ALS_50MS:
return 50
case ALS_100MS:
return 100
case ALS_200MS:
return 200
case ALS_400MS:
return 400
case ALS_800MS:
return 800
default:
return 100
}
}

func (v *VEML7700Driver) Lux() (float64, error) {
light, err := v.ReadRawLight()
if err != nil {
return 0, err
}
resolution := v.resolution()
return resolution * float64(light), nil
}

func (v *VEML7700Driver) resolution() float64 {
resolutionAtMax := 0.0036
gainMax := 2.0
integrationTimeMax := 800.0
integrationTimeValue := float64(v.IntegrationTimeValue())
gainValue := v.GainValue()

if gainValue == gainMax && integrationTimeValue == integrationTimeMax {
return resolutionAtMax
}
return resolutionAtMax * (integrationTimeMax / integrationTimeValue) * (gainMax / gainValue)
}
83 changes: 83 additions & 0 deletions drivers/i2c/veml7700_driver_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package i2c

import (
"bytes"
"errors"
"strings"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"gobot.io/x/gobot/v2"
)

// this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver
// and tests all implementations, so no further tests needed here for gobot.Driver interface
var _ gobot.Driver = (*VEML7700Driver)(nil)

func initTestVEML7700DriverWithStubbedAdaptor() (*VEML7700Driver, *i2cTestAdaptor) {
a := newI2cTestAdaptor()
d := NewVEML7700Driver(a)
if err := d.Start(); err != nil {
panic(err)
}
return d, a
}

func TestNewVEML7700Driver(t *testing.T) {
var di interface{} = NewVEML7700Driver(newI2cTestAdaptor())
d, ok := di.(*VEML7700Driver)
if !ok {
t.Errorf("NewVEML7700Driver() should have returned a *VEML7700Driver")
}
assert.NotNil(t, d.Driver)
assert.True(t, strings.HasPrefix(d.Name(), "VEML7700"))
assert.Equal(t, 0x10, d.defaultAddress)
}

func TestVEML7700Options(t *testing.T) {
// This is a general test, that options are applied in constructor by using the common WithBus() option and
// least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)".
d := NewVEML7700Driver(newI2cTestAdaptor(), WithBus(2))
assert.Equal(t, 2, d.GetBusOrDefault(1))
}

func TestVEML7700Start(t *testing.T) {
d := NewVEML7700Driver(newI2cTestAdaptor())
require.NoError(t, d.Start())
}

func TestVEML7700Halt(t *testing.T) {
d, _ := initTestVEML7700DriverWithStubbedAdaptor()
require.NoError(t, d.Halt())
}

func TestVEML7700NullLux(t *testing.T) {
d, _ := initTestVEML7700DriverWithStubbedAdaptor()
lux, _ := d.Lux()
assert.Equal(t, 0.0, lux)

Check failure on line 59 in drivers/i2c/veml7700_driver_test.go

View workflow job for this annotation

GitHub Actions / lint

float-compare: use assert.InEpsilon (or InDelta) (testifylint)
}

func TestVEML7700Lux(t *testing.T) {
d, a := initTestVEML7700DriverWithStubbedAdaptor()
a.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()
assert.Equal(t, 20764.108799999998, lux)

Check failure on line 72 in drivers/i2c/veml7700_driver_test.go

View workflow job for this annotation

GitHub Actions / lint

float-compare: use assert.InEpsilon (or InDelta) (testifylint)
}

func TestVEML7700LuxError(t *testing.T) {
d, a := initTestVEML7700DriverWithStubbedAdaptor()
a.i2cReadImpl = func(b []byte) (int, error) {
return 0, errors.New("wrong number of bytes read")
}

_, err := d.Lux()
require.ErrorContains(t, err, "wrong number of bytes read")
}
Loading