2018-12-05 21:22:06 +01:00
|
|
|
from datetime import datetime
|
2018-04-18 18:43:13 +02:00
|
|
|
import hashlib
|
2018-04-07 01:23:03 +02:00
|
|
|
import logging
|
2018-09-24 15:27:38 +02:00
|
|
|
import ssl
|
2018-09-25 10:36:12 +02:00
|
|
|
import sys
|
2018-12-05 21:22:06 +01:00
|
|
|
import time
|
2018-04-07 01:23:03 +02:00
|
|
|
|
|
|
|
import paho.mqtt.client as mqtt
|
|
|
|
|
2019-02-13 16:54:02 +01:00
|
|
|
from esphome.const import CONF_BROKER, CONF_DISCOVERY_PREFIX, CONF_ESPHOME, \
|
2018-12-05 21:22:06 +01:00
|
|
|
CONF_LOG_TOPIC, CONF_MQTT, CONF_NAME, CONF_PASSWORD, CONF_PORT, CONF_SSL_FINGERPRINTS, \
|
|
|
|
CONF_TOPIC, CONF_TOPIC_PREFIX, CONF_USERNAME
|
2019-02-13 16:54:02 +01:00
|
|
|
from esphome.core import CORE, EsphomeError
|
|
|
|
from esphome.helpers import color
|
|
|
|
from esphome.util import safe_print
|
2018-04-07 01:23:03 +02:00
|
|
|
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
def initialize(config, subscriptions, on_message, username, password, client_id):
|
2018-04-10 17:17:46 +02:00
|
|
|
def on_connect(client, userdata, flags, return_code):
|
2019-10-24 20:11:17 +02:00
|
|
|
_LOGGER.info("Connected to MQTT broker!")
|
2018-04-07 01:23:03 +02:00
|
|
|
for topic in subscriptions:
|
|
|
|
client.subscribe(topic)
|
|
|
|
|
2018-12-05 21:22:06 +01:00
|
|
|
def on_disconnect(client, userdata, result_code):
|
|
|
|
if result_code == 0:
|
|
|
|
return
|
|
|
|
|
|
|
|
tries = 0
|
|
|
|
while True:
|
|
|
|
try:
|
|
|
|
if client.reconnect() == 0:
|
|
|
|
_LOGGER.info("Successfully reconnected to the MQTT server")
|
|
|
|
break
|
2019-12-07 18:28:55 +01:00
|
|
|
except OSError:
|
2018-12-05 21:22:06 +01:00
|
|
|
pass
|
|
|
|
|
|
|
|
wait_time = min(2**tries, 300)
|
|
|
|
_LOGGER.warning(
|
|
|
|
"Disconnected from MQTT (%s). Trying to reconnect in %s s",
|
|
|
|
result_code, wait_time)
|
|
|
|
time.sleep(wait_time)
|
|
|
|
tries += 1
|
|
|
|
|
2019-12-07 18:28:55 +01:00
|
|
|
client = mqtt.Client(client_id or '')
|
2018-04-07 01:23:03 +02:00
|
|
|
client.on_connect = on_connect
|
|
|
|
client.on_message = on_message
|
2018-12-05 21:22:06 +01:00
|
|
|
client.on_disconnect = on_disconnect
|
2018-04-07 01:23:03 +02:00
|
|
|
if username is None:
|
|
|
|
if config[CONF_MQTT].get(CONF_USERNAME):
|
|
|
|
client.username_pw_set(config[CONF_MQTT][CONF_USERNAME],
|
|
|
|
config[CONF_MQTT][CONF_PASSWORD])
|
|
|
|
elif username:
|
|
|
|
client.username_pw_set(username, password)
|
2018-09-24 15:27:38 +02:00
|
|
|
|
|
|
|
if config[CONF_MQTT].get(CONF_SSL_FINGERPRINTS):
|
2018-09-25 10:36:12 +02:00
|
|
|
if sys.version_info >= (2, 7, 13):
|
|
|
|
tls_version = ssl.PROTOCOL_TLS # pylint: disable=no-member
|
|
|
|
else:
|
|
|
|
tls_version = ssl.PROTOCOL_SSLv23
|
2018-09-24 15:27:38 +02:00
|
|
|
client.tls_set(ca_certs=None, certfile=None, keyfile=None, cert_reqs=ssl.CERT_REQUIRED,
|
2018-09-25 10:36:12 +02:00
|
|
|
tls_version=tls_version, ciphers=None)
|
2018-12-05 21:22:06 +01:00
|
|
|
|
|
|
|
try:
|
2019-12-04 15:58:58 +01:00
|
|
|
host = str(config[CONF_MQTT][CONF_BROKER])
|
|
|
|
port = int(config[CONF_MQTT][CONF_PORT])
|
|
|
|
client.connect(host, port)
|
2019-12-07 18:28:55 +01:00
|
|
|
except OSError as err:
|
|
|
|
raise EsphomeError(f"Cannot connect to MQTT broker: {err}")
|
2018-04-07 01:23:03 +02:00
|
|
|
|
|
|
|
try:
|
|
|
|
client.loop_forever()
|
|
|
|
except KeyboardInterrupt:
|
|
|
|
pass
|
|
|
|
return 0
|
|
|
|
|
|
|
|
|
2018-12-05 21:22:06 +01:00
|
|
|
def show_logs(config, topic=None, username=None, password=None, client_id=None):
|
2018-04-07 01:23:03 +02:00
|
|
|
if topic is not None:
|
|
|
|
pass # already have topic
|
2018-04-18 18:43:13 +02:00
|
|
|
elif CONF_MQTT in config:
|
|
|
|
conf = config[CONF_MQTT]
|
|
|
|
if CONF_LOG_TOPIC in conf:
|
2018-06-06 11:12:29 +02:00
|
|
|
topic = config[CONF_MQTT][CONF_LOG_TOPIC][CONF_TOPIC]
|
2018-04-18 18:43:13 +02:00
|
|
|
elif CONF_TOPIC_PREFIX in config[CONF_MQTT]:
|
2019-12-07 18:28:55 +01:00
|
|
|
topic = config[CONF_MQTT][CONF_TOPIC_PREFIX] + '/debug'
|
2018-04-18 18:43:13 +02:00
|
|
|
else:
|
2019-12-07 18:28:55 +01:00
|
|
|
topic = config[CONF_ESPHOME][CONF_NAME] + '/debug'
|
2018-04-07 01:23:03 +02:00
|
|
|
else:
|
2019-12-07 18:28:55 +01:00
|
|
|
_LOGGER.error("MQTT isn't setup, can't start MQTT logs")
|
2018-04-18 18:43:13 +02:00
|
|
|
return 1
|
2019-12-07 18:28:55 +01:00
|
|
|
_LOGGER.info("Starting log output from %s", topic)
|
2018-04-07 01:23:03 +02:00
|
|
|
|
|
|
|
def on_message(client, userdata, msg):
|
2019-12-07 18:28:55 +01:00
|
|
|
time_ = datetime.now().time().strftime('[%H:%M:%S]')
|
|
|
|
payload = msg.payload.decode(errors='backslashreplace')
|
2019-10-24 20:11:17 +02:00
|
|
|
message = time_ + payload
|
2018-10-20 12:41:00 +02:00
|
|
|
safe_print(message)
|
2018-04-07 01:23:03 +02:00
|
|
|
|
|
|
|
return initialize(config, [topic], on_message, username, password, client_id)
|
|
|
|
|
|
|
|
|
|
|
|
def clear_topic(config, topic, username=None, password=None, client_id=None):
|
|
|
|
if topic is None:
|
2019-12-07 18:28:55 +01:00
|
|
|
discovery_prefix = config[CONF_MQTT].get(CONF_DISCOVERY_PREFIX, 'homeassistant')
|
2019-02-13 16:54:02 +01:00
|
|
|
name = config[CONF_ESPHOME][CONF_NAME]
|
2019-12-07 18:28:55 +01:00
|
|
|
topic = f'{discovery_prefix}/+/{name}/#'
|
|
|
|
_LOGGER.info("Clearing messages from '%s'", topic)
|
|
|
|
_LOGGER.info("Please close this window when no more messages appear and the "
|
|
|
|
"MQTT topic has been cleared of retained messages.")
|
2018-04-07 01:23:03 +02:00
|
|
|
|
|
|
|
def on_message(client, userdata, msg):
|
2018-08-13 19:11:33 +02:00
|
|
|
if not msg.payload or not msg.retain:
|
|
|
|
return
|
|
|
|
try:
|
2019-12-07 18:28:55 +01:00
|
|
|
print(f"Clearing topic {msg.topic}")
|
2018-08-13 19:11:33 +02:00
|
|
|
except UnicodeDecodeError:
|
2019-12-07 18:28:55 +01:00
|
|
|
print("Skipping non-UTF-8 topic (prohibited by MQTT standard)")
|
2018-04-07 01:23:03 +02:00
|
|
|
return
|
|
|
|
client.publish(msg.topic, None, retain=True)
|
|
|
|
|
|
|
|
return initialize(config, [topic], on_message, username, password, client_id)
|
2018-04-18 18:43:13 +02:00
|
|
|
|
|
|
|
|
|
|
|
# From marvinroger/async-mqtt-client -> scripts/get-fingerprint/get-fingerprint.py
|
|
|
|
def get_fingerprint(config):
|
2019-12-04 15:58:58 +01:00
|
|
|
addr = str(config[CONF_MQTT][CONF_BROKER]), int(config[CONF_MQTT][CONF_PORT])
|
2018-04-18 18:43:13 +02:00
|
|
|
_LOGGER.info("Getting fingerprint from %s:%s", addr[0], addr[1])
|
|
|
|
try:
|
|
|
|
cert_pem = ssl.get_server_certificate(addr)
|
2019-12-07 18:28:55 +01:00
|
|
|
except OSError as err:
|
2018-04-18 18:43:13 +02:00
|
|
|
_LOGGER.error("Unable to connect to server: %s", err)
|
|
|
|
return 1
|
|
|
|
cert_der = ssl.PEM_cert_to_DER_cert(cert_pem)
|
|
|
|
|
|
|
|
sha1 = hashlib.sha1(cert_der).hexdigest()
|
|
|
|
|
2019-12-07 18:28:55 +01:00
|
|
|
safe_print("SHA1 Fingerprint: " + color('cyan', sha1))
|
|
|
|
safe_print("Copy the string above into mqtt.ssl_fingerprints section of {}"
|
|
|
|
"".format(CORE.config_path))
|
2018-04-18 18:43:13 +02:00
|
|
|
return 0
|