-
Notifications
You must be signed in to change notification settings - Fork 0
/
thermostat.py
341 lines (270 loc) · 11.5 KB
/
thermostat.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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
import json
import os
import sqlite3
from datetime import datetime, timedelta
# Get the absolute path to the directory containg your script
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
# File paths
SETPOINT_JSON_PATH = os.path.join(SCRIPT_DIR, 'options/setpoint.json')
TEMPERATURE_JSON_PATH = os.path.join(SCRIPT_DIR, 'options/curr_temp.json')
SCHEDULE_JSON_PATH = os.path.join(SCRIPT_DIR, 'options/schedule.json')
SYSTEM_JSON_PATH = os.path.join(SCRIPT_DIR, 'options/system.json')
HUMIDITY_JSON_PATH = os.path.join(SCRIPT_DIR, 'options/humidity.json')
SQL_DB_PATH = os.path.join(SCRIPT_DIR, 'database/thermostat.db')
class Thermostat():
def __init__(self):
self.max_setpoint = 85
self.min_setpoint = 55
self.deadband = 1
def update_temp(self, new_temp):
""" Update the current temperature in curr_temp.json """
data = {"temperature": new_temp}
with open(TEMPERATURE_JSON_PATH, 'w') as json_file:
json.dump(data, json_file)
def get_temp(self):
""" Return the current temperature from curr_temp.json """
with open(TEMPERATURE_JSON_PATH, 'r') as json_file:
data = json.load(json_file)
return data["temperature"]
def update_humidity(self, new_humidity):
""" Update the current humidity (%) in humidity.json """
data = {"humidity": new_humidity}
with open(HUMIDITY_JSON_PATH, 'w') as json_file:
json.dump(data, json_file)
def get_humidity(self):
""" Return the current humidity (%) from humidity.json """
with open(HUMIDITY_JSON_PATH, 'r') as json_file:
data = json.load(json_file)
return data["humidity"]
def set_schedule_mode(self, mode):
""" Set the schedule mode to ON or OFF in system.json """
mode_options = ['ON', 'OFF']
if mode.upper() in mode_options:
with open(SYSTEM_JSON_PATH, 'r') as json_file:
data = json.load(json_file)
data['schedule'] = mode.upper()
with open(SYSTEM_JSON_PATH, 'w') as json_file:
json.dump(data, json_file)
def set_system(self, mode):
""" Set the system mode to AC, HEAT, or OFF in system.json """
mode_options = ['AC', 'HEAT', 'OFF']
if mode.upper() in mode_options:
with open(SYSTEM_JSON_PATH, 'r') as json_file:
data = json.load(json_file)
data['system'] = mode.upper()
with open(SYSTEM_JSON_PATH, 'w') as json_file:
json.dump(data, json_file)
def set_fan(self, mode):
""" Set the fan_mode to ON or AUTO in system.json """
mode_options = ['ON', 'AUTO']
if mode.upper() in mode_options:
with open(SYSTEM_JSON_PATH, 'r') as json_file:
data = json.load(json_file)
data['fan_mode'] = mode.upper()
with open(SYSTEM_JSON_PATH, 'w') as json_file:
json.dump(data, json_file)
def get_schedule_mode(self):
""" Return the schedule mode from system.json """
with open(SYSTEM_JSON_PATH, 'r') as json_file:
data = json.load(json_file)
return data["schedule"].upper()
def get_system(self):
""" Return the system mode from system.json """
with open(SYSTEM_JSON_PATH, 'r') as json_file:
data = json.load(json_file)
return data["system"]
def get_fan(self):
""" Return the fan mode from system.json """
with open(SYSTEM_JSON_PATH, 'r') as json_file:
data = json.load(json_file)
return data["fan_mode"].upper()
def get_rounded_time(self):
""" Return current time rounded to the nearest 30min in '12:30 PM' format"""
# Get the current date and time
current_datetime = datetime.now()
# Round to the neareset 30 minutes
hour = current_datetime.hour
minutes = current_datetime.minute
rounded_minutes = round(minutes / 30) * 30
# if minutes is greater than 30, round up to the next hour
if rounded_minutes == 60:
hour += 1
rounded_minutes = 0
# Convert military time to conventional
if hour == 12:
am_pm = "PM"
elif hour >= 13:
hour -= 12
am_pm = "PM"
else:
am_pm = "AM"
# Format the time string
formatted_time = f"{hour}:{rounded_minutes:02d} {am_pm}"
return formatted_time
def convert_to_standard_time(self, time_str):
"""
Example input and output:
Input = "1430", "0000", "0830"
Output = "2:30 PM", "12:00 AM", "8:30 AM"
"""
# Extract hour and minute
hour = int(time_str[:2])
minute = int(time_str[2:])
# Convert to standard time format
if hour == 12:
am_pm = "PM"
elif hour >= 13:
hour -= 12
am_pm = "PM"
elif hour == 0:
hour = 12
am_pm = "AM"
else:
am_pm = "AM"
standard_time_str = f"{hour}:{minute:02d} {am_pm}"
return standard_time_str
def convert_to_military_time(self, time_str):
"""
Example input and output:
Input = "02:30 PM", "12:00 AM", "8:30 AM"
Output = "1430", "0000", "0830"
"""
# Split the input time string into components
time_components = time_str.split(":")
# Extract hour, minute, and AM/PM indicator
hour = int(time_components[0])
minute = int(time_components[1][:2]) # Ensure only two digits are considered
am_pm = time_components[1][-2:].strip().lower() # Extract and normalize AM/PM
# Adjust the hour based on AM/PM indicator
if am_pm == "pm" and hour != 12:
hour += 12
elif am_pm == "am" and hour == 12:
hour = 0
# Convert to military time format
military_time_str = f"{hour:02d}{minute:02d}"
return military_time_str
def get_schedule(self):
""" Return the schedule as a dictionary """
# Load the schedule json file
with open(SCHEDULE_JSON_PATH, 'r') as json_file:
data = json.load(json_file)
return data
def set_setpoint(self, new_temperature):
""" Set the setpoint to the new temperature in setpoint.json
Input: new_temperature as an integer """
data = {"setpoint": new_temperature}
with open(SETPOINT_JSON_PATH, 'w') as json_file:
json.dump(data, json_file)
def get_setpoint(self):
""" Return the setpoint from setpoint.json """
with open(SETPOINT_JSON_PATH, 'r') as json_file:
data = json.load(json_file)
return data["setpoint"]
def get_schedule_setpoint(self):
""" Return the setpoint for the current time from schedule.json"""
# Load the schedule json file
with open(SCHEDULE_JSON_PATH, 'r') as json_file:
data = json.load(json_file)
# Get current time rounded the current time to the nearest 30 minutes
rounded_time = self.get_rounded_time()
# Format the current time in military time (24 hour clock)
current_military_time = self.convert_to_military_time(rounded_time)
# Return scheduled setpoint for current time
return data[current_military_time]
def update_schedule(self, start_time, end_time, setpoint):
""" Input start and end times in '12:30 PM' format and setpoint as a two digit integer
Example input: "12:30 PM", "2:30 PM", 75
Output: update the schedule.json file
"""
# format the start and end times in military time (24 hour clock)
start_time = self.convert_to_military_time(start_time)
end_time = self.convert_to_military_time(end_time)
# if end_time is before start_time, return error
if start_time > end_time:
print("Error: end_time is before start_time")
return
# Load the schedule json file
with open(SCHEDULE_JSON_PATH, 'r') as json_file:
data = json.load(json_file)
# Update the schedule json file
time = start_time
while True:
print(f'Updating time: {time}')
data[time] = setpoint
if time == end_time:
break
else:
time = self.increment_time(time)
# Save the updated schedule json file
with open(SCHEDULE_JSON_PATH, 'w') as json_file:
json.dump(data, json_file, indent=4)
def increment_time(self, time_str):
""" Example Input & Output:
Input = "1430", "0100", "2330"
Output = "1500", "0130", "0000"
"""
# Extract hour and minute
hour = int(time_str[:2])
minute = int(time_str[2:])
# Increment hour and minute
if minute == 30:
hour += 1
minute = 0
elif hour == 23 and minute == 30: # if it's 11:30 PM, increment to 12:00 AM
hour = 0
minute = 0
else:
minute = 30
# Convert to military time format
military_time_str = f"{hour:02d}{minute:02d}"
return military_time_str
def add_db_data(self, ac_action, heat_action):
""" The point of this is to save to thermostat.sql"""
# Create a SQLite database file or connect to an existing one
db = sqlite3.connect(SQL_DB_PATH)
# Create a cursor object to execute SQL commands
cursor = db.cursor()
# Create a table to store thermostat data
cursor.execute('''
CREATE TABLE IF NOT EXISTS thermostat_data (
id INTEGER PRIMARY KEY,
timestamp DATETIME,
ac_action TEXT,
heat_action TEXT,
temperature REAL,
humidity REAL
)
''')
# get current temp from JSON files
with open(TEMPERATURE_JSON_PATH, 'r') as json_file:
data = json.load(json_file)
temperature = data["temperature"]
# get current humidity from JSON files
with open(HUMIDITY_JSON_PATH, 'r') as json_file:
data = json.load(json_file)
humidity = data["humidity"]
# Insert a row of data
timestamp = datetime.now()
cursor.execute('''
INSERT INTO thermostat_data (timestamp, ac_action, heat_action, temperature, humidity)
VALUES (?, ?, ?, ?, ?)
''', (timestamp, ac_action, heat_action, temperature, humidity))
db.commit()
print(f"Record inserted: {timestamp} - AC Action: {ac_action}, Heat Action: {heat_action} Temperature: {temperature}, Humidity: {humidity}")
db.close()
def get_db_data(self, num_entries=10):
""" Return the last num_entries from the database """
# Create a SQLite database file or connect to an existing one
db = sqlite3.connect(SQL_DB_PATH)
# Create a cursor object to execute SQL commands
cursor = db.cursor()
# Get the last num_entries from the database
cursor.execute(f'SELECT * FROM thermostat_data ORDER BY id DESC LIMIT {num_entries}')
entries = cursor.fetchall()
# Close the database connection
db.close()
return entries
# This is for testing purposes
if __name__ == '__main__':
t = Thermostat()
print('thermostat.py ran successfully - Use the Thermostat class to interact with the thermostat')