From 64db99ce472d3867e0bb9c4a3339a2f9ad33eebe Mon Sep 17 00:00:00 2001 From: Yury Skaletskiy Date: Mon, 28 Jan 2019 12:16:25 +0300 Subject: [PATCH 1/9] add docker support --- Dockerfile | 5 +++++ README.md | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..e2d78d4 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,5 @@ +FROM python:3.6.8-slim-stretch + +ADD . /app +WORKDIR /app +RUN cd /app && python setup.py install diff --git a/README.md b/README.md index e6b019b..277f23b 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,30 @@ lw301_server --help CLI options overrided config options. +### Using Docker image + +#### How to pack + +```bash +docker build . -t lw301-server +``` + +#### How to use + +- mkdir /var/log/lw301 +- Create and run shell script run_lw301.sh + +```bash +#!/bin/sh +docker rm lw301 --force +docker run \ + --name lw301 -d \ + -p __OUTBOUND_IP_ADDR___:80:47265 \ + -v /var/log/lw301:/log \ + --restart always \ + lw301-server lw301_server --address=0.0.0.0 --log_file_prefix=/log/server.log +``` + ## Triggers From 8b579ead33f81eabac5b9c980eb2782dc853bae5 Mon Sep 17 00:00:00 2001 From: Yury Skaletskiy Date: Tue, 29 Jan 2019 12:52:32 +0300 Subject: [PATCH 2/9] add docker support --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 277f23b..93bd2dd 100644 --- a/README.md +++ b/README.md @@ -47,10 +47,10 @@ docker build . -t lw301-server docker rm lw301 --force docker run \ --name lw301 -d \ - -p __OUTBOUND_IP_ADDR___:80:47265 \ - -v /var/log/lw301:/log \ - --restart always \ - lw301-server lw301_server --address=0.0.0.0 --log_file_prefix=/log/server.log + --restart always \ + -p __OUTBOUND_IP_ADDR___:80:47265 \ + -v /var/log/lw301:/log \ + lw301-server lw301_server --address=0.0.0.0 --log_file_prefix=/log/server.log ``` From bde28e2c6b64297061862036b020f610e162c0c3 Mon Sep 17 00:00:00 2001 From: Yury Skaletskiy Date: Thu, 14 Feb 2019 22:36:06 +0300 Subject: [PATCH 3/9] add mqtt --- lw301_server | 10 +++- lw301_server_app/trigger/__init__.py | 3 ++ lw301_server_app/trigger/mqtt.py | 76 ++++++++++++++++++++++++++++ lw301_server_tests/test_mqtt.py | 15 ++++++ setup.py | 2 +- 5 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 lw301_server_app/trigger/mqtt.py create mode 100644 lw301_server_tests/test_mqtt.py diff --git a/lw301_server b/lw301_server index b49d15d..71af042 100755 --- a/lw301_server +++ b/lw301_server @@ -15,6 +15,7 @@ from lw301_server_app.handler.logging import LoggingHandler from lw301_server_app.handler.update import UpdateHandler from lw301_server_app.handler import api from lw301_server_app.trigger.influxdb import InfluxDbTrigger +from lw301_server_app.trigger.mqtt import MqttTrigger logger = logging.getLogger(os.path.basename(__file__).replace('.py', '')) @@ -39,8 +40,10 @@ def define_options(): # trigger options define('enable-influxdb', default=False, type=bool, help='enable influxdb trigger') - InfluxDbTrigger.add_options() + define('enable-mqtt', default=False, type=bool, help='enable mqtt trigger') + InfluxDbTrigger.add_options() + MqttTrigger.add_options() def parse_options(): define_options() @@ -60,6 +63,11 @@ def init_triggers(options: OptionParser, ioloop: IOLoop): if options.enable_influxdb: logger.info('influxdb trigger enabled') triggers.append(InfluxDbTrigger(ioloop, options)) + + if options.enable_mqtt: + logger.info('mqtt trigger enabled') + triggers.append(MqttTrigger(ioloop, options)) + return triggers diff --git a/lw301_server_app/trigger/__init__.py b/lw301_server_app/trigger/__init__.py index e37cfab..584754f 100644 --- a/lw301_server_app/trigger/__init__.py +++ b/lw301_server_app/trigger/__init__.py @@ -11,6 +11,9 @@ def __init__(self, ioloop: IOLoop, app_options: OptionParser): async def on_new_data(self, measurement, value): pass + def before_stop(self): + pass + @staticmethod def add_options(): pass diff --git a/lw301_server_app/trigger/mqtt.py b/lw301_server_app/trigger/mqtt.py new file mode 100644 index 0000000..0779e76 --- /dev/null +++ b/lw301_server_app/trigger/mqtt.py @@ -0,0 +1,76 @@ +# coding: utf-8 +from logging import getLogger +import time + +from tornado.ioloop import IOLoop +from tornado.options import define, OptionParser +from tornado.httpclient import HTTPRequest, HTTPClientError + +import paho.mqtt.client as mqtt + +from lw301_server_app.trigger import Trigger + + +class MqttTrigger(Trigger): + + _as_tags = ('mac', 'channel') + + log = getLogger('mqtt_trigger') + + + @staticmethod + def add_options(): + define('mqtt-host', type=str) + define('mqtt-port', type=int, default=1883) + define('mqtt-clientid', type=str, default='lw301') + define('mqtt-user', type=str, default=None) + define('mqtt-password', type=str, default=None) + + def __init__(self, ioloop: IOLoop, app_options: OptionParser): + super().__init__(ioloop, app_options) + # self.http_client = AsyncHTTPClient() + self.client = mqtt.Client() + + if self.app_options.mqtt_user is not None: + self.client.username_pw_set( + self.app_options.mqtt_user, + self.app_options.mqtt_password, + ) + + self.client.connect( + self.app_options.mqtt_host, + self.app_options.mqtt_port + ) + self.client.loop_start() + # test self.client.publish("lw301/1/2", 10.2) + + + def before_stop(self): + self.client.loop_stop() + + async def on_new_data(self, measurement, value): + v = value._asdict() + + self.client.publish("lw301/{}/{}".format(v['mac'], measurement), value) + + # # delay processing for next ioloop tick + # self.ioloop.add_callback( + # self._send_data, + # value=value, + # measurement=measurement, + # write_url=self.app_options.influxdb_writeurl, + # user=self.app_options.influxdb_user, + # password=self.app_options.influxdb_password, + # ) + # + # def _value(self, value): + # if isinstance(value, int): + # return '{}i'.format(value) + # elif isinstance(value, float): + # return '{:0.2f}'.format(value) + # return '{}'.format(value) + # + # def _tag_value(self, value): + # if isinstance(value, int): + # value = str(value) + # return self._value(value) diff --git a/lw301_server_tests/test_mqtt.py b/lw301_server_tests/test_mqtt.py new file mode 100644 index 0000000..bb97b60 --- /dev/null +++ b/lw301_server_tests/test_mqtt.py @@ -0,0 +1,15 @@ +# coding: utf-8 +from unittest import TestCase + +from lw301_server_app import protocol + + +class TestMqttTrigger(TestCase): + + def test_mqtt_send(self): + pass + # raw = b'mac=00001234abcd&id=c2&pv=0&lb=0&ac=0®=0001&lost=0000&baro=982&ptr=0&wfor=0&p=1' + # body = protocol.parse_body(raw) + # self.assertIsNone(body.channel) + # self.assertIsNone(body.sensor_values) + # self.assertEqual(body.global_values, {'pressure_hPa': 982}) diff --git a/setup.py b/setup.py index 25963fe..1ea810d 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name='lw301-server', version='0.0.1', - install_requires=['tornado>=5.1, <6.0'], + install_requires=['tornado>=5.1, <6.0', 'paho-mqtt'], tests_require=['nose', 'pycodestyle'], test_suite='nose.collector', scripts=['lw301_server'], From b58f4c466b27f7ebc59766aa5d3848fb1fb4e8a8 Mon Sep 17 00:00:00 2001 From: Yury Skaletskiy Date: Thu, 14 Feb 2019 22:37:30 +0300 Subject: [PATCH 4/9] before_stop handle --- lw301_server | 4 ++++ lw301_server_app/trigger/mqtt.py | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lw301_server b/lw301_server index 71af042..13c280d 100755 --- a/lw301_server +++ b/lw301_server @@ -87,4 +87,8 @@ if __name__ == "__main__": ioloop.start() except KeyboardInterrupt: logger.info('server stopped') + + for t in application.settings['triggers']: + t.before_stop() + sys.exit(0) diff --git a/lw301_server_app/trigger/mqtt.py b/lw301_server_app/trigger/mqtt.py index 0779e76..6f0abd1 100644 --- a/lw301_server_app/trigger/mqtt.py +++ b/lw301_server_app/trigger/mqtt.py @@ -44,7 +44,6 @@ def __init__(self, ioloop: IOLoop, app_options: OptionParser): self.client.loop_start() # test self.client.publish("lw301/1/2", 10.2) - def before_stop(self): self.client.loop_stop() From 22de1db1ff7262525eb38256a852235096669502 Mon Sep 17 00:00:00 2001 From: Yury Skaletskiy Date: Thu, 14 Feb 2019 19:53:48 +0000 Subject: [PATCH 5/9] fix mqtt serialization --- lw301_server_app/trigger/mqtt.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lw301_server_app/trigger/mqtt.py b/lw301_server_app/trigger/mqtt.py index 6f0abd1..2de7266 100644 --- a/lw301_server_app/trigger/mqtt.py +++ b/lw301_server_app/trigger/mqtt.py @@ -1,6 +1,7 @@ # coding: utf-8 from logging import getLogger import time +import json from tornado.ioloop import IOLoop from tornado.options import define, OptionParser @@ -50,7 +51,7 @@ def before_stop(self): async def on_new_data(self, measurement, value): v = value._asdict() - self.client.publish("lw301/{}/{}".format(v['mac'], measurement), value) + self.client.publish("lw301/{}/{}".format(v['mac'], measurement), json.dumps(v)) # # delay processing for next ioloop tick # self.ioloop.add_callback( From 0901458213c3259e3ca4c7c1e8d83f05f97d229c Mon Sep 17 00:00:00 2001 From: Yury Skaletskiy Date: Thu, 14 Feb 2019 19:56:57 +0000 Subject: [PATCH 6/9] added channel to mqtt topic --- lw301_server_app/trigger/mqtt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lw301_server_app/trigger/mqtt.py b/lw301_server_app/trigger/mqtt.py index 2de7266..20e20c2 100644 --- a/lw301_server_app/trigger/mqtt.py +++ b/lw301_server_app/trigger/mqtt.py @@ -51,7 +51,7 @@ def before_stop(self): async def on_new_data(self, measurement, value): v = value._asdict() - self.client.publish("lw301/{}/{}".format(v['mac'], measurement), json.dumps(v)) + self.client.publish("lw301/{}_{}/{}".format(v['mac'], v['channel'], measurement), json.dumps(v)) # # delay processing for next ioloop tick # self.ioloop.add_callback( From 8ce11886131da99efeb93ade29153b6e9d89444b Mon Sep 17 00:00:00 2001 From: Yury Skaletskiy Date: Thu, 14 Feb 2019 23:00:45 +0300 Subject: [PATCH 7/9] empty channel fix --- lw301_server_app/trigger/mqtt.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lw301_server_app/trigger/mqtt.py b/lw301_server_app/trigger/mqtt.py index 20e20c2..93f18a1 100644 --- a/lw301_server_app/trigger/mqtt.py +++ b/lw301_server_app/trigger/mqtt.py @@ -51,7 +51,9 @@ def before_stop(self): async def on_new_data(self, measurement, value): v = value._asdict() - self.client.publish("lw301/{}_{}/{}".format(v['mac'], v['channel'], measurement), json.dumps(v)) + ch = "" if v['channel'] is None else "_{}".format(v['channel']) + + self.client.publish("lw301/{}{}/{}".format(v['mac'], ch, measurement), json.dumps(v)) # # delay processing for next ioloop tick # self.ioloop.add_callback( From 21a5b28bd83d6e3a3f0ceeeb322cae47eb9a2877 Mon Sep 17 00:00:00 2001 From: Yury Skaletskiy Date: Sun, 17 Feb 2019 18:42:21 +0300 Subject: [PATCH 8/9] added mqtt params --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 93bd2dd..b5016f9 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ docker run \ --restart always \ -p __OUTBOUND_IP_ADDR___:80:47265 \ -v /var/log/lw301:/log \ + --enable-mqtt --mqtt-user=test --mqtt-password=test --mqtt-host=127.0.0.1 \ lw301-server lw301_server --address=0.0.0.0 --log_file_prefix=/log/server.log ``` From 1ea3116c6cb42dd856694a96e0440c39f451e577 Mon Sep 17 00:00:00 2001 From: Yury Skaletskiy Date: Mon, 18 Feb 2019 12:38:16 +0300 Subject: [PATCH 9/9] fix NRE on missing channel attr --- lw301_server_app/trigger/mqtt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lw301_server_app/trigger/mqtt.py b/lw301_server_app/trigger/mqtt.py index 93f18a1..f8a3eb8 100644 --- a/lw301_server_app/trigger/mqtt.py +++ b/lw301_server_app/trigger/mqtt.py @@ -51,7 +51,7 @@ def before_stop(self): async def on_new_data(self, measurement, value): v = value._asdict() - ch = "" if v['channel'] is None else "_{}".format(v['channel']) + ch = "" if ('channel' not in v or v['channel'] is None) else "_{}".format(v['channel']) self.client.publish("lw301/{}{}/{}".format(v['mac'], ch, measurement), json.dumps(v))