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:
Otto Winter
2019-02-10 16:57:34 +01:00
committed by GitHub
parent fcf5da66c0
commit d9cf91210e
13 changed files with 837 additions and 63 deletions
-2
View File
@@ -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 \
\ \
-2
View File
@@ -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 \
\ \
+1 -1
View File
@@ -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:
+1 -5
View File
@@ -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])))
+3 -3
View File
@@ -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]))
+16 -46
View File
@@ -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
View File
@@ -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
+7
View File
@@ -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
+1
View File
@@ -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,
+1
View File
@@ -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
+1
View File
@@ -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
-1
View File
@@ -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