package hw import ( "time" "github.com/warthog618/go-gpiocdev" ) const ( pinDoorOpen = 17 pinFanPower = 22 pinCoolerPower = 23 pinHeaterPower = 24 pinLightsPower = 25 // GPIO21 is located at pin 13 on RPi 1B rev 1. Rev 2 and never boards // has GPIO27 here. pinOneWirePower = 21 off = 0 on = 1 ) type HWEvent int const ( NoOp HWEvent = iota DoorClosed DoorOpened ) type Gpio struct { chip *gpiocdev.Chip doorOpen *gpiocdev.Line oneWirePower *gpiocdev.Line lightsPower *gpiocdev.Line fanPower *gpiocdev.Line coolerPower *gpiocdev.Line heaterPower *gpiocdev.Line C chan HWEvent } func NewGpio() (*Gpio, error) { var err error p := &Gpio{ C: make(chan HWEvent, 1), } p.chip, err = gpiocdev.NewChip("gpiochip0", gpiocdev.WithConsumer("fermentord")) if err != nil { return nil, err } p.doorOpen, err = p.chip.RequestLine( pinDoorOpen, gpiocdev.AsInput, gpiocdev.LineBiasPullUp, gpiocdev.WithDebounce(200*time.Millisecond), gpiocdev.WithBothEdges, gpiocdev.WithEventHandler(p.onDoorStateChanged), ) if err != nil { return nil, err } // 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 } p.oneWirePower, err = p.chip.RequestLine(pinOneWirePower, gpiocdev.AsOutput(0)) if err != nil { return nil, err } p.lightsPower, err = p.chip.RequestLine(pinLightsPower, gpiocdev.AsOutput(0)) if err != nil { return nil, err } p.fanPower, err = p.chip.RequestLine(pinFanPower, gpiocdev.AsOutput(0)) if err != nil { return nil, err } p.coolerPower, err = p.chip.RequestLine(pinCoolerPower, gpiocdev.AsOutput(0)) if err != nil { return nil, err } p.heaterPower, err = p.chip.RequestLine(pinHeaterPower, gpiocdev.AsOutput(0)) 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) p.oneWirePower.Close() p.heaterPower.Close() p.coolerPower.Close() p.fanPower.Close() p.lightsPower.Close() p.doorOpen.Close() p.chip.Close() close(p.C) } 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) } func (p *Gpio) onDoorStateChanged(le gpiocdev.LineEvent) { switch le.Type { case gpiocdev.LineEventFallingEdge: p.C <- DoorOpened case gpiocdev.LineEventRisingEdge: p.C <- DoorClosed } }