add MQTT support plus homeassistant MQTT discovery
This commit is contained in:
parent
6d3755e465
commit
84cae7fc26
@ -22,16 +22,15 @@ Python gateway for the [custom firmware](https://github.com/atc1441/ATC_MiThermo
|
||||
- Make in runnable in a docker container (because only cool people are using docker)
|
||||
- Make docker image smaller. I mean shiiit 1GB D: should be possible to be under 500MB (It's now around 100MB)
|
||||
- Implement a loop for fetching the data every X seconds
|
||||
- Storing temperature, humidity and battery state as json in a text file
|
||||
- Can run on Raspberry Pi (3, 4, zero w) or any other Linux driven hardware which has BLE and WiFi support
|
||||
|
||||
**TODOs:**
|
||||
- [WIP] Can run on Raspberry Pi (3, 4, zero w) or any other Linux driven hardware which has BLE and WiFi support
|
||||
- [WIP] Storing temperature, humidity and battery state as json in a text file
|
||||
- [WIP] MQTT publishing with discovery for homeassistant
|
||||
- [TODO] Make a microPython version for using the raspberry pico w or any other microcontroller with BLE and WiFi support
|
||||
- [TODO] Collect data from multiple devices/gateways
|
||||
- [TODO] Command line tool for managing the devices
|
||||
- [TODO] Analyzing tool for making statistics
|
||||
- [TODO] HomeAssistant integration
|
||||
- [TODO] MQTT publishing
|
||||
- [TODO] Maybe... a webinterface. But I suck at web stuff, so I don't know.
|
||||
- [TODO] Implement other BLE Sensors
|
||||
|
||||
|
||||
@ -7,4 +7,6 @@ API=true
|
||||
DEBUG=DEBUG
|
||||
MODE=1
|
||||
LOOP=20
|
||||
TIMEOUT=20
|
||||
TIMEOUT=20
|
||||
MQTT_IP=
|
||||
MQTT_PORT=1883
|
||||
@ -7,6 +7,18 @@ from logger import get_logger
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
def generate_json(device:Device):
|
||||
dev, data_obj, from_config = device
|
||||
return {
|
||||
"timestamp": data_obj.timestamp,
|
||||
"temperature": data_obj.temperature,
|
||||
"humidity": data_obj.humidity,
|
||||
"battery_percent": data_obj.battery_percent,
|
||||
"battery_volt": data_obj.battery_volt,
|
||||
"rssi": dev.rssi
|
||||
}
|
||||
|
||||
|
||||
def log_to_json(devices):
|
||||
workdir, filename = os.path.split(os.path.abspath(__file__))
|
||||
|
||||
@ -29,15 +41,7 @@ def log_to_json(devices):
|
||||
file.write(json.dumps(new_file))
|
||||
data = new_file
|
||||
|
||||
measurements = {
|
||||
"timestamp": data_obj.timestamp,
|
||||
"temperature": data_obj.temperature,
|
||||
"humidity": data_obj.humidity,
|
||||
"battery_percent": data_obj.battery_percent,
|
||||
"battery_volt": data_obj.battery_volt,
|
||||
"rssi": dev.rssi
|
||||
}
|
||||
data['measurements'].append(measurements)
|
||||
data['measurements'].append(generate_json(device))
|
||||
|
||||
# logger.debug(measurements)
|
||||
|
||||
@ -48,6 +52,5 @@ def log_to_mongodb(data):
|
||||
pass
|
||||
|
||||
|
||||
def log_to_mqtt(data):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
@ -1,13 +1,25 @@
|
||||
from time import sleep
|
||||
from log_data import log_to_json
|
||||
from mqtt import publish_home_assistant_device_config
|
||||
from mqtt import publish_device_state
|
||||
from devices import Device
|
||||
from data_class import Data
|
||||
|
||||
from ble_discovery import start_discovery
|
||||
from logger import get_logger
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
def publish_data(devices):
|
||||
log_to_json(devices)
|
||||
for device in devices:
|
||||
publish_home_assistant_device_config(device)
|
||||
publish_device_state(device)
|
||||
|
||||
|
||||
def start_loop(interval=40, timeout=20):
|
||||
logger.info(f"Starting loop with interval {interval}s")
|
||||
while True:
|
||||
devices = start_discovery(timeout=timeout)
|
||||
log_to_json(devices)
|
||||
publish_data(devices)
|
||||
sleep(interval)
|
||||
|
||||
@ -26,20 +26,17 @@ logger.debug(f"VERSION: {os.getenv('VERSION')}")
|
||||
update_state = check_for_update()
|
||||
print_state(update_state)
|
||||
|
||||
try:
|
||||
if DOCKER:
|
||||
logger.info('Running in Docker')
|
||||
if DOCKER:
|
||||
logger.info('Running in Docker')
|
||||
|
||||
try:INTERVAL = int(interval)
|
||||
except:pass
|
||||
try:INTERVAL = int(interval)
|
||||
except:pass
|
||||
|
||||
try:TIMEOUT = int(timeout)
|
||||
except:pass
|
||||
try:TIMEOUT = int(timeout)
|
||||
except:pass
|
||||
|
||||
if interval is None: log_to_json(start_discovery(timeout=TIMEOUT))
|
||||
else:start_loop(INTERVAL, TIMEOUT)
|
||||
if interval is None: log_to_json(start_discovery(timeout=TIMEOUT))
|
||||
else:start_loop(INTERVAL, TIMEOUT)
|
||||
|
||||
else:
|
||||
start_loop(interval=40)
|
||||
except Exception as err:
|
||||
logger.error(err)
|
||||
else:
|
||||
start_loop(interval=40)
|
||||
|
||||
@ -1,15 +1,105 @@
|
||||
import paho.mqtt.client as MQTT
|
||||
import os
|
||||
import json
|
||||
import paho.mqtt.client as mqtt
|
||||
|
||||
topic_root = "/atc_mithermometer_gateway"
|
||||
from devices import Device
|
||||
from data_class import Data
|
||||
from logger import get_logger
|
||||
|
||||
mqtt = MQTT.Client(mqtt.CallbackAPIVersion.VERSION2)
|
||||
mqtt.connect("192.168.178.140", 1883, 60)
|
||||
topic_root = "homeassistant"
|
||||
logger = get_logger(__name__)
|
||||
client = mqtt.Client(client_id='atc_mithermometer_gateway')
|
||||
IP = os.getenv('MQTT_IP')
|
||||
PORT = os.getenv('MQTT_PORT')
|
||||
if IP and PORT:
|
||||
client.connect(IP, int(PORT), 60)
|
||||
|
||||
|
||||
def publish_measurement(mac):
|
||||
topic = f"{topic_root}/measurements/{mac}"
|
||||
topic_temp = f"{topic}/temperature"
|
||||
topic_humid = f"{topic}/humidity"
|
||||
topic_battery = f"{topic}/battery"
|
||||
def generate_json(device:Device):
|
||||
dev, data_obj, from_config = device
|
||||
return {
|
||||
"timestamp": data_obj.timestamp,
|
||||
"temperature": data_obj.temperature,
|
||||
"humidity": data_obj.humidity,
|
||||
"battery_percent": data_obj.battery_percent,
|
||||
"battery_volt": data_obj.battery_volt,
|
||||
"rssi": dev.rssi
|
||||
}
|
||||
|
||||
mqtt.publish(topic_temp, )
|
||||
|
||||
def generate_config_payloads(device:Device):
|
||||
mac = '-'.join(device.mac.split(':')[3:])
|
||||
|
||||
state_topic = f"atc/device/{mac}/state"
|
||||
|
||||
device_json = {
|
||||
"name": f"ATC {device.name}",
|
||||
"identifiers":[f"atc-{mac}"],
|
||||
}
|
||||
|
||||
config_temperature_payload = {
|
||||
"name": f"{device.name} temperature",
|
||||
"unique_id": f"atc-{mac}-temperature",
|
||||
"state_topic": state_topic,
|
||||
"unit_of_measurement": "°C",
|
||||
"value_template": "{{ value_json.temperature}}",
|
||||
"device": device_json
|
||||
}
|
||||
|
||||
config_humidity_payload = {
|
||||
"name": f"{device.name} humidity",
|
||||
"unique_id": f"atc-{mac}-humidity",
|
||||
"state_topic": state_topic,
|
||||
"unit_of_measurement": "%",
|
||||
"value_template": "{{ value_json.humidity}}",
|
||||
"device": device_json
|
||||
}
|
||||
|
||||
config_battery_percent_payload = {
|
||||
"name": f"{device.name} battery",
|
||||
"unique_id": f"atc-{mac}-battery-percent",
|
||||
"state_topic": state_topic,
|
||||
"unit_of_measurement": "%",
|
||||
"value_template": "{{ value_json.battery_percent}}",
|
||||
"device": device_json
|
||||
}
|
||||
|
||||
config_rssi_payload = {
|
||||
"name": f"{device.name} rssi",
|
||||
"unique_id": f"atc-{mac}-rssi",
|
||||
"state_topic": state_topic,
|
||||
"value_template": "{{ value_json.rssi}}",
|
||||
"device": device_json
|
||||
}
|
||||
|
||||
return [config_temperature_payload, config_humidity_payload, config_battery_percent_payload, config_rssi_payload]
|
||||
|
||||
|
||||
def publish_device_state(device:Device):
|
||||
dev, data_obj, from_config = device
|
||||
data_obj: Data
|
||||
from_config: Device
|
||||
mac = '-'.join(from_config.mac.split(':')[3:])
|
||||
state_topic = f"atc/device/{mac}/state"
|
||||
payload = generate_json(device)
|
||||
logger.info(f"Publishing {payload}")
|
||||
client.publish(state_topic, json.dumps(payload))
|
||||
|
||||
|
||||
def publish_home_assistant_device_config(device:Device):
|
||||
dev, data_obj, from_config = device
|
||||
data_obj: Data
|
||||
from_config: Device
|
||||
mac = '-'.join(from_config.mac.split(':')[3:])
|
||||
topic = f"{topic_root}/sensor/atc-{mac}/config"
|
||||
|
||||
temperature_payload, humidity_payload, battery_percent, rssi_payload = generate_config_payloads(from_config)
|
||||
client.publish(f'{topic}-temperature/config', json.dumps(temperature_payload))
|
||||
client.publish(f'{topic}-humidity/config', json.dumps(humidity_payload))
|
||||
client.publish(f'{topic}-battery/config', json.dumps(battery_percent))
|
||||
client.publish(f'{topic}-rssi/config', json.dumps(rssi_payload))
|
||||
|
||||
# client.publish(f'{topic}-temperature/config', json.dumps({}))
|
||||
# client.publish(f'{topic}-humidity/config', json.dumps({}))
|
||||
# client.publish(f'{topic}-battery/config', json.dumps({}))
|
||||
# client.publish(f'{topic}-rssi/config', json.dumps({}))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user