Initial commit
This commit is contained in:
commit
26a396f8da
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
.pyenv/
|
||||
.vscode/
|
||||
__pycache__/
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal 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
24
Dockerfile
Normal 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
1
bluetooth_utils
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 416a8925682d6ee4ad607936d897646a3a83a331
|
18
docker-compose.yaml
Normal file
18
docker-compose.yaml
Normal 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
6
entrypoint.sh
Normal file
|
@ -0,0 +1,6 @@
|
|||
#!/bin/sh
|
||||
|
||||
service dbus start
|
||||
service bluetooth start
|
||||
|
||||
python get_data.py ${@}
|
87
get_data.py
Normal file
87
get_data.py
Normal 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
2
requirements.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
paho-mqtt
|
||||
pybluez
|
Loading…
Reference in a new issue