Reset 1-wire bus when temperature readings fail 60 consecutive times
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Søren Rasmussen 2022-08-01 19:49:52 +02:00
parent dac484d802
commit e25905c20f
5 changed files with 79 additions and 26 deletions

View file

@ -2,7 +2,6 @@ package main
import ( import (
"context" "context"
"encoding/json"
"log" "log"
"sync" "sync"
"time" "time"
@ -68,6 +67,11 @@ func mainLoop(ctx context.Context, wg *sync.WaitGroup, js nats.JetStream, config
go temperature.PollSensors(ctx, wg, 1*time.Second, config.Sensors.Weight) go temperature.PollSensors(ctx, wg, 1*time.Second, config.Sensors.Weight)
go tilt.PollSensors(ctx, wg, 1*time.Minute, 20*time.Second) go tilt.PollSensors(ctx, wg, 1*time.Minute, 20*time.Second)
oneWirePowerUpChannel := make(chan bool)
oneWirePowerUpTimer := time.AfterFunc(1*time.Millisecond, func() {
oneWirePowerUpChannel <- true
})
for { for {
select { select {
case reading := <-temperature.Reading: case reading := <-temperature.Reading:
@ -75,6 +79,25 @@ func mainLoop(ctx context.Context, wg *sync.WaitGroup, js nats.JetStream, config
ingest.AddReading(reading) ingest.AddReading(reading)
//display.SetTemperature(reading) //display.SetTemperature(reading)
case <-temperature.RequestReset:
log.Print("Powering down one wire bus for 20 seconds")
gpio.StopOneWirePower()
oneWirePowerUpTimer.Reset(20 * time.Second)
// Publish to NATS
e := dwingest.Event{
Time: time.Now().UTC(),
Event: "ONEWIRE_RESET",
}
if err := ingest.Publish(config.NATS.Subject.Event, js, e); err != nil {
hub.CaptureException(err)
log.Print(err)
}
case <-oneWirePowerUpChannel:
log.Print("Powering up one wire bus")
gpio.StartOneWirePower()
case ev := <-gpio.C: case ev := <-gpio.C:
var evs string var evs string
@ -96,19 +119,12 @@ func mainLoop(ctx context.Context, wg *sync.WaitGroup, js nats.JetStream, config
evs = "DOOR_OPENED" evs = "DOOR_OPENED"
} }
b, err := json.Marshal(map[string]interface{}{
"time": time.Now().UTC(),
"event": evs,
})
if err != nil {
hub.CaptureException(err)
log.Printf("Error marshaling JSON: %v", err)
break
}
// Publish to NATS // Publish to NATS
_, err = js.Publish(config.NATS.Subject.Event, b, nats.AckWait(1*time.Second)) e := dwingest.Event{
if err != nil { Time: time.Now().UTC(),
Event: evs,
}
if err := ingest.Publish(config.NATS.Subject.Event, js, e); err != nil {
hub.CaptureException(err) hub.CaptureException(err)
log.Print(err) log.Print(err)
} }

View file

@ -64,16 +64,16 @@ func (p *DWIngest) Run(ctx context.Context, wg *sync.WaitGroup, js nats.JetStrea
for { for {
select { select {
case reading := <-p.chTemperatureReading: case reading := <-p.chTemperatureReading:
p.publish(config.NATS.Subject.Temp, js, reading) p.Publish(config.NATS.Subject.Temp, js, reading)
case state := <-p.chState: case state := <-p.chState:
p.publish(config.NATS.Subject.State, js, State{ p.Publish(config.NATS.Subject.State, js, State{
Time: time.Now().UTC(), Time: time.Now().UTC(),
State: controllers.ChamberStateMap[state], State: controllers.ChamberStateMap[state],
}) })
case t := <-tilt.C: case t := <-tilt.C:
p.publish(config.NATS.Subject.Tilt, js, Tilt{ p.Publish(config.NATS.Subject.Tilt, js, Tilt{
Time: time.Now().UTC(), Time: time.Now().UTC(),
Color: string(t.Color()), Color: string(t.Color()),
Gravity: t.Gravity(), Gravity: t.Gravity(),
@ -86,7 +86,7 @@ func (p *DWIngest) Run(ctx context.Context, wg *sync.WaitGroup, js nats.JetStrea
} }
} }
func (p *DWIngest) publish(subject string, js nats.JetStream, reading any) error { func (p *DWIngest) Publish(subject string, js nats.JetStream, reading any) error {
b, err := json.Marshal(reading) b, err := json.Marshal(reading)
if err != nil { if err != nil {
p.hub.CaptureException(err) p.hub.CaptureException(err)

View file

@ -13,3 +13,8 @@ type Tilt struct {
Gravity float64 `json:"gravity"` Gravity float64 `json:"gravity"`
Temperature float64 `json:"temperature"` Temperature float64 `json:"temperature"`
} }
type Event struct {
Time time.Time `json:"time"`
Event string `json:"event"`
}

View file

@ -13,6 +13,10 @@ const (
pinHeaterPower = 24 pinHeaterPower = 24
pinLightsPower = 25 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 off = 0
on = 1 on = 1
) )
@ -28,6 +32,7 @@ const (
type Gpio struct { type Gpio struct {
chip *gpiod.Chip chip *gpiod.Chip
doorOpen *gpiod.Line doorOpen *gpiod.Line
oneWirePower *gpiod.Line
lightsPower *gpiod.Line lightsPower *gpiod.Line
fanPower *gpiod.Line fanPower *gpiod.Line
coolerPower *gpiod.Line coolerPower *gpiod.Line
@ -71,6 +76,11 @@ func NewGpio() (*Gpio, error) {
p.C <- DoorClosed p.C <- DoorClosed
} }
p.oneWirePower, err = p.chip.RequestLine(pinOneWirePower, gpiod.AsOutput(0))
if err != nil {
return nil, err
}
p.lightsPower, err = p.chip.RequestLine(pinLightsPower, gpiod.AsOutput(0)) p.lightsPower, err = p.chip.RequestLine(pinLightsPower, gpiod.AsOutput(0))
if err != nil { if err != nil {
return nil, err return nil, err
@ -99,7 +109,9 @@ func (p *Gpio) Close() {
p.heaterPower.SetValue(off) p.heaterPower.SetValue(off)
p.fanPower.SetValue(off) p.fanPower.SetValue(off)
p.lightsPower.SetValue(off) p.lightsPower.SetValue(off)
p.oneWirePower.SetValue(off)
p.oneWirePower.Close()
p.heaterPower.Close() p.heaterPower.Close()
p.coolerPower.Close() p.coolerPower.Close()
p.fanPower.Close() p.fanPower.Close()
@ -142,6 +154,16 @@ func (p *Gpio) LightsOff() {
p.lightsPower.SetValue(off) 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 gpiod.LineEvent) { func (p *Gpio) onDoorStateChanged(le gpiod.LineEvent) {
switch le.Type { switch le.Type {
case gpiod.LineEventFallingEdge: case gpiod.LineEventFallingEdge:

View file

@ -42,6 +42,7 @@ var (
// Reading receives the temperature readings // Reading receives the temperature readings
Reading chan TemperatureReading Reading chan TemperatureReading
ConfigUpdate chan configuration.Configuration ConfigUpdate chan configuration.Configuration
RequestReset chan bool
accErrTrigger int accErrTrigger int
sensors []Sensor sensors []Sensor
@ -50,6 +51,7 @@ var (
func init() { func init() {
Reading = make(chan TemperatureReading, 30) Reading = make(chan TemperatureReading, 30)
ConfigUpdate = make(chan configuration.Configuration, 1) ConfigUpdate = make(chan configuration.Configuration, 1)
RequestReset = make(chan bool)
sensors = make([]Sensor, 0) sensors = make([]Sensor, 0)
} }
@ -75,7 +77,6 @@ func PollSensors(ctx context.Context, wg *sync.WaitGroup, readingInterval time.D
defer ticker.Stop() defer ticker.Stop()
for { for {
work_loop:
select { select {
case <-ticker.C: case <-ticker.C:
poll_bus: poll_bus:
@ -100,7 +101,7 @@ func PollSensors(ctx context.Context, wg *sync.WaitGroup, readingInterval time.D
accErrTrigger++ accErrTrigger++
hub.CaptureException(err) hub.CaptureException(err)
log.Print(err) log.Print(err)
break work_loop break
} }
accErrTrigger = 0 accErrTrigger = 0
@ -119,8 +120,17 @@ func PollSensors(ctx context.Context, wg *sync.WaitGroup, readingInterval time.D
} }
if accErrTrigger > 60 { if accErrTrigger > 60 {
select {
case RequestReset <- true:
log.Print("Thermal bulk read failed 60 times in a row -- bus reset")
// Reset counter to allow 60 more reads
accErrTrigger = 0
default:
log.Fatal("Thermal bulk read failed 60 times in a row -- terminating") log.Fatal("Thermal bulk read failed 60 times in a row -- terminating")
} }
}
case c := <-ConfigUpdate: case c := <-ConfigUpdate:
configure(c) configure(c)