mirror of
https://github.com/esphome/esphome.git
synced 2025-09-06 05:12:21 +01:00
allow to use MQTT for discovery of IPs if mDNS is no option (#3887)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
128
esphome/mqtt.py
128
esphome/mqtt.py
@@ -4,6 +4,7 @@ import logging
|
||||
import ssl
|
||||
import sys
|
||||
import time
|
||||
import json
|
||||
|
||||
import paho.mqtt.client as mqtt
|
||||
|
||||
@@ -24,15 +25,45 @@ from esphome.const import (
|
||||
from esphome.core import CORE, EsphomeError
|
||||
from esphome.log import color, Fore
|
||||
from esphome.util import safe_print
|
||||
from esphome.helpers import get_str_env, get_int_env
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def initialize(config, subscriptions, on_message, username, password, client_id):
|
||||
def on_connect(client, userdata, flags, return_code):
|
||||
def config_from_env():
|
||||
config = {
|
||||
CONF_MQTT: {
|
||||
CONF_USERNAME: get_str_env("ESPHOME_DASHBOARD_MQTT_USERNAME"),
|
||||
CONF_PASSWORD: get_str_env("ESPHOME_DASHBOARD_MQTT_PASSWORD"),
|
||||
CONF_BROKER: get_str_env("ESPHOME_DASHBOARD_MQTT_BROKER"),
|
||||
CONF_PORT: get_int_env("ESPHOME_DASHBOARD_MQTT_PORT", 1883),
|
||||
},
|
||||
}
|
||||
return config
|
||||
|
||||
|
||||
def initialize(
|
||||
config, subscriptions, on_message, on_connect, username, password, client_id
|
||||
):
|
||||
client = prepare(
|
||||
config, subscriptions, on_message, on_connect, username, password, client_id
|
||||
)
|
||||
try:
|
||||
client.loop_forever()
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
return 0
|
||||
|
||||
|
||||
def prepare(
|
||||
config, subscriptions, on_message, on_connect, username, password, client_id
|
||||
):
|
||||
def on_connect_(client, userdata, flags, return_code):
|
||||
_LOGGER.info("Connected to MQTT broker!")
|
||||
for topic in subscriptions:
|
||||
client.subscribe(topic)
|
||||
if on_connect is not None:
|
||||
on_connect(client, userdata, flags, return_code)
|
||||
|
||||
def on_disconnect(client, userdata, result_code):
|
||||
if result_code == 0:
|
||||
@@ -57,7 +88,7 @@ def initialize(config, subscriptions, on_message, username, password, client_id)
|
||||
tries += 1
|
||||
|
||||
client = mqtt.Client(client_id or "")
|
||||
client.on_connect = on_connect
|
||||
client.on_connect = on_connect_
|
||||
client.on_message = on_message
|
||||
client.on_disconnect = on_disconnect
|
||||
if username is None:
|
||||
@@ -89,11 +120,88 @@ def initialize(config, subscriptions, on_message, username, password, client_id)
|
||||
except OSError as err:
|
||||
raise EsphomeError(f"Cannot connect to MQTT broker: {err}") from err
|
||||
|
||||
try:
|
||||
client.loop_forever()
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
return 0
|
||||
return client
|
||||
|
||||
|
||||
def show_discover(config, username=None, password=None, client_id=None):
|
||||
topic = "esphome/discover/#"
|
||||
_LOGGER.info("Starting log output from %s", topic)
|
||||
|
||||
def on_message(client, userdata, msg):
|
||||
time_ = datetime.now().time().strftime("[%H:%M:%S]")
|
||||
payload = msg.payload.decode(errors="backslashreplace")
|
||||
if len(payload) > 0:
|
||||
message = time_ + " " + payload
|
||||
safe_print(message)
|
||||
|
||||
def on_connect(client, userdata, flags, return_code):
|
||||
_LOGGER.info("Send discover via MQTT broker")
|
||||
client.publish("esphome/discover", None, retain=False)
|
||||
|
||||
return initialize(
|
||||
config, [topic], on_message, on_connect, username, password, client_id
|
||||
)
|
||||
|
||||
|
||||
def get_esphome_device_ip(
|
||||
config, username=None, password=None, client_id=None, timeout=25
|
||||
):
|
||||
if CONF_MQTT not in config:
|
||||
raise EsphomeError(
|
||||
"Cannot discover IP via MQTT as the config does not include the mqtt: "
|
||||
"component"
|
||||
)
|
||||
if CONF_ESPHOME not in config or CONF_NAME not in config[CONF_ESPHOME]:
|
||||
raise EsphomeError(
|
||||
"Cannot discover IP via MQTT as the config does not include the device name: "
|
||||
"component"
|
||||
)
|
||||
|
||||
dev_name = config[CONF_ESPHOME][CONF_NAME]
|
||||
dev_ip = None
|
||||
|
||||
topic = "esphome/discover/" + dev_name
|
||||
_LOGGER.info("Starting looking for IP in topic %s", topic)
|
||||
|
||||
def on_message(client, userdata, msg):
|
||||
nonlocal dev_ip
|
||||
time_ = datetime.now().time().strftime("[%H:%M:%S]")
|
||||
payload = msg.payload.decode(errors="backslashreplace")
|
||||
if len(payload) > 0:
|
||||
message = time_ + " " + payload
|
||||
_LOGGER.debug(message)
|
||||
|
||||
data = json.loads(payload)
|
||||
if "name" not in data or data["name"] != dev_name:
|
||||
_LOGGER.Warn("Wrong device answer")
|
||||
return
|
||||
|
||||
if "ip" in data:
|
||||
dev_ip = data["ip"]
|
||||
client.disconnect()
|
||||
|
||||
def on_connect(client, userdata, flags, return_code):
|
||||
topic = "esphome/ping/" + dev_name
|
||||
_LOGGER.info("Send discover via MQTT broker topic: %s", topic)
|
||||
client.publish(topic, None, retain=False)
|
||||
|
||||
mqtt_client = prepare(
|
||||
config, [topic], on_message, on_connect, username, password, client_id
|
||||
)
|
||||
|
||||
mqtt_client.loop_start()
|
||||
while timeout > 0:
|
||||
if dev_ip is not None:
|
||||
break
|
||||
timeout -= 0.250
|
||||
time.sleep(0.250)
|
||||
mqtt_client.loop_stop()
|
||||
|
||||
if dev_ip is None:
|
||||
raise EsphomeError("Failed to find IP via MQTT")
|
||||
|
||||
_LOGGER.info("Found IP: %s", dev_ip)
|
||||
return dev_ip
|
||||
|
||||
|
||||
def show_logs(config, topic=None, username=None, password=None, client_id=None):
|
||||
@@ -118,7 +226,7 @@ def show_logs(config, topic=None, username=None, password=None, client_id=None):
|
||||
message = time_ + payload
|
||||
safe_print(message)
|
||||
|
||||
return initialize(config, [topic], on_message, username, password, client_id)
|
||||
return initialize(config, [topic], on_message, None, username, password, client_id)
|
||||
|
||||
|
||||
def clear_topic(config, topic, username=None, password=None, client_id=None):
|
||||
@@ -142,7 +250,7 @@ def clear_topic(config, topic, username=None, password=None, client_id=None):
|
||||
return
|
||||
client.publish(msg.topic, None, retain=True)
|
||||
|
||||
return initialize(config, [topic], on_message, username, password, client_id)
|
||||
return initialize(config, [topic], on_message, None, username, password, client_id)
|
||||
|
||||
|
||||
# From marvinroger/async-mqtt-client -> scripts/get-fingerprint/get-fingerprint.py
|
||||
|
Reference in New Issue
Block a user