mirror of
https://github.com/esphome/esphome.git
synced 2024-11-15 03:28:12 +01:00
Merge branch 'mdns_cache' into integration
This commit is contained in:
commit
4b50b6cfc7
12 changed files with 138 additions and 53 deletions
|
@ -3,7 +3,7 @@
|
||||||
# See https://pre-commit.com/hooks.html for more hooks
|
# See https://pre-commit.com/hooks.html for more hooks
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/psf/black-pre-commit-mirror
|
- repo: https://github.com/psf/black-pre-commit-mirror
|
||||||
rev: 23.10.1
|
rev: 23.11.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: black
|
- id: black
|
||||||
args:
|
args:
|
||||||
|
|
|
@ -246,6 +246,7 @@ esphome/components/radon_eye_rd200/* @jeffeb3
|
||||||
esphome/components/rc522/* @glmnet
|
esphome/components/rc522/* @glmnet
|
||||||
esphome/components/rc522_i2c/* @glmnet
|
esphome/components/rc522_i2c/* @glmnet
|
||||||
esphome/components/rc522_spi/* @glmnet
|
esphome/components/rc522_spi/* @glmnet
|
||||||
|
esphome/components/resistance_sampler/* @jesserockz
|
||||||
esphome/components/restart/* @esphome/core
|
esphome/components/restart/* @esphome/core
|
||||||
esphome/components/rf_bridge/* @jesserockz
|
esphome/components/rf_bridge/* @jesserockz
|
||||||
esphome/components/rgbct/* @jesserockz
|
esphome/components/rgbct/* @jesserockz
|
||||||
|
|
|
@ -2,7 +2,7 @@ from math import log
|
||||||
|
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
from esphome.components import sensor
|
from esphome.components import sensor, resistance_sampler
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
CONF_CALIBRATION,
|
CONF_CALIBRATION,
|
||||||
CONF_REFERENCE_RESISTANCE,
|
CONF_REFERENCE_RESISTANCE,
|
||||||
|
@ -15,6 +15,8 @@ from esphome.const import (
|
||||||
UNIT_CELSIUS,
|
UNIT_CELSIUS,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
AUTO_LOAD = ["resistance_sampler"]
|
||||||
|
|
||||||
ntc_ns = cg.esphome_ns.namespace("ntc")
|
ntc_ns = cg.esphome_ns.namespace("ntc")
|
||||||
NTC = ntc_ns.class_("NTC", cg.Component, sensor.Sensor)
|
NTC = ntc_ns.class_("NTC", cg.Component, sensor.Sensor)
|
||||||
|
|
||||||
|
@ -124,7 +126,7 @@ CONFIG_SCHEMA = (
|
||||||
)
|
)
|
||||||
.extend(
|
.extend(
|
||||||
{
|
{
|
||||||
cv.Required(CONF_SENSOR): cv.use_id(sensor.Sensor),
|
cv.Required(CONF_SENSOR): cv.use_id(resistance_sampler.ResistanceSampler),
|
||||||
cv.Required(CONF_CALIBRATION): process_calibration,
|
cv.Required(CONF_CALIBRATION): process_calibration,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/components/resistance_sampler/resistance_sampler.h"
|
||||||
#include "esphome/components/sensor/sensor.h"
|
#include "esphome/components/sensor/sensor.h"
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace resistance {
|
namespace resistance {
|
||||||
|
@ -11,7 +12,7 @@ enum ResistanceConfiguration {
|
||||||
DOWNSTREAM,
|
DOWNSTREAM,
|
||||||
};
|
};
|
||||||
|
|
||||||
class ResistanceSensor : public Component, public sensor::Sensor {
|
class ResistanceSensor : public Component, public sensor::Sensor, resistance_sampler::ResistanceSampler {
|
||||||
public:
|
public:
|
||||||
void set_sensor(Sensor *sensor) { sensor_ = sensor; }
|
void set_sensor(Sensor *sensor) { sensor_ = sensor; }
|
||||||
void set_configuration(ResistanceConfiguration configuration) { configuration_ = configuration; }
|
void set_configuration(ResistanceConfiguration configuration) { configuration_ = configuration; }
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome.components import sensor
|
from esphome.components import sensor, resistance_sampler
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
CONF_SENSOR,
|
CONF_SENSOR,
|
||||||
STATE_CLASS_MEASUREMENT,
|
STATE_CLASS_MEASUREMENT,
|
||||||
|
@ -8,8 +8,15 @@ from esphome.const import (
|
||||||
ICON_FLASH,
|
ICON_FLASH,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
AUTO_LOAD = ["resistance_sampler"]
|
||||||
|
|
||||||
resistance_ns = cg.esphome_ns.namespace("resistance")
|
resistance_ns = cg.esphome_ns.namespace("resistance")
|
||||||
ResistanceSensor = resistance_ns.class_("ResistanceSensor", cg.Component, sensor.Sensor)
|
ResistanceSensor = resistance_ns.class_(
|
||||||
|
"ResistanceSensor",
|
||||||
|
cg.Component,
|
||||||
|
sensor.Sensor,
|
||||||
|
resistance_sampler.ResistanceSampler,
|
||||||
|
)
|
||||||
|
|
||||||
CONF_REFERENCE_VOLTAGE = "reference_voltage"
|
CONF_REFERENCE_VOLTAGE = "reference_voltage"
|
||||||
CONF_CONFIGURATION = "configuration"
|
CONF_CONFIGURATION = "configuration"
|
||||||
|
|
6
esphome/components/resistance_sampler/__init__.py
Normal file
6
esphome/components/resistance_sampler/__init__.py
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
|
||||||
|
resistance_sampler_ns = cg.esphome_ns.namespace("resistance_sampler")
|
||||||
|
ResistanceSampler = resistance_sampler_ns.class_("ResistanceSampler")
|
||||||
|
|
||||||
|
CODEOWNERS = ["@jesserockz"]
|
10
esphome/components/resistance_sampler/resistance_sampler.h
Normal file
10
esphome/components/resistance_sampler/resistance_sampler.h
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace resistance_sampler {
|
||||||
|
|
||||||
|
/// Abstract interface to mark components that provide resistance values.
|
||||||
|
class ResistanceSampler {};
|
||||||
|
|
||||||
|
} // namespace resistance_sampler
|
||||||
|
} // namespace esphome
|
|
@ -43,11 +43,17 @@ def validate_mode(mode):
|
||||||
return mode
|
return mode
|
||||||
|
|
||||||
|
|
||||||
|
def validate_pin(pin):
|
||||||
|
if pin in (8, 9):
|
||||||
|
raise cv.Invalid(f"pin {pin} doesn't exist")
|
||||||
|
return pin
|
||||||
|
|
||||||
|
|
||||||
XL9535_PIN_SCHEMA = cv.All(
|
XL9535_PIN_SCHEMA = cv.All(
|
||||||
{
|
{
|
||||||
cv.GenerateID(): cv.declare_id(XL9535GPIOPin),
|
cv.GenerateID(): cv.declare_id(XL9535GPIOPin),
|
||||||
cv.Required(CONF_XL9535): cv.use_id(XL9535Component),
|
cv.Required(CONF_XL9535): cv.use_id(XL9535Component),
|
||||||
cv.Required(CONF_NUMBER): cv.int_range(min=0, max=15),
|
cv.Required(CONF_NUMBER): cv.All(cv.int_range(min=0, max=17), validate_pin),
|
||||||
cv.Optional(CONF_MODE, default={}): cv.All(
|
cv.Optional(CONF_MODE, default={}): cv.All(
|
||||||
{
|
{
|
||||||
cv.Optional(CONF_INPUT, default=False): cv.boolean,
|
cv.Optional(CONF_INPUT, default=False): cv.boolean,
|
||||||
|
|
|
@ -18,6 +18,7 @@ import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import threading
|
import threading
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
import tornado
|
import tornado
|
||||||
import tornado.concurrent
|
import tornado.concurrent
|
||||||
|
@ -398,19 +399,40 @@ class EsphomeCommandWebSocket(tornado.websocket.WebSocketHandler):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
class EsphomeLogsHandler(EsphomeCommandWebSocket):
|
DASHBOARD_COMMAND = ["esphome", "--dashboard"]
|
||||||
def build_command(self, json_message):
|
|
||||||
config_file = settings.rel_path(json_message["configuration"])
|
|
||||||
|
class EsphomePortCommandWebSocket(EsphomeCommandWebSocket):
|
||||||
|
"""Base class for commands that require a port."""
|
||||||
|
|
||||||
|
def run_command(self, args: list[str], json_message: dict[str, Any]) -> list[str]:
|
||||||
|
"""Build the command to run."""
|
||||||
|
configuration = json_message["configuration"]
|
||||||
|
config_file = settings.rel_path(configuration)
|
||||||
|
port = json_message["port"]
|
||||||
|
if (
|
||||||
|
port == "OTA"
|
||||||
|
and (mdns := MDNS_CONTAINER.get_mdns())
|
||||||
|
and (host_name := mdns.filename_to_host_name_thread_safe(configuration))
|
||||||
|
and (address := mdns.resolve_host_thread_safe(host_name))
|
||||||
|
):
|
||||||
|
port = address
|
||||||
|
|
||||||
return [
|
return [
|
||||||
"esphome",
|
*DASHBOARD_COMMAND,
|
||||||
"--dashboard",
|
*args,
|
||||||
"logs",
|
|
||||||
config_file,
|
config_file,
|
||||||
"--device",
|
"--device",
|
||||||
json_message["port"],
|
port,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class EsphomeLogsHandler(EsphomePortCommandWebSocket):
|
||||||
|
def build_command(self, json_message: dict[str, Any]) -> list[str]:
|
||||||
|
"""Build the command to run."""
|
||||||
|
return self.run_command(["logs"], json_message)
|
||||||
|
|
||||||
|
|
||||||
class EsphomeRenameHandler(EsphomeCommandWebSocket):
|
class EsphomeRenameHandler(EsphomeCommandWebSocket):
|
||||||
old_name: str
|
old_name: str
|
||||||
|
|
||||||
|
@ -418,8 +440,7 @@ class EsphomeRenameHandler(EsphomeCommandWebSocket):
|
||||||
config_file = settings.rel_path(json_message["configuration"])
|
config_file = settings.rel_path(json_message["configuration"])
|
||||||
self.old_name = json_message["configuration"]
|
self.old_name = json_message["configuration"]
|
||||||
return [
|
return [
|
||||||
"esphome",
|
*DASHBOARD_COMMAND,
|
||||||
"--dashboard",
|
|
||||||
"rename",
|
"rename",
|
||||||
config_file,
|
config_file,
|
||||||
json_message["newName"],
|
json_message["newName"],
|
||||||
|
@ -435,36 +456,22 @@ class EsphomeRenameHandler(EsphomeCommandWebSocket):
|
||||||
PING_RESULT.pop(self.old_name, None)
|
PING_RESULT.pop(self.old_name, None)
|
||||||
|
|
||||||
|
|
||||||
class EsphomeUploadHandler(EsphomeCommandWebSocket):
|
class EsphomeUploadHandler(EsphomePortCommandWebSocket):
|
||||||
def build_command(self, json_message):
|
def build_command(self, json_message: dict[str, Any]) -> list[str]:
|
||||||
config_file = settings.rel_path(json_message["configuration"])
|
"""Build the command to run."""
|
||||||
return [
|
return self.run_command(["upload"], json_message)
|
||||||
"esphome",
|
|
||||||
"--dashboard",
|
|
||||||
"upload",
|
|
||||||
config_file,
|
|
||||||
"--device",
|
|
||||||
json_message["port"],
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class EsphomeRunHandler(EsphomeCommandWebSocket):
|
class EsphomeRunHandler(EsphomePortCommandWebSocket):
|
||||||
def build_command(self, json_message):
|
def build_command(self, json_message: dict[str, Any]) -> list[str]:
|
||||||
config_file = settings.rel_path(json_message["configuration"])
|
"""Build the command to run."""
|
||||||
return [
|
return self.run_command(["run"], json_message)
|
||||||
"esphome",
|
|
||||||
"--dashboard",
|
|
||||||
"run",
|
|
||||||
config_file,
|
|
||||||
"--device",
|
|
||||||
json_message["port"],
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class EsphomeCompileHandler(EsphomeCommandWebSocket):
|
class EsphomeCompileHandler(EsphomeCommandWebSocket):
|
||||||
def build_command(self, json_message):
|
def build_command(self, json_message):
|
||||||
config_file = settings.rel_path(json_message["configuration"])
|
config_file = settings.rel_path(json_message["configuration"])
|
||||||
command = ["esphome", "--dashboard", "compile"]
|
command = [*DASHBOARD_COMMAND, "compile"]
|
||||||
if json_message.get("only_generate", False):
|
if json_message.get("only_generate", False):
|
||||||
command.append("--only-generate")
|
command.append("--only-generate")
|
||||||
command.append(config_file)
|
command.append(config_file)
|
||||||
|
@ -474,7 +481,7 @@ class EsphomeCompileHandler(EsphomeCommandWebSocket):
|
||||||
class EsphomeValidateHandler(EsphomeCommandWebSocket):
|
class EsphomeValidateHandler(EsphomeCommandWebSocket):
|
||||||
def build_command(self, json_message):
|
def build_command(self, json_message):
|
||||||
config_file = settings.rel_path(json_message["configuration"])
|
config_file = settings.rel_path(json_message["configuration"])
|
||||||
command = ["esphome", "--dashboard", "config", config_file]
|
command = [*DASHBOARD_COMMAND, "config", config_file]
|
||||||
if not settings.streamer_mode:
|
if not settings.streamer_mode:
|
||||||
command.append("--show-secrets")
|
command.append("--show-secrets")
|
||||||
return command
|
return command
|
||||||
|
@ -483,28 +490,28 @@ class EsphomeValidateHandler(EsphomeCommandWebSocket):
|
||||||
class EsphomeCleanMqttHandler(EsphomeCommandWebSocket):
|
class EsphomeCleanMqttHandler(EsphomeCommandWebSocket):
|
||||||
def build_command(self, json_message):
|
def build_command(self, json_message):
|
||||||
config_file = settings.rel_path(json_message["configuration"])
|
config_file = settings.rel_path(json_message["configuration"])
|
||||||
return ["esphome", "--dashboard", "clean-mqtt", config_file]
|
return [*DASHBOARD_COMMAND, "clean-mqtt", config_file]
|
||||||
|
|
||||||
|
|
||||||
class EsphomeCleanHandler(EsphomeCommandWebSocket):
|
class EsphomeCleanHandler(EsphomeCommandWebSocket):
|
||||||
def build_command(self, json_message):
|
def build_command(self, json_message):
|
||||||
config_file = settings.rel_path(json_message["configuration"])
|
config_file = settings.rel_path(json_message["configuration"])
|
||||||
return ["esphome", "--dashboard", "clean", config_file]
|
return [*DASHBOARD_COMMAND, "clean", config_file]
|
||||||
|
|
||||||
|
|
||||||
class EsphomeVscodeHandler(EsphomeCommandWebSocket):
|
class EsphomeVscodeHandler(EsphomeCommandWebSocket):
|
||||||
def build_command(self, json_message):
|
def build_command(self, json_message):
|
||||||
return ["esphome", "--dashboard", "-q", "vscode", "dummy"]
|
return [*DASHBOARD_COMMAND, "-q", "vscode", "dummy"]
|
||||||
|
|
||||||
|
|
||||||
class EsphomeAceEditorHandler(EsphomeCommandWebSocket):
|
class EsphomeAceEditorHandler(EsphomeCommandWebSocket):
|
||||||
def build_command(self, json_message):
|
def build_command(self, json_message):
|
||||||
return ["esphome", "--dashboard", "-q", "vscode", "--ace", settings.config_dir]
|
return [*DASHBOARD_COMMAND, "-q", "vscode", "--ace", settings.config_dir]
|
||||||
|
|
||||||
|
|
||||||
class EsphomeUpdateAllHandler(EsphomeCommandWebSocket):
|
class EsphomeUpdateAllHandler(EsphomeCommandWebSocket):
|
||||||
def build_command(self, json_message):
|
def build_command(self, json_message):
|
||||||
return ["esphome", "--dashboard", "update-all", settings.config_dir]
|
return [*DASHBOARD_COMMAND, "update-all", settings.config_dir]
|
||||||
|
|
||||||
|
|
||||||
class SerialPortRequestHandler(BaseHandler):
|
class SerialPortRequestHandler(BaseHandler):
|
||||||
|
@ -964,23 +971,38 @@ class BoardsRequestHandler(BaseHandler):
|
||||||
|
|
||||||
|
|
||||||
class MDNSStatusThread(threading.Thread):
|
class MDNSStatusThread(threading.Thread):
|
||||||
def __init__(self):
|
"""Thread that updates the mdns status."""
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
"""Initialize the MDNSStatusThread."""
|
"""Initialize the MDNSStatusThread."""
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
self.zeroconf: EsphomeZeroconf | None = None
|
||||||
# This is the current mdns state for each host (True, False, None)
|
# This is the current mdns state for each host (True, False, None)
|
||||||
self.host_mdns_state: dict[str, bool | None] = {}
|
self.host_mdns_state: dict[str, bool | None] = {}
|
||||||
# This is the hostnames to filenames mapping
|
# This is the hostnames to filenames mapping
|
||||||
self.host_name_to_filename: dict[str, str] = {}
|
self.host_name_to_filename: dict[str, str] = {}
|
||||||
|
self.filename_to_host_name: dict[str, str] = {}
|
||||||
# This is a set of host names to track (i.e no_mdns = false)
|
# This is a set of host names to track (i.e no_mdns = false)
|
||||||
self.host_name_with_mdns_enabled: set[set] = set()
|
self.host_name_with_mdns_enabled: set[set] = set()
|
||||||
self._refresh_hosts()
|
self._refresh_hosts()
|
||||||
|
|
||||||
|
def filename_to_host_name_thread_safe(self, filename: str) -> str | None:
|
||||||
|
"""Resolve a filename to an address in a thread-safe manner."""
|
||||||
|
return self.filename_to_host_name.get(filename)
|
||||||
|
|
||||||
|
def resolve_host_thread_safe(self, host_name: str) -> str | None:
|
||||||
|
"""Resolve a host name to an address in a thread-safe manner."""
|
||||||
|
if zc := self.zeroconf:
|
||||||
|
return zc.resolve_host(host_name)
|
||||||
|
return None
|
||||||
|
|
||||||
def _refresh_hosts(self):
|
def _refresh_hosts(self):
|
||||||
"""Refresh the hosts to track."""
|
"""Refresh the hosts to track."""
|
||||||
entries = _list_dashboard_entries()
|
entries = _list_dashboard_entries()
|
||||||
host_name_with_mdns_enabled = self.host_name_with_mdns_enabled
|
host_name_with_mdns_enabled = self.host_name_with_mdns_enabled
|
||||||
host_mdns_state = self.host_mdns_state
|
host_mdns_state = self.host_mdns_state
|
||||||
host_name_to_filename = self.host_name_to_filename
|
host_name_to_filename = self.host_name_to_filename
|
||||||
|
filename_to_host_name = self.filename_to_host_name
|
||||||
|
|
||||||
for entry in entries:
|
for entry in entries:
|
||||||
name = entry.name
|
name = entry.name
|
||||||
|
@ -1003,11 +1025,13 @@ class MDNSStatusThread(threading.Thread):
|
||||||
# so when we get an mdns update we can map it back
|
# so when we get an mdns update we can map it back
|
||||||
# to the filename
|
# to the filename
|
||||||
host_name_to_filename[name] = filename
|
host_name_to_filename[name] = filename
|
||||||
|
filename_to_host_name[filename] = name
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
global IMPORT_RESULT
|
global IMPORT_RESULT
|
||||||
|
|
||||||
zc = EsphomeZeroconf()
|
zc = EsphomeZeroconf()
|
||||||
|
self.zeroconf = zc
|
||||||
host_mdns_state = self.host_mdns_state
|
host_mdns_state = self.host_mdns_state
|
||||||
host_name_to_filename = self.host_name_to_filename
|
host_name_to_filename = self.host_name_to_filename
|
||||||
host_name_with_mdns_enabled = self.host_name_with_mdns_enabled
|
host_name_with_mdns_enabled = self.host_name_with_mdns_enabled
|
||||||
|
@ -1035,6 +1059,7 @@ class MDNSStatusThread(threading.Thread):
|
||||||
|
|
||||||
browser.cancel()
|
browser.cancel()
|
||||||
zc.close()
|
zc.close()
|
||||||
|
self.zeroconf = None
|
||||||
|
|
||||||
|
|
||||||
class PingStatusThread(threading.Thread):
|
class PingStatusThread(threading.Thread):
|
||||||
|
@ -1211,11 +1236,26 @@ class UndoDeleteRequestHandler(BaseHandler):
|
||||||
shutil.move(os.path.join(trash_path, configuration), config_file)
|
shutil.move(os.path.join(trash_path, configuration), config_file)
|
||||||
|
|
||||||
|
|
||||||
|
class MDNSContainer:
|
||||||
|
def __init__(self) -> None:
|
||||||
|
"""Initialize the MDNSContainer."""
|
||||||
|
self._mdns: MDNSStatusThread | None = None
|
||||||
|
|
||||||
|
def set_mdns(self, mdns: MDNSStatusThread) -> None:
|
||||||
|
"""Set the MDNSStatusThread instance."""
|
||||||
|
self._mdns = mdns
|
||||||
|
|
||||||
|
def get_mdns(self) -> MDNSStatusThread | None:
|
||||||
|
"""Return the MDNSStatusThread instance."""
|
||||||
|
return self._mdns
|
||||||
|
|
||||||
|
|
||||||
PING_RESULT: dict = {}
|
PING_RESULT: dict = {}
|
||||||
IMPORT_RESULT = {}
|
IMPORT_RESULT = {}
|
||||||
STOP_EVENT = threading.Event()
|
STOP_EVENT = threading.Event()
|
||||||
PING_REQUEST = threading.Event()
|
PING_REQUEST = threading.Event()
|
||||||
MQTT_PING_REQUEST = threading.Event()
|
MQTT_PING_REQUEST = threading.Event()
|
||||||
|
MDNS_CONTAINER = MDNSContainer()
|
||||||
|
|
||||||
|
|
||||||
class LoginHandler(BaseHandler):
|
class LoginHandler(BaseHandler):
|
||||||
|
@ -1506,6 +1546,7 @@ def start_web_server(args):
|
||||||
status_thread = PingStatusThread()
|
status_thread = PingStatusThread()
|
||||||
else:
|
else:
|
||||||
status_thread = MDNSStatusThread()
|
status_thread = MDNSStatusThread()
|
||||||
|
MDNS_CONTAINER.set_mdns(status_thread)
|
||||||
status_thread.start()
|
status_thread.start()
|
||||||
|
|
||||||
if settings.status_use_mqtt:
|
if settings.status_use_mqtt:
|
||||||
|
@ -1519,6 +1560,7 @@ def start_web_server(args):
|
||||||
STOP_EVENT.set()
|
STOP_EVENT.set()
|
||||||
PING_REQUEST.set()
|
PING_REQUEST.set()
|
||||||
status_thread.join()
|
status_thread.join()
|
||||||
|
MDNS_CONTAINER.set_mdns(None)
|
||||||
if settings.status_use_mqtt:
|
if settings.status_use_mqtt:
|
||||||
status_thread_mqtt.join()
|
status_thread_mqtt.join()
|
||||||
MQTT_PING_REQUEST.set()
|
MQTT_PING_REQUEST.set()
|
||||||
|
|
|
@ -147,12 +147,13 @@ class DashboardImportDiscovery:
|
||||||
|
|
||||||
|
|
||||||
class EsphomeZeroconf(Zeroconf):
|
class EsphomeZeroconf(Zeroconf):
|
||||||
def resolve_host(self, host: str, timeout=3.0):
|
def resolve_host(self, host: str, timeout: float = 3.0) -> str | None:
|
||||||
"""Resolve a host name to an IP address."""
|
"""Resolve a host name to an IP address."""
|
||||||
name = host.partition(".")[0]
|
name = host.partition(".")[0]
|
||||||
info = HostResolver(f"{name}.{ESPHOME_SERVICE_TYPE}", ESPHOME_SERVICE_TYPE)
|
info = HostResolver(ESPHOME_SERVICE_TYPE, f"{name}.{ESPHOME_SERVICE_TYPE}")
|
||||||
if (info.load_from_cache(self) or info.request(self, timeout * 1000)) and (
|
if (
|
||||||
addresses := info.ip_addresses_by_version(IPVersion.V4Only)
|
info.load_from_cache(self)
|
||||||
):
|
or (timeout and info.request(self, timeout * 1000))
|
||||||
|
) and (addresses := info.ip_addresses_by_version(IPVersion.V4Only)):
|
||||||
return str(addresses[0])
|
return str(addresses[0])
|
||||||
return None
|
return None
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
pylint==2.17.6
|
pylint==2.17.6
|
||||||
flake8==6.1.0 # also change in .pre-commit-config.yaml when updating
|
flake8==6.1.0 # also change in .pre-commit-config.yaml when updating
|
||||||
black==23.10.1 # also change in .pre-commit-config.yaml when updating
|
black==23.11.0 # also change in .pre-commit-config.yaml when updating
|
||||||
pyupgrade==3.15.0 # also change in .pre-commit-config.yaml when updating
|
pyupgrade==3.15.0 # also change in .pre-commit-config.yaml when updating
|
||||||
pre-commit
|
pre-commit
|
||||||
|
|
||||||
|
|
|
@ -425,6 +425,15 @@ binary_sensor:
|
||||||
input: true
|
input: true
|
||||||
inverted: false
|
inverted: false
|
||||||
|
|
||||||
|
- platform: gpio
|
||||||
|
name: XL9535 Pin 17
|
||||||
|
pin:
|
||||||
|
xl9535: xl9535_hub
|
||||||
|
number: 17
|
||||||
|
mode:
|
||||||
|
input: true
|
||||||
|
inverted: false
|
||||||
|
|
||||||
climate:
|
climate:
|
||||||
- platform: tuya
|
- platform: tuya
|
||||||
id: tuya_climate
|
id: tuya_climate
|
||||||
|
|
Loading…
Reference in a new issue