diff --git a/.gitignore b/.gitignore index 5392b09..15ef3d7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ config.yaml __pycache__/ +.idea/ diff --git a/README.md b/README.md index 15bdb6a..e283044 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ See [Wiki](https://github.com/zewelor/bt-mqtt-gateway/wiki) for more information * [Linak Desk](https://www.linak.com/business-areas/desks/office-desks/) via [linak_bt_desk](https://github.com/zewelor/linak_bt_desk) * [MySensors](https://www.mysensors.org/) * [Xiaomi Mi Flora plant sensor](https://xiaomi-mi.com/sockets-and-sensors/xiaomi-huahuacaocao-flower-care-smart-monitor/) via [miflora](https://github.com/open-homeautomation/miflora) +* Xiaomi Aqara thermometer via [mithermometer](https://github.com/hobbypunk90/mithermometer) ## Getting Started diff --git a/config.yaml.example b/config.yaml.example index 9794ffe..369301f 100644 --- a/config.yaml.example +++ b/config.yaml.example @@ -1,7 +1,9 @@ mqtt: host: 192.168.1.1 + port: 1883 username: user password: password + topic_prefix: hostname manager: topic_subscription: @@ -38,3 +40,9 @@ manager: topic_prefix: miflora update_interval: 300 + mithermometer: + args: + devices: + living_room: 00:11:22:33:44:55 + topic_prefix: mithermometer + update_interval: 300 diff --git a/mqtt.py b/mqtt.py index 06c64f4..9f9b48a 100644 --- a/mqtt.py +++ b/mqtt.py @@ -6,34 +6,53 @@ class MqttClient: def __init__(self, config): self._config = config self._mqttc = mqtt.Client(client_id='bt-mqtt-gateway', clean_session=False) + + if self.username is not None and self.password is not None: + self._auth = {'username': self.username, 'password': self.password} + else: + self._auth = None def publish(self, messages): - if messages is None: + if messages is None or len(messages) == 0: return - + + if self.topic_prefix is not None: + for m in messages: + m.topic = "{}/{}".format(self.topic_prefix, m.topic) + publish.multiple(list(map(lambda m: m.as_dict, messages)), hostname=self.hostname, - auth={'username': self.username, 'password': self.password}) + port=self.port, + auth=self._auth) @property def hostname(self): return self._config['host'] + @property + def port(self): + return self._config['port'] if 'port' in self._config else 1883 + @property def username(self): - return self._config['username'] + return self._config['username'] if 'username' in self._config else None @property def password(self): - return self._config['password'] + return self._config['password'] if 'password' in self._config else None + + @property + def topic_prefix(self): + return self._config['topic_prefix'] if 'topic_prefix' in self._config else None @property def mqttc(self): return self._mqttc def callbacks_subscription(self, callbacks): - self.mqttc.username_pw_set(self.username, self.password) - self.mqttc.connect(self.hostname) + if self.username is not None and self.password is not None: + self.mqttc.username_pw_set(self.username, self.password) + self.mqttc.connect(self.hostname, port=self.port) for topic, callback in callbacks: self.mqttc.message_callback_add(topic, callback) diff --git a/workers/mithermometer.py b/workers/mithermometer.py new file mode 100644 index 0000000..c48f90f --- /dev/null +++ b/workers/mithermometer.py @@ -0,0 +1,37 @@ +from interruptingcow import timeout +from mqtt import MqttMessage +from workers.base import BaseWorker + +REQUIREMENTS = ['mithermometer'] + +monitoredAttrs = ["temperature", "humidity", "battery"] + +class MithermometerWorker(BaseWorker): + def _setup(self): + from mithermometer.mithermometer_poller import MiThermometerPoller + from btlewrap.bluepy import BluepyBackend + + + for name, mac in self.devices.items(): + self.devices[name] = MiThermometerPoller(mac, BluepyBackend) + + def status_update(self): + ret = [] + for name, poller in self.devices.items(): + try: + ret += self.update_device_state(name, poller) + except RuntimeError: + pass + + return ret + + @timeout(8.0) + + def update_device_state(self, name, poller): + + ret = [] + for attr in monitoredAttrs: + + ret.append(MqttMessage(topic=self.format_topic(name, attr), payload=poller.parameter_value(attr))) + + return ret diff --git a/workers_manager.py b/workers_manager.py index de9dcaa..8051841 100644 --- a/workers_manager.py +++ b/workers_manager.py @@ -1,7 +1,7 @@ import importlib import threading -import pip +from pip._internal import main as pip_main from apscheduler.schedulers.background import BackgroundScheduler from interruptingcow import timeout from functools import partial @@ -95,7 +95,7 @@ class WorkersManager: @staticmethod def _pip_install_helper(package_names): for package in package_names: - pip.main(['install', '-q', package]) + pip_main(['install', '-q', package]) def _on_command_wrapper(self, worker_obj, client, _, c): _LOGGER.debug("on command wrapper for with %s: %s", c.topic, c.payload)