Add more error output
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Søren Rasmussen 2022-07-25 10:55:25 +02:00
parent 9e9992a0d9
commit 7f4718fabc
9 changed files with 124 additions and 62 deletions

View file

@ -11,9 +11,10 @@ import (
) )
func shutdownHTTP(ctx context.Context, wg *sync.WaitGroup, srv *http.Server) { func shutdownHTTP(ctx context.Context, wg *sync.WaitGroup, srv *http.Server) {
defer wg.Done()
hub := sentry.CurrentHub().Clone() hub := sentry.CurrentHub().Clone()
defer hub.Flush(10 * time.Second) defer hub.Flush(10 * time.Second)
defer wg.Done()
ctx2, cancel := context.WithTimeout(ctx, 10*time.Second) ctx2, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel() defer cancel()

View file

@ -11,6 +11,7 @@ import (
"git.joco.dk/sng/fermentord/internal/controllers" "git.joco.dk/sng/fermentord/internal/controllers"
"git.joco.dk/sng/fermentord/internal/dwingest" "git.joco.dk/sng/fermentord/internal/dwingest"
"git.joco.dk/sng/fermentord/internal/hw" "git.joco.dk/sng/fermentord/internal/hw"
"git.joco.dk/sng/fermentord/internal/lcd"
"git.joco.dk/sng/fermentord/pkg/temperature" "git.joco.dk/sng/fermentord/pkg/temperature"
"git.joco.dk/sng/fermentord/pkg/tilt" "git.joco.dk/sng/fermentord/pkg/tilt"
"github.com/fsnotify/fsnotify" "github.com/fsnotify/fsnotify"
@ -20,18 +21,18 @@ import (
) )
func mainLoop(ctx context.Context, wg *sync.WaitGroup, js nats.JetStream, config *configuration.Configuration) { func mainLoop(ctx context.Context, wg *sync.WaitGroup, js nats.JetStream, config *configuration.Configuration) {
hub := sentry.CurrentHub().Clone()
defer hub.Flush(10 * time.Second)
defer wg.Done() defer wg.Done()
hub := sentry.CurrentHub().Clone()
defer hub.Flush(10 * time.Second)
// Display // Display
/*display, err := lcd.NewLCD() display, err := lcd.NewLCD()
if err != nil { if err != nil {
hub.CaptureException(err) hub.CaptureException(err)
log.Fatal(err) log.Fatal(err)
} }
defer display.Close() defer display.Close()
*/
// Controller // Controller
ctrl := controllers.NewChamberController(*config) ctrl := controllers.NewChamberController(*config)
@ -60,8 +61,8 @@ func mainLoop(ctx context.Context, wg *sync.WaitGroup, js nats.JetStream, config
} }
defer gpio.Close() defer gpio.Close()
wg.Add(4) wg.Add(5)
//go display.Run(ctx, wg) go display.Run(ctx, wg)
go ctrl.Run(ctx, wg) go ctrl.Run(ctx, wg)
go ingest.Run(ctx, wg, js, config) go ingest.Run(ctx, wg, js, config)
go temperature.PollSensors(ctx, wg, 1*time.Second, config.Sensors.Weight) go temperature.PollSensors(ctx, wg, 1*time.Second, config.Sensors.Weight)

View file

@ -57,8 +57,7 @@ func main() {
mux.HandleFunc("/health", api.HealthCheck) mux.HandleFunc("/health", api.HealthCheck)
// Main // Main
ctxb := context.Background() ctx, shutdown := context.WithCancel(context.Background())
ctx, shutdown := context.WithCancel(ctxb)
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
wg.Add(1) wg.Add(1)
@ -71,7 +70,7 @@ func main() {
// Initiate graceful shutdown. // Initiate graceful shutdown.
wg.Add(1) wg.Add(1)
go shutdownHTTP(ctxb, wg, srv) go shutdownHTTP(context.Background(), wg, srv)
shutdown() shutdown()
wg.Wait() wg.Wait()
nc.Close() nc.Close()

View file

@ -2,7 +2,6 @@ package configuration
import ( import (
"log" "log"
"time"
"github.com/getsentry/sentry-go" "github.com/getsentry/sentry-go"
"github.com/spf13/viper" "github.com/spf13/viper"
@ -56,9 +55,6 @@ type Configuration struct {
} }
func LoadConfiguration() *Configuration { func LoadConfiguration() *Configuration {
hub := sentry.CurrentHub().Clone()
defer hub.Flush(10 * time.Second)
viper.SetDefault("cooler_enabled", true) viper.SetDefault("cooler_enabled", true)
viper.SetDefault("heater_enabled", true) viper.SetDefault("heater_enabled", true)
viper.SetDefault("http.port", 8000) viper.SetDefault("http.port", 8000)
@ -91,7 +87,7 @@ func LoadConfiguration() *Configuration {
config := &Configuration{} config := &Configuration{}
if err := viper.Unmarshal(config); err != nil { if err := viper.Unmarshal(config); err != nil {
hub.CaptureException(err) sentry.CaptureException(err)
log.Fatal(err) log.Fatal(err)
} }

View file

@ -2,6 +2,7 @@ package controllers
import ( import (
"context" "context"
"fmt"
"log" "log"
"sync" "sync"
"time" "time"
@ -62,8 +63,8 @@ func NewChamberController(config configuration.Configuration) *ChamberController
} }
func (p *ChamberController) Run(ctx context.Context, wg *sync.WaitGroup) { func (p *ChamberController) Run(ctx context.Context, wg *sync.WaitGroup) {
defer p.hub.Flush(10 * time.Second)
defer wg.Done() defer wg.Done()
defer p.hub.Flush(10 * time.Second)
ticker := time.NewTicker(1 * time.Second) ticker := time.NewTicker(1 * time.Second)
@ -173,9 +174,10 @@ func (p *ChamberController) computeChamberState() ChamberState {
//p.chamberTemperature > chamberTargetTemp+p.config.DeltaTemperatureCool //p.chamberTemperature > chamberTargetTemp+p.config.DeltaTemperatureCool
if cooler && heater { if cooler && heater {
// This should not happen! // This should NOT happen!
log.Print("Trying to set cooler and heater on at the same time. This should NOT happen! Setting IDLE mode.") err := fmt.Errorf("heater and cooler activated at same time")
p.hub.CaptureMessage("Trying to set cooler and heater on at the same time") p.hub.CaptureException(err)
log.Print(err)
next = ChamberStateIdle next = ChamberStateIdle
} else if !cooler && !heater { } else if !cooler && !heater {
next = ChamberStateIdle next = ChamberStateIdle

View file

@ -3,6 +3,7 @@ package dwingest
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"fmt"
"log" "log"
"sync" "sync"
"time" "time"
@ -18,61 +19,66 @@ import (
type DWIngest struct { type DWIngest struct {
chTemperatureReading chan temperature.TemperatureReading chTemperatureReading chan temperature.TemperatureReading
chState chan controllers.ChamberState chState chan controllers.ChamberState
hub *sentry.Hub
} }
func NewDWIngest() *DWIngest { func NewDWIngest() *DWIngest {
return &DWIngest{ return &DWIngest{
chTemperatureReading: make(chan temperature.TemperatureReading, 3600), chTemperatureReading: make(chan temperature.TemperatureReading, 3600),
chState: make(chan controllers.ChamberState, 100), chState: make(chan controllers.ChamberState, 100),
hub: sentry.CurrentHub().Clone(),
} }
} }
func (p *DWIngest) AddReading(reading temperature.TemperatureReading) { func (p *DWIngest) AddReading(reading temperature.TemperatureReading) {
// Non-blocking send
select { select {
case p.chTemperatureReading <- reading: case p.chTemperatureReading <- reading:
break
default: default:
err := fmt.Errorf("channel overflow on dwingest temperature channel")
p.hub.CaptureException(err)
log.Print(err)
} }
} }
func (p *DWIngest) AddState(state controllers.ChamberState) { func (p *DWIngest) AddState(state controllers.ChamberState) {
// Non-blocking send
select { select {
case p.chState <- state: case p.chState <- state:
break
default: default:
err := fmt.Errorf("channel overflow on dwingest state channel")
p.hub.CaptureException(err)
log.Print(err)
} }
} }
func (p *DWIngest) Run(ctx context.Context, wg *sync.WaitGroup, js nats.JetStream, config *configuration.Configuration) { func (p *DWIngest) Run(ctx context.Context, wg *sync.WaitGroup, js nats.JetStream, config *configuration.Configuration) {
hub := sentry.CurrentHub().Clone()
defer hub.Flush(10 * time.Second)
defer wg.Done() defer wg.Done()
defer p.hub.Flush(10 * time.Second)
for { for {
select { select {
case reading := <-p.chTemperatureReading: case reading := <-p.chTemperatureReading:
publish(config.NATS.Subject.Temp, js, hub, reading) publish(config.NATS.Subject.Temp, js, p.hub, reading)
case state := <-p.chState: case state := <-p.chState:
reading := State{ publish(config.NATS.Subject.State, js, p.hub, State{
Time: time.Now().UTC(), Time: time.Now().UTC(),
State: controllers.ChamberStateMap[state], State: controllers.ChamberStateMap[state],
} })
publish(config.NATS.Subject.State, js, hub, reading)
case t := <-tilt.C: case t := <-tilt.C:
reading := Tilt{ publish(config.NATS.Subject.Tilt, js, p.hub, Tilt{
Time: time.Now().UTC(), Time: time.Now().UTC(),
Color: string(t.Color()), Color: string(t.Color()),
Gravity: t.Gravity(), Gravity: t.Gravity(),
Temperature: t.Celsius(), Temperature: t.Celsius(),
} })
publish(config.NATS.Subject.Tilt, js, hub, reading)
case <-ctx.Done(): case <-ctx.Done():
close(p.chTemperatureReading)
close(p.chState)
return return
} }
} }

View file

@ -11,6 +11,7 @@ import (
"git.joco.dk/sng/fermentord/pkg/temperature" "git.joco.dk/sng/fermentord/pkg/temperature"
device "github.com/d2r2/go-hd44780" device "github.com/d2r2/go-hd44780"
"github.com/d2r2/go-i2c" "github.com/d2r2/go-i2c"
"github.com/getsentry/sentry-go"
) )
type LCD struct { type LCD struct {
@ -24,6 +25,7 @@ type LCD struct {
chState chan controllers.ChamberState chState chan controllers.ChamberState
chSetpoint chan float64 chSetpoint chan float64
lastUpdate time.Time lastUpdate time.Time
hub *sentry.Hub
} }
func NewLCD() (*LCD, error) { func NewLCD() (*LCD, error) {
@ -34,6 +36,7 @@ func NewLCD() (*LCD, error) {
chState: make(chan controllers.ChamberState, 10), chState: make(chan controllers.ChamberState, 10),
chSetpoint: make(chan float64, 10), chSetpoint: make(chan float64, 10),
lastUpdate: time.Now(), lastUpdate: time.Now(),
hub: sentry.CurrentHub().Clone(),
} }
p.bus, err = i2c.NewI2C(0x27, 0) p.bus, err = i2c.NewI2C(0x27, 0)
@ -47,30 +50,32 @@ func NewLCD() (*LCD, error) {
return nil, err return nil, err
} }
err = p.lcd.BacklightOn() err = p.lcd.BacklightOff()
if err != nil { if err != nil {
p.bus.Close() p.bus.Close()
return nil, err return nil, err
} }
/*
err = p.lcd.ShowMessage("Fermentor", device.SHOW_LINE_1) err = p.lcd.ShowMessage("Fermentor", device.SHOW_LINE_1)
if err != nil { if err != nil {
p.bus.Close() p.bus.Close()
return nil, err return nil, err
} }
err = p.lcd.ShowMessage("Initializing", device.SHOW_LINE_2 /*|device.SHOW_BLANK_PADDING*/) err = p.lcd.ShowMessage("Initializing", device.SHOW_LINE_2|device.SHOW_BLANK_PADDING)
if err != nil { if err != nil {
p.bus.Close() p.bus.Close()
return nil, err return nil, err
} }
*/
return p, nil return p, nil
} }
func (p *LCD) Close() error { func (p *LCD) Close() error {
if err := p.lcd.BacklightOff(); err != nil { if err := p.lcd.BacklightOff(); err != nil {
p.hub.CaptureException(err)
log.Print(err) log.Print(err)
} }
@ -78,19 +83,44 @@ func (p *LCD) Close() error {
} }
func (p *LCD) SetTemperature(t temperature.TemperatureReading) { func (p *LCD) SetTemperature(t temperature.TemperatureReading) {
p.chTemp <- t select {
case p.chTemp <- t:
break
default:
err := fmt.Errorf("channel overflow on display temperature channel")
p.hub.CaptureException(err)
log.Print(err)
}
} }
func (p *LCD) SetSetpointTemp(t float64) { func (p *LCD) SetSetpointTemp(t float64) {
p.chSetpoint <- t select {
case p.chSetpoint <- t:
break
default:
err := fmt.Errorf("channel overflow on display setpoint temperature channel")
p.hub.CaptureException(err)
log.Print(err)
}
} }
func (p *LCD) SetState(state controllers.ChamberState) { func (p *LCD) SetState(state controllers.ChamberState) {
p.chState <- state select {
case p.chState <- state:
break
default:
err := fmt.Errorf("channel overflow on display state channel")
p.hub.CaptureException(err)
log.Print(err)
}
} }
func (p *LCD) Run(ctx context.Context, wg *sync.WaitGroup) { func (p *LCD) Run(ctx context.Context, wg *sync.WaitGroup) {
defer wg.Done() defer wg.Done()
defer p.hub.Flush(10 * time.Second)
for { for {
select { select {
@ -98,7 +128,11 @@ func (p *LCD) Run(ctx context.Context, wg *sync.WaitGroup) {
p.ambient = t.Ambient p.ambient = t.Ambient
p.chamber = t.Chamber p.chamber = t.Chamber
p.wort = t.Wort p.wort = t.Wort
p.update()
if err := p.update(); err != nil {
p.hub.CaptureException(err)
log.Print(err)
}
case state := <-p.chState: case state := <-p.chState:
switch state { switch state {
@ -111,19 +145,29 @@ func (p *LCD) Run(ctx context.Context, wg *sync.WaitGroup) {
case controllers.ChamberStateCooling: case controllers.ChamberStateCooling:
p.state = "Co" p.state = "Co"
} }
p.update()
if err := p.update(); err != nil {
p.hub.CaptureException(err)
log.Print(err)
}
case t := <-p.chSetpoint: case t := <-p.chSetpoint:
p.setpoint = t p.setpoint = t
p.update()
if err := p.update(); err != nil {
p.hub.CaptureException(err)
log.Print(err)
}
case <-ctx.Done(): case <-ctx.Done():
p.lcd.ShowMessage("Fermentor", device.SHOW_LINE_1|device.SHOW_BLANK_PADDING) if err := p.lcd.ShowMessage("Fermentor", device.SHOW_LINE_1|device.SHOW_BLANK_PADDING); err != nil {
p.lcd.ShowMessage("Shutting down", device.SHOW_LINE_2|device.SHOW_BLANK_PADDING) p.hub.CaptureException(err)
log.Print(err)
close(p.chSetpoint) }
close(p.chState) if err := p.lcd.ShowMessage("Shutting down", device.SHOW_LINE_2|device.SHOW_BLANK_PADDING); err != nil {
close(p.chTemp) p.hub.CaptureException(err)
log.Print(err)
}
return return
} }

View file

@ -5,6 +5,7 @@ package temperature
import ( import (
"context" "context"
"errors" "errors"
"fmt"
"io/ioutil" "io/ioutil"
"log" "log"
"os" "os"
@ -61,9 +62,10 @@ func configure(config configuration.Configuration) {
} }
func PollSensors(ctx context.Context, wg *sync.WaitGroup, readingInterval time.Duration, filterWeight float64) { func PollSensors(ctx context.Context, wg *sync.WaitGroup, readingInterval time.Duration, filterWeight float64) {
defer wg.Done()
hub := sentry.CurrentHub().Clone() hub := sentry.CurrentHub().Clone()
defer hub.Flush(10 * time.Second) defer hub.Flush(10 * time.Second)
defer wg.Done()
if readingInterval < sensorConversionTime { if readingInterval < sensorConversionTime {
log.Fatalf("Reading interval must be at least %v ms.", sensorConversionTime) log.Fatalf("Reading interval must be at least %v ms.", sensorConversionTime)
@ -179,7 +181,9 @@ func readSensors(hub *sentry.Hub) {
break break
default: default:
log.Fatal("Temperature channel overflow!") err := fmt.Errorf("channel overflow on ds18b20 temperature channel")
hub.CaptureException(err)
log.Fatal(err)
} }
} }
@ -219,12 +223,12 @@ func read(sensor string) (int64, error) {
raw := string(data) raw := string(data)
if !strings.Contains(raw, " YES") { if !strings.Contains(raw, " YES") {
return 0.0, ErrReadSensor return 0.0, fmt.Errorf("%w: checksum failed", ErrReadSensor)
} }
i := strings.LastIndex(raw, "t=") i := strings.LastIndex(raw, "t=")
if i == -1 { if i == -1 {
return 0.0, ErrReadSensor return 0.0, fmt.Errorf("%w: t= not found", ErrReadSensor)
} }
c, err := strconv.ParseInt(raw[i+2:len(raw)-1], 10, 64) c, err := strconv.ParseInt(raw[i+2:len(raw)-1], 10, 64)

View file

@ -2,21 +2,27 @@ package tilt
import ( import (
"context" "context"
"fmt"
"log" "log"
"sync" "sync"
"time" "time"
"github.com/getsentry/sentry-go"
) )
var ( var (
C chan Tilt C chan Tilt
hub *sentry.Hub
) )
func init() { func init() {
C = make(chan Tilt, 10) C = make(chan Tilt, 10)
hub = sentry.CurrentHub().Clone()
} }
func PollSensors(ctx context.Context, wg *sync.WaitGroup, interval time.Duration, scanDuration time.Duration) { func PollSensors(ctx context.Context, wg *sync.WaitGroup, interval time.Duration, scanDuration time.Duration) {
defer wg.Done() defer wg.Done()
defer hub.Flush(10 * time.Second)
if interval < scanDuration { if interval < scanDuration {
log.Fatal("Unable to use interval < scanDuration") log.Fatal("Unable to use interval < scanDuration")
@ -54,6 +60,9 @@ func scan(ctx context.Context, timeout time.Duration) {
// Message sent // Message sent
default: default:
// No recipients on channel // No recipients on channel
err := fmt.Errorf("channel overflow on tilt reading channel")
hub.CaptureException(err)
log.Print(err)
} }
} }
} }