From 18fb4bad6d8714e4b8222d0ce6ba992dccb7d796 Mon Sep 17 00:00:00 2001 From: Mike Shoup Date: Fri, 28 Sep 2018 15:26:27 -0600 Subject: [PATCH] Basic thermostat stuff --- config.go | 4 ++-- main.go | 15 +++++++++--- run.go | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 77 insertions(+), 10 deletions(-) diff --git a/config.go b/config.go index 362583f..6264dc0 100644 --- a/config.go +++ b/config.go @@ -14,10 +14,10 @@ type Sensor struct { LowTemp float64 `yaml:"lowtemp"` HeatGPIO int32 `yaml:"heatgpio"` HeatPullup bool `yaml:"heatpullup"` - HeatMinutes int32 `yaml:"heatminutes"` + HeatMinutes float64 `yaml:"heatminutes"` CoolGPIO int32 `yaml:"coolgpio"` CoolPullup bool `yaml:"coolpullup"` - CoolMinutes int32 `yaml:"coolminutes"` + CoolMinutes float64 `yaml:"coolminutes"` } // Config contains the applications configuration diff --git a/main.go b/main.go index 705f06a..7f36efa 100644 --- a/main.go +++ b/main.go @@ -4,7 +4,8 @@ import ( "log" "sync" - arg "github.com/alexflint/go-arg" + "github.com/alexflint/go-arg" + "github.com/stianeikeland/go-rpio" ) func main() { @@ -23,12 +24,20 @@ func main() { log.Fatal(err) } - var wg sync.WaitGroup + // Prep for GPIO access + err = rpio.Open() + if err != nil { + log.Fatal(err) + } + // Launch the thermostat go routines + var wg sync.WaitGroup for _, sensor := range config.Sensors { wg.Add(1) go RunThermostat(sensor) } - wg.Wait() + + // Close the GPIO access + rpio.Close() } diff --git a/run.go b/run.go index 6506309..2f31436 100644 --- a/run.go +++ b/run.go @@ -5,15 +5,16 @@ import ( "log" "time" + "github.com/stianeikeland/go-rpio" "github.com/yryz/ds18b20" ) // State represents the current state of the thermostat type State struct { - Temp float64 - Cooling bool - Heating bool - Duration time.Duration + Temp float64 + Cooling bool + Heating bool + Changed time.Time } // ReadTemperature will return the current temperature (in degrees celsius) of a specific sensor. @@ -33,9 +34,42 @@ func ReadTemperature(id string) (float64, error) { return 0.0, errors.New("Sensor not found") } +// SetPinState is used to turn a pin on or off. +// If pullup is true, the pin will be pulled up when turned on, and pulled down when turned off. +func SetPinState(pin rpio.Pin, on bool, pullup bool) { + switch { + case on && pullup: + pin.PullUp() + case on && !pullup: + pin.PullDown() + case !on && !pullup: + pin.PullUp() + default: + pin.PullDown() + } +} + +// GetPinState will return true if the pin is on. +// If pullup is true, the pin will be on when pulled up. +func GetPinState(pin rpio.Pin, pullup bool) bool { + switch pin.Read() { + case rpio.High: + return pullup + default: + return !pullup + } +} + // RunThermostat monitors the temperature of the supplied sensor and does its best to keep it at the desired state. func RunThermostat(sensor Sensor) { var s State + s.Changed = time.Now() + + cpin := rpio.Pin(sensor.CoolGPIO) + cpin.Output() + + hpin := rpio.Pin(sensor.HeatGPIO) + hpin.Output() for { t, err := ReadTemperature(sensor.ID) @@ -43,7 +77,31 @@ func RunThermostat(sensor Sensor) { log.Panicln(err) } + min := time.Since(s.Changed).Minutes() + + switch { + case t > sensor.HighTemp && t < sensor.HighTemp: + log.Panic("Invalid state! Temperature is too high AND too low!") + case t > sensor.HighTemp && GetPinState(hpin, sensor.HeatPullup): + SetPinState(hpin, false, sensor.HeatPullup) + case t > sensor.HighTemp && min > sensor.CoolMinutes: + SetPinState(cpin, true, sensor.CoolPullup) + case t > sensor.HighTemp: + break + case t < sensor.LowTemp && GetPinState(cpin, sensor.CoolPullup): + SetPinState(cpin, false, sensor.CoolPullup) + case t < sensor.LowTemp && min > sensor.HeatMinutes: + SetPinState(hpin, true, sensor.HeatPullup) + case t < sensor.LowTemp: + break + default: // Turn off both switches + SetPinState(cpin, false, sensor.CoolPullup) + SetPinState(hpin, false, sensor.HeatPullup) + } + s.Temp = t - log.Printf("Temp: %.2f, Cooling: %t, Heating: %t Duration: %d", s.Temp, s.Cooling, s.Heating, s.Duration) + s.Cooling = GetPinState(cpin, sensor.CoolPullup) + s.Heating = GetPinState(hpin, sensor.HeatPullup) + log.Printf("Temp: %.2f, Cooling: %t, Heating: %t, Changed: %s", s.Temp, s.Cooling, s.Heating, s.Changed) } }