-
-
Notifications
You must be signed in to change notification settings - Fork 1k
/
relay_driver.go
137 lines (112 loc) · 2.93 KB
/
relay_driver.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package gpio
import (
"fmt"
"gobot.io/x/gobot/v2"
)
// relayOptionApplier needs to be implemented by each configurable option type
type relayOptionApplier interface {
apply(cfg *relayConfiguration)
}
// relayConfiguration contains all changeable attributes of the driver.
type relayConfiguration struct {
inverted bool
}
// relayInvertedOption is the type for applying inverted behavior to the configuration
type relayInvertedOption bool
// RelayDriver represents a digital relay
type RelayDriver struct {
*driver
relayCfg *relayConfiguration
high bool
}
// NewRelayDriver return a new RelayDriver given a DigitalWriter and pin.
//
// Supported options:
//
// "WithName"
// "WithRelayInverted"
//
// Adds the following API Commands:
//
// "Toggle" - See RelayDriver.Toggle
// "On" - See RelayDriver.On
// "Off" - See RelayDriver.Off
func NewRelayDriver(a DigitalWriter, pin string, opts ...interface{}) *RelayDriver {
//nolint:forcetypeassert // no error return value, so there is no better way
d := &RelayDriver{
driver: newDriver(a.(gobot.Connection), "Relay", withPin(pin)),
relayCfg: &relayConfiguration{},
}
for _, opt := range opts {
switch o := opt.(type) {
case optionApplier:
o.apply(d.driverCfg)
case relayOptionApplier:
o.apply(d.relayCfg)
default:
panic(fmt.Sprintf("'%s' can not be applied on '%s'", opt, d.driverCfg.name))
}
}
d.AddCommand("Toggle", func(params map[string]interface{}) interface{} {
return d.Toggle()
})
d.AddCommand("On", func(params map[string]interface{}) interface{} {
return d.On()
})
d.AddCommand("Off", func(params map[string]interface{}) interface{} {
return d.Off()
})
return d
}
// WithRelayInverted change the relay action to inverted.
func WithRelayInverted() relayOptionApplier {
return relayInvertedOption(true)
}
// State return true if the relay is On and false if the relay is Off
func (d *RelayDriver) State() bool {
if d.relayCfg.inverted {
return !d.high
}
return d.high
}
// On sets the relay to a high state.
func (d *RelayDriver) On() error {
newValue := byte(1)
if d.relayCfg.inverted {
newValue = 0
}
if err := d.digitalWrite(d.driverCfg.pin, newValue); err != nil {
return err
}
d.high = !d.relayCfg.inverted
return nil
}
// Off sets the relay to a low state.
func (d *RelayDriver) Off() error {
newValue := byte(0)
if d.relayCfg.inverted {
newValue = 1
}
if err := d.digitalWrite(d.driverCfg.pin, newValue); err != nil {
return err
}
d.high = d.relayCfg.inverted
return nil
}
// Toggle sets the relay to the opposite of it's current state
func (d *RelayDriver) Toggle() error {
if d.State() {
return d.Off()
}
return d.On()
}
// IsInverted returns true if the relay acts inverted
func (d *RelayDriver) IsInverted() bool {
return d.relayCfg.inverted
}
func (o relayInvertedOption) String() string {
return "relay acts inverted option"
}
func (o relayInvertedOption) apply(cfg *relayConfiguration) {
cfg.inverted = bool(o)
}