mirror of
https://github.com/esphome/esphome.git
synced 2026-05-09 21:28:40 +08:00
HassIO add-on (#18)
* HassIO Beginnings * Updates * Fix pylint errors * Fix pylint error
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
include README.md
|
||||
include esphomeyaml/hassio/templates/index.html
|
||||
include esphomeyaml/hassio/static/materialize-stepper.min.css
|
||||
include esphomeyaml/hassio/static/materialize-stepper.min.js
|
||||
+192
-88
@@ -1,18 +1,19 @@
|
||||
from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
from datetime import datetime
|
||||
import logging
|
||||
import os
|
||||
import random
|
||||
import sys
|
||||
|
||||
from esphomeyaml import core, mqtt, wizard, writer, yaml_util, const
|
||||
from esphomeyaml import const, core, mqtt, wizard, writer, yaml_util
|
||||
from esphomeyaml.config import core_to_code, get_component, iter_components, read_config
|
||||
from esphomeyaml.const import CONF_BAUD_RATE, CONF_DOMAIN, CONF_ESPHOMEYAML, CONF_HOSTNAME, \
|
||||
CONF_LOGGER, CONF_MANUAL_IP, CONF_NAME, CONF_STATIC_IP, CONF_WIFI
|
||||
CONF_LOGGER, CONF_MANUAL_IP, CONF_NAME, CONF_STATIC_IP, CONF_WIFI, ESP_PLATFORM_ESP8266
|
||||
from esphomeyaml.core import ESPHomeYAMLError
|
||||
from esphomeyaml.helpers import AssignmentExpression, RawStatement, _EXPRESSIONS, add, add_task, \
|
||||
color, get_variable, indent, quote, statement, Expression
|
||||
from esphomeyaml.helpers import AssignmentExpression, Expression, RawStatement, _EXPRESSIONS, add, \
|
||||
add_task, color, get_variable, indent, quote, statement
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@@ -27,28 +28,27 @@ def get_base_path(config):
|
||||
return os.path.join(os.path.dirname(core.CONFIG_PATH), get_name(config))
|
||||
|
||||
|
||||
def discover_serial_ports():
|
||||
def get_serial_ports():
|
||||
# from https://github.com/pyserial/pyserial/blob/master/serial/tools/list_ports.py
|
||||
try:
|
||||
from serial.tools.list_ports import comports
|
||||
except ImportError:
|
||||
return None
|
||||
|
||||
from serial.tools.list_ports import comports
|
||||
result = []
|
||||
descs = []
|
||||
for port, desc, info in comports():
|
||||
if not port:
|
||||
continue
|
||||
if "VID:PID" in info:
|
||||
result.append(port)
|
||||
descs.append(desc)
|
||||
result.append((port, desc))
|
||||
return result
|
||||
|
||||
|
||||
def choose_serial_port(config):
|
||||
result = get_serial_ports()
|
||||
|
||||
if not result:
|
||||
return None
|
||||
return 'OTA'
|
||||
print(u"Found multiple serial port options, please choose one:")
|
||||
for i, (res, desc) in enumerate(zip(result, descs)):
|
||||
for i, (res, desc) in enumerate(result):
|
||||
print(u" [{}] {} ({})".format(i, res, desc))
|
||||
print(u" [{}] Over The Air".format(len(result)))
|
||||
print(u" [{}] Over The Air ({})".format(len(result), get_upload_host(config)))
|
||||
print()
|
||||
while True:
|
||||
opt = raw_input('(number): ')
|
||||
@@ -63,11 +63,11 @@ def discover_serial_ports():
|
||||
except ValueError:
|
||||
print(color('red', u"Invalid option: '{}'".format(opt)))
|
||||
if opt == len(result):
|
||||
return None
|
||||
return result[opt]
|
||||
return 'OTA'
|
||||
return result[opt][0]
|
||||
|
||||
|
||||
def run_platformio(*cmd):
|
||||
def run_platformio(*cmd, **kwargs):
|
||||
def mock_exit(return_code):
|
||||
raise SystemExit(return_code)
|
||||
|
||||
@@ -76,10 +76,13 @@ def run_platformio(*cmd):
|
||||
full_cmd = u' '.join(quote(x) for x in cmd)
|
||||
_LOGGER.info(u"Running: %s", full_cmd)
|
||||
try:
|
||||
import platformio.__main__
|
||||
func = kwargs.get('main')
|
||||
if func is None:
|
||||
import platformio.__main__
|
||||
func = platformio.__main__.main
|
||||
sys.argv = list(cmd)
|
||||
sys.exit = mock_exit
|
||||
return platformio.__main__.main()
|
||||
return func() or 0
|
||||
except KeyboardInterrupt:
|
||||
return 1
|
||||
except SystemExit as err:
|
||||
@@ -92,13 +95,19 @@ def run_platformio(*cmd):
|
||||
sys.exit = orig_exit
|
||||
|
||||
|
||||
def run_miniterm(config, port):
|
||||
from serial.tools import miniterm
|
||||
def run_miniterm(config, port, escape=False):
|
||||
import serial
|
||||
baud_rate = config.get(CONF_LOGGER, {}).get(CONF_BAUD_RATE, 115200)
|
||||
sys.argv = ['miniterm', '--raw', '--exit-char', '3']
|
||||
miniterm.main(
|
||||
default_port=port,
|
||||
default_baudrate=baud_rate)
|
||||
_LOGGER.info("Starting log output from %s with baud rate %s", port, baud_rate)
|
||||
|
||||
with serial.Serial(port, baudrate=baud_rate) as ser:
|
||||
while True:
|
||||
line = ser.readline()
|
||||
time = datetime.now().time().strftime('[%H:%M:%S]')
|
||||
message = time + line.decode('unicode-escape').replace('\r', '').replace('\n', '')
|
||||
if escape:
|
||||
message = message.replace('\033', '\\033').encode('ascii', 'replace')
|
||||
print(message)
|
||||
|
||||
|
||||
def write_cpp(config):
|
||||
@@ -153,9 +162,32 @@ def compile_program(config):
|
||||
return run_platformio('platformio', 'run', '-d', get_base_path(config))
|
||||
|
||||
|
||||
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):
|
||||
import esptool
|
||||
|
||||
name = get_name(config)
|
||||
path = os.path.join(get_base_path(config), '.pioenvs', name, 'firmware.bin')
|
||||
# pylint: disable=protected-access
|
||||
return run_platformio('esptool.py', '--before', 'default_reset', '--after', 'hard_reset',
|
||||
'--chip', 'esp8266', '--port', port, 'write_flash', '0x0',
|
||||
path, main=esptool._main)
|
||||
|
||||
|
||||
def upload_program(config, args, port):
|
||||
_LOGGER.info("Uploading binary...")
|
||||
if port is not None:
|
||||
if port != 'OTA':
|
||||
if core.ESP_PLATFORM == ESP_PLATFORM_ESP8266 and args.use_esptoolpy:
|
||||
return upload_using_esptool(config, port)
|
||||
return run_platformio('platformio', 'run', '-d', get_base_path(config),
|
||||
'-t', 'upload', '--upload-port', port)
|
||||
|
||||
@@ -163,12 +195,7 @@ def upload_program(config, args, port):
|
||||
_LOGGER.error("No serial port found and OTA not enabled. Can't upload!")
|
||||
return -1
|
||||
|
||||
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]
|
||||
host = get_upload_host(config)
|
||||
|
||||
from esphomeyaml.components import ota
|
||||
from esphomeyaml import espota
|
||||
@@ -184,11 +211,12 @@ def upload_program(config, args, port):
|
||||
return espota.main(espota_args)
|
||||
|
||||
|
||||
def show_logs(config, args, port):
|
||||
if port is not None and port != 'OTA':
|
||||
run_miniterm(config, port)
|
||||
def show_logs(config, args, port, escape=False):
|
||||
if port != 'OTA':
|
||||
run_miniterm(config, port, escape=escape)
|
||||
return 0
|
||||
return mqtt.show_logs(config, args.topic, args.username, args.password, args.client_id)
|
||||
return mqtt.show_logs(config, args.topic, args.username, args.password, args.client_id,
|
||||
escape=escape)
|
||||
|
||||
|
||||
def clean_mqtt(config, args):
|
||||
@@ -221,11 +249,98 @@ def setup_log():
|
||||
pass
|
||||
|
||||
|
||||
def main():
|
||||
setup_log()
|
||||
def command_wizard(args):
|
||||
return wizard.wizard(args.configuration)
|
||||
|
||||
|
||||
def command_config(args, config):
|
||||
print(yaml_util.dump(config))
|
||||
return 0
|
||||
|
||||
|
||||
def command_compile(args, config):
|
||||
exit_code = write_cpp(config)
|
||||
if exit_code != 0:
|
||||
return exit_code
|
||||
exit_code = compile_program(config)
|
||||
if exit_code != 0:
|
||||
return exit_code
|
||||
_LOGGER.info(u"Successfully compiled program.")
|
||||
return 0
|
||||
|
||||
|
||||
def command_upload(args, config):
|
||||
port = args.upload_port or choose_serial_port(config)
|
||||
exit_code = upload_program(config, args, port)
|
||||
if exit_code != 0:
|
||||
return exit_code
|
||||
_LOGGER.info(u"Successfully uploaded program.")
|
||||
return 0
|
||||
|
||||
|
||||
def command_logs(args, config):
|
||||
port = args.serial_port or choose_serial_port(config)
|
||||
return show_logs(config, args, port, escape=args.escape)
|
||||
|
||||
|
||||
def command_run(args, config):
|
||||
exit_code = write_cpp(config)
|
||||
if exit_code != 0:
|
||||
return exit_code
|
||||
exit_code = compile_program(config)
|
||||
if exit_code != 0:
|
||||
return exit_code
|
||||
_LOGGER.info(u"Successfully compiled program.")
|
||||
port = args.upload_port or choose_serial_port(config)
|
||||
exit_code = upload_program(config, args, port)
|
||||
if exit_code != 0:
|
||||
return exit_code
|
||||
_LOGGER.info(u"Successfully uploaded program.")
|
||||
if args.no_logs:
|
||||
return 0
|
||||
return show_logs(config, args, port, escape=args.escape)
|
||||
|
||||
|
||||
def command_clean_mqtt(args, config):
|
||||
return clean_mqtt(config, args)
|
||||
|
||||
|
||||
def command_mqtt_fingerprint(args, config):
|
||||
return mqtt.get_fingerprint(config)
|
||||
|
||||
|
||||
def command_version(args):
|
||||
print(u"Version: {}".format(const.__version__))
|
||||
return 0
|
||||
|
||||
|
||||
def command_hassio(args):
|
||||
from esphomeyaml.hassio import hassio
|
||||
|
||||
return hassio.start_web_server(args)
|
||||
|
||||
|
||||
PRE_CONFIG_ACTIONS = {
|
||||
'wizard': command_wizard,
|
||||
'version': command_version,
|
||||
'hassio': command_hassio
|
||||
}
|
||||
|
||||
POST_CONFIG_ACTIONS = {
|
||||
'config': command_config,
|
||||
'compile': command_compile,
|
||||
'upload': command_upload,
|
||||
'logs': command_logs,
|
||||
'run': command_run,
|
||||
'clean-mqtt': command_clean_mqtt,
|
||||
'mqtt-fingerprint': command_mqtt_fingerprint,
|
||||
}
|
||||
|
||||
|
||||
def parse_args(argv):
|
||||
parser = argparse.ArgumentParser(prog='esphomeyaml')
|
||||
parser.add_argument('configuration', help='Your YAML configuration file.')
|
||||
|
||||
subparsers = parser.add_subparsers(help='Commands', dest='command')
|
||||
subparsers.required = True
|
||||
subparsers.add_parser('config', help='Validate the configuration and spit it out.')
|
||||
@@ -237,6 +352,9 @@ def main():
|
||||
parser_upload.add_argument('--upload-port', help="Manually specify the upload port to use. "
|
||||
"For example /dev/cu.SLAB_USBtoUART.")
|
||||
parser_upload.add_argument('--host-port', help="Specify the host port.", type=int)
|
||||
parser_upload.add_argument('--use-esptoolpy',
|
||||
help="Use esptool.py for HassIO (only for ESP8266)",
|
||||
action='store_true')
|
||||
|
||||
parser_logs = subparsers.add_parser('logs', help='Validate the configuration '
|
||||
'and show all MQTT logs.')
|
||||
@@ -246,6 +364,8 @@ def main():
|
||||
parser_logs.add_argument('--client-id', help='Manually set the client id.')
|
||||
parser_logs.add_argument('--serial-port', help="Manually specify a serial port to use"
|
||||
"For example /dev/cu.SLAB_USBtoUART.")
|
||||
parser_logs.add_argument('--escape', help="Escape ANSI color codes for HassIO",
|
||||
action='store_true')
|
||||
|
||||
parser_run = subparsers.add_parser('run', help='Validate the configuration, create a binary, '
|
||||
'upload it, and start MQTT logs.')
|
||||
@@ -258,6 +378,10 @@ def main():
|
||||
parser_run.add_argument('--username', help='Manually set the MQTT username for logs.')
|
||||
parser_run.add_argument('--password', help='Manually set the MQTT password for logs.')
|
||||
parser_run.add_argument('--client-id', help='Manually set the client id for logs.')
|
||||
parser_run.add_argument('--escape', help="Escape ANSI color codes for HassIO",
|
||||
action='store_true')
|
||||
parser_run.add_argument('--use-esptoolpy', help="Use esptool.py for HassIO (only for ESP8266)",
|
||||
action='store_true')
|
||||
|
||||
parser_clean = subparsers.add_parser('clean-mqtt', help="Helper to clear an MQTT topic from "
|
||||
"retain messages.")
|
||||
@@ -270,12 +394,25 @@ def main():
|
||||
"you through setting up esphomeyaml.")
|
||||
|
||||
subparsers.add_parser('mqtt-fingerprint', help="Get the SSL fingerprint from a MQTT broker.")
|
||||
|
||||
subparsers.add_parser('version', help="Print the esphomeyaml version and exit.")
|
||||
|
||||
args = parser.parse_args()
|
||||
hassio = subparsers.add_parser('hassio', help="Create a simple webserver for a HassIO add-on.")
|
||||
hassio.add_argument("--port", help="The HTTP port to open connections on.", type=int,
|
||||
default=6052)
|
||||
|
||||
if args.command == 'wizard':
|
||||
return wizard.wizard(args.configuration)
|
||||
return parser.parse_args(argv[1:])
|
||||
|
||||
|
||||
def run_esphomeyaml(argv):
|
||||
setup_log()
|
||||
args = parse_args(argv)
|
||||
if args.command in PRE_CONFIG_ACTIONS:
|
||||
try:
|
||||
return PRE_CONFIG_ACTIONS[args.command](args)
|
||||
except ESPHomeYAMLError as e:
|
||||
_LOGGER.error(e)
|
||||
return 1
|
||||
|
||||
core.CONFIG_PATH = args.configuration
|
||||
|
||||
@@ -283,58 +420,25 @@ def main():
|
||||
if config is None:
|
||||
return 1
|
||||
|
||||
if args.command == 'config':
|
||||
print(yaml_util.dump(config))
|
||||
return 0
|
||||
elif args.command == 'compile':
|
||||
if args.command in POST_CONFIG_ACTIONS:
|
||||
try:
|
||||
exit_code = write_cpp(config)
|
||||
return POST_CONFIG_ACTIONS[args.command](args, config)
|
||||
except ESPHomeYAMLError as e:
|
||||
_LOGGER.error(e)
|
||||
return 1
|
||||
if exit_code != 0:
|
||||
return exit_code
|
||||
exit_code = compile_program(config)
|
||||
if exit_code != 0:
|
||||
return exit_code
|
||||
_LOGGER.info(u"Successfully compiled program.")
|
||||
return 0
|
||||
elif args.command == 'upload':
|
||||
port = args.upload_port or discover_serial_ports()
|
||||
exit_code = upload_program(config, args, port)
|
||||
if exit_code != 0:
|
||||
return exit_code
|
||||
_LOGGER.info(u"Successfully uploaded program.")
|
||||
return 0
|
||||
elif args.command == 'logs':
|
||||
port = args.serial_port or discover_serial_ports()
|
||||
return show_logs(config, args, port)
|
||||
elif args.command == 'clean-mqtt':
|
||||
return clean_mqtt(config, args)
|
||||
elif args.command == 'mqtt-fingerprint':
|
||||
return mqtt.get_fingerprint(config)
|
||||
elif args.command == 'run':
|
||||
exit_code = write_cpp(config)
|
||||
if exit_code != 0:
|
||||
return exit_code
|
||||
exit_code = compile_program(config)
|
||||
if exit_code != 0:
|
||||
return exit_code
|
||||
_LOGGER.info(u"Successfully compiled program.")
|
||||
port = args.upload_port or discover_serial_ports()
|
||||
exit_code = upload_program(config, args, port)
|
||||
if exit_code != 0:
|
||||
return exit_code
|
||||
_LOGGER.info(u"Successfully uploaded program.")
|
||||
if args.no_logs:
|
||||
return 0
|
||||
return show_logs(config, args, port)
|
||||
elif args.command == 'version':
|
||||
print(u"Version: {}".format(const.__version__))
|
||||
return 0
|
||||
print(u"Unknown command {}".format(args.command))
|
||||
return 1
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
return run_esphomeyaml(sys.argv)
|
||||
except ESPHomeYAMLError as e:
|
||||
_LOGGER.error(e)
|
||||
return 1
|
||||
except KeyboardInterrupt:
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
|
||||
@@ -4,11 +4,10 @@ import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.components import switch
|
||||
from esphomeyaml.components.ir_transmitter import IRTransmitterComponent
|
||||
from esphomeyaml.const import CONF_ADDRESS, CONF_CARRIER_FREQUENCY, CONF_COMMAND, CONF_DATA, \
|
||||
CONF_ID, CONF_INVERTED, CONF_IR_TRANSMITTER_ID, CONF_LG, CONF_NAME, CONF_NBITS, CONF_NEC, \
|
||||
CONF_INVERTED, CONF_IR_TRANSMITTER_ID, CONF_LG, CONF_NAME, CONF_NBITS, CONF_NEC, \
|
||||
CONF_PANASONIC, CONF_RAW, CONF_REPEAT, CONF_SONY, CONF_TIMES, CONF_WAIT_TIME
|
||||
from esphomeyaml.core import ESPHomeYAMLError
|
||||
from esphomeyaml.helpers import App, ArrayInitializer, HexIntLiteral, Pvariable, \
|
||||
get_variable
|
||||
from esphomeyaml.helpers import App, ArrayInitializer, HexIntLiteral, get_variable
|
||||
|
||||
DEPENDENCIES = ['ir_transmitter']
|
||||
|
||||
@@ -98,8 +97,7 @@ def to_code(config):
|
||||
ir = get_variable(config.get(CONF_IR_TRANSMITTER_ID), IRTransmitterComponent)
|
||||
send_data = exp_send_data(config)
|
||||
rhs = App.register_component(ir.create_transmitter(config[CONF_NAME], send_data))
|
||||
switch_ = Pvariable(DataTransmitter, config[CONF_ID], rhs)
|
||||
switch.register_switch(switch_, config)
|
||||
switch.register_switch(rhs, config)
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_IR_TRANSMITTER'
|
||||
|
||||
@@ -26,7 +26,7 @@ zero_to_one_float = vol.All(vol.Coerce(float), vol.Range(min=0, max=1))
|
||||
positive_int = vol.All(vol.Coerce(int), vol.Range(min=0))
|
||||
positive_not_null_int = vol.All(vol.Coerce(int), vol.Range(min=0, min_included=False))
|
||||
|
||||
ALLOWED_NAME_CHARS = u'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_'
|
||||
ALLOWED_NAME_CHARS = u'abcdefghijklmnopqrstuvwxyz0123456789_'
|
||||
|
||||
RESERVED_IDS = [
|
||||
# C++ keywords http://en.cppreference.com/w/cpp/keyword
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"""Constants used by esphomeyaml."""
|
||||
|
||||
MAJOR_VERSION = 1
|
||||
MINOR_VERSION = 5
|
||||
PATCH_VERSION = '3'
|
||||
MINOR_VERSION = 6
|
||||
PATCH_VERSION = '0'
|
||||
__short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION)
|
||||
__version__ = '{}.{}'.format(__short_version__, PATCH_VERSION)
|
||||
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
from __future__ import print_function
|
||||
|
||||
import codecs
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import random
|
||||
import subprocess
|
||||
|
||||
try:
|
||||
import tornado
|
||||
import tornado.gen
|
||||
import tornado.ioloop
|
||||
import tornado.iostream
|
||||
import tornado.process
|
||||
import tornado.web
|
||||
import tornado.websocket
|
||||
import tornado.concurrent
|
||||
except ImportError as err:
|
||||
pass
|
||||
|
||||
from esphomeyaml import const, core, __main__
|
||||
from esphomeyaml.__main__ import get_serial_ports, get_base_path, get_name
|
||||
from esphomeyaml.helpers import quote
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
CONFIG_DIR = ''
|
||||
|
||||
# pylint: disable=abstract-method, arguments-differ
|
||||
class EsphomeyamlCommandWebSocket(tornado.websocket.WebSocketHandler):
|
||||
def __init__(self, application, request, **kwargs):
|
||||
super(EsphomeyamlCommandWebSocket, self).__init__(application, request, **kwargs)
|
||||
self.proc = None
|
||||
self.closed = False
|
||||
|
||||
def on_message(self, message):
|
||||
if self.proc is not None:
|
||||
return
|
||||
command = self.build_command(message)
|
||||
_LOGGER.debug(u"WebSocket opened for command %s", [quote(x) for x in command])
|
||||
self.proc = tornado.process.Subprocess(command,
|
||||
stdout=tornado.process.Subprocess.STREAM,
|
||||
stderr=subprocess.STDOUT)
|
||||
self.proc.set_exit_callback(self.proc_on_exit)
|
||||
tornado.ioloop.IOLoop.current().spawn_callback(self.redirect_stream)
|
||||
|
||||
@tornado.gen.coroutine
|
||||
def redirect_stream(self):
|
||||
while True:
|
||||
try:
|
||||
data = yield self.proc.stdout.read_until_regex('[\n\r]')
|
||||
except tornado.iostream.StreamClosedError:
|
||||
break
|
||||
if data.endswith('\r') and random.randrange(100) < 90:
|
||||
continue
|
||||
data = data.replace('\033', '\\033')
|
||||
self.write_message({'event': 'line', 'data': data})
|
||||
|
||||
def proc_on_exit(self, returncode):
|
||||
if not self.closed:
|
||||
_LOGGER.debug("Process exited with return code %s", returncode)
|
||||
self.write_message({'event': 'exit', 'code': returncode})
|
||||
|
||||
def on_close(self):
|
||||
self.closed = True
|
||||
if self.proc is not None and self.proc.returncode is None:
|
||||
_LOGGER.debug("Terminating process")
|
||||
self.proc.proc.terminate()
|
||||
|
||||
def build_command(self, message):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class EsphomeyamlLogsHandler(EsphomeyamlCommandWebSocket):
|
||||
def build_command(self, message):
|
||||
js = json.loads(message)
|
||||
config_file = CONFIG_DIR + '/' + js['configuration']
|
||||
return ["esphomeyaml", config_file, "logs", '--serial-port', js["port"], '--escape']
|
||||
|
||||
|
||||
class EsphomeyamlRunHandler(EsphomeyamlCommandWebSocket):
|
||||
def build_command(self, message):
|
||||
js = json.loads(message)
|
||||
config_file = os.path.join(CONFIG_DIR, js['configuration'])
|
||||
return ["esphomeyaml", config_file, "run", '--upload-port', js["port"],
|
||||
'--escape', '--use-esptoolpy']
|
||||
|
||||
|
||||
class EsphomeyamlCompileHandler(EsphomeyamlCommandWebSocket):
|
||||
def build_command(self, message):
|
||||
js = json.loads(message)
|
||||
config_file = os.path.join(CONFIG_DIR, js['configuration'])
|
||||
return ["esphomeyaml", config_file, "compile"]
|
||||
|
||||
|
||||
class SerialPortRequestHandler(tornado.web.RequestHandler):
|
||||
def get(self):
|
||||
ports = get_serial_ports()
|
||||
data = []
|
||||
for port, desc in ports:
|
||||
if port == '/dev/ttyAMA0':
|
||||
# ignore RPi built-in serial port
|
||||
continue
|
||||
data.append({'port': port, 'desc': desc})
|
||||
data.append({'port': 'OTA', 'desc': 'Over-The-Air Upload/Logs'})
|
||||
self.write(json.dumps(data))
|
||||
|
||||
|
||||
class WizardRequestHandler(tornado.web.RequestHandler):
|
||||
def post(self):
|
||||
from esphomeyaml import wizard
|
||||
|
||||
kwargs = {k: ''.join(v) for k, v in self.request.arguments.iteritems()}
|
||||
config = wizard.wizard_file(**kwargs)
|
||||
destination = os.path.join(CONFIG_DIR, kwargs['name'] + '.yaml')
|
||||
with codecs.open(destination, 'w') as f_handle:
|
||||
f_handle.write(config)
|
||||
|
||||
self.redirect('/')
|
||||
|
||||
|
||||
class DownloadBinaryRequestHandler(tornado.web.RequestHandler):
|
||||
def get(self):
|
||||
configuration = self.get_argument('configuration')
|
||||
config_file = os.path.join(CONFIG_DIR, configuration)
|
||||
core.CONFIG_PATH = config_file
|
||||
config = __main__.read_config(core.CONFIG_PATH)
|
||||
name = get_name(config)
|
||||
path = os.path.join(get_base_path(config), '.pioenvs', name, 'firmware.bin')
|
||||
self.set_header('Content-Type', 'application/octet-stream')
|
||||
self.set_header("Content-Disposition", 'attachment; filename="{}.bin"'.format(name))
|
||||
with open(path, 'rb') as f:
|
||||
while 1:
|
||||
data = f.read(16384) # or some other nice-sized chunk
|
||||
if not data:
|
||||
break
|
||||
self.write(data)
|
||||
self.finish()
|
||||
|
||||
|
||||
class MainRequestHandler(tornado.web.RequestHandler):
|
||||
def get(self):
|
||||
files = [f for f in os.listdir(CONFIG_DIR) if f.endswith('.yaml')]
|
||||
full_path_files = [os.path.join(CONFIG_DIR, f) for f in files]
|
||||
self.render("templates/index.html", files=files, full_path_files=full_path_files,
|
||||
version=const.__version__)
|
||||
|
||||
|
||||
def make_app():
|
||||
static_path = os.path.join(os.path.dirname(__file__), 'static')
|
||||
return tornado.web.Application([
|
||||
(r"/", MainRequestHandler),
|
||||
(r"/logs", EsphomeyamlLogsHandler),
|
||||
(r"/run", EsphomeyamlRunHandler),
|
||||
(r"/compile", EsphomeyamlCompileHandler),
|
||||
(r"/download.bin", DownloadBinaryRequestHandler),
|
||||
(r"/serial-ports", SerialPortRequestHandler),
|
||||
(r"/wizard.html", WizardRequestHandler),
|
||||
(r'/static/(.*)', tornado.web.StaticFileHandler, {'path': static_path}),
|
||||
], debug=True)
|
||||
|
||||
|
||||
def start_web_server(args):
|
||||
global CONFIG_DIR
|
||||
CONFIG_DIR = args.configuration
|
||||
if not os.path.exists(CONFIG_DIR):
|
||||
os.makedirs(CONFIG_DIR)
|
||||
|
||||
_LOGGER.info("Starting HassIO add-on web server on port %s and configuration dir %s...",
|
||||
args.port, CONFIG_DIR)
|
||||
app = make_app()
|
||||
app.listen(args.port)
|
||||
try:
|
||||
tornado.ioloop.IOLoop.current().start()
|
||||
except KeyboardInterrupt:
|
||||
_LOGGER.info("Shutting down...")
|
||||
+5
File diff suppressed because one or more lines are too long
+5
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
+5
-2
@@ -39,7 +39,7 @@ def initialize(config, subscriptions, on_message, username, password, client_id)
|
||||
return 0
|
||||
|
||||
|
||||
def show_logs(config, topic=None, username=None, password=None, client_id=None):
|
||||
def show_logs(config, topic=None, username=None, password=None, client_id=None, escape=False):
|
||||
if topic is not None:
|
||||
pass # already have topic
|
||||
elif CONF_MQTT in config:
|
||||
@@ -57,7 +57,10 @@ def show_logs(config, topic=None, username=None, password=None, client_id=None):
|
||||
|
||||
def on_message(client, userdata, msg):
|
||||
time = datetime.now().time().strftime(u'[%H:%M:%S]')
|
||||
print(time + msg.payload)
|
||||
message = msg.payload.decode('utf-8')
|
||||
if escape:
|
||||
message = message.replace('\033', '\\033')
|
||||
print(time + message)
|
||||
|
||||
return initialize(config, [topic], on_message, username, password, client_id)
|
||||
|
||||
|
||||
+16
-8
@@ -70,6 +70,18 @@ logger:
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def wizard_file(**kwargs):
|
||||
config = BASE_CONFIG.format(**kwargs)
|
||||
|
||||
if kwargs['ota_password']:
|
||||
config += "ota:\n password: '{}'\n".format(kwargs['ota_password'])
|
||||
else:
|
||||
config += "ota:\n"
|
||||
|
||||
return config
|
||||
|
||||
|
||||
if os.getenv('ESPHOMEYAML_QUICKWIZARD', False):
|
||||
def sleep(time):
|
||||
pass
|
||||
@@ -272,14 +284,10 @@ def wizard(path):
|
||||
print("Press ENTER for no password")
|
||||
ota_password = raw_input(color('bold_white', '(password): '))
|
||||
|
||||
config = BASE_CONFIG.format(name=name, platform=platform, board=board,
|
||||
ssid=ssid, psk=psk, broker=broker,
|
||||
mqtt_username=mqtt_username, mqtt_password=mqtt_password)
|
||||
|
||||
if ota_password:
|
||||
config += "ota:\n password: '{}'\n".format(ota_password)
|
||||
else:
|
||||
config += "ota:\n"
|
||||
config = wizard_file(name=name, platform=platform, board=board,
|
||||
ssid=ssid, psk=psk, broker=broker,
|
||||
mqtt_username=mqtt_username, mqtt_password=mqtt_password,
|
||||
ota_password=ota_password)
|
||||
|
||||
with codecs.open(path, 'w') as f_handle:
|
||||
f_handle.write(config)
|
||||
|
||||
Reference in New Issue
Block a user