forked from jerrod-lankford/GarageQTPi
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.py
112 lines (84 loc) · 3.66 KB
/
main.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
import os
import binascii
import yaml
import paho.mqtt.client as mqtt
import re
from lib.garage import GarageDoor
print ('Welcome to GarageBerryPi!')
# Update the mqtt state topic
def update_state(value, topic):
print ('State change triggered: {} -> {}'.format(topic, value))
client.publish(topic, value, retain=True)
# The callback for when the client receives a CONNACK response from the server.
def on_connect(client, userdata, rc):
print ('Connected with result code: {}'.format(mqtt.connack_string(rc)))
for config in CONFIG['doors']:
command_topic = config['command_topic']
print('Listening for commands on {}'.format(command_topic))
client.subscribe(command_topic)
# Execute the specified command for a door
def execute_command(door, command):
try:
doorName = door.name
except:
doorName = door.id
print ('Executing command {} for door {}'.format(command, doorName))
if command == "OPEN" and door.state == 'closed':
door.open()
elif command == "CLOSE" and door.state == 'open':
door.close()
elif command == "STOP":
door.stop()
else:
print ('Invalid command:', command)
with open(os.path.join(os.path.abspath(os.path.dirname(__file__)), 'config.yaml'), 'r') as ymlfile:
CONFIG = yaml.load(ymlfile)
### SETUP MQTT ###
user = CONFIG['mqtt']['user']
password = CONFIG['mqtt']['password']
host = CONFIG['mqtt']['host']
print(CONFIG['mqtt']['port'])
port = int(CONFIG['mqtt']['port'])
discovery = bool(CONFIG['mqtt'].get('discovery'))
if 'discovery_prefix' not in CONFIG['mqtt']:
discovery_prefix = 'homeassistant'
else:
discovery_prefix = CONFIG['mqtt']['discovery_prefix']
client = mqtt.Client(client_id='MQTTGarageDoor_{}'.format(binascii.b2a_hex(os.urandom(6))), clean_session=True, userdata=None, protocol=4)
client.on_connect = on_connect
client.username_pw_set(user, password=password)
client.connect(host, port, 60)
### SETUP END ###
### MAIN LOOP ###
if __name__ == "__main__":
# Create door objects and create callback functions
for doorCfg in CONFIG['doors']:
# If no name it set, then set to id
if not doorCfg['name']:
doorCfg['name'] = doorCfg['id']
# Sanitize id value for mqtt
doorCfg['id'] = re.sub('\W+', '', re.sub('\s', ' ', doorCfg['id']))
if discovery is True:
base_topic = discovery_prefix + "/cover/" + doorCfg['id']
config_topic = base_topic + "/config"
doorCfg['command_topic'] = base_topic + "/set"
doorCfg['state_topic'] = base_topic + "/state"
command_topic = doorCfg['command_topic']
state_topic = doorCfg['state_topic']
door = GarageDoor(doorCfg)
# Callback per door that passes a reference to the door
def on_message(client, userdata, msg, door=door):
execute_command(door, str(msg.payload.decode('utf-8')))
# Callback per door that passes the doors state topic
def on_state_change(value, topic=state_topic):
update_state(value, topic)
client.message_callback_add(command_topic, on_message)
# You can add additional listeners here and they will all be executed when the door state changes
door.onStateChange.addHandler(on_state_change)
# Publish initial door state
client.publish(state_topic, door.state, retain=True)
# If discovery is enabled publish configuration
if discovery is True:
client.publish(config_topic,'{"name": "' + doorCfg['name'] + '", "command_topic": "' + command_topic + '", "state_topic": "' + state_topic + '"}', retain=True)
# Main loop
client.loop_forever()