TVR: Add valve state and local temperature

This commit is contained in:
Nicolas Duhamel 2022-12-11 17:39:21 +01:00
parent f5e9d460c8
commit 4174d627fb
4 changed files with 98 additions and 23 deletions

View File

@ -65,6 +65,7 @@ func (app *App) subscribe(
) context.CancelFunc {
ctx, cancelFunc := context.WithCancel(app.ctx)
ctx = context.WithValue(ctx, "pubchan", app.PubChan)
log := zerolog.Ctx(ctx)

View File

@ -7,7 +7,6 @@ import (
"time"
"git.quimbo.fr/nicolas/mqtt"
"github.com/ohler55/ojg/jp"
"github.com/ohler55/ojg/oj"
"github.com/rs/zerolog"
// "reflect"
@ -22,11 +21,13 @@ type Error string
func (e Error) Error() string { return string(e) }
type DeviceState struct {
Mode string `json:"mode"`
Setpoint int `json:"setpoint"`
Time time.Time `json:"time"`
ProgramName string `json:"program_name"`
UntilTime time.Time `json:"until_time"`
Mode string `json:"mode"`
Setpoint int `json:"setpoint"`
Time time.Time `json:"time"`
ProgramName string `json:"program_name"`
UntilTime time.Time `json:"until_time"`
ValveState string `json:"valve_state"`
LocalTemperature int `json:"local_temperature"`
}
func (s *DeviceState) Equivalent(state DeviceState) bool {
@ -136,12 +137,15 @@ func (d *Device) SetSetpoint(value int, pubchan chan Message) error {
}
func (d *Device) SetState(log zerolog.Logger, state DeviceState, pubchan chan Message) error {
// Called on mqtt state/set cmd received
// If same state do nothing
// else use checksetpoint for changing state
if d.State.Equivalent(state) {
log.Debug().Msg("same state no change")
return nil
}
// keep tvr state
state.LocalTemperature = d.State.LocalTemperature
state.ValveState = d.State.ValveState
d.State = state
@ -213,19 +217,38 @@ func (d *Device) onMessage(ctx context.Context, msg mqtt.Message) {
log.Error().Err(err).Msg("during payload parse")
return
}
x, err := jp.ParseString(d.Settings.TVR.Setpoint_state_jp)
// Setpoint
setpoint, err := d.Settings.TVR.ParseSetpoint(obj)
if err != nil {
log.Error().Err(err).Msg("while parsing payload")
log.Error().Err(err).Msg("while parsing setpoint")
return
}
d.CurrentSetpoint = setpoint
r := x.First(obj)
// LocalTemperature
localTemperature, err := d.Settings.TVR.ParseLocalTemperature(obj)
if err != nil {
log.Error().Err(err).Msg("while parsing LocalTemperature")
return
}
d.State.LocalTemperature = localTemperature
if v, ok := r.(int64); ok {
d.CurrentSetpoint = int(v)
// Valve
valve, err := d.Settings.TVR.ParseValve(obj)
if err != nil {
log.Error().Err(err).Msg("while parsing Valve")
return
}
d.State.ValveState = valve
if v := ctx.Value("pubchan"); v != nil {
if pubchan, ok := v.(chan Message); ok {
d.publishState(pubchan)
} else {
log.Error().Msg("invalid pubchan ctx type")
}
} else {
log.Error().Err(err).Interface("parsing payload", r).Msg("while parsing payload")
log.Error().Msg("pubchan not found in ctx")
}
}

View File

@ -417,7 +417,7 @@ func TestUpdate(t *testing.T) {
go func(result chan Message, changechan chan bool, errchan chan error) {
logger := zerolog.New(ioutil.Discard).With().Timestamp().Logger()
change, err := tt.device.update(&logger, result)
change, err := tt.device.update(logger, result)
errchan <- err
changechan <- change
close(rchan)

View File

@ -5,6 +5,8 @@ import (
"fmt"
"text/template"
"time"
"github.com/ohler55/ojg/jp"
)
type DayOfWeek int
@ -149,10 +151,57 @@ type Preset struct {
}
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"`
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"`
StateLocalTemperatureJP string `json:"state_local_temperature_jp"`
StateValveJP string `json:"state_valve_jp"`
}
func (s TVRSettings) ParseSetpoint(obj interface{}) (int, error) {
jp, err := jp.ParseString(s.Setpoint_state_jp)
if err != nil {
return 0, err
}
r := jp.First(obj)
if v, ok := r.(int64); ok {
return int(v), nil
} else {
return 0, Error("Unexpected type")
}
}
func (s TVRSettings) ParseLocalTemperature(obj interface{}) (int, error) {
jp, err := jp.ParseString(s.StateLocalTemperatureJP)
if err != nil {
return 0, err
}
r := jp.First(obj)
if v, ok := r.(int64); ok {
return int(v), nil
} else {
return 0, Error("Unexpected type")
}
}
func (s TVRSettings) ParseValve(obj interface{}) (string, error) {
jp, err := jp.ParseString(s.StateValveJP)
if err != nil {
return "", err
}
r := jp.First(obj)
if v, ok := r.(string); ok {
return string(v), nil
} else {
return "", Error("Unexpected type")
}
}
func (s TVRSettings) FormatTopicState(device_name string) (string, error) {
@ -242,10 +291,12 @@ var DefaultPrograms = Programs{
}
var DefaultTVRSettings = TVRSettings{
Setpoint_topic: "zigbee2mqtt/TVR/{{.Device}}/set",
Setpoint_payload: "{\"current_heating_setpoint\": {{.Setpoint}}}",
Setpoint_state_topic: "zigbee2mqtt/TVR/{{.Device}}",
Setpoint_state_jp: "$.current_heating_setpoint",
Setpoint_topic: "zigbee2mqtt/TVR/{{.Device}}/set",
Setpoint_payload: "{\"current_heating_setpoint\": {{.Setpoint}}}",
Setpoint_state_topic: "zigbee2mqtt/TVR/{{.Device}}",
Setpoint_state_jp: "$.current_heating_setpoint",
StateLocalTemperatureJP: "$.local_temperature",
StateValveJP: "$.valve_state",
}
var DefaultDeviceSettings = DeviceSettings{