Initial Commit

This commit is contained in:
2025-03-23 12:59:17 +00:00
commit 1b9fc0ae1d
2 changed files with 473 additions and 0 deletions

238
src/main.py Normal file
View File

@@ -0,0 +1,238 @@
import time
from pytevolve import Tevolve
import paho.mqtt.client as mqtt
import threading
import json
broker_address = "192.168.0.100"
def on_disconnect(client, userdata, rc):
client.connect(broker_address)
def on_connect(client, userdata, flags, rc):
try:
# client.username_pw_set("admin", "bK2F2ZPjyyngmsN6R32s")
# client.username_pw_set(username="admin", password ="bK2F2ZPjyyngmsN6R32s")
client.connect(broker_address)
except:
time.sleep(10)
client.connect(client)
def on_message(client, userdata, message):
new_topic = str(message.topic)
if new_topic == "hallway/heater/settemp":
tevolve.set_temperature("3", str(message.payload.decode("utf-8")))
# Assume set temp success (Prevent debounce)
client.publish("hallway/heater/currentsettemp", payload=str(message.payload.decode("utf-8")), qos=0, retain=False)
if new_topic == "hallway/heater/setmode":
if str(message.payload.decode("utf-8")) == "heat":
mode = "manual"
# client.publish("hallway/heater/idleaction", payload="heating", qos=0, retain=False)
client.publish("hallway/heater/currentmode", payload="heat", qos=0, retain=False)
else:
mode = "off"
client.publish("hallway/heater/currentmode", payload="off", qos=0, retain=False)
client.publish("hallway/heater/idleaction", payload="off", qos=0, retain=False)
if mode == "manual":
if float(Tevolve.hallway_current_temp) > float(Tevolve.hallway_set_temp):
client.publish("hallway/heater/idleaction", payload="idle", qos=0, retain=False)
else:
client.publish("hallway/heater/idleaction", payload="heating", qos=0, retain=False)
Tevolve.setmode = mode
tevolve.set_mode("3")
if new_topic == "livingroom/heater/settemp":
tevolve.set_temperature("2", str(message.payload.decode("utf-8")))
# Assume set temp success (Prevent debounce)
client.publish("livingroom/heater/currentsettemp", payload=str(message.payload.decode("utf-8")), qos=0,
retain=False)
if new_topic == "livingroom/heater/setmode":
# print(str(message.payload.decode("utf-8")))
if str(message.payload.decode("utf-8")) == "heat":
mode = "manual"
client.publish("livingroom/heater/idleaction", payload="heating", qos=0, retain=False)
client.publish("livingroom/heater/currentmode", payload="heat", qos=0, retain=False)
else:
mode = "off"
client.publish("livingroom/heater/currentmode", payload="off", qos=0, retain=False)
client.publish("livingroom/heater/idleaction", payload="off", qos=0, retain=False)
if mode == "manual":
if float(Tevolve.livingroom_current_temp) > float(Tevolve.livingroom_set_temp):
client.publish("livingroom/heater/idleaction", payload="idle", qos=0, retain=False)
else:
client.publish("livingroom/heater/idleaction", payload="heating", qos=0, retain=False)
Tevolve.setmode = mode
tevolve.set_mode("2")
if __name__ == '__main__':
tevolve = Tevolve()
tevolve.post_websocket()
time.sleep(1)
t = threading.Thread(target=tevolve.create_websocket, daemon=True, args=())
t.start()
client = mqtt.Client("ryan-heating")
# client.username_pw_set("admin", "bK2F2ZPjyyngmsN6R32s")
client.connect(broker_address)
client.on_message = on_message
client.on_disconnect = on_disconnect
client.loop_start()
client.subscribe("hallway/heater/settemp")
client.subscribe("hallway/heater/setmode")
client.subscribe("livingroom/heater/settemp")
client.subscribe("livingroom/heater/setmode")
livingroom_status = tevolve.get_status("2")
hallway_status = tevolve.get_status("3")
Tevolve.hallway_active = hallway_status["active"]
Tevolve.hallway_mode = hallway_status["mode"]
Tevolve.hallway_set_temp = hallway_status["stemp"]
Tevolve.hallway_current_temp = hallway_status["mtemp"]
# Tevolve.livingroom_active = livingroom_status["active"]
# Tevolve.livingroom_mode = livingroom_status["mode"]
# Tevolve.livingroom_set_temp = livingroom_status["stemp"]
# Tevolve.livingroom_current_temp = livingroom_status["mtemp"]
if Tevolve.livingroom_mode == "manual":
Tevolve.livingroom_mode = "heat"
if Tevolve.hallway_mode == "manual":
Tevolve.hallway_mode = "heat"
client.publish("hallway/heater/currenttemp", payload=Tevolve.hallway_current_temp, qos=0, retain=False)
client.publish("livingroom/heater/currenttemp", payload=Tevolve.livingroom_current_temp, qos=0, retain=False)
client.publish("hallway/heater/currentmode", payload=Tevolve.hallway_mode, qos=0, retain=False)
client.publish("livingroom/heater/currentmode", payload=Tevolve.livingroom_mode, qos=0, retain=False)
client.publish("hallway/heater/currentsettemp", payload=Tevolve.hallway_set_temp, qos=0, retain=False)
client.publish("livingroom/heater/currentsettemp", payload=Tevolve.livingroom_set_temp, qos=0, retain=False)
# Setup initial hallway heater values
if Tevolve.hallway_mode == "off":
client.publish("hallway/heater/setmode", payload="off", qos=0, retain=False)
# client.publish("hallway/heater/idleaction", payload="idle", qos=0, retain=False)
if Tevolve.hallway_mode == "manual":
if float(Tevolve.hallway_current_temp) >= float(Tevolve.hallway_set_temp):
client.publish("hallway/heater/idleaction", payload="idle", qos=0, retain=False)
if float(Tevolve.hallway_set_temp) > float(Tevolve.hallway_current_temp):
client.publish("hallway/heater/idleaction", payload="heating", qos=0, retain=False)
# Setup initial living room heater values
if Tevolve.livingroom_mode == "off":
client.publish("livingroom/heater/setmode", payload="off", qos=0, retain=False)
if Tevolve.livingroom_mode == "manual":
if float(Tevolve.livingroom_current_temp) >= float(Tevolve.livingroom_set_temp):
client.publish("livingroom/heater/idleaction", payload="idle", qos=0, retain=False)
if float(Tevolve.livingroom_set_temp) > float(Tevolve.livingroom_current_temp):
client.publish("livignroom/heater/idleaction", payload="heating", qos=0, retain=False)
while True:
if Tevolve.websocket_message != "":
if "/api/v2" in Tevolve.websocket_message:
print(Tevolve.websocket_message[30:-1])
m = json.loads(Tevolve.websocket_message[30:-1])
# print(m)
if m["path"] == "/htr/3/status":
Tevolve.hallway_active = m["body"]["active"]
Tevolve.hallway_mode = m["body"]["mode"]
Tevolve.hallway_set_temp = m["body"]["stemp"]
Tevolve.hallway_current_temp = m["body"]["mtemp"]
if Tevolve.hallway_mode == "off":
client.publish("hallway/heater/setmode", payload="off", qos=0, retain=False)
# client.publish("hallway/heater/idleaction", payload="idle", qos=0, retain=False)
if Tevolve.hallway_mode == "manual":
if float(Tevolve.hallway_set_temp) > float(Tevolve.hallway_current_temp):
client.publish("hallway/heater/idleaction", payload="heating", qos=0, retain=False)
client.publish("hallway/heater/currentmode", payload="heat", qos=0, retain=False)
if float(Tevolve.hallway_set_temp) <= float(Tevolve.hallway_current_temp):
client.publish("hallway/heater/idleaction", payload="idle", qos=0, retain=False)
client.publish("hallway/heater/currentmode", payload="heat", qos=0, retain=False)
client.publish("hallway/heater/currentsettemp", payload=m["body"]["stemp"], qos=0, retain=False)
# Publish hallway current temperature
client.publish("hallway/heater/currenttemp", payload=m["body"]["mtemp"], qos=0, retain=False)
if m["path"] == "/htr/2/status":
Tevolve.livingroom_active = m["body"]["active"]
Tevolve.livingroom_mode = m["body"]["mode"]
Tevolve.livingroom_set_temp = m["body"]["stemp"]
Tevolve.livingroom_current_temp = m["body"]["mtemp"]
if Tevolve.livingroom_mode == "off":
client.publish("livingroom/heater/setmode", payload="off", qos=0, retain=False)
if Tevolve.livingroom_mode == "manual":
if float(Tevolve.livingroom_set_temp) > float(Tevolve.livingroom_current_temp):
client.publish("livingroom/heater/idleaction", payload="heating", qos=0, retain=False)
client.publish("livingroom/heater/currentmode", payload="heat", qos=0, retain=False)
if float(Tevolve.livingroom_set_temp) <= float(Tevolve.livingroom_current_temp):
client.publish("livingroom/heater/idleaction", payload="idle", qos=0, retain=False)
client.publish("livingroom/heater/currentmode", payload="heat", qos=0, retain=False)
client.publish("livingroom/heater/currentsettemp", payload=m["body"]["stemp"], qos=0, retain=False)
# Publish hallway current temperature
client.publish("livingroom/heater/currenttemp", payload=m["body"]["mtemp"], qos=0, retain=False)
Tevolve.websocket_message = ""
time.sleep(1)

