support for xiaomi aqara thermometer and few other fixes (#18)
* import pip._internal.main to work with pip version > 10 * make auth optional and add support for an optional port * add worker for xiaomi aqara thermometer * add support for optional global publishing topic_prefix * Update config.yaml.example
This commit is contained in:
@@ -1,2 +1,3 @@
|
|||||||
config.yaml
|
config.yaml
|
||||||
__pycache__/
|
__pycache__/
|
||||||
|
.idea/
|
||||||
|
|||||||
@@ -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)
|
* [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/)
|
* [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 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
|
## Getting Started
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
mqtt:
|
mqtt:
|
||||||
host: 192.168.1.1
|
host: 192.168.1.1
|
||||||
|
port: 1883
|
||||||
username: user
|
username: user
|
||||||
password: password
|
password: password
|
||||||
|
topic_prefix: hostname
|
||||||
|
|
||||||
manager:
|
manager:
|
||||||
topic_subscription:
|
topic_subscription:
|
||||||
@@ -38,3 +40,9 @@ manager:
|
|||||||
topic_prefix: miflora
|
topic_prefix: miflora
|
||||||
update_interval: 300
|
update_interval: 300
|
||||||
|
|
||||||
|
mithermometer:
|
||||||
|
args:
|
||||||
|
devices:
|
||||||
|
living_room: 00:11:22:33:44:55
|
||||||
|
topic_prefix: mithermometer
|
||||||
|
update_interval: 300
|
||||||
|
|||||||
@@ -7,33 +7,52 @@ class MqttClient:
|
|||||||
self._config = config
|
self._config = config
|
||||||
self._mqttc = mqtt.Client(client_id='bt-mqtt-gateway', clean_session=False)
|
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):
|
def publish(self, messages):
|
||||||
if messages is None:
|
if messages is None or len(messages) == 0:
|
||||||
return
|
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)),
|
publish.multiple(list(map(lambda m: m.as_dict, messages)),
|
||||||
hostname=self.hostname,
|
hostname=self.hostname,
|
||||||
auth={'username': self.username, 'password': self.password})
|
port=self.port,
|
||||||
|
auth=self._auth)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def hostname(self):
|
def hostname(self):
|
||||||
return self._config['host']
|
return self._config['host']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def port(self):
|
||||||
|
return self._config['port'] if 'port' in self._config else 1883
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def username(self):
|
def username(self):
|
||||||
return self._config['username']
|
return self._config['username'] if 'username' in self._config else None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def password(self):
|
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
|
@property
|
||||||
def mqttc(self):
|
def mqttc(self):
|
||||||
return self._mqttc
|
return self._mqttc
|
||||||
|
|
||||||
def callbacks_subscription(self, callbacks):
|
def callbacks_subscription(self, callbacks):
|
||||||
self.mqttc.username_pw_set(self.username, self.password)
|
if self.username is not None and self.password is not None:
|
||||||
self.mqttc.connect(self.hostname)
|
self.mqttc.username_pw_set(self.username, self.password)
|
||||||
|
self.mqttc.connect(self.hostname, port=self.port)
|
||||||
|
|
||||||
for topic, callback in callbacks:
|
for topic, callback in callbacks:
|
||||||
self.mqttc.message_callback_add(topic, callback)
|
self.mqttc.message_callback_add(topic, callback)
|
||||||
|
|||||||
@@ -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
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
import importlib
|
import importlib
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
import pip
|
from pip._internal import main as pip_main
|
||||||
from apscheduler.schedulers.background import BackgroundScheduler
|
from apscheduler.schedulers.background import BackgroundScheduler
|
||||||
from interruptingcow import timeout
|
from interruptingcow import timeout
|
||||||
from functools import partial
|
from functools import partial
|
||||||
@@ -95,7 +95,7 @@ class WorkersManager:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def _pip_install_helper(package_names):
|
def _pip_install_helper(package_names):
|
||||||
for package in 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):
|
def _on_command_wrapper(self, worker_obj, client, _, c):
|
||||||
_LOGGER.debug("on command wrapper for with %s: %s", c.topic, c.payload)
|
_LOGGER.debug("on command wrapper for with %s: %s", c.topic, c.payload)
|
||||||
|
|||||||
Reference in New Issue
Block a user