screen_status_to_mqtt/mqtt_client.py

156 lines
5.5 KiB
Python
Raw Normal View History

2022-03-12 22:06:40 +01:00
import json
import logging
import socket
import subprocess
import sys
from os import path
from time import sleep
import paho.mqtt.client as mqtt
import yaml
from yaml import SafeLoader
import app_path
logger = logging.getLogger("MqttClient")
configLocation = app_path.config_path
ha_objects = [
{
"component": "sensor",
"unique_id": "display",
"name": "Display",
"category": "diagnostic",
"icon": "mdi:monitor-shimmer",
"additional_data": None,
"init_payload": "On"
},
{
"component": "binary_sensor",
"unique_id": "monitor",
"name": "Monitor",
"category": "diagnostic",
"icon": "mdi:monitor",
"additional_data": None,
"init_payload": "ON"
}
]
class MqttClient:
prefix = None
discovery_prefix = None
device_name = None
device_id = None
host = None
port = None
username = None
password = None
def __init__(self, client_name) -> None:
super().__init__()
self.client = mqtt.Client(client_name)
self.client.enable_logger(logging.getLogger("MqttLib"))
self.client.user_data_set({"self": self})
def init_connection(self):
if not path.exists(app_path.config_path):
self._generate_default_conf()
self._load_conf()
self.client.username_pw_set(self.username, self.password)
self.client.connect(self.host, port=self.port)
self.client.on_connect = MqttClient.__on_connect
self.client.loop_start()
def disconnect(self):
message = self.client.publish(f"{self.prefix}/mqtt", payload="offline")
message.wait_for_publish(timeout=10)
self.client.disconnect()
def publish_status(self, sensor, payload):
return self.client.publish(f"{self.prefix}/{sensor}/state", payload=payload)
def _publish_home_assistant_discovery(self):
for ha_object in ha_objects:
self._send_discovery_payload_for(ha_object["component"], ha_object["unique_id"], ha_object["name"],
ha_object["category"], ha_object["icon"], ha_object["additional_data"])
def _publish_init_payload(self):
for ha_object in ha_objects:
self.publish_status(ha_object["unique_id"], ha_object["init_payload"])
@staticmethod
def __on_connect(client, userdata, flag, rc):
logger.info("Connected to MQTT: " + mqtt.connack_string(rc))
self: MqttClient = userdata['self']
client.publish(f"{self.prefix}/mqtt", payload="online")
self._publish_init_payload()
self._publish_home_assistant_discovery()
self._publish_init_payload()
def _send_discovery_payload_for(self, component, unique_id, name, category, icon, additional_data=None):
topic = f"{self.discovery_prefix}/{component}/{self.device_id}/{self.device_id}_sensor_{unique_id}/config"
safe_name = self.device_name.lower().replace(' ', '_').encode('ascii', "ignore").decode()
payload = {
"state_topic": f"{self.prefix}/{unique_id}/state",
"availability": {
"topic": f"{self.prefix}/mqtt"
},
"device": {
"identifiers": [
self.device_id
],
"name": self.device_name
},
"entity_category": category,
"icon": icon,
2022-03-12 22:14:31 +01:00
"name": f"{self.device_name} {name}",
"unique_id": f"{self.device_id} {unique_id}",
"object_id": f"{safe_name} {unique_id}"
2022-03-12 22:06:40 +01:00
}
if additional_data:
payload.update(additional_data)
self.client.publish(topic, json.dumps(payload))
def _generate_default_conf(self):
logger.warning("Generate default conf")
current_machine_id = subprocess.check_output('wmic csproduct get uuid').split()[1].decode("utf-8")
default = {
"mqtt_host": "exemple.local",
"mqtt_port": 1883,
"mqtt_username": "username",
"mqtt_password": "password",
"mqtt_prefix": socket.gethostname(),
"discovery_prefix": "homeassistant",
"device_name": socket.gethostname(),
"device_id": current_machine_id
}
with open(app_path.config_path, "w") as stream:
yaml.dump(default, stream)
def _load_conf(self):
with open(app_path.config_path, "r") as stream:
conf = yaml.load(stream, Loader=SafeLoader)
keys = ["mqtt_host", "mqtt_username", "mqtt_password"]
if all(key in conf for key in keys):
current_machine_id = subprocess.check_output('wmic csproduct get uuid').split()[1].decode("utf-8")
self.prefix = conf.get("mqtt_prefix", "screen_status")
self.discovery_prefix = conf.get("discovery_prefix", "homeassistant")
self.device_name = conf.get("device_name", socket.gethostname())
self.device_id = conf.get("device_id", current_machine_id)
self.host = conf.get("mqtt_host")
self.port = conf.get("mqtt_port", 1883)
self.username = conf.get("mqtt_username")
self.password = conf.get("mqtt_password")
else:
logger.critical("CONFIG FILE INVALID.")
logger.critical("Delete the config file dans restart the service if you want to restore the default "
"config.")
sys.exit(1)