235
src/pytevolve.py Normal file
View File

@@ -0,0 +1,235 @@
import requests
import json
import threading
import websocket
import time
data = "username=1202283%40uad.ac.uk&password=24e76d8e4&grant_type=password"
url = "https://api-tevolve.termoweb.net/client/token"
headers = {'content-type': 'application/x-www-form-urlencoded',
'authorization': 'Basic NWM0OWRjZTk3NzUxMDM1MTUwNmM0MmRiOnRldm9sdmU='}
dev_id = "082e858131ff012c51"
class Tevolve:
setmode = ""
setTemperature = ""
token = None
sid = ""
websocket_url = ""
mode = ""
set_point = ""
websocket_message = ""
hallway_mode = ""
hallway_current_temp = ""
hallway_set_temp = ""
hallway_active = ""
livingroom_mode = ""
livingroom_current_temp = ""
livingroom_set_temp = ""
livingroom_active = ""
@staticmethod
def token_manager():
while Tevolve.token is None:
x = requests.post(url, headers=headers, data=data)
print(x)
if x.status_code == 200:
Tevolve.token = x.json()["access_token"]
else:
time.sleep(30)
@staticmethod
def get_sid():
time.sleep(5)
url = "https://api-tevolve.termoweb.net/socket.io/?token=" + Tevolve.token + "&dev_id=082e858131ff012c51&EIO" \
"=3&transport=polling"
payload = {}
response = requests.request("GET", url, data=payload)
if response.status_code == 200:
temp = response.text[5:]
temp = json.loads(temp)
Tevolve.sid = temp['sid']
else:
Tevolve.token = None
Tevolve.token_manager()
@staticmethod
def post_websocket():
Tevolve.token_manager()
Tevolve.get_sid()
url = "https://api-tevolve.termoweb.net/socket.io/?token=" + Tevolve.token + "&dev_id=082e858131ff012c51&EIO" \
"=3&transport=polling&t=Ntb6xXn" \
"&sid=" + Tevolve.sid
payload = "401:40/api/v2/socket_io?token=" + Tevolve.token + "&dev_id=082e858131ff012c51"
headers = {
'Cookie': "io=" + Tevolve.sid,
'Content-Type': 'text/plain',
'Connection': 'keep-alive'
}
requests.request("POST", url, headers=headers, data=payload)
@staticmethod
def create_websocket():
time.sleep(5)
websocket_url = "wss://api-tevolve.termoweb.net/socket.io/?token=" + Tevolve.token + "&dev_id=082e858131ff012c51&EIO=3&transport=websocket&sid=" + Tevolve.sid + ""
def on_message(ws, message):
Tevolve.websocket_message = message
def on_open(ws):
def run():
print("websocket (run)")
counter = 0
ws.send("2probe")
time.sleep(2)
ws.send(str("5"))
while 1:
ws.send("2")
counter = counter + 1
if counter >= 360:
break
time.sleep(10)
r = threading.Thread(target=run, daemon=True)
r.start()
def on_close(ws, close_status_code, close_msg):
print("WEB SOCKET ClOSED")
Tevolve.post_websocket()
Tevolve.create_websocket()
def on_error(ws, err):
print("WEB SOCKET ERROR")
Tevolve.post_websocket()
Tevolve.create_websocket()
ws = websocket.WebSocketApp(websocket_url)
websocket.enableTrace(False)
ws.on_message = on_message
ws.on_open = on_open
ws.on_close = on_close
ws.on_error = on_error
ws.run_forever(ping_interval=10, ping_payload='42/api/v2/socket_io,["message","ping"]')
@staticmethod
def set_mode(heater_id):
heater_id = heater_id
mode = Tevolve.setmode
headers = {
'host': 'api-tevolve.termoweb.net',
'origin': 'https://tevolve.termoweb.net',
'content-type': 'application/json',
'accept': 'application/json, text/plain, */*',
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) '
'Version/15.4 Safari/605.1.15',
'authorization': 'Bearer ' + Tevolve.token,
'referer': 'https://tevolve.termoweb.net/'
}
url = "https://api-tevolve.termoweb.net/api/v2/devs/082e858131ff012c51/htr/" + heater_id + "/status"
if mode == "heat":
mode = "manual"
payload = json.dumps({
"mode": mode
})
response = requests.post(url, headers=headers, data=payload)
if response.status_code == 201 or response.status_code == 200:
pass
@staticmethod
def get_mode(heater_id):
headers = {
'host': 'api-tevolve.termoweb.net',
'origin': 'https://tevolve.termoweb.net',
'content-type': 'application/json',
'accept': 'application/json, text/plain, */*',
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) '
'Version/15.4 Safari/605.1.15',
'authorization': 'Bearer ' + Tevolve.token,
'referer': 'https://tevolve.termoweb.net/',
}
url = "https://api-tevolve.termoweb.net/api/v2/devs/082e858131ff012c51/htr/" + heater_id + "/status"
response = requests.get(url, headers=headers)
if response.status_code == 201 or response.status_code == 200:
mode = response.json()["mode"]
if mode == "manual":
return "heat"
@staticmethod
def get_status(heater_id):
headers = {
'host': 'api-tevolve.termoweb.net',
'origin': 'https://tevolve.termoweb.net',
'content-type': 'application/json',
'accept': 'application/json, text/plain, */*',
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) '
'Version/15.4 Safari/605.1.15',
'authorization': 'Bearer ' + Tevolve.token,
'referer': 'https://tevolve.termoweb.net/',
}
url = "https://api-tevolve.termoweb.net/api/v2/devs/082e858131ff012c51/htr/" + heater_id + "/status"
response = requests.get(url, headers=headers)
if response.status_code == 201 or response.status_code == 200:
return response.json()
@staticmethod
def set_temperature(heater_id, set_temperature):
headers = {
'host': 'api-tevolve.termoweb.net',
'origin': 'https://tevolve.termoweb.net',
'content-type': 'application/json',
'accept': 'application/json, text/plain, */*',
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) '
'Version/15.4 Safari/605.1.15',
'authorization': 'Bearer ' + Tevolve.token,
'referer': 'https://tevolve.termoweb.net/'
}
url = "https://api-tevolve.termoweb.net/api/v2/devs/082e858131ff012c51/htr/" + heater_id + "/status"
payload = json.dumps({
"stemp": str(float(set_temperature)),
"units": "C",
"mode": "manual"
})
response = requests.post(url, headers=headers, data=payload)
if response.status_code == 201 or response.status_code == 200:
pass