forked from bpicode/fritzctl
/
ain_based.go
96 lines (82 loc) · 2.81 KB
/
ain_based.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
package fritz
import (
"fmt"
"github.com/bpicode/fritzctl/httpread"
)
// ainBased API definition, guided by
// https://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/AHA-HTTP-Interface.pdf.
type ainBased interface {
listDevices() (*Devicelist, error)
switchOn(ain string) (string, error)
switchOff(ain string) (string, error)
toggle(ain string) (string, error)
applyTemperature(value float64, ain string) (string, error)
}
// newAinBased creates a Fritz AHA API (working on AINs) from a given client.
func newAinBased(client *Client) ainBased {
return &ainBasedClient{client: client}
}
type ainBasedClient struct {
client *Client
}
// listDevices lists the basic data of the smart home devices.
func (a *ainBasedClient) listDevices() (*Devicelist, error) {
url := a.homeAutoSwitch().
query("switchcmd", "getdevicelistinfos").
build()
var deviceList Devicelist
errRead := httpread.XML(a.client.getf(url), &deviceList)
return &deviceList, errRead
}
// switchOn switches a device on. The device is identified by its AIN.
func (a *ainBasedClient) switchOn(ain string) (string, error) {
return a.switchForAin(ain, "setswitchon")
}
// switchOff switches a device off. The device is identified by its AIN.
func (a *ainBasedClient) switchOff(ain string) (string, error) {
return a.switchForAin(ain, "setswitchoff")
}
// toggle toggles the on/off state of a device. The device is identified by its AIN.
func (a *ainBasedClient) toggle(ain string) (string, error) {
url := a.homeAutoSwitch().
query("ain", ain).
query("switchcmd", "setswitchtoggle").
build()
return httpread.String(a.client.getf(url))
}
// applyTemperature sets the desired temperature on a "HKR" device. The device is identified by its AIN.
func (a *ainBasedClient) applyTemperature(value float64, ain string) (string, error) {
param, err := temperatureParam(value)
if err != nil {
return "", err
}
url := a.homeAutoSwitch().
query("ain", ain).
query("switchcmd", "sethkrtsoll").
query("param", fmt.Sprintf("%d", param)).
build()
return httpread.String(a.client.getf(url))
}
func (a *ainBasedClient) switchForAin(ain, command string) (string, error) {
url := a.homeAutoSwitch().
query("ain", ain).
query("switchcmd", command).
build()
return httpread.String(a.client.getf(url))
}
func (a *ainBasedClient) homeAutoSwitch() fritzURLBuilder {
return a.client.query().path(homeAutomationURI)
}
func temperatureParam(t float64) (int64, error) {
doubled := round(2 * t)
regular := doubled >= 16 && doubled <= 56
special := doubled == 253 || doubled == 254
if !(regular || special) {
return 0, fmt.Errorf("invalid temperature value: %.1f°C is not contained in the set of acceptable values: 8-28°C, 126.5, 127", t)
}
return doubled, nil
}
// round rounds a float64 value to an integer.
func round(v float64) int64 {
return int64(v + 0.5)
}