Add sensor weight
This commit is contained in:
parent
e5d5b6ca2f
commit
2d4dfa73d6
7 changed files with 61 additions and 26 deletions
|
@ -55,7 +55,7 @@ func persistData(ctx context.Context, wg *sync.WaitGroup, chState <-chan control
|
|||
break
|
||||
}
|
||||
|
||||
err := datlog("%v TEMP %v %v", t.Time.Unix(), t.Sensor, t.MilliDegrees)
|
||||
err := datlog("%v TEMP %v %v", t.Time.Unix(), t.Sensor, t.Degrees)
|
||||
if err != nil {
|
||||
hub.CaptureException(err)
|
||||
log.Printf("Error persisting temperature reading: %v", err)
|
||||
|
|
|
@ -56,7 +56,7 @@ func mainLoop(ctx context.Context, wg *sync.WaitGroup, js nats.JetStream, config
|
|||
wg.Add(3)
|
||||
go persistData(ctx, wg, chDbState, chDbTemp, config)
|
||||
go ctrl.Run(ctx, wg)
|
||||
go temperature.PollSensors(ctx, wg, 1*time.Second)
|
||||
go temperature.PollSensors(ctx, wg, 1*time.Second, config.Sensors.Weight)
|
||||
|
||||
for {
|
||||
select {
|
||||
|
|
|
@ -89,18 +89,18 @@ func (p *ChamberController) Run(ctx context.Context, wg *sync.WaitGroup) {
|
|||
|
||||
func (p *ChamberController) setTemperature(t temperature.TemperatureReading) {
|
||||
switch t.Sensor {
|
||||
case p.config.Sensor.Ambient:
|
||||
p.ambientTemperature = t.Degrees()
|
||||
case p.config.Sensors.Ambient:
|
||||
p.ambientTemperature = t.Degrees
|
||||
|
||||
case p.config.Sensor.Chamber:
|
||||
p.chamberTemperature = t.Degrees()
|
||||
case p.config.Sensors.Chamber:
|
||||
p.chamberTemperature = t.Degrees
|
||||
|
||||
case p.config.Sensor.Wort:
|
||||
p.wortTemperature = t.Degrees()
|
||||
case p.config.Sensors.Wort:
|
||||
p.wortTemperature = t.Degrees
|
||||
|
||||
default:
|
||||
log.Printf("Unknown sensor: sensor=%v temp=%v", t.Sensor, t.MilliDegrees)
|
||||
p.hub.CaptureMessage(fmt.Sprintf("Unknown sensor: sensor=%v temp=%v", t.Sensor, t.MilliDegrees))
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,10 +16,11 @@ type ControllerConfig struct {
|
|||
|
||||
DataPath string `mapstructure:"data_path"`
|
||||
|
||||
Sensor struct {
|
||||
Wort string `mapstructure:"wort"`
|
||||
Chamber string `mapstructure:"chamber"`
|
||||
Ambient string `mapstructure:"ambient"`
|
||||
Sensors struct {
|
||||
Wort string `mapstructure:"wort"`
|
||||
Chamber string `mapstructure:"chamber"`
|
||||
Ambient string `mapstructure:"ambient"`
|
||||
Weight float64 `mapstructure:"weight"`
|
||||
} `mapstructure:"sensors"`
|
||||
|
||||
FermentationTemperature float64 `mapstructure:"fermentation_temp"`
|
||||
|
|
|
@ -36,16 +36,18 @@ var (
|
|||
sensors []string
|
||||
accErrTrigger int
|
||||
accErrSensor map[string]int
|
||||
filters map[string]*EWMAFilter
|
||||
)
|
||||
|
||||
func Initialize() {
|
||||
sensors = make([]string, 0)
|
||||
filters = make(map[string]*EWMAFilter)
|
||||
C = make(chan TemperatureReading, 30)
|
||||
ConfigUpdates = make(chan []string, 1)
|
||||
accErrSensor = make(map[string]int)
|
||||
}
|
||||
|
||||
func PollSensors(ctx context.Context, wg *sync.WaitGroup, readingInterval time.Duration) {
|
||||
func PollSensors(ctx context.Context, wg *sync.WaitGroup, readingInterval time.Duration, filterWeight float64) {
|
||||
hub := sentry.CurrentHub().Clone()
|
||||
defer hub.Flush(10 * time.Second)
|
||||
defer wg.Done()
|
||||
|
@ -95,6 +97,13 @@ func PollSensors(ctx context.Context, wg *sync.WaitGroup, readingInterval time.D
|
|||
case c := <-ConfigUpdates:
|
||||
sensors = c
|
||||
|
||||
for k := range filters {
|
||||
delete(filters, k)
|
||||
}
|
||||
for _, x := range sensors {
|
||||
filters[x] = NewEWMAFilter(filterWeight)
|
||||
}
|
||||
|
||||
case <-ctx.Done():
|
||||
close(C)
|
||||
return
|
||||
|
@ -115,16 +124,17 @@ func readSensors(hub *sentry.Hub) {
|
|||
}
|
||||
|
||||
accErrSensor[sensor] = 0
|
||||
tw := filters[sensor].Update(float64(t) / 1000)
|
||||
|
||||
r := TemperatureReading{
|
||||
Time: time.Now(),
|
||||
Sensor: sensor,
|
||||
MilliDegrees: t,
|
||||
Time: time.Now(),
|
||||
Sensor: sensor,
|
||||
Degrees: tw,
|
||||
}
|
||||
|
||||
metrics.TemperatureSensorReadingDegreesCelcius.
|
||||
WithLabelValues(sensor).
|
||||
Set(r.Degrees())
|
||||
Set(tw)
|
||||
|
||||
C <- r
|
||||
|
||||
|
|
28
pkg/temperature/filter.go
Normal file
28
pkg/temperature/filter.go
Normal file
|
@ -0,0 +1,28 @@
|
|||
package temperature
|
||||
|
||||
// EWMAFilter is an exponentially weighted moving average filter
|
||||
// See https://hackaday.com/2019/09/06/sensor-filters-for-coders/
|
||||
type EWMAFilter struct {
|
||||
weight float64
|
||||
prevTemp float64
|
||||
isInitialized bool
|
||||
}
|
||||
|
||||
func NewEWMAFilter(weight float64) *EWMAFilter {
|
||||
return &EWMAFilter{
|
||||
weight: weight,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *EWMAFilter) Update(input float64) float64 {
|
||||
if !p.isInitialized {
|
||||
p.prevTemp = input
|
||||
p.isInitialized = true
|
||||
return input
|
||||
}
|
||||
|
||||
ewmf := (1-p.weight)*p.prevTemp + p.weight*input
|
||||
p.prevTemp = ewmf
|
||||
|
||||
return ewmf
|
||||
}
|
|
@ -3,11 +3,7 @@ package temperature
|
|||
import "time"
|
||||
|
||||
type TemperatureReading struct {
|
||||
Sensor string `json:"sensor"`
|
||||
Time time.Time `json:"time"`
|
||||
MilliDegrees int64 `json:"milli_degrees"`
|
||||
}
|
||||
|
||||
func (t *TemperatureReading) Degrees() float64 {
|
||||
return float64(t.MilliDegrees) / 1000.0
|
||||
Sensor string `json:"sensor"`
|
||||
Time time.Time `json:"time"`
|
||||
Degrees float64 `json:"degrees"`
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue