Reset 1-wire bus when temperature readings fail 60 consecutive times
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
dac484d802
commit
e25905c20f
5 changed files with 79 additions and 26 deletions
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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"`
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
)
|
)
|
||||||
|
@ -26,12 +30,13 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Gpio struct {
|
type Gpio struct {
|
||||||
chip *gpiod.Chip
|
chip *gpiod.Chip
|
||||||
doorOpen *gpiod.Line
|
doorOpen *gpiod.Line
|
||||||
lightsPower *gpiod.Line
|
oneWirePower *gpiod.Line
|
||||||
fanPower *gpiod.Line
|
lightsPower *gpiod.Line
|
||||||
coolerPower *gpiod.Line
|
fanPower *gpiod.Line
|
||||||
heaterPower *gpiod.Line
|
coolerPower *gpiod.Line
|
||||||
|
heaterPower *gpiod.Line
|
||||||
|
|
||||||
C chan HWEvent
|
C chan HWEvent
|
||||||
}
|
}
|
||||||
|
@ -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:
|
||||||
|
|
|
@ -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,7 +120,16 @@ func PollSensors(ctx context.Context, wg *sync.WaitGroup, readingInterval time.D
|
||||||
}
|
}
|
||||||
|
|
||||||
if accErrTrigger > 60 {
|
if accErrTrigger > 60 {
|
||||||
log.Fatal("Thermal bulk read failed 60 times in a row -- terminating")
|
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")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case c := <-ConfigUpdate:
|
case c := <-ConfigUpdate:
|
||||||
|
|
Loading…
Reference in a new issue