heater/pkg/device/settings.go

207 lines
4.8 KiB
Go

package device
import (
"time"
"bytes"
"text/template"
"fmt"
)
type DayOfWeek int
func (d DayOfWeek) Next() DayOfWeek {
if d == Sunday {
return Monday
}
return d+1
}
func (d DayOfWeek) Previous() DayOfWeek {
if d == Monday {
return Sunday
}
return d-1
}
func (d DayOfWeek) DurationBetween(n DayOfWeek) time.Duration {
// return duration between two day of week
var duration time.Duration
if (d-n == 0) {
duration, _ = time.ParseDuration("168h")
} else {
duration, _ = time.ParseDuration(fmt.Sprintf("%dh", (d-n)*24 ))
}
return duration
}
const (
Monday DayOfWeek = 0
Thuesday = 1
Wednesday = 2
Thursday = 3
Friday = 4
Saturday = 5
Sunday = 6
)
func WeekDayEnToFr(weekday time.Weekday) DayOfWeek {
// translate weekday to french week, start by Monday
return map[time.Weekday]DayOfWeek {
time.Monday : Monday,
time.Tuesday : Thuesday,
time.Wednesday: Wednesday,
time.Thursday : Thursday,
time.Friday: Friday,
time.Saturday: Saturday,
time.Sunday: Sunday,
}[weekday]
}
func daytime(t time.Time) int {
return t.Hour()*60 + t.Minute()
}
func weekday(t time.Time) DayOfWeek {
return WeekDayEnToFr(t.Weekday())
}
type Message struct {
Payload []byte
Topic string
Retain bool
}
type Setpoint struct {
Start int `json:"start"`
Preset_id int `json:"preset_id"`
}
type WeekProgram map[DayOfWeek][]Setpoint
func (p WeekProgram) Current() Setpoint {
// return current Setpoint
now := time.Now()
weekday := weekday(now)
daytime := daytime(now)
setpoint := Setpoint{}
for _, sp := range p[weekday] {
if daytime < sp.Start {
break
}
setpoint = sp
}
return setpoint
}
func (p WeekProgram) NextTime(t time.Time) (time.Time, error) {
// return next program change
setpoint := Setpoint{}
var next time.Time
weekday := weekday(t)
daytime := daytime(t)
// Recursive func to find setpoint on weekday
get := func (weekday DayOfWeek, daytime int) Setpoint {
setpoint := Setpoint{}
for _, sp := range p[weekday] {
setpoint = sp
if daytime < sp.Start {
return setpoint
}
}
return Setpoint{}
}
startweekday := weekday
for (setpoint == Setpoint{}) {
setpoint = get(weekday, daytime)
if (setpoint != Setpoint{}) {
// setpoint found, compute time
next := t.Add( startweekday.DurationBetween(weekday) )
next = t.Add( time.Duration(setpoint.Start - daytime ) * time.Minute )
return next, nil
}
weekday = weekday.Next()
daytime = 0
if weekday == startweekday {
return next, fmt.Errorf("Shouldn't happen no setpoint found over the week")
}
}
return next, nil
}
type Programs map[string]WeekProgram
type Preset struct {
Label string `json:"label"`
Value int `json:"value"`
Color string `json:"color"`
}
type TVRSettings struct {
Setpoint_topic string `json:"setpoint_topic"`
Setpoint_payload string `json:"setpoint_payload"`
Setpoint_state_topic string `json:"setpoint_state_topic"`
Setpoint_state_jp string `json:"setpoint_state_jp"`
}
func (s TVRSettings) FormatTopicState(device_name string) (string, error) {
type Variable struct {
Device string
}
variables := Variable{device_name}
t, err := template.New("topic").Parse(s.Setpoint_state_topic)
if err != nil {
return "", err
}
buf := new(bytes.Buffer)
err = t.Execute(buf, variables)
if err != nil {
return "", err
}
return buf.String(), nil
}
func (s TVRSettings) FormatTopic(device_name string) (string, error) {
type Variable struct {
Device string
}
variables := Variable{device_name}
t, err := template.New("topic").Parse(s.Setpoint_topic)
if err != nil {
return "", err
}
buf := new(bytes.Buffer)
err = t.Execute(buf, variables)
if err != nil {
return "", err
}
return buf.String(), nil
}
func (s TVRSettings) FormatPayload(setpoint int) (string, error) {
type Variable struct {
Setpoint int
}
variables := Variable{setpoint}
t, err := template.New("payload").Parse(s.Setpoint_payload)
if err != nil {
return "", err
}
buf := new(bytes.Buffer)
err = t.Execute(buf, variables)
if err != nil {
return "", err
}
return buf.String(), nil
}
type DeviceSettings struct {
Programs Programs `json:"programs"`
Presets []Preset `json:"presets"`
TVR TVRSettings `json:"TVR"`
}