mirror of
https://github.com/esphome/esphome.git
synced 2026-06-02 19:18:20 +08:00
Add local mDNS responder for .local (#386)
* Add local mDNS responder * Fix * Use mDNS in dashboard status * Lint * Lint * Fix test * Remove hostname * Fix use enum * Lint
This commit is contained in:
@@ -24,8 +24,6 @@ RUN \
|
|||||||
python-pil \
|
python-pil \
|
||||||
# Git for esphomelib downloads
|
# Git for esphomelib downloads
|
||||||
git \
|
git \
|
||||||
# Ping for dashboard online/offline status
|
|
||||||
iputils-ping \
|
|
||||||
# NGINX proxy
|
# NGINX proxy
|
||||||
nginx \
|
nginx \
|
||||||
\
|
\
|
||||||
|
|||||||
@@ -22,8 +22,6 @@ RUN \
|
|||||||
python-pil \
|
python-pil \
|
||||||
# Git for esphomelib downloads
|
# Git for esphomelib downloads
|
||||||
git \
|
git \
|
||||||
# Ping for dashboard online/offline status
|
|
||||||
iputils-ping \
|
|
||||||
# NGINX proxy
|
# NGINX proxy
|
||||||
nginx \
|
nginx \
|
||||||
\
|
\
|
||||||
|
|||||||
@@ -454,7 +454,7 @@ def run_logs(config, address):
|
|||||||
|
|
||||||
wait_time = min(2**tries, 300)
|
wait_time = min(2**tries, 300)
|
||||||
if not has_connects:
|
if not has_connects:
|
||||||
_LOGGER.warning(u"Initial connection failed. The ESP might not be connected"
|
_LOGGER.warning(u"Initial connection failed. The ESP might not be connected "
|
||||||
u"to WiFi yet (%s). Re-Trying in %s seconds",
|
u"to WiFi yet (%s). Re-Trying in %s seconds",
|
||||||
error, wait_time)
|
error, wait_time)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import voluptuous as vol
|
|||||||
from esphomeyaml import pins
|
from esphomeyaml import pins
|
||||||
from esphomeyaml.components import wifi
|
from esphomeyaml.components import wifi
|
||||||
import esphomeyaml.config_validation as cv
|
import esphomeyaml.config_validation as cv
|
||||||
from esphomeyaml.const import CONF_DOMAIN, CONF_HOSTNAME, CONF_ID, CONF_MANUAL_IP, CONF_TYPE, \
|
from esphomeyaml.const import CONF_DOMAIN, CONF_ID, CONF_MANUAL_IP, CONF_TYPE, \
|
||||||
ESP_PLATFORM_ESP32
|
ESP_PLATFORM_ESP32
|
||||||
from esphomeyaml.cpp_generator import Pvariable, add
|
from esphomeyaml.cpp_generator import Pvariable, add
|
||||||
from esphomeyaml.cpp_helpers import gpio_output_pin_expression
|
from esphomeyaml.cpp_helpers import gpio_output_pin_expression
|
||||||
@@ -43,7 +43,6 @@ CONFIG_SCHEMA = vol.Schema({
|
|||||||
vol.Optional(CONF_PHY_ADDR, default=0): vol.All(cv.int_, vol.Range(min=0, max=31)),
|
vol.Optional(CONF_PHY_ADDR, default=0): vol.All(cv.int_, vol.Range(min=0, max=31)),
|
||||||
vol.Optional(CONF_POWER_PIN): pins.gpio_output_pin_schema,
|
vol.Optional(CONF_POWER_PIN): pins.gpio_output_pin_schema,
|
||||||
vol.Optional(CONF_MANUAL_IP): wifi.STA_MANUAL_IP_SCHEMA,
|
vol.Optional(CONF_MANUAL_IP): wifi.STA_MANUAL_IP_SCHEMA,
|
||||||
vol.Optional(CONF_HOSTNAME): cv.hostname,
|
|
||||||
vol.Optional(CONF_DOMAIN, default='.local'): cv.domain_name,
|
vol.Optional(CONF_DOMAIN, default='.local'): cv.domain_name,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -63,9 +62,6 @@ def to_code(config):
|
|||||||
yield
|
yield
|
||||||
add(eth.set_power_pin(pin))
|
add(eth.set_power_pin(pin))
|
||||||
|
|
||||||
if CONF_HOSTNAME in config:
|
|
||||||
add(eth.set_hostname(config[CONF_HOSTNAME]))
|
|
||||||
|
|
||||||
if CONF_MANUAL_IP in config:
|
if CONF_MANUAL_IP in config:
|
||||||
add(eth.set_manual_ip(wifi.manual_ip(config[CONF_MANUAL_IP])))
|
add(eth.set_manual_ip(wifi.manual_ip(config[CONF_MANUAL_IP])))
|
||||||
|
|
||||||
|
|||||||
@@ -111,6 +111,9 @@ CONFIG_SCHEMA = vol.All(vol.Schema({
|
|||||||
vol.Optional(CONF_REBOOT_TIMEOUT): cv.positive_time_period_milliseconds,
|
vol.Optional(CONF_REBOOT_TIMEOUT): cv.positive_time_period_milliseconds,
|
||||||
vol.Optional(CONF_POWER_SAVE_MODE): cv.one_of(*WIFI_POWER_SAVE_MODES, upper=True),
|
vol.Optional(CONF_POWER_SAVE_MODE): cv.one_of(*WIFI_POWER_SAVE_MODES, upper=True),
|
||||||
vol.Optional(CONF_FAST_CONNECT): cv.boolean,
|
vol.Optional(CONF_FAST_CONNECT): cv.boolean,
|
||||||
|
|
||||||
|
vol.Optional(CONF_HOSTNAME): cv.invalid("The hostname option has been removed in 1.11.0, "
|
||||||
|
"now it's always the node name.")
|
||||||
}), validate)
|
}), validate)
|
||||||
|
|
||||||
|
|
||||||
@@ -166,9 +169,6 @@ def to_code(config):
|
|||||||
if CONF_AP in config:
|
if CONF_AP in config:
|
||||||
add(wifi.set_ap(wifi_network(config[CONF_AP], config.get(CONF_MANUAL_IP))))
|
add(wifi.set_ap(wifi_network(config[CONF_AP], config.get(CONF_MANUAL_IP))))
|
||||||
|
|
||||||
if CONF_HOSTNAME in config:
|
|
||||||
add(wifi.set_hostname(config[CONF_HOSTNAME]))
|
|
||||||
|
|
||||||
if CONF_REBOOT_TIMEOUT in config:
|
if CONF_REBOOT_TIMEOUT in config:
|
||||||
add(wifi.set_reboot_timeout(config[CONF_REBOOT_TIMEOUT]))
|
add(wifi.set_reboot_timeout(config[CONF_REBOOT_TIMEOUT]))
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,9 @@
|
|||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
import codecs
|
import codecs
|
||||||
import collections
|
|
||||||
import hmac
|
import hmac
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import multiprocessing
|
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import threading
|
import threading
|
||||||
@@ -25,7 +23,7 @@ import tornado.websocket
|
|||||||
|
|
||||||
from esphomeyaml import const
|
from esphomeyaml import const
|
||||||
from esphomeyaml.__main__ import get_serial_ports
|
from esphomeyaml.__main__ import get_serial_ports
|
||||||
from esphomeyaml.helpers import mkdir_p, run_system_command
|
from esphomeyaml.helpers import mkdir_p
|
||||||
from esphomeyaml.py_compat import IS_PY2
|
from esphomeyaml.py_compat import IS_PY2
|
||||||
from esphomeyaml.storage_json import EsphomeyamlStorageJSON, StorageJSON, \
|
from esphomeyaml.storage_json import EsphomeyamlStorageJSON, StorageJSON, \
|
||||||
esphomeyaml_storage_path, ext_storage_path
|
esphomeyaml_storage_path, ext_storage_path
|
||||||
@@ -34,6 +32,8 @@ from esphomeyaml.util import shlex_quote
|
|||||||
# pylint: disable=unused-import, wrong-import-order
|
# pylint: disable=unused-import, wrong-import-order
|
||||||
from typing import Optional # noqa
|
from typing import Optional # noqa
|
||||||
|
|
||||||
|
from esphomeyaml.zeroconf import Zeroconf, DashboardStatus
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
CONFIG_DIR = ''
|
CONFIG_DIR = ''
|
||||||
PASSWORD_DIGEST = ''
|
PASSWORD_DIGEST = ''
|
||||||
@@ -315,55 +315,25 @@ class MainRequestHandler(BaseHandler):
|
|||||||
get_static_file_url=get_static_file_url)
|
get_static_file_url=get_static_file_url)
|
||||||
|
|
||||||
|
|
||||||
def _ping_func(filename, address):
|
|
||||||
if os.name == 'nt':
|
|
||||||
command = ['ping', '-n', '1', address]
|
|
||||||
else:
|
|
||||||
command = ['ping', '-c', '1', address]
|
|
||||||
rc, _, _ = run_system_command(*command)
|
|
||||||
return filename, rc == 0
|
|
||||||
|
|
||||||
|
|
||||||
class PingThread(threading.Thread):
|
class PingThread(threading.Thread):
|
||||||
def run(self):
|
def run(self):
|
||||||
pool = multiprocessing.Pool(processes=8)
|
zc = Zeroconf()
|
||||||
|
|
||||||
|
def on_update(dat):
|
||||||
|
for key, b in dat.items():
|
||||||
|
PING_RESULT[key] = b
|
||||||
|
|
||||||
|
stat = DashboardStatus(zc, on_update)
|
||||||
|
stat.start()
|
||||||
while not STOP_EVENT.is_set():
|
while not STOP_EVENT.is_set():
|
||||||
# Only do pings if somebody has the dashboard open
|
entries = _list_dashboard_entries()
|
||||||
|
stat.request_query({entry.filename: entry.name + '.local.' for entry in entries})
|
||||||
|
|
||||||
PING_REQUEST.wait()
|
PING_REQUEST.wait()
|
||||||
PING_REQUEST.clear()
|
PING_REQUEST.clear()
|
||||||
|
stat.stop()
|
||||||
def callback(ret):
|
stat.join()
|
||||||
PING_RESULT[ret[0]] = ret[1]
|
zc.close()
|
||||||
|
|
||||||
entries = _list_dashboard_entries()
|
|
||||||
queue = collections.deque()
|
|
||||||
for entry in entries:
|
|
||||||
if entry.address is None:
|
|
||||||
PING_RESULT[entry.filename] = None
|
|
||||||
continue
|
|
||||||
|
|
||||||
result = pool.apply_async(_ping_func, (entry.filename, entry.address),
|
|
||||||
callback=callback)
|
|
||||||
queue.append(result)
|
|
||||||
|
|
||||||
while queue:
|
|
||||||
item = queue[0]
|
|
||||||
if item.ready():
|
|
||||||
queue.popleft()
|
|
||||||
continue
|
|
||||||
|
|
||||||
try:
|
|
||||||
item.get(0.1)
|
|
||||||
except OSError:
|
|
||||||
# ping not installed
|
|
||||||
pass
|
|
||||||
except multiprocessing.TimeoutError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if STOP_EVENT.is_set():
|
|
||||||
pool.terminate()
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
class PingRequestHandler(BaseHandler):
|
class PingRequestHandler(BaseHandler):
|
||||||
|
|||||||
+26
-3
@@ -7,6 +7,7 @@ import socket
|
|||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from esphomeyaml.py_compat import text_type, char_to_byte
|
from esphomeyaml.py_compat import text_type, char_to_byte
|
||||||
|
from esphomeyaml.zeroconf import Zeroconf
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -100,12 +101,34 @@ def is_ip_address(host):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _resolve_with_zeroconf(host):
|
||||||
|
from esphomeyaml.core import EsphomeyamlError
|
||||||
|
try:
|
||||||
|
zc = Zeroconf()
|
||||||
|
except Exception:
|
||||||
|
raise EsphomeyamlError("Cannot start mDNS sockets, is this a docker container without "
|
||||||
|
"host network mode?")
|
||||||
|
try:
|
||||||
|
info = zc.resolve_host(host + '.')
|
||||||
|
except Exception as err:
|
||||||
|
raise EsphomeyamlError("Error resolving mDNS hostname: {}".format(err))
|
||||||
|
finally:
|
||||||
|
zc.close()
|
||||||
|
if info is None:
|
||||||
|
raise EsphomeyamlError("Error resolving address with mDNS: Did not respond. "
|
||||||
|
"Maybe the device is offline.")
|
||||||
|
return info
|
||||||
|
|
||||||
|
|
||||||
def resolve_ip_address(host):
|
def resolve_ip_address(host):
|
||||||
|
from esphomeyaml.core import EsphomeyamlError
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ip = socket.gethostbyname(host)
|
ip = socket.gethostbyname(host)
|
||||||
except socket.error as err:
|
except socket.error as err:
|
||||||
from esphomeyaml.core import EsphomeyamlError
|
if host.endswith('.local'):
|
||||||
|
ip = _resolve_with_zeroconf(host)
|
||||||
raise EsphomeyamlError("Error resolving IP address: {}".format(err))
|
else:
|
||||||
|
raise EsphomeyamlError("Error resolving IP address: {}".format(err))
|
||||||
|
|
||||||
return ip
|
return ip
|
||||||
|
|||||||
@@ -62,3 +62,10 @@ def sort_by_cmp(list_, cmp):
|
|||||||
list_.sort(cmp=cmp)
|
list_.sort(cmp=cmp)
|
||||||
else:
|
else:
|
||||||
list_.sort(key=functools.cmp_to_key(cmp))
|
list_.sort(key=functools.cmp_to_key(cmp))
|
||||||
|
|
||||||
|
|
||||||
|
def indexbytes(buf, i):
|
||||||
|
if IS_PY3:
|
||||||
|
return buf[i]
|
||||||
|
else:
|
||||||
|
return ord(buf[i])
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -14,6 +14,7 @@ disable=
|
|||||||
too-many-statements,
|
too-many-statements,
|
||||||
too-many-arguments,
|
too-many-arguments,
|
||||||
too-many-return-statements,
|
too-many-return-statements,
|
||||||
|
too-many-instance-attributes,
|
||||||
duplicate-code,
|
duplicate-code,
|
||||||
invalid-name,
|
invalid-name,
|
||||||
cyclic-import,
|
cyclic-import,
|
||||||
|
|||||||
@@ -8,3 +8,4 @@ esptool>=2.3.1
|
|||||||
typing>=3.0.0
|
typing>=3.0.0
|
||||||
protobuf>=3.4
|
protobuf>=3.4
|
||||||
pyserial>=3.4,<4
|
pyserial>=3.4,<4
|
||||||
|
ifaddr>=0.1.6
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ REQUIRES = [
|
|||||||
'protobuf>=3.4',
|
'protobuf>=3.4',
|
||||||
'tzlocal>=1.4',
|
'tzlocal>=1.4',
|
||||||
'pyserial>=3.4,<4',
|
'pyserial>=3.4,<4',
|
||||||
|
'ifaddr>=0.1.6',
|
||||||
]
|
]
|
||||||
|
|
||||||
# If you have problems importing platformio and esptool as modules you can set
|
# If you have problems importing platformio and esptool as modules you can set
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ wifi:
|
|||||||
subnet: 255.255.255.0
|
subnet: 255.255.255.0
|
||||||
dns1: 1.1.1.1
|
dns1: 1.1.1.1
|
||||||
dns2: 1.2.2.1
|
dns2: 1.2.2.1
|
||||||
hostname: myverylonghostname
|
|
||||||
domain: .local
|
domain: .local
|
||||||
reboot_timeout: 120s
|
reboot_timeout: 120s
|
||||||
power_save_mode: none
|
power_save_mode: none
|
||||||
|
|||||||
Reference in New Issue
Block a user