Skip to content

Commit 51eba62

Browse files
committed
apply style changes and rename module
1 parent 36500ef commit 51eba62

File tree

4 files changed

+235
-55
lines changed

4 files changed

+235
-55
lines changed

.gitignore

+162
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
2+
# Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode,python
3+
# Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode,python
4+
5+
### Python ###
6+
# Byte-compiled / optimized / DLL files
7+
__pycache__/
8+
*.py[cod]
9+
*$py.class
10+
11+
# C extensions
12+
*.so
13+
14+
# Distribution / packaging
15+
.Python
16+
build/
17+
develop-eggs/
18+
dist/
19+
downloads/
20+
eggs/
21+
.eggs/
22+
lib/
23+
lib64/
24+
parts/
25+
sdist/
26+
var/
27+
wheels/
28+
share/python-wheels/
29+
*.egg-info/
30+
.installed.cfg
31+
*.egg
32+
MANIFEST
33+
34+
# PyInstaller
35+
# Usually these files are written by a python script from a template
36+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
37+
*.manifest
38+
*.spec
39+
40+
# Installer logs
41+
pip-log.txt
42+
pip-delete-this-directory.txt
43+
44+
# Unit test / coverage reports
45+
htmlcov/
46+
.tox/
47+
.nox/
48+
.coverage
49+
.coverage.*
50+
.cache
51+
nosetests.xml
52+
coverage.xml
53+
*.cover
54+
*.py,cover
55+
.hypothesis/
56+
.pytest_cache/
57+
cover/
58+
59+
# Translations
60+
*.mo
61+
*.pot
62+
63+
# Django stuff:
64+
*.log
65+
local_settings.py
66+
db.sqlite3
67+
db.sqlite3-journal
68+
69+
# Flask stuff:
70+
instance/
71+
.webassets-cache
72+
73+
# Scrapy stuff:
74+
.scrapy
75+
76+
# Sphinx documentation
77+
docs/_build/
78+
79+
# PyBuilder
80+
.pybuilder/
81+
target/
82+
83+
# Jupyter Notebook
84+
.ipynb_checkpoints
85+
86+
# IPython
87+
profile_default/
88+
ipython_config.py
89+
90+
# pyenv
91+
# For a library or package, you might want to ignore these files since the code is
92+
# intended to run in multiple environments; otherwise, check them in:
93+
# .python-version
94+
95+
# pipenv
96+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
97+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
98+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
99+
# install all needed dependencies.
100+
#Pipfile.lock
101+
102+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
103+
__pypackages__/
104+
105+
# Celery stuff
106+
celerybeat-schedule
107+
celerybeat.pid
108+
109+
# SageMath parsed files
110+
*.sage.py
111+
112+
# Environments
113+
.env
114+
.venv
115+
env/
116+
venv/
117+
ENV/
118+
env.bak/
119+
venv.bak/
120+
121+
# Spyder project settings
122+
.spyderproject
123+
.spyproject
124+
125+
# Rope project settings
126+
.ropeproject
127+
128+
# mkdocs documentation
129+
/site
130+
131+
# mypy
132+
.mypy_cache/
133+
.dmypy.json
134+
dmypy.json
135+
136+
# Pyre type checker
137+
.pyre/
138+
139+
# pytype static type analyzer
140+
.pytype/
141+
142+
# Cython debug symbols
143+
cython_debug/
144+
145+
### VisualStudioCode ###
146+
.vscode/*
147+
!.vscode/settings.json
148+
!.vscode/tasks.json
149+
!.vscode/launch.json
150+
!.vscode/extensions.json
151+
*.code-workspace
152+
153+
# Local History for Visual Studio Code
154+
.history/
155+
156+
### VisualStudioCode Patch ###
157+
# Ignore all local history of files
158+
.history
159+
.ionide
160+
161+
# End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,python
162+
.vscode/settings.json

Dockerfile

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
FROM arm32v6/python:3-alpine
1+
FROM python:alpine
22

33
WORKDIR /usr/src/app
44

5-
COPY requirements.txt .
6-
RUN pip install --no-cache-dir -r requirements.txt
5+
COPY requirements.txt /tmp/requirements.txt
6+
RUN pip install --no-cache-dir -r /tmp/requirements.txt
77

8-
COPY . .
8+
COPY paradox2mqtt.py .
9+
COPY config.yaml .
910

10-
CMD [ "python", "p1738.py"]
11+
CMD [ "python", "paradox2mqtt.py"]

p1738.py paradox2mqtt.py

+65-48
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,17 @@
11
"""
2-
p1738.py
2+
paradox2mqtt.py
33
This script listens for debug serial port packets from a Paradox Spectra 1738
44
alarm panel and sends decoded messages to a MQTT broker.
55
"""
6+
7+
68
import logging
79
import sys
810
import struct
911
import serial
1012
import paho.mqtt.client as mqtt
1113
import yaml
1214

13-
print("""
14-
██╗███████╗██████╗ █████╗
15-
███║╚════██║╚════██╗██╔══██╗
16-
╚██║ ██╔╝ █████╔╝╚█████╔╝
17-
██║ ██╔╝ ╚═══██╗██╔══██╗
18-
██║ ██║ ██████╔╝╚█████╔╝
19-
╚═╝ ╚═╝ ╚═════╝ ╚════╝
20-
A MQTT bridge for Paradox Spectra alarm panel
21-
""")
2215

2316
# Notes on the Paradox P1738 Serial Output packets
2417
# This info comes from looking at the different packets received on the serial
@@ -33,6 +26,7 @@
3326
# | |T| E | | Zone | | Hours | | Minutes | |
3427
# +-------------------------------+-------------------------------+
3528

29+
3630
def parse_msg(packet):
3731
""" Decodes a serial packet into event code and timestamp parts """
3832
raw = struct.unpack("!BBH", packet)
@@ -41,19 +35,22 @@ def parse_msg(packet):
4135
minutes = (raw[2] >> 4) & 0b111111
4236
return code, hours, minutes
4337

38+
4439
def find_mapping(code):
4540
""" Looks-up an event code for a matching message mapping """
46-
for mapping in MESSAGE_MAPPING:
41+
for mapping in _message_mapping:
4742
if mapping['bytes'] == code:
4843
return mapping
4944

45+
5046
def log_msg_bytes(packet):
5147
""" Logs the packet content """
5248
raw = struct.unpack("BBBB", packet)
5349
text = (hex(raw[0]) + " " + hex(raw[1]) + " " + hex(raw[2]) + " "
5450
+ hex(raw[3]))
55-
MQTT_CLIENT.publish("p1738/debug", payload=text, qos=1)
56-
logging.info("In: " + text)
51+
_mqtt_client.publish("paradox2mqtt/debug", payload=text, qos=1)
52+
logging.info("In: %s", text)
53+
5754

5855
def run_loop():
5956
"""
@@ -62,58 +59,78 @@ def run_loop():
6259
"""
6360
while True:
6461
# Read first byte
65-
rcv = SERIAL.read(1)
62+
rcv = _serial.read(1)
6663
if len(rcv) == 1:
6764
# Read the following 3 bytes
68-
rcv += SERIAL.read(3)
65+
rcv += _serial.read(3)
6966
if len(rcv) == 4:
7067
log_msg_bytes(rcv)
7168
(code, _hours, _minutes) = parse_msg(rcv)
7269
mapping = find_mapping(code)
7370
if mapping:
7471
topic = mapping['topic']
7572
message = mapping['message']
76-
logging.info("Out: " + repr(topic) + ", " + repr(message))
77-
MQTT_CLIENT.publish(topic, payload=message, qos=1)
73+
logging.info("Out: %s, %s", repr(topic), repr(message))
74+
_mqtt_client.publish(topic, payload=message, qos=1)
7875
else:
79-
logging.warning("The following bytes have been discarded: " +
80-
repr(rcv))
76+
logging.warning("The following bytes have been discarded: %s", repr(rcv))
77+
78+
79+
_PROGRAM_START_MESSAGE = """
80+
81+
paradox2mqtt
82+
83+
An MQTT bridge for the Paradox Spectra 1738 alarm panel
84+
85+
"""
86+
87+
_message_mapping = []
88+
_mqtt_client = None
89+
_serial = None
90+
91+
92+
def main():
93+
print(_PROGRAM_START_MESSAGE)
94+
95+
logging.getLogger().setLevel(logging.INFO)
96+
logging_file_handler = logging.FileHandler('paradox2mqtt.log', 'w')
97+
logging_file_handler.setLevel(logging.WARNING)
98+
logging_stream_handler = logging.StreamHandler(sys.stdout)
99+
logging_stream_handler.setLevel(logging.INFO)
100+
logging.getLogger().addHandler(logging_file_handler)
101+
logging.getLogger().addHandler(logging_stream_handler)
102+
103+
# Read configuration
104+
logging.info("Reading configuration file")
105+
config = yaml.safe_load(open("config.yaml"))
81106

82-
logging.getLogger().setLevel(logging.INFO)
83-
LOGGING_FILE_HANDLER = logging.FileHandler('p1738.log', 'w')
84-
LOGGING_FILE_HANDLER.setLevel(logging.WARNING)
85-
LOGGING_STREAM_HANDLER = logging.StreamHandler(sys.stdout)
86-
LOGGING_STREAM_HANDLER.setLevel(logging.INFO)
87-
logging.getLogger().addHandler(LOGGING_FILE_HANDLER)
88-
logging.getLogger().addHandler(LOGGING_STREAM_HANDLER)
107+
mqtt_broker = config['mqtt_broker']
108+
serial_device = config['serial_device']
109+
status_topic = config['status']['topic']
110+
status_message_connect = config['status']['message_connect']
111+
status_message_disconnect = config['status']['message_disconnect']
112+
_message_mapping = config['message_mapping']
89113

90-
# Read configuration
91-
logging.info("Reading configuration file")
92-
CONFIG = yaml.safe_load(open("config.yaml"))
114+
logging.info("Connecting to MQTT Broker: %s", mqtt_broker)
93115

94-
MQTT_BROKER = CONFIG['mqtt_broker']
95-
SERIAL_DEVICE = CONFIG['serial_device']
96-
STATUS_TOPIC = CONFIG['status']['topic']
97-
STATUS_MESSAGE_CONNECT = CONFIG['status']['message_connect']
98-
STATUS_MESSAGE_DISCONNECT = CONFIG['status']['message_disconnect']
99-
MESSAGE_MAPPING = CONFIG['message_mapping']
116+
_mqtt_client = mqtt.Client()
117+
_mqtt_client.will_set(status_topic, payload=status_message_disconnect, qos=1,
118+
retain=True)
119+
_mqtt_client.connect(mqtt_broker)
120+
_mqtt_client.loop_start()
100121

101-
logging.info("Connecting to MQTT Broker: " + MQTT_BROKER)
122+
_mqtt_client.publish(status_topic, payload=status_message_connect, qos=1,
123+
retain=True)
102124

103-
MQTT_CLIENT = mqtt.Client()
104-
MQTT_CLIENT.will_set(STATUS_TOPIC, payload=STATUS_MESSAGE_DISCONNECT, qos=1,
105-
retain=True)
106-
MQTT_CLIENT.connect(MQTT_BROKER)
107-
MQTT_CLIENT.loop_start()
125+
logging.info("Connected")
108126

109-
MQTT_CLIENT.publish(STATUS_TOPIC, payload=STATUS_MESSAGE_CONNECT, qos=1,
110-
retain=True)
127+
logging.info("Opening serial device: %s", serial_device)
128+
_serial = serial.Serial(serial_device, baudrate=9600, timeout=5)
111129

112-
logging.info("Connected")
130+
logging.info("Listening for packets")
113131

114-
logging.info("Opening serial device: " + SERIAL_DEVICE)
115-
SERIAL = serial.Serial(SERIAL_DEVICE, baudrate=9600, timeout=5)
132+
run_loop()
116133

117-
logging.info("Listening for packets")
118134

119-
run_loop()
135+
if __name__ == '__main__':
136+
main()

requirements.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
pyyaml==5.4
2-
pyserial==3.4
3-
paho-mqtt==1.5.0
2+
pyserial==3.5
3+
paho-mqtt==1.5

0 commit comments

Comments
 (0)