Initial commit

This commit is contained in:
Scott Wallace 2021-06-16 07:00:43 +01:00
commit 26a396f8da
Signed by: scott
GPG key ID: AA742FDC5AFE2A72
8 changed files with 144 additions and 0 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
.pyenv/
.vscode/
__pycache__/

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "bluetooth_utils"]
path = bluetooth_utils
url = https://github.com/colin-guyon/py-bluetooth-utils.git

24
Dockerfile Normal file
View file

@ -0,0 +1,24 @@
FROM python:3.8-slim-buster
# Keeps Python from generating .pyc files in the container
ENV PYTHONDONTWRITEBYTECODE 1
# Turns off buffering for easier container logging
ENV PYTHONUNBUFFERED 1
RUN apt update
RUN apt install -y gcc libbluetooth-dev bluez bluetooth
RUN apt clean
ADD requirements.txt .
RUN python -m pip install -r requirements.txt
RUN useradd -d /app -m appuser
WORKDIR /app
USER appuser
COPY get_data.py /app
COPY bluetooth_utils /app/bluetooth_utils
COPY entrypoint.sh /app
ENTRYPOINT ["/bin/bash", "/app/entrypoint.sh"]

1
bluetooth_utils Submodule

@ -0,0 +1 @@
Subproject commit 416a8925682d6ee4ad607936d897646a3a83a331

18
docker-compose.yaml Normal file
View file

@ -0,0 +1,18 @@
---
version: "3"
services:
xiaomi2mqtt:
image: xiaomi2mqtt:latest
container_name: xiaomi2mqtt
user: root:root
environment:
- TZ=Europe/London
- MQTT_HOST=mqtt.lan
devices:
- /dev/bus/usb
network_mode: host
cap_add:
- SYS_ADMIN
- CAP_SYSLOG
- NET_ADMIN
restart: unless-stopped

6
entrypoint.sh Normal file
View file

@ -0,0 +1,6 @@
#!/bin/sh
service dbus start
service bluetooth start
python get_data.py ${@}

87
get_data.py Normal file
View file

@ -0,0 +1,87 @@
"""
Read Xiaomi LYWSD03MMC advertised packets and send them to MQTT
"""
import os
from datetime import datetime
import bluetooth._bluetooth as bluez
import paho.mqtt.publish as publish
from bluetooth_utils.bluetooth_utils import (disable_le_scan, enable_le_scan,
parse_le_advertising_events,
raw_packet_to_str, toggle_device)
def send_to_mqtt(data: dict):
"""
Send data from LYWSD03MMC to MQTT
"""
msgs = [
{
'topic': f'sensors/home/{data["mac"]}/temperature',
'payload': data['temperature'],
},
{
'topic': f'sensors/home/{data["mac"]}/humidity',
'payload': data['humidity'],
},
{
'topic': f'sensors/home/{data["mac"]}/battery',
'payload': data['battery'],
},
]
publish.multiple(msgs, hostname=os.environ.get('MQTT_HOST', 'mqtt'))
def le_advertise_packet_handler(mac: str, _, data: bytes, __):
"""
Handle new Xiaomi LYWSD03MMC BTLE advertise packet
"""
data_str = raw_packet_to_str(data)
# Check for ATC preamble
if data_str[0:2] == '11' and data_str[6:10] == '1a18':
temp = int(data_str[22:26], 16) / 10
hum = int(data_str[26:28], 16)
batt = int(data_str[28:30], 16)
send_to_mqtt(
{
'timestamp': datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
'mac': mac,
'temperature': temp,
'humidity': hum,
'battery': batt,
}
)
if __name__ == '__main__':
def main():
"""
Main program
"""
# Use 0 for hci0
dev_id = 0
toggle_device(dev_id, True)
try:
sock = bluez.hci_open_dev(dev_id) # pylint: disable=c-extension-no-member
except:
print(f'Cannot open bluetooth device {dev_id}')
raise
# Set filter to "True" to see only one packet per device
enable_le_scan(sock, filter_duplicates=False)
try:
# Called on new LE packet
parse_le_advertising_events(
sock, handler=le_advertise_packet_handler, debug=False
)
# Scan until Ctrl-C
except KeyboardInterrupt:
disable_le_scan(sock)
main()

2
requirements.txt Normal file
View file

@ -0,0 +1,2 @@
paho-mqtt
pybluez