78 lines
1.8 KiB
Go
78 lines
1.8 KiB
Go
package controllers
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/rs/zerolog/log"
|
|
)
|
|
|
|
type ChamberState int
|
|
|
|
const (
|
|
ChamberStateIdle ChamberState = iota
|
|
ChamberStateCooling
|
|
ChamberStateHeating
|
|
)
|
|
|
|
type ChamberController struct {
|
|
config *Config
|
|
|
|
// Current state.
|
|
chamberState ChamberState
|
|
lastChamberStateChange time.Time
|
|
C chan ChamberState
|
|
mutex *sync.Mutex
|
|
|
|
name string
|
|
|
|
// Current temperature readings.
|
|
ambientTemperature float64
|
|
chamberTemperature float64
|
|
wortTemperature float64
|
|
|
|
pid *PIDController
|
|
initialized bool
|
|
}
|
|
|
|
func NewChamberController(name string, config *Config) *ChamberController {
|
|
return &ChamberController{
|
|
C: make(chan ChamberState),
|
|
name: name,
|
|
config: config,
|
|
pid: NewPIDController(config.PID.Kp, config.PID.Ki, config.PID.Kd),
|
|
mutex: &sync.Mutex{},
|
|
}
|
|
}
|
|
|
|
func (p *ChamberController) Run() {
|
|
for {
|
|
offset := p.pid.Compute(p.wortTemperature, p.config.FermentationTemperature)
|
|
chamberTargetTemp := p.config.FermentationTemperature + offset
|
|
log.Debug().Float64("chamber_target_temp", chamberTargetTemp).Send()
|
|
|
|
// TODO Merge hysteresis algorithm into this one.
|
|
|
|
if !p.initialized {
|
|
// heater off
|
|
// cooler off
|
|
continue
|
|
}
|
|
|
|
if p.wortTemperature < p.config.FermentationTemperature && p.chamberTemperature < chamberTargetTemp {
|
|
// heater on
|
|
} else if p.wortTemperature >= p.config.FermentationTemperature || p.chamberTemperature >= chamberTargetTemp {
|
|
// heater off
|
|
} else {
|
|
// heater off
|
|
}
|
|
|
|
if p.wortTemperature > p.config.FermentationTemperature && p.chamberTemperature > chamberTargetTemp {
|
|
// cooler on
|
|
} else if p.wortTemperature <= p.config.FermentationTemperature || p.chamberTemperature <= chamberTargetTemp {
|
|
// cooler off
|
|
} else {
|
|
// cooler off
|
|
}
|
|
}
|
|
}
|