Skip to content

Commit

Permalink
add AnalogActuatorDriver, analog temperature sensor, driver for PCF85…
Browse files Browse the repository at this point in the history
…91 (with 400kbit stabilization), driver for YL-40
  • Loading branch information
gen2thomas authored and deadprogram committed Apr 24, 2022
1 parent 6347285 commit 3b3ad4d
Show file tree
Hide file tree
Showing 18 changed files with 2,088 additions and 149 deletions.
2 changes: 2 additions & 0 deletions drivers/aio/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ go get -d -u gobot.io/x/gobot/...
## Hardware Support
Gobot has a extensible system for connecting to hardware devices. The following AIO devices are currently supported:
- Analog Sensor
- Analog Actuator
- Grove Light Sensor
- Grove Rotary Dial
- Grove Sound Sensor
- Grove Temperature Sensor
- Temperature Sensor (supports linear and NTC thermistor in normal and inverse mode)

More drivers are coming soon...
12 changes: 10 additions & 2 deletions drivers/aio/aio.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,20 @@ const (
Error = "error"
// Data event
Data = "data"
// Value event
Value = "value"
// Vibration event
Vibration = "vibration"
)

// AnalogReader interface represents an Adaptor which has Analog capabilities
// AnalogReader interface represents an Adaptor which has AnalogRead capabilities
type AnalogReader interface {
//gobot.Adaptor
AnalogRead(string) (val int, err error)
AnalogRead(pin string) (val int, err error)
}

// AnalogWriter interface represents an Adaptor which has AnalogWrite capabilities
type AnalogWriter interface {
//gobot.Adaptor
AnalogWrite(pin string, val int) (err error)
}
111 changes: 111 additions & 0 deletions drivers/aio/analog_actuator_driver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package aio

import (
"strconv"

"gobot.io/x/gobot"
)

// AnalogActuatorDriver represents an analog actuator
type AnalogActuatorDriver struct {
name string
pin string
connection AnalogWriter
gobot.Eventer
gobot.Commander
scale func(input float64) (value int)
lastValue float64
lastRawValue int
}

// NewAnalogActuatorDriver returns a new AnalogActuatorDriver given by an AnalogWriter and pin.
// The driver supports customizable scaling from given float64 value to written int.
// The default scaling is 1:1. An adjustable linear scaler is provided by the driver.
//
// Adds the following API Commands:
// "Write" - See AnalogActuator.Write
// "RawWrite" - See AnalogActuator.RawWrite
func NewAnalogActuatorDriver(a AnalogWriter, pin string) *AnalogActuatorDriver {
d := &AnalogActuatorDriver{
name: gobot.DefaultName("AnalogActuator"),
connection: a,
pin: pin,
Commander: gobot.NewCommander(),
scale: func(input float64) (value int) { return int(input) },
}

d.AddCommand("Write", func(params map[string]interface{}) interface{} {
val, err := strconv.ParseFloat(params["val"].(string), 64)
if err != nil {
return err
}
return d.Write(val)
})

d.AddCommand("RawWrite", func(params map[string]interface{}) interface{} {
val, _ := strconv.Atoi(params["val"].(string))
return d.RawWrite(val)
})

return d
}

// Start starts driver
func (a *AnalogActuatorDriver) Start() (err error) { return }

// Halt is for halt
func (a *AnalogActuatorDriver) Halt() (err error) { return }

// Name returns the drivers name
func (a *AnalogActuatorDriver) Name() string { return a.name }

// SetName sets the drivers name
func (a *AnalogActuatorDriver) SetName(n string) { a.name = n }

// Pin returns the drivers pin
func (a *AnalogActuatorDriver) Pin() string { return a.pin }

// Connection returns the drivers Connection
func (a *AnalogActuatorDriver) Connection() gobot.Connection { return a.connection.(gobot.Connection) }

// RawWrite write the given raw value to the actuator
func (a *AnalogActuatorDriver) RawWrite(val int) (err error) {
a.lastRawValue = val
return a.connection.AnalogWrite(a.Pin(), val)
}

// SetScaler substitute the default 1:1 return value function by a new scaling function
func (a *AnalogActuatorDriver) SetScaler(scaler func(float64) int) {
a.scale = scaler
}

// Write writes the given value to the actuator
func (a *AnalogActuatorDriver) Write(val float64) (err error) {
a.lastValue = val
rawValue := a.scale(val)
return a.RawWrite(rawValue)
}

// RawValue returns the last written raw value
func (a *AnalogActuatorDriver) RawValue() (val int) {
return a.lastRawValue
}

// Value returns the last written value
func (a *AnalogActuatorDriver) Value() (val float64) {
return a.lastValue
}

func AnalogActuatorLinearScaler(fromMin, fromMax float64, toMin, toMax int) func(input float64) (value int) {
m := float64(toMax-toMin) / (fromMax - fromMin)
n := float64(toMin) - m*fromMin
return func(input float64) (value int) {
if input <= fromMin {
return toMin
}
if input >= fromMax {
return toMax
}
return int(input*m + n)
}
}
105 changes: 105 additions & 0 deletions drivers/aio/analog_actuator_driver_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package aio

import (
"strings"
"testing"

"gobot.io/x/gobot/gobottest"
)

func TestAnalogActuatorDriver(t *testing.T) {
a := newAioTestAdaptor()
d := NewAnalogActuatorDriver(a, "47")

gobottest.Refute(t, d.Connection(), nil)
gobottest.Assert(t, d.Pin(), "47")

err := d.RawWrite(100)
gobottest.Assert(t, err, nil)
gobottest.Assert(t, len(a.written), 1)
gobottest.Assert(t, a.written[0], 100)

err = d.Write(247.0)
gobottest.Assert(t, err, nil)
gobottest.Assert(t, len(a.written), 2)
gobottest.Assert(t, a.written[1], 247)
gobottest.Assert(t, d.RawValue(), 247)
gobottest.Assert(t, d.Value(), 247.0)
}

func TestAnalogActuatorDriverWithScaler(t *testing.T) {
// commands
a := newAioTestAdaptor()
d := NewAnalogActuatorDriver(a, "7")
d.SetScaler(func(input float64) int { return int((input + 3) / 2.5) })

err := d.Command("RawWrite")(map[string]interface{}{"val": "100"})
gobottest.Assert(t, err, nil)
gobottest.Assert(t, len(a.written), 1)
gobottest.Assert(t, a.written[0], 100)

err = d.Command("Write")(map[string]interface{}{"val": "247.0"})
gobottest.Assert(t, err, nil)
gobottest.Assert(t, len(a.written), 2)
gobottest.Assert(t, a.written[1], 100)
}

func TestAnalogActuatorDriverLinearScaler(t *testing.T) {
var tests = map[string]struct {
fromMin float64
fromMax float64
input float64
want int
}{
"byte_range_min": {fromMin: 0, fromMax: 255, input: 0, want: 0},
"byte_range_max": {fromMin: 0, fromMax: 255, input: 255, want: 255},
"signed_percent_range_min": {fromMin: -100, fromMax: 100, input: -100, want: 0},
"signed_percent_range_mid": {fromMin: -100, fromMax: 100, input: 0, want: 127},
"signed_percent_range_max": {fromMin: -100, fromMax: 100, input: 100, want: 255},
"voltage_range_min": {fromMin: 0, fromMax: 5.1, input: 0, want: 0},
"voltage_range_nearmin": {fromMin: 0, fromMax: 5.1, input: 0.02, want: 1},
"voltage_range_mid": {fromMin: 0, fromMax: 5.1, input: 2.55, want: 127},
"voltage_range_nearmax": {fromMin: 0, fromMax: 5.1, input: 5.08, want: 254},
"voltage_range_max": {fromMin: 0, fromMax: 5.1, input: 5.1, want: 255},
"upscale": {fromMin: 0, fromMax: 24, input: 12, want: 127},
"below_min": {fromMin: -10, fromMax: 10, input: -11, want: 0},
"exceed_max": {fromMin: 0, fromMax: 20, input: 21, want: 255},
}
a := newAioTestAdaptor()
d := NewAnalogActuatorDriver(a, "7")

for name, tt := range tests {
t.Run(name, func(t *testing.T) {
// arrange
d.SetScaler(AnalogActuatorLinearScaler(tt.fromMin, tt.fromMax, 0, 255))
a.written = []int{} // reset previous write
// act
err := d.Write(tt.input)
// assert
gobottest.Assert(t, err, nil)
gobottest.Assert(t, len(a.written), 1)
gobottest.Assert(t, a.written[0], tt.want)
})
}
}

func TestAnalogActuatorDriverStart(t *testing.T) {
d := NewAnalogActuatorDriver(newAioTestAdaptor(), "1")
gobottest.Assert(t, d.Start(), nil)
}

func TestAnalogActuatorDriverHalt(t *testing.T) {
d := NewAnalogActuatorDriver(newAioTestAdaptor(), "1")
gobottest.Assert(t, d.Halt(), nil)
}

func TestAnalogActuatorDriverDefaultName(t *testing.T) {
d := NewAnalogActuatorDriver(newAioTestAdaptor(), "1")
gobottest.Assert(t, strings.HasPrefix(d.Name(), "AnalogActuator"), true)
}

func TestAnalogActuatorDriverSetName(t *testing.T) {
d := NewAnalogActuatorDriver(newAioTestAdaptor(), "1")
d.SetName("mybot")
gobottest.Assert(t, d.Name(), "mybot")
}
Loading

0 comments on commit 3b3ad4d

Please sign in to comment.