fermentord/internal/hw/gpio.go

176 lines
3.3 KiB
Go
Raw Normal View History

2021-08-10 21:29:24 +00:00
package hw
import (
"time"
2024-06-15 13:58:47 +00:00
"github.com/warthog618/go-gpiocdev"
2021-08-10 21:29:24 +00:00
)
const (
pinDoorOpen = 17
pinFanPower = 22
2022-03-05 19:42:17 +00:00
pinCoolerPower = 23
pinHeaterPower = 24
pinLightsPower = 25
2021-08-10 21:29:24 +00:00
// GPIO21 is located at pin 13 on RPi 1B rev 1. Rev 2 and never boards
// has GPIO27 here.
pinOneWirePower = 21
2021-08-10 21:29:24 +00:00
off = 0
on = 1
)
type HWEvent int
const (
NoOp HWEvent = iota
DoorClosed
DoorOpened
)
2021-08-10 21:29:24 +00:00
type Gpio struct {
2024-06-15 13:58:47 +00:00
chip *gpiocdev.Chip
doorOpen *gpiocdev.Line
oneWirePower *gpiocdev.Line
lightsPower *gpiocdev.Line
fanPower *gpiocdev.Line
coolerPower *gpiocdev.Line
heaterPower *gpiocdev.Line
C chan HWEvent
2021-08-10 21:29:24 +00:00
}
func NewGpio() (*Gpio, error) {
var err error
p := &Gpio{
2022-07-23 23:16:40 +00:00
C: make(chan HWEvent, 1),
}
2021-08-10 21:29:24 +00:00
2024-06-15 13:58:47 +00:00
p.chip, err = gpiocdev.NewChip("gpiochip0", gpiocdev.WithConsumer("fermentord"))
2021-08-10 21:29:24 +00:00
if err != nil {
return nil, err
}
p.doorOpen, err = p.chip.RequestLine(
pinDoorOpen,
2024-06-15 13:58:47 +00:00
gpiocdev.AsInput,
gpiocdev.LineBiasPullUp,
gpiocdev.WithDebounce(200*time.Millisecond),
gpiocdev.WithBothEdges,
gpiocdev.WithEventHandler(p.onDoorStateChanged),
)
if err != nil {
return nil, err
}
2022-07-23 23:16:40 +00:00
// Add an initial door reading to the channel to ensure correct state when booting
isDoorOpen, err := p.doorOpen.Value()
if err != nil {
return nil, err
}
switch isDoorOpen {
case 0: // Line is pulled low when door is open (circuit is closed)
p.C <- DoorOpened
default: // Pull-up resistor sets line high when door is closed (open circuit)
p.C <- DoorClosed
}
2024-06-15 13:58:47 +00:00
p.oneWirePower, err = p.chip.RequestLine(pinOneWirePower, gpiocdev.AsOutput(0))
if err != nil {
return nil, err
}
2024-06-15 13:58:47 +00:00
p.lightsPower, err = p.chip.RequestLine(pinLightsPower, gpiocdev.AsOutput(0))
if err != nil {
return nil, err
}
2024-06-15 13:58:47 +00:00
p.fanPower, err = p.chip.RequestLine(pinFanPower, gpiocdev.AsOutput(0))
if err != nil {
return nil, err
}
2024-06-15 13:58:47 +00:00
p.coolerPower, err = p.chip.RequestLine(pinCoolerPower, gpiocdev.AsOutput(0))
2021-08-10 21:29:24 +00:00
if err != nil {
return nil, err
}
2024-06-15 13:58:47 +00:00
p.heaterPower, err = p.chip.RequestLine(pinHeaterPower, gpiocdev.AsOutput(0))
2021-08-10 21:29:24 +00:00
if err != nil {
return nil, err
}
return p, nil
}
func (p *Gpio) Close() {
p.coolerPower.SetValue(off)
p.heaterPower.SetValue(off)
p.fanPower.SetValue(off)
p.lightsPower.SetValue(off)
p.oneWirePower.SetValue(off)
2021-08-10 21:29:24 +00:00
p.oneWirePower.Close()
2021-08-10 21:29:24 +00:00
p.heaterPower.Close()
p.coolerPower.Close()
p.fanPower.Close()
p.lightsPower.Close()
p.doorOpen.Close()
2021-08-10 21:29:24 +00:00
p.chip.Close()
close(p.C)
2021-08-10 21:29:24 +00:00
}
2021-08-30 20:46:38 +00:00
func (p *Gpio) StartCooler() {
p.coolerPower.SetValue(on)
}
func (p *Gpio) StopCooler() {
p.coolerPower.SetValue(off)
}
func (p *Gpio) StartHeater() {
p.heaterPower.SetValue(on)
}
func (p *Gpio) StopHeater() {
p.heaterPower.SetValue(off)
}
func (p *Gpio) StartFan() {
p.fanPower.SetValue(on)
}
func (p *Gpio) StopFan() {
p.fanPower.SetValue(off)
}
func (p *Gpio) LightsOn() {
p.lightsPower.SetValue(on)
}
func (p *Gpio) LightsOff() {
p.lightsPower.SetValue(off)
}
func (p *Gpio) StartOneWirePower() {
// Inverted logic due to PNP transistor switch
p.oneWirePower.SetValue(off)
}
func (p *Gpio) StopOneWirePower() {
// Inverted logic due to PNP transistor switch
p.oneWirePower.SetValue(on)
}
2024-06-15 13:58:47 +00:00
func (p *Gpio) onDoorStateChanged(le gpiocdev.LineEvent) {
switch le.Type {
2024-06-15 13:58:47 +00:00
case gpiocdev.LineEventFallingEdge:
p.C <- DoorOpened
2024-06-15 13:58:47 +00:00
case gpiocdev.LineEventRisingEdge:
p.C <- DoorClosed
}
}