-
Notifications
You must be signed in to change notification settings - Fork 0
/
capability_temperature.go
170 lines (140 loc) · 4.31 KB
/
capability_temperature.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package go_fritzbox_api
import (
"encoding/json"
"fmt"
"github.com/ByteSizedMarius/go-fritzbox-api/util"
"github.com/clbanning/mxj/v2"
"net/http"
"net/url"
"strconv"
"strings"
)
type Temperature struct {
CapName string
Celsius string `json:"celsius"`
Offset string `json:"offset"`
device *SmarthomeDevice
}
type TemperatureStats struct {
Values []float64
AmountOfValues int
SecondsBetweenMeasurements int
}
// Reload fetches the current device and updates the current capability
func (t *Temperature) Reload(c *Client) error {
tt, err := getDeviceInfosFromCapability(c, t)
if err != nil {
return err
}
// update current capability
th := tt.(*Temperature)
t.CapName = th.CapName
t.Celsius = th.Celsius
t.Offset = th.Offset
t.device = th.device
return nil
}
// GetCelsiusNumeric returns the temperature reading in float converted to the usual format (eg. 21.5)
func (t *Temperature) GetCelsiusNumeric() float64 {
return toTemp(t.Celsius)
}
// GetOffsetNumeric returns the temperature offset set for the device in float converted to the usual format (eg. 21.5)
func (t *Temperature) GetOffsetNumeric() float64 {
return toTemp(t.Offset)
}
// DECTGetCelsiusNumeric is the same as GetIstNumeric, but it will fetch the current value from the fritzbox and update the local state of the device before returning.
func (t *Temperature) DECTGetCelsiusNumeric(c *Client) (float64, error) {
resp, err := dectGetter(c, "gettemperature", t)
if err != nil {
return 0, err
}
// update local device
t.Celsius = resp
return t.GetCelsiusNumeric(), nil
}
// PyaSetOffset sets the temperature offset for the device using the PyAdapter
func (t *Temperature) PyaSetOffset(pya *PyAdapter, offset float64) (err error) {
// Setting the Offset is done via the HKR, despite the Offset being part of the Temperature capability.
// Get the HKR via the Device
if !t.device.HasCapability(CHKR) {
return fmt.Errorf("device does not have capability %s", CHKR)
}
hkr := GetCapability[*Hkr](*t.Device())
data, err := hkr.pyaPrepare(pya)
data["Offset"] = util.ToUrlValue(offset)
_, err = pya.Client.doRequest(http.MethodPost, "data.lua", data, true)
if err != nil {
return
}
err = t.Reload(pya.Client)
if t.GetOffsetNumeric() != offset {
err = fmt.Errorf("could not set offset. If offset is set multiple time in a short period of time, the fritzbox will block the requests.")
}
return
}
// DECTGetDeviceStats returns the temperatures measured from the device in the last 24 hours
func (t *Temperature) DECTGetDeviceStats(c *Client) (ts TemperatureStats, err error) {
data := url.Values{
"sid": {c.SID()},
"ain": {t.Device().Identifier},
"switchcmd": {"getbasicdevicestats"},
}
code, resp, err := c.CustomRequest(http.MethodGet, "webservices/homeautoswitch.lua", data)
if err != nil {
return
}
if code != 200 {
err = fmt.Errorf("unknown error: " + resp)
return
}
mv, err := mxj.NewMapXml([]byte(resp))
if err != nil {
return
}
mv, err = mv.NewMap("devicestats.temperature.stats:stats")
if err != nil {
return
}
ets := extTemperatureStats{}
err = mv.Struct(&ets)
ts.AmountOfValues, _ = strconv.Atoi(ets.Stats.Count)
ts.SecondsBetweenMeasurements, _ = strconv.Atoi(ets.Stats.Grid)
for _, tv := range strings.Split(ets.Stats.Text, ",") {
ts.Values = append(ts.Values, toTemp(tv))
}
return
}
func (ts TemperatureStats) String() string {
return fmt.Sprintf("Temperature-Stats: {Amount of Values: %d, Amount of Seconds between Measurements: %d, Measurements: %v}", ts.AmountOfValues, ts.SecondsBetweenMeasurements, ts.Values)
}
func (t *Temperature) Name() string {
return t.CapName
}
func (t *Temperature) String() string {
return fmt.Sprintf("%s: {Celsius: %f, Offset: %f}", t.CapName, t.GetCelsiusNumeric(), t.GetOffsetNumeric())
}
func (t *Temperature) Device() *SmarthomeDevice {
return t.device
}
func (t *Temperature) fromJSON(m map[string]json.RawMessage, d *SmarthomeDevice) (Capability, error) {
err := json.Unmarshal(m["temperature"], &t)
if err != nil {
return t, err
}
t.device = d
return t, nil
}
func toTemp(o string) float64 {
s, _ := strconv.ParseFloat(o, 64)
if s != 0 {
s /= 10
}
return s
}
type extTemperatureStats struct {
Stats struct {
Text string `json:"#text"`
Count string `json:"-count"`
Grid string `json:"-grid"`
} `json:"stats"`
}