]> git.giacomolli.uk - onehouse/blob - driver/alamo/thermostat_state.go
Poll and command shared Alamo thermostats
[onehouse] / driver / alamo / thermostat_state.go
1 package alamo
2
3 import (
4 "context"
5 "encoding/json"
6 "fmt"
7 "time"
8
9 "onehouse/driver"
10 "onehouse/protocol"
11 )
12
13 type thermostatState struct {
14 settings Thermostat
15 queue <-chan []driver.Command
16 ledger *driver.Ledger
17 publisher *driver.Publisher
18 missed int
19 }
20
21 func (s *thermostatState) descriptor(ctx context.Context) error {
22 err := s.publisher.Descriptor(ctx, s.settings.DeviceID, protocol.Metadata{}, protocol.DescriptorPayload{
23 Manufacturer: "alamo",
24 Model: "slim-wifi",
25 Firmware: "unknown",
26 Capabilities: []protocol.Capability{{
27 ID: "control",
28 Type: "floor-heating",
29 ReportsState: true,
30 AcceptsCommands: true,
31 }},
32 })
33 if err != nil {
34 return fmt.Errorf("publish descriptor: %w", err)
35 }
36
37 return nil
38 }
39
40 func (s *thermostatState) record(ctx context.Context, state State, observedAt time.Time, causationID string) error {
41 s.missed = 0
42 metadata := protocol.Metadata{
43 SentAt: &observedAt,
44 CausationID: causationID,
45 }
46
47 err := s.publisher.Availability(ctx, s.settings.DeviceID, protocol.Metadata{SentAt: &observedAt}, protocol.AvailabilityPayload{Status: "online"})
48 if err != nil {
49 return fmt.Errorf("publish thermostat contact: %w", err)
50 }
51
52 value, err := json.Marshal(newReportedControl(state))
53 if err != nil {
54 return fmt.Errorf("encode thermostat feedback: %w", err)
55 }
56
57 err = s.publisher.Reported(ctx, s.settings.DeviceID, "control", metadata, protocol.ValuePayload{Value: value})
58 if err != nil {
59 return fmt.Errorf("publish thermostat feedback: %w", err)
60 }
61
62 return nil
63 }
64
65 func (s *thermostatState) miss(ctx context.Context) error {
66 s.missed = min(s.missed+1, 3)
67 if s.missed < 3 {
68 return nil
69 }
70
71 err := s.publisher.Availability(ctx, s.settings.DeviceID, protocol.Metadata{}, protocol.AvailabilityPayload{Status: "offline"})
72 if err != nil {
73 return fmt.Errorf("publish offline: %w", err)
74 }
75
76 return nil
77 }
78
79 func (s *thermostatState) result(ctx context.Context, command driver.Command, payload protocol.ResultPayload) error {
80 record, err := s.ledger.Remember(command.Metadata.MessageID, payload)
81 if err != nil {
82 return fmt.Errorf("remember thermostat result: %w", err)
83 }
84
85 err = s.publisher.Result(ctx, s.settings.DeviceID, command.Metadata.MessageID, record.Metadata, record.Payload)
86 if err != nil {
87 return fmt.Errorf("publish thermostat result: %w", err)
88 }
89
90 return nil
91 }