Add display code
This commit is contained in:
parent
7adca39509
commit
37ffb95543
10 changed files with 271 additions and 89 deletions
|
@ -13,6 +13,7 @@ import (
|
|||
"git.joco.dk/sng/fermentord/internal/controllers"
|
||||
"git.joco.dk/sng/fermentord/internal/dwingest"
|
||||
"git.joco.dk/sng/fermentord/internal/hw"
|
||||
"git.joco.dk/sng/fermentord/internal/lcd"
|
||||
"git.joco.dk/sng/fermentord/internal/metrics"
|
||||
"git.joco.dk/sng/fermentord/pkg/daemon"
|
||||
"git.joco.dk/sng/fermentord/pkg/temperature"
|
||||
|
@ -29,6 +30,14 @@ func mainLoop(ctx context.Context, wg *sync.WaitGroup, js nats.JetStream, config
|
|||
defer hub.Flush(10 * time.Second)
|
||||
defer wg.Done()
|
||||
|
||||
// Display
|
||||
display, err := lcd.NewLCD()
|
||||
if err != nil {
|
||||
hub.CaptureException(err)
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer display.Close()
|
||||
|
||||
// Controller
|
||||
ctrl := controllers.NewChamberController("Chamber 1", *config)
|
||||
|
||||
|
@ -36,11 +45,17 @@ func mainLoop(ctx context.Context, wg *sync.WaitGroup, js nats.JetStream, config
|
|||
ingest := dwingest.NewDWIngest()
|
||||
|
||||
// Configuration reload
|
||||
loadConfiguration := func() {
|
||||
temperature.ConfigUpdate <- *config
|
||||
ctrl.ConfigUpdates <- *config
|
||||
display.SetSetpointTemp(config.FermentationTemperature)
|
||||
}
|
||||
|
||||
viper.OnConfigChange(func(in fsnotify.Event) {
|
||||
controllers.ReloadConfiguration(config, ctrl)
|
||||
loadConfiguration()
|
||||
})
|
||||
loadConfiguration()
|
||||
viper.WatchConfig()
|
||||
controllers.ReloadConfiguration(config, ctrl)
|
||||
|
||||
gpio, err := hw.NewGpio()
|
||||
if err != nil {
|
||||
|
@ -49,7 +64,8 @@ func mainLoop(ctx context.Context, wg *sync.WaitGroup, js nats.JetStream, config
|
|||
}
|
||||
defer gpio.Close()
|
||||
|
||||
wg.Add(4)
|
||||
wg.Add(5)
|
||||
go display.Run(ctx, wg)
|
||||
go ctrl.Run(ctx, wg)
|
||||
go ingest.Run(ctx, wg, js, config)
|
||||
go temperature.PollSensors(ctx, wg, 1*time.Second, config.Sensors.Weight)
|
||||
|
@ -57,13 +73,15 @@ func mainLoop(ctx context.Context, wg *sync.WaitGroup, js nats.JetStream, config
|
|||
|
||||
for {
|
||||
select {
|
||||
case reading := <-temperature.C:
|
||||
case reading := <-temperature.Reading:
|
||||
ctrl.SetTemperature(reading)
|
||||
ingest.AddReading(reading)
|
||||
display.SetTemperature(reading)
|
||||
|
||||
case state := <-ctrl.C:
|
||||
gpioSetState(state, gpio)
|
||||
ingest.AddState(state)
|
||||
display.SetState(state)
|
||||
|
||||
case <-ctx.Done():
|
||||
return
|
||||
|
|
5
go.mod
5
go.mod
|
@ -4,6 +4,8 @@ go 1.18
|
|||
|
||||
require (
|
||||
github.com/JuulLabs-OSS/ble v0.0.0-20200716215611-d4fcc9d598bb
|
||||
github.com/d2r2/go-hd44780 v0.0.0-20181002113701-74cc28c83a3e
|
||||
github.com/d2r2/go-i2c v0.0.0-20191123181816-73a8a799d6bc
|
||||
github.com/fsnotify/fsnotify v1.5.4
|
||||
github.com/getsentry/sentry-go v0.13.0
|
||||
github.com/nats-io/nats.go v1.15.0
|
||||
|
@ -17,6 +19,8 @@ require (
|
|||
github.com/JuulLabs-OSS/cbgo v0.0.1 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/d2r2/go-logger v0.0.0-20210606094344-60e9d1233e22 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3 // indirect
|
||||
|
@ -30,6 +34,7 @@ require (
|
|||
github.com/nats-io/nats-server/v2 v2.7.1 // indirect
|
||||
github.com/nats-io/nkeys v0.3.0 // indirect
|
||||
github.com/nats-io/nuid v1.0.1 // indirect
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 // indirect
|
||||
github.com/pelletier/go-toml v1.9.5 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.1 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
|
|
8
go.sum
8
go.sum
|
@ -63,6 +63,12 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX
|
|||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/d2r2/go-hd44780 v0.0.0-20181002113701-74cc28c83a3e h1:3gLJWdofXjBoecDb9e+giWp77saiF6r2Mtu+edWCksY=
|
||||
github.com/d2r2/go-hd44780 v0.0.0-20181002113701-74cc28c83a3e/go.mod h1:IruYZr0O1UbQs3rV5N2WPM8CpaT5rRgvPPzksu1+N6o=
|
||||
github.com/d2r2/go-i2c v0.0.0-20191123181816-73a8a799d6bc h1:HLRSIWzUGMLCq4ldt0W1GLs3nnAxa5EGoP+9qHgh6j0=
|
||||
github.com/d2r2/go-i2c v0.0.0-20191123181816-73a8a799d6bc/go.mod h1:AwxDPnsgIpy47jbGXZHA9Rv7pDkOJvQbezPuK1Y+nNk=
|
||||
github.com/d2r2/go-logger v0.0.0-20210606094344-60e9d1233e22 h1:nO+SY4KOMsF/LsZ5EtbSKhiT3M6sv/igo2PEru/xEHI=
|
||||
github.com/d2r2/go-logger v0.0.0-20210606094344-60e9d1233e22/go.mod h1:eSx+YfcVy5vCjRZBNIhpIpfCGFMQ6XSOSQkDk7+VCpg=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
|
@ -211,6 +217,8 @@ github.com/nats-io/nkeys v0.3.0 h1:cgM5tL53EvYRU+2YLXIK0G2mJtK12Ft9oeooSZMA2G8=
|
|||
github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4=
|
||||
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88=
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
|
||||
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU=
|
||||
|
|
|
@ -2,7 +2,6 @@ package controllers
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"sync"
|
||||
"time"
|
||||
|
@ -74,8 +73,10 @@ func (p *ChamberController) Run(ctx context.Context, wg *sync.WaitGroup) {
|
|||
state := p.computeChamberState()
|
||||
p.setChamberState(state)
|
||||
|
||||
case temp := <-p.chTemp:
|
||||
p.updateTemperature(temp)
|
||||
case t := <-p.chTemp:
|
||||
p.ambientTemperature = t.Ambient
|
||||
p.chamberTemperature = t.Chamber
|
||||
p.wortTemperature = t.Wort
|
||||
|
||||
case c := <-p.ConfigUpdates:
|
||||
p.config = c
|
||||
|
@ -95,23 +96,6 @@ func (p *ChamberController) SetTemperature(t temperature.TemperatureReading) {
|
|||
p.chTemp <- t
|
||||
}
|
||||
|
||||
func (p *ChamberController) updateTemperature(t temperature.TemperatureReading) {
|
||||
switch t.Sensor {
|
||||
case p.config.Sensors.Ambient:
|
||||
p.ambientTemperature = t.Degrees
|
||||
|
||||
case p.config.Sensors.Chamber:
|
||||
p.chamberTemperature = t.Degrees
|
||||
|
||||
case p.config.Sensors.Wort:
|
||||
p.wortTemperature = t.Degrees
|
||||
|
||||
default:
|
||||
log.Printf("Unknown sensor: sensor=%v temp=%v", t.Sensor, t.Degrees)
|
||||
p.hub.CaptureMessage(fmt.Sprintf("Unknown sensor: sensor=%v temp=%v", t.Sensor, t.Degrees))
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ChamberController) setChamberState(state ChamberState) {
|
||||
if state == p.chamberState {
|
||||
return
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
package controllers
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"git.joco.dk/sng/fermentord/internal/configuration"
|
||||
"git.joco.dk/sng/fermentord/pkg/temperature"
|
||||
)
|
||||
|
||||
func ReloadConfiguration(config *configuration.Configuration, ctrl *ChamberController) {
|
||||
log.Printf("Reloading configuration")
|
||||
|
||||
temperature.ConfigUpdates <- []string{
|
||||
config.Sensors.Ambient,
|
||||
config.Sensors.Chamber,
|
||||
config.Sensors.Wort,
|
||||
}
|
||||
|
||||
ctrl.ConfigUpdates <- *config
|
||||
}
|
146
internal/lcd/hd44780.go
Normal file
146
internal/lcd/hd44780.go
Normal file
|
@ -0,0 +1,146 @@
|
|||
package lcd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"git.joco.dk/sng/fermentord/internal/controllers"
|
||||
"git.joco.dk/sng/fermentord/pkg/temperature"
|
||||
device "github.com/d2r2/go-hd44780"
|
||||
"github.com/d2r2/go-i2c"
|
||||
)
|
||||
|
||||
type LCD struct {
|
||||
ambient, chamber, setpoint, wort float64
|
||||
state string
|
||||
|
||||
bus *i2c.I2C
|
||||
lcd *device.Lcd
|
||||
l1, l2 string
|
||||
chTemp chan temperature.TemperatureReading
|
||||
chState chan controllers.ChamberState
|
||||
chSetpoint chan float64
|
||||
}
|
||||
|
||||
func NewLCD() (*LCD, error) {
|
||||
var err error
|
||||
|
||||
p := &LCD{
|
||||
chTemp: make(chan temperature.TemperatureReading, 10),
|
||||
chState: make(chan controllers.ChamberState, 10),
|
||||
chSetpoint: make(chan float64, 10),
|
||||
}
|
||||
|
||||
p.bus, err = i2c.NewI2C(0x27, 2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p.lcd, err = device.NewLcd(p.bus, device.LCD_16x2)
|
||||
if err != nil {
|
||||
p.bus.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = p.lcd.BacklightOn()
|
||||
if err != nil {
|
||||
p.bus.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = p.lcd.ShowMessage("Fermentor", device.SHOW_LINE_1|device.SHOW_BLANK_PADDING)
|
||||
if err != nil {
|
||||
p.bus.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = p.lcd.ShowMessage("Initializing", device.SHOW_LINE_2|device.SHOW_BLANK_PADDING)
|
||||
if err != nil {
|
||||
p.bus.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return p, nil
|
||||
|
||||
}
|
||||
|
||||
func (p *LCD) Close() error {
|
||||
return p.bus.Close()
|
||||
}
|
||||
|
||||
func (p *LCD) SetTemperature(t temperature.TemperatureReading) {
|
||||
p.chTemp <- t
|
||||
}
|
||||
|
||||
func (p *LCD) SetSetpointTemp(t float64) {
|
||||
p.chSetpoint <- t
|
||||
}
|
||||
|
||||
func (p *LCD) SetState(state controllers.ChamberState) {
|
||||
p.chState <- state
|
||||
}
|
||||
|
||||
func (p *LCD) Run(ctx context.Context, wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
|
||||
for {
|
||||
select {
|
||||
case t := <-p.chTemp:
|
||||
p.ambient = t.Ambient
|
||||
p.chamber = t.Chamber
|
||||
p.wort = t.Wort
|
||||
p.update()
|
||||
|
||||
case state := <-p.chState:
|
||||
switch state {
|
||||
case controllers.ChamberStateIdle:
|
||||
p.state = "Id"
|
||||
|
||||
case controllers.ChamberStateHeating:
|
||||
p.state = "He"
|
||||
|
||||
case controllers.ChamberStateCooling:
|
||||
p.state = "Co"
|
||||
}
|
||||
p.update()
|
||||
|
||||
case t := <-p.chSetpoint:
|
||||
p.setpoint = t
|
||||
p.update()
|
||||
|
||||
case <-ctx.Done():
|
||||
p.lcd.ShowMessage("Fermentor", device.SHOW_LINE_1|device.SHOW_BLANK_PADDING)
|
||||
p.lcd.ShowMessage("Shutting down", device.SHOW_LINE_2|device.SHOW_BLANK_PADDING)
|
||||
|
||||
close(p.chSetpoint)
|
||||
close(p.chState)
|
||||
close(p.chTemp)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *LCD) update() error {
|
||||
l1 := fmt.Sprintf("W:%4.1f C:%4.1f %s", p.wort, p.chamber, p.state)
|
||||
l2 := fmt.Sprintf("S:%4.1f A:%4.1f", p.ambient, p.setpoint)
|
||||
|
||||
if l1 != p.l1 {
|
||||
if err := p.lcd.ShowMessage(l1, device.SHOW_LINE_1|device.SHOW_BLANK_PADDING); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.l1 = l1
|
||||
}
|
||||
|
||||
if l2 != p.l2 {
|
||||
if err := p.lcd.ShowMessage(l2, device.SHOW_LINE_2|device.SHOW_BLANK_PADDING); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.l2 = l2
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -14,6 +14,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"git.joco.dk/sng/fermentord/internal/configuration"
|
||||
"git.joco.dk/sng/fermentord/internal/metrics"
|
||||
"github.com/getsentry/sentry-go"
|
||||
)
|
||||
|
@ -21,6 +22,8 @@ import (
|
|||
type BulkReadBusState int
|
||||
|
||||
const (
|
||||
NaN = -999
|
||||
|
||||
BulkReadIdle BulkReadBusState = 0
|
||||
BulkReadBusy BulkReadBusState = -1
|
||||
BulkReadReady BulkReadBusState = 1
|
||||
|
@ -35,23 +38,26 @@ var (
|
|||
)
|
||||
|
||||
var (
|
||||
// C receives the temperature readings
|
||||
C chan TemperatureReading
|
||||
// Reading receives the temperature readings
|
||||
Reading chan TemperatureReading
|
||||
ConfigUpdate chan configuration.Configuration
|
||||
|
||||
// ConfigUpdates receives the list of sensors to read
|
||||
ConfigUpdates chan []string
|
||||
sensors []string
|
||||
accErrTrigger int
|
||||
accErrSensor map[string]int
|
||||
filters map[string]*EWMAFilter
|
||||
sensors []Sensor
|
||||
)
|
||||
|
||||
func init() {
|
||||
sensors = make([]string, 0)
|
||||
filters = make(map[string]*EWMAFilter)
|
||||
C = make(chan TemperatureReading, 30)
|
||||
ConfigUpdates = make(chan []string, 1)
|
||||
accErrSensor = make(map[string]int)
|
||||
Reading = make(chan TemperatureReading, 30)
|
||||
ConfigUpdate = make(chan configuration.Configuration)
|
||||
sensors = make([]Sensor, 0)
|
||||
}
|
||||
|
||||
func configure(config configuration.Configuration) {
|
||||
sensors = []Sensor{
|
||||
NewSensor("Ambient", config.Sensors.Ambient, config.Sensors.Weight),
|
||||
NewSensor("Chamber", config.Sensors.Chamber, config.Sensors.Weight),
|
||||
NewSensor("Wort", config.Sensors.Wort, config.Sensors.Weight),
|
||||
}
|
||||
}
|
||||
|
||||
func PollSensors(ctx context.Context, wg *sync.WaitGroup, readingInterval time.Duration, filterWeight float64) {
|
||||
|
@ -76,12 +82,6 @@ func PollSensors(ctx context.Context, wg *sync.WaitGroup, readingInterval time.D
|
|||
log.Fatal("Thermal bulk read failed 60 times in a row -- terminating")
|
||||
}
|
||||
|
||||
for _, sensor := range sensors {
|
||||
if accErrSensor[sensor] > 60 {
|
||||
log.Fatalf("Thermal sensor read of %v failed 60 times in a row -- terminating", sensor)
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger a bulk read to start conversion on all sensors.
|
||||
if err := triggerBulkRead(); err != nil {
|
||||
accErrTrigger++
|
||||
|
@ -118,52 +118,57 @@ func PollSensors(ctx context.Context, wg *sync.WaitGroup, readingInterval time.D
|
|||
readSensors(hub)
|
||||
}
|
||||
|
||||
case c := <-ConfigUpdates:
|
||||
sensors = c
|
||||
|
||||
for k := range filters {
|
||||
delete(filters, k)
|
||||
}
|
||||
for _, x := range sensors {
|
||||
filters[x] = NewEWMAFilter(filterWeight)
|
||||
}
|
||||
case c := <-ConfigUpdate:
|
||||
configure(c)
|
||||
|
||||
case <-ctx.Done():
|
||||
close(C)
|
||||
close(Reading)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func readSensors(hub *sentry.Hub) {
|
||||
r := TemperatureReading{
|
||||
Time: time.Now(),
|
||||
Ambient: NaN,
|
||||
Chamber: NaN,
|
||||
Wort: NaN,
|
||||
}
|
||||
|
||||
for _, sensor := range sensors {
|
||||
t, err := read(sensor)
|
||||
t, err := read(sensor.Path)
|
||||
|
||||
if err != nil {
|
||||
accErrSensor[sensor]++
|
||||
sensor.Fail()
|
||||
hub.CaptureException(err)
|
||||
log.Printf("Error reading temperature sensor %v: %v", sensor, err)
|
||||
metrics.TemperatureSensorReadingStatus.WithLabelValues(sensor, "failed").Inc()
|
||||
metrics.TemperatureSensorReadingStatus.WithLabelValues(sensor.Name, "failed").Inc()
|
||||
continue
|
||||
}
|
||||
|
||||
accErrSensor[sensor] = 0
|
||||
tw := filters[sensor].Update(float64(t) / 1000)
|
||||
tw := sensor.Update(t)
|
||||
|
||||
r := TemperatureReading{
|
||||
Time: time.Now(),
|
||||
Sensor: sensor,
|
||||
Degrees: tw,
|
||||
switch sensor.Name {
|
||||
case "Ambient":
|
||||
r.Ambient = tw
|
||||
|
||||
case "Chamber":
|
||||
r.Chamber = tw
|
||||
|
||||
case "Wort":
|
||||
r.Wort = tw
|
||||
}
|
||||
|
||||
// TODO Move metrics out
|
||||
metrics.TemperatureSensorReadingDegreesCelcius.
|
||||
WithLabelValues(sensor).
|
||||
WithLabelValues(sensor.Name).
|
||||
Set(tw)
|
||||
|
||||
C <- r
|
||||
|
||||
metrics.TemperatureSensorReadingStatus.WithLabelValues(sensor, "ok").Inc()
|
||||
metrics.TemperatureSensorReadingStatus.WithLabelValues(sensor.Name, "ok").Inc()
|
||||
}
|
||||
|
||||
Reading <- r
|
||||
}
|
||||
|
||||
func triggerBulkRead() error {
|
||||
|
|
|
@ -8,8 +8,8 @@ type EWMAFilter struct {
|
|||
isInitialized bool
|
||||
}
|
||||
|
||||
func NewEWMAFilter(weight float64) *EWMAFilter {
|
||||
return &EWMAFilter{
|
||||
func NewEWMAFilter(weight float64) EWMAFilter {
|
||||
return EWMAFilter{
|
||||
weight: weight,
|
||||
}
|
||||
}
|
||||
|
|
35
pkg/temperature/sensor.go
Normal file
35
pkg/temperature/sensor.go
Normal file
|
@ -0,0 +1,35 @@
|
|||
package temperature
|
||||
|
||||
import "log"
|
||||
|
||||
type Sensor struct {
|
||||
Name string
|
||||
Path string
|
||||
Filter EWMAFilter
|
||||
accErrors int
|
||||
}
|
||||
|
||||
func NewSensor(name, path string, weight float64) Sensor {
|
||||
return Sensor{
|
||||
Name: name,
|
||||
Path: path,
|
||||
Filter: NewEWMAFilter(weight),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Sensor) Update(value int64) float64 {
|
||||
p.accErrors = 0
|
||||
degrees := float64(value) / 1000
|
||||
|
||||
return p.Filter.Update(degrees)
|
||||
}
|
||||
|
||||
func (p *Sensor) Fail() error {
|
||||
p.accErrors++
|
||||
|
||||
if p.accErrors > 60 {
|
||||
log.Fatalf("Thermal sensor read of %v failed 60 times in a row -- terminating", p.Name)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -3,7 +3,8 @@ package temperature
|
|||
import "time"
|
||||
|
||||
type TemperatureReading struct {
|
||||
Sensor string `json:"sensor"`
|
||||
Time time.Time `json:"time"`
|
||||
Degrees float64 `json:"degrees"`
|
||||
Ambient float64 `json:"ambient"`
|
||||
Chamber float64 `json:"chamber"`
|
||||
Wort float64 `json:"wort"`
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue