-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathac.py
executable file
·178 lines (148 loc) · 5.33 KB
/
ac.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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#!/usr/bin/env python3
import sys
from urllib.request import urlopen
import json
import time
from calendar import timegm
from datetime import datetime
import requests
import acmod
tgt_temp_heat=26
tgt_temp_cool=20
now = datetime.now()
now_str = now.strftime("%Y-%m-%dT%H:%M:%SZ")
#
# Resync loop
# Both iteratons must result in b_sync == True to update state
#
b_sync = False
b_force = False
b_auto_mode = ""
b_mode = ""
for loop in range(2):
if (loop > 0):
# sleep 10 seconds and retest, must require sync both times
time.sleep(10)
print(">>>>>>> " + now_str + " [" + str(loop) + "]")
try:
ss_data = acmod.ac_get_data()
except RuntimeError as e:
print("Getting data failed: " + str(e))
sys.exit(-1)
if (not ss_data['result']['smartMode']['enabled']):
print("Not in auto mode")
break
if ('lastACStateChange' not in ss_data['result']):
print("Last state change too old - no change key")
break
b_on = ss_data['result']['acState']['on']
cur_temp = ss_data['result']['measurements']['temperature']
last_evt_sec = ss_data['result']['lastACStateChange']['time']['secondsAgo']
last_evt_reason = ss_data['result']['lastACStateChange']['reason'].lower()
print("On: " + str(b_on))
print("Temp Now: " + str(cur_temp))
b_auto_mode = ""
b_sync = False
b_force = False
b_mode = ss_data['result']['acState']['mode']
if ss_data['result']['smartMode']['lowTemperatureState']['on']:
print("Smart mode is: Heat")
b_auto_mode = "heat"
on_temp = ss_data['result']['smartMode']['lowTemperatureThreshold']
off_temp = ss_data['result']['smartMode']['highTemperatureThreshold']
elif ss_data['result']['smartMode']['highTemperatureState']['on']:
print("Smart mode is: Cool")
b_auto_mode = "cool"
on_temp = ss_data['result']['smartMode']['highTemperatureThreshold']
off_temp = ss_data['result']['smartMode']['lowTemperatureThreshold']
else:
print("Smart mode is: Undefined")
break
print("Temp On: " + str(on_temp))
print("Temp Off: " + str(off_temp))
print("Last event " + str(last_evt_sec) + " sec ago")
if last_evt_sec < 300:
print("Last state chg too recent")
break
elif last_evt_sec > 7000:
print("Last state chg too old")
break
#elif last_evt_reason != "trigger":
# print("Last event not in auto mode")
# break
if b_auto_mode == "heat":
mode_temp = tgt_temp_heat
if not b_on:
temp_diff = cur_temp - off_temp
if temp_diff > 0.4:
b_sync = True
else:
if last_evt_sec > 1500 and cur_temp < off_temp:
b_sync = True
elif b_auto_mode == "cool":
mode_temp = tgt_temp_cool
if not b_on:
# Current temperature well below off (low) limit
# Assume runaway cooling mode
if (off_temp - cur_temp) > 0.3:
b_sync = True
# AC off, above on (upper) limit
# Assume failed smart mode start
if (cur_temp - on_temp > 0.1):
b_force = True
else:
# linearly adjust thold from on_temp + 0.5 immediately (delayed by 500 sec)
# to off temp itself at 1hr
# If current temperature is above thold, assume "underrun" (not actually cooling)
temp_thold = off_temp + (on_temp + 0.5 - off_temp) * ((3600 - last_evt_sec) / 3300)
print("Temp thold: " + str(temp_thold))
if last_evt_sec > 500 and cur_temp >= temp_thold:
b_sync = True
# AC on, below off (lower) limit
# Assume failed smart mode stop
if (off_temp - cur_temp) > 0.2:
b_force = True
if not (b_sync or b_force):
print("Run state OK")
break
if b_sync:
print("Need to sync, current on: " + str(b_on) + ", auto mode: " + str(b_auto_mode))
# patch current state to the opposite
try:
acmod.ac_patch_state(b_on)
except RuntimeError as e:
print("Patch failed: " + str(e))
sys.exit(-1)
# actually apply current state
try:
acmod.ac_set_state(b_on, b_auto_mode, mode_temp, "auto")
except RuntimeError as e:
print("Command on/off failed: " + str(e))
sys.exit(-1)
print ("Flipped state and applied state: " + str(b_on))
sys.exit(2)
if b_force:
print("Need to force, current on: " + str(b_on) + ", auto mode: " + str(b_auto_mode))
# apply opposite state
b_on = not b_on;
try:
acmod.ac_set_state(b_on, b_auto_mode, mode_temp, "auto")
except RuntimeError as e:
print("Command on/off failed: " + str(e))
sys.exit(-1)
print ("Force applied state: " + str(b_on))
sys.exit(2)
# In cooling mode run fan periodically
# Attempting to proactively switch to the fan from autorun cool
# results in autorun shortly canceling the fan (and then fan restarting
# on the "soon after cooling" condition
if b_auto_mode == "cool":
#if (b_on and b_mode == "cool" and cur_temp <= off_temp) or ((not b_on) and last_evt_reason == "trigger" and last_evt_sec <= 120):
if ((not b_on) and last_evt_reason == "trigger" and last_evt_sec <= 120):
print("Fan is off - will turn on")
try:
acmod.ac_set_state(True, "fan", tgt_temp_cool, "low")
acmod.ac_set_state_after(False, "fan", tgt_temp_cool, "low", 1)
except RuntimeError as e:
print("Fan on failed: " + str(e))
sys.exit(-1)