-
Notifications
You must be signed in to change notification settings - Fork 9
/
eq3_control.py
162 lines (139 loc) · 7.17 KB
/
eq3_control.py
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
#!/usr/bin/python3
# -*-coding: utf-8 -*-
import datetime
import subprocess
import time
class EQ3Thermostat(object):
def __init__(self, address):
self.address = address
self.locked = False
self.temperature = 0
self.update()
def update(self):
"""Reads the current temperature from the thermostat. We need to kill
the gatttool process as the --listen option puts it into an infinite
loop."""
p = subprocess.Popen(["timeout", "-s", "INT", "2", "gatttool", "-b",
self.address, "--char-write-req", "-a", "0x0411",
"-n", "03", "--listen"],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
value_string = out.decode("utf-8")
if "Notification handle" in value_string:
value_string_splt = value_string.split()
temperature = value_string_splt[-1]
locked = value_string_splt[-4]
try:
subprocess.Popen.kill(p)
except ProcessLookupError:
pass
if locked == "20":
self.locked = True
elif locked == "00":
self.locked = False
else:
print("Could not read lockstate of {}".format(self.address))
try:
self.temperature = int(temperature, 16) / 2
except Exception as e:
print("Getting temperature of {} failed {}".format(self.address, e))
def activate_boostmode(self):
"""Boostmode fully opens the thermostat for 300sec."""
p = subprocess.Popen(["gatttool", "-b", self.address, "--char-write-req",
"-a", "0x0411", "-n", "4501"],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
def deactivate_boostmode(self):
"""Use only to stop boostmode before 300sec."""
p = subprocess.Popen(["gatttool", "-b", self.address, "--char-write-req",
"-a", "0x0411", "-n", "4500"],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
def set_automatic_mode(self):
"""Put thermostat in automatic mode."""
p = subprocess.Popen(["gatttool", "-b", self.address, "--char-write-req",
"-a", "0x0411", "-n", "4000"],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
def set_manual_mode(self):
"""Put thermostat in manual mode."""
p = subprocess.Popen(["gatttool", "-b", self.address, "--char-write-req",
"-a", "0x0411", "-n", "4040"],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
def set_eco_mode(self):
"""Put thermostat in eco mode."""
p = subprocess.Popen(["gatttool", "-b", self.address, "--char-write-req",
"-a", "0x0411", "-n", "4080"],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
def lock_thermostat(self):
"""Locks the thermostat for manual use."""
p = subprocess.Popen(["gatttool", "-b", self.address, "--char-write-req",
"-a", "0x0411", "-n", "8001"],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
def unlock_thermostat(self):
"""Unlocks the thermostat for manual use."""
p = subprocess.Popen(["gatttool", "-b", self.address, "--char-write-req",
"-a", "0x0411", "-n", "8000"],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
def set_temperature(self, temperature):
"""Transform the temperature in celcius to make it readable to the thermostat."""
temperature = hex(int(2 * float(temperature)))[2:]
p = subprocess.Popen(["gatttool", "-b", self.address, "--char-write-req",
"-a", "0x0411", "-n", "41{}".format(temperature)],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# Block for 3 secs to let the thermostat adjust the temperature
time.sleep(3)
def set_temperature_offset(self, offset):
"""Untested."""
temperature = hex(int(2 * float(offset) + 7))[2:]
p = subprocess.Popen(["gatttool", "-b", self.address, "--char-write-req",
"-a", "0x0411", "-n", "13{}".format(temperature)],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
def set_day(self):
"""Puts thermostat into day mode (sun icon)."""
p = subprocess.Popen(["gatttool", "-b", self.address, "--char-write-req",
"-a", "0x0411", "-n", "43"],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
def set_night(self):
"""Puts thermostat into night mode (moon icon)."""
p = subprocess.Popen(["gatttool", "-b", self.address, "--char-write-req",
"-a", "0x0411", "-n", "44"],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
def set_day_night(self, night, day):
"""Sets comfort temperature for day and night."""
day = hex(int(2 * float(day)))[2:]
night = hex(int(2 * float(night)))[2:]
p = subprocess.Popen(["gatttool", "-b", self.address, "--char-write-req",
"-a", "0x0411", "-n", "11{}{}".format(day, night)],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
def set_windows_open(self, temperature, duration_min):
"""Untested."""
temperature = hex(int(2 * float(temperature)))[2:]
duration_min = hex(int(duration_min / 5.0))[2:]
p = subprocess.Popen(["gatttool", "-b", self.address, "--char-write-req",
"-a", "0x0411", "-n", "11{}{}".format(temperature, duration_min)],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
def set_time(self, datetimeobj):
"""Takes a datetimeobj (like datetime.datetime.now()) and sets the time
in the thermostat."""
command_prefix = "03"
year = "{:02X}".format(datetimeobj.year % 100)
month = "{:02X}".format(datetimeobj.month)
day = "{:02X}".format(datetimeobj.day)
hour = "{:02X}".format(datetimeobj.hour)
minute = "{:02X}".format(datetimeobj.minute)
second = "{:02X}".format(datetimeobj.second)
control_string = "{}{}{}{}{}{}{}".format(
command_prefix, year, month, day, hour, minute, second)
p = subprocess.Popen(["gatttool", "-b", self.address, "--char-write-req",
"-a", "0x0411", "-n", control_string],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# Block for 3 secs to let the thermostat adjust the settings
time.sleep(3)
if __name__ == '__main__':
h = EQ3Thermostat("00:AA:BB:CC:DD:EE")
# Take some time
time.sleep(5)
# Deactivate autonomous behavior on the thermostat
h.set_manual_mode()
# Set current date
h.set_time(datetime.datetime.now())
# Set the current temperature
h.set_temperature(20)