mirror of
https://github.com/esphome/esphome.git
synced 2024-11-10 01:07:45 +01:00
Fix some stuff
This commit is contained in:
parent
da2821ab36
commit
5a7b66e207
12 changed files with 242 additions and 177 deletions
|
@ -18,11 +18,7 @@ VOLUME /config
|
||||||
WORKDIR /usr/src/app
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
COPY docker/platformio.ini /pio/platformio.ini
|
COPY docker/platformio.ini /pio/platformio.ini
|
||||||
ARG ESPHOMELIB_VERSION=""
|
RUN platformio run -d /pio; rm -rf /pio
|
||||||
RUN platformio run -d /pio; rm -rf /pio && \
|
|
||||||
/bin/bash -c "if [ ! -z '$ESPHOMELIB_VERSION']; then \
|
|
||||||
platformio lib -g install '${ESPHOMELIB_VERSION}'; \
|
|
||||||
fi"
|
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN pip install --no-cache-dir --no-binary :all: -e . && \
|
RUN pip install --no-cache-dir --no-binary :all: -e . && \
|
||||||
|
|
|
@ -10,10 +10,11 @@ import sys
|
||||||
|
|
||||||
from esphomeyaml import const, core_config, mqtt, platformio_api, wizard, writer, yaml_util
|
from esphomeyaml import const, core_config, mqtt, platformio_api, wizard, writer, yaml_util
|
||||||
from esphomeyaml.api.client import run_logs
|
from esphomeyaml.api.client import run_logs
|
||||||
|
from esphomeyaml.components import wifi
|
||||||
from esphomeyaml.config import get_component, iter_components, read_config, strip_default_ids
|
from esphomeyaml.config import get_component, iter_components, read_config, strip_default_ids
|
||||||
from esphomeyaml.const import CONF_BAUD_RATE, CONF_DOMAIN, CONF_ESPHOMEYAML, \
|
from esphomeyaml.const import CONF_BAUD_RATE, CONF_DOMAIN, CONF_ESPHOMEYAML, \
|
||||||
CONF_HOSTNAME, CONF_LOGGER, CONF_MANUAL_IP, CONF_NAME, CONF_STATIC_IP, CONF_USE_CUSTOM_CODE, \
|
CONF_HOSTNAME, CONF_LOGGER, CONF_MANUAL_IP, CONF_NAME, CONF_STATIC_IP, CONF_USE_CUSTOM_CODE, \
|
||||||
CONF_WIFI
|
CONF_WIFI, CONF_BROKER
|
||||||
from esphomeyaml.core import CORE, EsphomeyamlError
|
from esphomeyaml.core import CORE, EsphomeyamlError
|
||||||
from esphomeyaml.cpp_generator import Expression, RawStatement, add, statement
|
from esphomeyaml.cpp_generator import Expression, RawStatement, add, statement
|
||||||
from esphomeyaml.helpers import color, indent
|
from esphomeyaml.helpers import color, indent
|
||||||
|
@ -39,31 +40,57 @@ def get_serial_ports():
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def choose_serial_port(config):
|
def choose_prompt(options):
|
||||||
result = get_serial_ports()
|
if not options:
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
|
if len(options) == 1:
|
||||||
|
return options[0][1]
|
||||||
|
|
||||||
|
safe_print(u"Found multiple options, please choose one:")
|
||||||
|
for i, (desc, _) in enumerate(options):
|
||||||
|
safe_print(u" [{}] {}".format(i + 1, desc))
|
||||||
|
|
||||||
if not result:
|
|
||||||
return 'OTA'
|
|
||||||
safe_print(u"Found multiple serial port options, please choose one:")
|
|
||||||
for i, (res, desc) in enumerate(result):
|
|
||||||
safe_print(u" [{}] {} ({})".format(i, res, desc))
|
|
||||||
safe_print(u" [{}] Over The Air ({})".format(len(result), get_upload_host(config)))
|
|
||||||
safe_print()
|
|
||||||
while True:
|
while True:
|
||||||
opt = raw_input('(number): ')
|
opt = raw_input('(number): ')
|
||||||
if opt in result:
|
if opt in options:
|
||||||
opt = result.index(opt)
|
opt = options.index(opt)
|
||||||
break
|
break
|
||||||
try:
|
try:
|
||||||
opt = int(opt)
|
opt = int(opt)
|
||||||
if opt < 0 or opt > len(result):
|
if opt < 1 or opt > len(options):
|
||||||
raise ValueError
|
raise ValueError
|
||||||
break
|
break
|
||||||
except ValueError:
|
except ValueError:
|
||||||
safe_print(color('red', u"Invalid option: '{}'".format(opt)))
|
safe_print(color('red', u"Invalid option: '{}'".format(opt)))
|
||||||
if opt == len(result):
|
return options[opt - 1][1]
|
||||||
return 'OTA'
|
|
||||||
return result[opt][0]
|
|
||||||
|
def choose_upload_log_host(default, check_default, show_ota, show_mqtt, show_api):
|
||||||
|
options = []
|
||||||
|
for res, desc in get_serial_ports():
|
||||||
|
options.append((u"{} ({})".format(res, desc), res))
|
||||||
|
if (show_ota and 'ota' in CORE.config) or (show_api and 'api' in CORE.config):
|
||||||
|
options.append((u"Over The Air ({})".format(CORE.address), CORE.address))
|
||||||
|
if default == 'OTA':
|
||||||
|
return CORE.address
|
||||||
|
if show_mqtt and 'mqtt' in CORE.config:
|
||||||
|
options.append((u"MQTT ({})".format(CORE.config['mqtt'][CONF_BROKER]), 'MQTT'))
|
||||||
|
if default == 'OTA':
|
||||||
|
return 'MQTT'
|
||||||
|
if default is not None:
|
||||||
|
return default
|
||||||
|
if check_default is not None and check_default in [opt[1] for opt in options]:
|
||||||
|
return check_default
|
||||||
|
return choose_prompt(options)
|
||||||
|
|
||||||
|
|
||||||
|
def get_port_type(port):
|
||||||
|
if port.startswith('/') or port.startswith('COM'):
|
||||||
|
return 'SERIAL'
|
||||||
|
if port == 'MQTT':
|
||||||
|
return 'MQTT'
|
||||||
|
return 'NETWORK'
|
||||||
|
|
||||||
|
|
||||||
def run_miniterm(config, port):
|
def run_miniterm(config, port):
|
||||||
|
@ -132,16 +159,6 @@ def compile_program(args, config):
|
||||||
return rc
|
return rc
|
||||||
|
|
||||||
|
|
||||||
def get_upload_host(config):
|
|
||||||
if CONF_MANUAL_IP in config[CONF_WIFI]:
|
|
||||||
host = str(config[CONF_WIFI][CONF_MANUAL_IP][CONF_STATIC_IP])
|
|
||||||
elif CONF_HOSTNAME in config[CONF_WIFI]:
|
|
||||||
host = config[CONF_WIFI][CONF_HOSTNAME] + config[CONF_WIFI][CONF_DOMAIN]
|
|
||||||
else:
|
|
||||||
host = config[CONF_ESPHOMEYAML][CONF_NAME] + config[CONF_WIFI][CONF_DOMAIN]
|
|
||||||
return host
|
|
||||||
|
|
||||||
|
|
||||||
def upload_using_esptool(config, port):
|
def upload_using_esptool(config, port):
|
||||||
import esptool
|
import esptool
|
||||||
|
|
||||||
|
@ -152,24 +169,12 @@ def upload_using_esptool(config, port):
|
||||||
return run_external_command(esptool._main, *cmd)
|
return run_external_command(esptool._main, *cmd)
|
||||||
|
|
||||||
|
|
||||||
def upload_program(config, args, port):
|
def upload_program(config, args, host):
|
||||||
# if upload is to a serial port use platformio, otherwise assume ota
|
# if upload is to a serial port use platformio, otherwise assume ota
|
||||||
serial_port = port.startswith('/') or port.startswith('COM')
|
if get_port_type(host) == 'SERIAL':
|
||||||
if port != 'OTA' and serial_port:
|
|
||||||
if CORE.is_esp8266:
|
if CORE.is_esp8266:
|
||||||
return upload_using_esptool(config, port)
|
return upload_using_esptool(config, host)
|
||||||
return platformio_api.run_upload(config, args.verbose, port)
|
return platformio_api.run_upload(config, args.verbose, host)
|
||||||
|
|
||||||
if 'ota' not in config:
|
|
||||||
_LOGGER.error("No serial port found and OTA not enabled. Can't upload!")
|
|
||||||
return -1
|
|
||||||
|
|
||||||
# If hostname/ip is explicitly provided as upload-port argument, use this instead of zeroconf
|
|
||||||
# hostname. This is to support use cases where zeroconf (hostname.local) does not work.
|
|
||||||
if port != 'OTA':
|
|
||||||
host = port
|
|
||||||
else:
|
|
||||||
host = get_upload_host(config)
|
|
||||||
|
|
||||||
from esphomeyaml.components import ota
|
from esphomeyaml.components import ota
|
||||||
from esphomeyaml import espota2
|
from esphomeyaml import espota2
|
||||||
|
@ -199,13 +204,15 @@ def upload_program(config, args, port):
|
||||||
|
|
||||||
|
|
||||||
def show_logs(config, args, port):
|
def show_logs(config, args, port):
|
||||||
serial_port = port.startswith('/') or port.startswith('COM')
|
if get_port_type(port) == 'SERIAL':
|
||||||
if port != 'OTA' and serial_port:
|
|
||||||
run_miniterm(config, port)
|
run_miniterm(config, port)
|
||||||
return 0
|
return 0
|
||||||
if 'api' in config:
|
elif get_port_type(port) == 'NETWORK':
|
||||||
return run_logs(config, get_upload_host(config))
|
return run_logs(config, port)
|
||||||
return mqtt.show_logs(config, args.topic, args.username, args.password, args.client_id)
|
elif get_port_type(port) == 'MQTT':
|
||||||
|
return mqtt.show_logs(config, args.topic, args.username, args.password, args.client_id)
|
||||||
|
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
|
|
||||||
def clean_mqtt(config, args):
|
def clean_mqtt(config, args):
|
||||||
|
@ -266,7 +273,8 @@ def command_compile(args, config):
|
||||||
|
|
||||||
|
|
||||||
def command_upload(args, config):
|
def command_upload(args, config):
|
||||||
port = args.upload_port or choose_serial_port(config)
|
port = choose_upload_log_host(default=args.upload_port, check_default=None,
|
||||||
|
show_ota=True, show_mqtt=False, show_api=False)
|
||||||
exit_code = upload_program(config, args, port)
|
exit_code = upload_program(config, args, port)
|
||||||
if exit_code != 0:
|
if exit_code != 0:
|
||||||
return exit_code
|
return exit_code
|
||||||
|
@ -275,7 +283,8 @@ def command_upload(args, config):
|
||||||
|
|
||||||
|
|
||||||
def command_logs(args, config):
|
def command_logs(args, config):
|
||||||
port = args.serial_port or choose_serial_port(config)
|
port = choose_upload_log_host(default=args.serial_port, check_default=None,
|
||||||
|
show_ota=False, show_mqtt=True, show_api=True)
|
||||||
return show_logs(config, args, port)
|
return show_logs(config, args, port)
|
||||||
|
|
||||||
|
|
||||||
|
@ -287,13 +296,16 @@ def command_run(args, config):
|
||||||
if exit_code != 0:
|
if exit_code != 0:
|
||||||
return exit_code
|
return exit_code
|
||||||
_LOGGER.info(u"Successfully compiled program.")
|
_LOGGER.info(u"Successfully compiled program.")
|
||||||
port = args.upload_port or choose_serial_port(config)
|
port = choose_upload_log_host(default=args.upload_port, check_default=None,
|
||||||
|
show_ota=True, show_mqtt=False, show_api=True)
|
||||||
exit_code = upload_program(config, args, port)
|
exit_code = upload_program(config, args, port)
|
||||||
if exit_code != 0:
|
if exit_code != 0:
|
||||||
return exit_code
|
return exit_code
|
||||||
_LOGGER.info(u"Successfully uploaded program.")
|
_LOGGER.info(u"Successfully uploaded program.")
|
||||||
if args.no_logs:
|
if args.no_logs:
|
||||||
return 0
|
return 0
|
||||||
|
port = choose_upload_log_host(default=args.upload_port, check_default=port,
|
||||||
|
show_ota=False, show_mqtt=True, show_api=True)
|
||||||
return show_logs(config, args, port)
|
return show_logs(config, args, port)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -290,6 +290,7 @@ message SubscribeLogsResponse {
|
||||||
LogLevel level = 1;
|
LogLevel level = 1;
|
||||||
string tag = 2;
|
string tag = 2;
|
||||||
string message = 3;
|
string message = 3;
|
||||||
|
bool send_failed = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message SubscribeServiceCallsRequest {
|
message SubscribeServiceCallsRequest {
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -13,7 +13,7 @@ from esphomeyaml import const
|
||||||
import esphomeyaml.api.api_pb2 as pb
|
import esphomeyaml.api.api_pb2 as pb
|
||||||
from esphomeyaml.const import CONF_PASSWORD, CONF_PORT
|
from esphomeyaml.const import CONF_PASSWORD, CONF_PORT
|
||||||
from esphomeyaml.core import EsphomeyamlError
|
from esphomeyaml.core import EsphomeyamlError
|
||||||
from esphomeyaml.helpers import resolve_ip_address
|
from esphomeyaml.helpers import resolve_ip_address, indent, color
|
||||||
from esphomeyaml.util import safe_print
|
from esphomeyaml.util import safe_print
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
@ -100,6 +100,8 @@ class APIClient(threading.Thread):
|
||||||
self._port = port # type: int
|
self._port = port # type: int
|
||||||
self._password = password # type: Optional[str]
|
self._password = password # type: Optional[str]
|
||||||
self._socket = None # type: Optional[socket.socket]
|
self._socket = None # type: Optional[socket.socket]
|
||||||
|
self._socket_open_event = threading.Event()
|
||||||
|
self._socket_write_lock = threading.Lock()
|
||||||
self._connected = False
|
self._connected = False
|
||||||
self._authenticated = False
|
self._authenticated = False
|
||||||
self._message_handlers = []
|
self._message_handlers = []
|
||||||
|
@ -111,9 +113,8 @@ class APIClient(threading.Thread):
|
||||||
self.on_connect = None
|
self.on_connect = None
|
||||||
self.on_login = None
|
self.on_login = None
|
||||||
self.auto_reconnect = False
|
self.auto_reconnect = False
|
||||||
self._running = False
|
self._running_event = threading.Event()
|
||||||
self._stop_event = threading.Event()
|
self._stop_event = threading.Event()
|
||||||
self._socket_open = False
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def stopped(self):
|
def stopped(self):
|
||||||
|
@ -131,12 +132,28 @@ class APIClient(threading.Thread):
|
||||||
try:
|
try:
|
||||||
self.ping()
|
self.ping()
|
||||||
except APIConnectionError:
|
except APIConnectionError:
|
||||||
self._on_error()
|
self._fatal_error()
|
||||||
self._refresh_ping()
|
else:
|
||||||
|
self._refresh_ping()
|
||||||
|
|
||||||
self._ping_timer = threading.Timer(self._keepalive, func)
|
self._ping_timer = threading.Timer(self._keepalive, func)
|
||||||
self._ping_timer.start()
|
self._ping_timer.start()
|
||||||
|
|
||||||
|
def _cancel_ping(self):
|
||||||
|
if self._ping_timer is not None:
|
||||||
|
self._ping_timer.cancel()
|
||||||
|
self._ping_timer = None
|
||||||
|
|
||||||
|
def _close_socket(self):
|
||||||
|
self._cancel_ping()
|
||||||
|
if self._socket is not None:
|
||||||
|
self._socket.close()
|
||||||
|
self._socket = None
|
||||||
|
self._socket_open_event.clear()
|
||||||
|
self._connected = False
|
||||||
|
self._authenticated = False
|
||||||
|
self._message_handlers = []
|
||||||
|
|
||||||
def stop(self, force=False):
|
def stop(self, force=False):
|
||||||
if self.stopped:
|
if self.stopped:
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
@ -146,29 +163,19 @@ class APIClient(threading.Thread):
|
||||||
self.disconnect()
|
self.disconnect()
|
||||||
except APIConnectionError:
|
except APIConnectionError:
|
||||||
pass
|
pass
|
||||||
if self._socket is not None:
|
self._close_socket()
|
||||||
self._socket.close()
|
|
||||||
self._socket = None
|
|
||||||
|
|
||||||
self._stop_event.set()
|
self._stop_event.set()
|
||||||
if self._ping_timer is not None:
|
|
||||||
self._ping_timer.cancel()
|
|
||||||
self._ping_timer = None
|
|
||||||
if not force:
|
if not force:
|
||||||
self.join()
|
self.join()
|
||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
if not self._running:
|
if not self._running_event.wait(0.1):
|
||||||
raise APIConnectionError("You need to call start() first!")
|
raise APIConnectionError("You need to call start() first!")
|
||||||
|
|
||||||
if self._connected:
|
if self._connected:
|
||||||
raise APIConnectionError("Already connected!")
|
raise APIConnectionError("Already connected!")
|
||||||
|
|
||||||
self._message_handlers = []
|
|
||||||
self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
||||||
self._socket.settimeout(10.0)
|
|
||||||
self._socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ip = resolve_ip_address(self._address)
|
ip = resolve_ip_address(self._address)
|
||||||
except EsphomeyamlError as err:
|
except EsphomeyamlError as err:
|
||||||
|
@ -179,21 +186,24 @@ class APIClient(threading.Thread):
|
||||||
raise APIConnectionError(err)
|
raise APIConnectionError(err)
|
||||||
|
|
||||||
_LOGGER.info("Connecting to %s:%s (%s)", self._address, self._port, ip)
|
_LOGGER.info("Connecting to %s:%s (%s)", self._address, self._port, ip)
|
||||||
|
self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
self._socket.settimeout(10.0)
|
||||||
|
self._socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
||||||
try:
|
try:
|
||||||
self._socket.connect((ip, self._port))
|
self._socket.connect((ip, self._port))
|
||||||
except socket.error as err:
|
except socket.error as err:
|
||||||
self._on_error()
|
self._fatal_error()
|
||||||
raise APIConnectionError("Error connecting to {}: {}".format(ip, err))
|
raise APIConnectionError("Error connecting to {}: {}".format(ip, err))
|
||||||
self._socket_open = True
|
|
||||||
|
|
||||||
self._socket.settimeout(0.1)
|
self._socket.settimeout(0.1)
|
||||||
|
|
||||||
|
self._socket_open_event.set()
|
||||||
|
|
||||||
hello = pb.HelloRequest()
|
hello = pb.HelloRequest()
|
||||||
hello.client_info = 'esphomeyaml v{}'.format(const.__version__)
|
hello.client_info = 'esphomeyaml v{}'.format(const.__version__)
|
||||||
try:
|
try:
|
||||||
resp = self._send_message_await_response(hello, pb.HelloResponse)
|
resp = self._send_message_await_response(hello, pb.HelloResponse)
|
||||||
except APIConnectionError as err:
|
except APIConnectionError as err:
|
||||||
self._on_error()
|
self._fatal_error()
|
||||||
raise err
|
raise err
|
||||||
_LOGGER.debug("Successfully connected to %s ('%s' API=%s.%s)", self._address,
|
_LOGGER.debug("Successfully connected to %s ('%s' API=%s.%s)", self._address,
|
||||||
resp.server_info, resp.api_version_major, resp.api_version_minor)
|
resp.server_info, resp.api_version_major, resp.api_version_minor)
|
||||||
|
@ -203,7 +213,7 @@ class APIClient(threading.Thread):
|
||||||
|
|
||||||
def _check_connected(self):
|
def _check_connected(self):
|
||||||
if not self._connected:
|
if not self._connected:
|
||||||
self._on_error()
|
self._fatal_error()
|
||||||
raise APIConnectionError("Must be connected!")
|
raise APIConnectionError("Must be connected!")
|
||||||
|
|
||||||
def login(self):
|
def login(self):
|
||||||
|
@ -222,25 +232,25 @@ class APIClient(threading.Thread):
|
||||||
if self.on_login is not None:
|
if self.on_login is not None:
|
||||||
self.on_login()
|
self.on_login()
|
||||||
|
|
||||||
def _on_error(self):
|
def _fatal_error(self):
|
||||||
if self._connected and self.on_disconnect is not None:
|
was_connected = self._connected
|
||||||
|
|
||||||
|
self._close_socket()
|
||||||
|
|
||||||
|
if was_connected and self.on_disconnect is not None:
|
||||||
self.on_disconnect()
|
self.on_disconnect()
|
||||||
|
|
||||||
if self._socket is not None:
|
|
||||||
self._socket.close()
|
|
||||||
self._socket = None
|
|
||||||
self._socket_open = False
|
|
||||||
|
|
||||||
self._connected = False
|
|
||||||
self._authenticated = False
|
|
||||||
|
|
||||||
def _write(self, data): # type: (bytes) -> None
|
def _write(self, data): # type: (bytes) -> None
|
||||||
|
if self._socket is None:
|
||||||
|
raise APIConnectionError("Socket closed")
|
||||||
|
|
||||||
_LOGGER.debug("Write: %s", ' '.join('{:02X}'.format(ord(x)) for x in data))
|
_LOGGER.debug("Write: %s", ' '.join('{:02X}'.format(ord(x)) for x in data))
|
||||||
try:
|
with self._socket_write_lock:
|
||||||
self._socket.sendall(data)
|
try:
|
||||||
except socket.error as err:
|
self._socket.sendall(data)
|
||||||
self._on_error()
|
except socket.error as err:
|
||||||
raise APIConnectionError("Error while writing data: {}".format(err))
|
self._fatal_error()
|
||||||
|
raise APIConnectionError("Error while writing data: {}".format(err))
|
||||||
|
|
||||||
def _send_message(self, msg):
|
def _send_message(self, msg):
|
||||||
# type: (message.Message) -> None
|
# type: (message.Message) -> None
|
||||||
|
@ -251,7 +261,7 @@ class APIClient(threading.Thread):
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
encoded = msg.SerializeToString()
|
encoded = msg.SerializeToString()
|
||||||
_LOGGER.debug("Sending %s: %s", type(message), unicode(message))
|
_LOGGER.debug("Sending %s:\n%s", type(msg), indent(unicode(msg)))
|
||||||
req = chr(0x00)
|
req = chr(0x00)
|
||||||
req += _varuint_to_bytes(len(encoded))
|
req += _varuint_to_bytes(len(encoded))
|
||||||
req += _varuint_to_bytes(message_type)
|
req += _varuint_to_bytes(message_type)
|
||||||
|
@ -302,11 +312,8 @@ class APIClient(threading.Thread):
|
||||||
self._send_message_await_response(pb.DisconnectRequest(), pb.DisconnectResponse)
|
self._send_message_await_response(pb.DisconnectRequest(), pb.DisconnectResponse)
|
||||||
except APIConnectionError:
|
except APIConnectionError:
|
||||||
pass
|
pass
|
||||||
if self._socket is not None:
|
self._close_socket()
|
||||||
self._socket.close()
|
|
||||||
self._socket = None
|
|
||||||
self._socket_open = False
|
|
||||||
self._connected = False
|
|
||||||
if self.on_disconnect is not None:
|
if self.on_disconnect is not None:
|
||||||
self.on_disconnect()
|
self.on_disconnect()
|
||||||
|
|
||||||
|
@ -335,7 +342,7 @@ class APIClient(threading.Thread):
|
||||||
while len(ret) < amount:
|
while len(ret) < amount:
|
||||||
if self.stopped:
|
if self.stopped:
|
||||||
raise APIConnectionError("Stopped!")
|
raise APIConnectionError("Stopped!")
|
||||||
if self._socket is None or not self._socket_open:
|
if not self._socket_open_event.is_set():
|
||||||
raise APIConnectionError("No socket!")
|
raise APIConnectionError("No socket!")
|
||||||
try:
|
try:
|
||||||
val = self._socket.recv(amount - len(ret))
|
val = self._socket.recv(amount - len(ret))
|
||||||
|
@ -353,8 +360,7 @@ class APIClient(threading.Thread):
|
||||||
return _bytes_to_varuint(raw)
|
return _bytes_to_varuint(raw)
|
||||||
|
|
||||||
def _run_once(self):
|
def _run_once(self):
|
||||||
if self._socket is None or not self._socket_open:
|
if not self._socket_open_event.wait(0.1):
|
||||||
time.sleep(0.1)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# Preamble
|
# Preamble
|
||||||
|
@ -371,14 +377,14 @@ class APIClient(threading.Thread):
|
||||||
|
|
||||||
msg = MESSAGE_TYPE_TO_PROTO[msg_type]()
|
msg = MESSAGE_TYPE_TO_PROTO[msg_type]()
|
||||||
msg.ParseFromString(raw_msg)
|
msg.ParseFromString(raw_msg)
|
||||||
_LOGGER.debug("Got message of type %s: %s", type(msg), msg)
|
_LOGGER.debug("Got message: %s:\n%s", type(msg), indent(str(msg)))
|
||||||
for msg_handler in self._message_handlers[:]:
|
for msg_handler in self._message_handlers[:]:
|
||||||
msg_handler(msg)
|
msg_handler(msg)
|
||||||
self._handle_internal_messages(msg)
|
self._handle_internal_messages(msg)
|
||||||
self._refresh_ping()
|
self._refresh_ping()
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self._running = True
|
self._running_event.set()
|
||||||
while not self.stopped:
|
while not self.stopped:
|
||||||
try:
|
try:
|
||||||
self._run_once()
|
self._run_once()
|
||||||
|
@ -387,8 +393,8 @@ class APIClient(threading.Thread):
|
||||||
break
|
break
|
||||||
if self._connected:
|
if self._connected:
|
||||||
_LOGGER.error("Error while reading incoming messages: %s", err)
|
_LOGGER.error("Error while reading incoming messages: %s", err)
|
||||||
self._on_error()
|
self._fatal_error()
|
||||||
self._running = False
|
self._running_event.clear()
|
||||||
|
|
||||||
def _handle_internal_messages(self, msg):
|
def _handle_internal_messages(self, msg):
|
||||||
if isinstance(msg, pb.DisconnectRequest):
|
if isinstance(msg, pb.DisconnectRequest):
|
||||||
|
@ -397,7 +403,6 @@ class APIClient(threading.Thread):
|
||||||
self._socket.close()
|
self._socket.close()
|
||||||
self._socket = None
|
self._socket = None
|
||||||
self._connected = False
|
self._connected = False
|
||||||
self._socket_open = False
|
|
||||||
if self.on_disconnect is not None:
|
if self.on_disconnect is not None:
|
||||||
self.on_disconnect()
|
self.on_disconnect()
|
||||||
elif isinstance(msg, pb.PingRequest):
|
elif isinstance(msg, pb.PingRequest):
|
||||||
|
@ -428,26 +433,29 @@ def run_logs(config, address):
|
||||||
while retry_timer:
|
while retry_timer:
|
||||||
retry_timer.pop(0).cancel()
|
retry_timer.pop(0).cancel()
|
||||||
|
|
||||||
error = None
|
|
||||||
try:
|
try:
|
||||||
cli.connect()
|
cli.connect()
|
||||||
cli.login()
|
cli.login()
|
||||||
except APIConnectionError as error:
|
except APIConnectionError as error:
|
||||||
pass
|
pass
|
||||||
|
else:
|
||||||
if error is None:
|
|
||||||
_LOGGER.info("Successfully connected to %s", address)
|
_LOGGER.info("Successfully connected to %s", address)
|
||||||
return
|
return
|
||||||
|
|
||||||
wait_time = min(2**tries, 300)
|
wait_time = min(2**tries, 300)
|
||||||
_LOGGER.warning(u"Couldn't connect to API. Trying to reconnect in %s seconds", wait_time)
|
_LOGGER.warning(u"Couldn't connect to API (%s). Trying to reconnect in %s seconds",
|
||||||
|
error, wait_time)
|
||||||
timer = threading.Timer(wait_time, functools.partial(try_connect, tries + 1, is_disconnect))
|
timer = threading.Timer(wait_time, functools.partial(try_connect, tries + 1, is_disconnect))
|
||||||
timer.start()
|
timer.start()
|
||||||
retry_timer.append(timer)
|
retry_timer.append(timer)
|
||||||
|
|
||||||
def on_log(msg):
|
def on_log(msg):
|
||||||
time_ = datetime.now().time().strftime(u'[%H:%M:%S]')
|
time_ = datetime.now().time().strftime(u'[%H:%M:%S]')
|
||||||
safe_print(time_ + msg.message)
|
text = msg.message
|
||||||
|
if msg.send_failed:
|
||||||
|
text = color('white', '(Message not received because it was too big to fit in '
|
||||||
|
'TCP buffer)')
|
||||||
|
safe_print(time_ + text)
|
||||||
|
|
||||||
has_connects = []
|
has_connects = []
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ from esphomeyaml.automation import ACTION_REGISTRY, LambdaAction
|
||||||
import esphomeyaml.config_validation as cv
|
import esphomeyaml.config_validation as cv
|
||||||
from esphomeyaml.const import CONF_ARGS, CONF_BAUD_RATE, CONF_FORMAT, CONF_ID, CONF_LEVEL, \
|
from esphomeyaml.const import CONF_ARGS, CONF_BAUD_RATE, CONF_FORMAT, CONF_ID, CONF_LEVEL, \
|
||||||
CONF_LOGS, CONF_TAG, CONF_TX_BUFFER_SIZE
|
CONF_LOGS, CONF_TAG, CONF_TX_BUFFER_SIZE
|
||||||
from esphomeyaml.core import EsphomeyamlError, Lambda
|
from esphomeyaml.core import EsphomeyamlError, Lambda, CORE
|
||||||
from esphomeyaml.cpp_generator import Pvariable, RawExpression, add, process_lambda, statement
|
from esphomeyaml.cpp_generator import Pvariable, RawExpression, add, process_lambda, statement
|
||||||
from esphomeyaml.cpp_types import App, Component, esphomelib_ns, global_ns
|
from esphomeyaml.cpp_types import App, Component, esphomelib_ns, global_ns
|
||||||
|
|
||||||
|
@ -69,9 +69,15 @@ def to_code(config):
|
||||||
|
|
||||||
|
|
||||||
def required_build_flags(config):
|
def required_build_flags(config):
|
||||||
|
flags = []
|
||||||
if CONF_LEVEL in config:
|
if CONF_LEVEL in config:
|
||||||
return u'-DESPHOMELIB_LOG_LEVEL={}'.format(str(LOG_LEVELS[config[CONF_LEVEL]]))
|
flags.append(u'-DESPHOMELIB_LOG_LEVEL={}'.format(str(LOG_LEVELS[config[CONF_LEVEL]])))
|
||||||
return None
|
this_severity = LOG_LEVEL_SEVERITY.index(config[CONF_LEVEL])
|
||||||
|
verbose_severity = LOG_LEVEL_SEVERITY.index('VERBOSE')
|
||||||
|
if CORE.is_esp8266 and config.get(CONF_BAUD_RATE) != 0 and \
|
||||||
|
this_severity >= verbose_severity:
|
||||||
|
flags.append(u"-DDEBUG_ESP_PORT=Serial")
|
||||||
|
return flags
|
||||||
|
|
||||||
|
|
||||||
def maybe_simple_message(schema):
|
def maybe_simple_message(schema):
|
||||||
|
|
|
@ -46,13 +46,13 @@ FILTERS_SCHEMA = cv.ensure_list({
|
||||||
vol.Optional(CONF_FILTER_OUT): cv.float_,
|
vol.Optional(CONF_FILTER_OUT): cv.float_,
|
||||||
vol.Optional(CONF_FILTER_NAN): None,
|
vol.Optional(CONF_FILTER_NAN): None,
|
||||||
vol.Optional(CONF_SLIDING_WINDOW_MOVING_AVERAGE): vol.All(vol.Schema({
|
vol.Optional(CONF_SLIDING_WINDOW_MOVING_AVERAGE): vol.All(vol.Schema({
|
||||||
vol.Required(CONF_WINDOW_SIZE): cv.positive_not_null_int,
|
vol.Optional(CONF_WINDOW_SIZE, default=15): cv.positive_not_null_int,
|
||||||
vol.Required(CONF_SEND_EVERY): cv.positive_not_null_int,
|
vol.Optional(CONF_SEND_EVERY, default=15): cv.positive_not_null_int,
|
||||||
vol.Optional(CONF_SEND_FIRST_AT): cv.positive_not_null_int,
|
vol.Optional(CONF_SEND_FIRST_AT): cv.positive_not_null_int,
|
||||||
}), validate_send_first_at),
|
}), validate_send_first_at),
|
||||||
vol.Optional(CONF_EXPONENTIAL_MOVING_AVERAGE): vol.Schema({
|
vol.Optional(CONF_EXPONENTIAL_MOVING_AVERAGE): vol.Schema({
|
||||||
vol.Required(CONF_ALPHA): cv.positive_float,
|
vol.Optional(CONF_ALPHA, default=0.1): cv.positive_float,
|
||||||
vol.Required(CONF_SEND_EVERY): cv.positive_not_null_int,
|
vol.Optional(CONF_SEND_EVERY, default=15): cv.positive_not_null_int,
|
||||||
}),
|
}),
|
||||||
vol.Optional(CONF_LAMBDA): cv.lambda_,
|
vol.Optional(CONF_LAMBDA): cv.lambda_,
|
||||||
vol.Optional(CONF_THROTTLE): cv.positive_time_period_milliseconds,
|
vol.Optional(CONF_THROTTLE): cv.positive_time_period_milliseconds,
|
||||||
|
|
|
@ -62,11 +62,10 @@ WIFI_NETWORK_BASE = vol.Schema({
|
||||||
})
|
})
|
||||||
|
|
||||||
WIFI_NETWORK_AP = WIFI_NETWORK_BASE.extend({
|
WIFI_NETWORK_AP = WIFI_NETWORK_BASE.extend({
|
||||||
vol.Optional(CONF_MANUAL_IP): AP_MANUAL_IP_SCHEMA,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
WIFI_NETWORK_STA = WIFI_NETWORK_BASE.extend({
|
WIFI_NETWORK_STA = WIFI_NETWORK_BASE.extend({
|
||||||
vol.Optional(CONF_MANUAL_IP): STA_MANUAL_IP_SCHEMA,
|
|
||||||
vol.Optional(CONF_BSSID): cv.mac_address,
|
vol.Optional(CONF_BSSID): cv.mac_address,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -79,8 +78,6 @@ def validate(config):
|
||||||
network = {CONF_SSID: config.pop(CONF_SSID)}
|
network = {CONF_SSID: config.pop(CONF_SSID)}
|
||||||
if CONF_PASSWORD in config:
|
if CONF_PASSWORD in config:
|
||||||
network[CONF_PASSWORD] = config.pop(CONF_PASSWORD)
|
network[CONF_PASSWORD] = config.pop(CONF_PASSWORD)
|
||||||
if CONF_MANUAL_IP in config:
|
|
||||||
network[CONF_MANUAL_IP] = config.pop(CONF_MANUAL_IP)
|
|
||||||
if CONF_NETWORKS in config:
|
if CONF_NETWORKS in config:
|
||||||
raise vol.Invalid("You cannot use the 'ssid:' option together with 'networks:'. Please "
|
raise vol.Invalid("You cannot use the 'ssid:' option together with 'networks:'. Please "
|
||||||
"copy your network into the 'networks:' key")
|
"copy your network into the 'networks:' key")
|
||||||
|
@ -127,7 +124,7 @@ def manual_ip(config):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def wifi_network(config):
|
def wifi_network(config, static_ip):
|
||||||
ap = variable(config[CONF_ID], WiFiAP())
|
ap = variable(config[CONF_ID], WiFiAP())
|
||||||
if CONF_SSID in config:
|
if CONF_SSID in config:
|
||||||
add(ap.set_ssid(config[CONF_SSID]))
|
add(ap.set_ssid(config[CONF_SSID]))
|
||||||
|
@ -138,21 +135,28 @@ def wifi_network(config):
|
||||||
add(ap.set_bssid(ArrayInitializer(*bssid, multiline=False)))
|
add(ap.set_bssid(ArrayInitializer(*bssid, multiline=False)))
|
||||||
if CONF_CHANNEL in config:
|
if CONF_CHANNEL in config:
|
||||||
add(ap.set_channel(config[CONF_CHANNEL]))
|
add(ap.set_channel(config[CONF_CHANNEL]))
|
||||||
if CONF_MANUAL_IP in config:
|
if static_ip is not None:
|
||||||
add(ap.set_manual_ip(manual_ip(config[CONF_MANUAL_IP])))
|
add(ap.set_manual_ip(manual_ip(static_ip)))
|
||||||
|
|
||||||
return ap
|
return ap
|
||||||
|
|
||||||
|
|
||||||
|
def get_upload_host(config):
|
||||||
|
if CONF_MANUAL_IP in config:
|
||||||
|
return str(config[CONF_MANUAL_IP][CONF_STATIC_IP])
|
||||||
|
hostname = config.get(CONF_HOSTNAME) or CORE.name
|
||||||
|
return hostname + config[CONF_DOMAIN]
|
||||||
|
|
||||||
|
|
||||||
def to_code(config):
|
def to_code(config):
|
||||||
rhs = App.init_wifi()
|
rhs = App.init_wifi()
|
||||||
wifi = Pvariable(config[CONF_ID], rhs)
|
wifi = Pvariable(config[CONF_ID], rhs)
|
||||||
|
|
||||||
for network in config.get(CONF_NETWORKS, []):
|
for network in config.get(CONF_NETWORKS, []):
|
||||||
add(wifi.add_sta(wifi_network(network)))
|
add(wifi.add_sta(wifi_network(network, config.get(CONF_MANUAL_IP))))
|
||||||
|
|
||||||
if CONF_AP in config:
|
if CONF_AP in config:
|
||||||
add(wifi.set_ap(wifi_network(config[CONF_AP])))
|
add(wifi.set_ap(wifi_network(config[CONF_AP], config.get(CONF_MANUAL_IP))))
|
||||||
|
|
||||||
if CONF_HOSTNAME in config:
|
if CONF_HOSTNAME in config:
|
||||||
add(wifi.set_hostname(config[CONF_HOSTNAME]))
|
add(wifi.set_hostname(config[CONF_HOSTNAME]))
|
||||||
|
|
|
@ -378,7 +378,10 @@ def validate_config(config):
|
||||||
continue
|
continue
|
||||||
result[domain][i] = p_validated
|
result[domain][i] = p_validated
|
||||||
|
|
||||||
do_id_pass(result)
|
if not result.errors:
|
||||||
|
# Only parse IDs if no validation error. Otherwise
|
||||||
|
# user gets confusing messages
|
||||||
|
do_id_pass(result)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -307,13 +307,9 @@ class EsphomeyamlCore(object):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def address(self): # type: () -> str
|
def address(self): # type: () -> str
|
||||||
if CONF_MANUAL_IP in self.config[CONF_WIFI]:
|
from esphomeyaml.components import wifi
|
||||||
return str(self.config[CONF_WIFI][CONF_MANUAL_IP][CONF_STATIC_IP])
|
|
||||||
elif CONF_HOSTNAME in self.config[CONF_WIFI]:
|
return wifi.get_upload_host(self.config[CONF_WIFI])
|
||||||
hostname = self.config[CONF_WIFI][CONF_HOSTNAME]
|
|
||||||
else:
|
|
||||||
hostname = self.name
|
|
||||||
return hostname + self.config[CONF_WIFI][CONF_DOMAIN]
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def esphomelib_version(self): # type: () -> Dict[str, str]
|
def esphomelib_version(self): # type: () -> Dict[str, str]
|
||||||
|
|
|
@ -224,7 +224,7 @@ def perform_ota(sock, password, file_handle, filename):
|
||||||
_LOGGER.info("OTA successful")
|
_LOGGER.info("OTA successful")
|
||||||
|
|
||||||
# Do not connect logs until it is fully on
|
# Do not connect logs until it is fully on
|
||||||
time.sleep(2)
|
time.sleep(1)
|
||||||
|
|
||||||
|
|
||||||
def run_ota_impl_(remote_host, remote_port, password, filename):
|
def run_ota_impl_(remote_host, remote_port, password, filename):
|
||||||
|
|
|
@ -279,7 +279,7 @@ def gather_lib_deps():
|
||||||
# Manual fix for AsyncTCP
|
# Manual fix for AsyncTCP
|
||||||
if CORE.config[CONF_ESPHOMEYAML].get(CONF_ARDUINO_VERSION) == ARDUINO_VERSION_ESP32_DEV:
|
if CORE.config[CONF_ESPHOMEYAML].get(CONF_ARDUINO_VERSION) == ARDUINO_VERSION_ESP32_DEV:
|
||||||
lib_deps.add('https://github.com/me-no-dev/AsyncTCP.git#idf-update')
|
lib_deps.add('https://github.com/me-no-dev/AsyncTCP.git#idf-update')
|
||||||
lib_deps.remove('AsyncTCP@1.0.1')
|
lib_deps.discard('AsyncTCP@1.0.1')
|
||||||
# avoid changing build flags order
|
# avoid changing build flags order
|
||||||
return sorted(x for x in lib_deps if x)
|
return sorted(x for x in lib_deps if x)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue