diff --git a/esphomeyaml/__main__.py b/esphomeyaml/__main__.py index e6c0d5ae32..8c814446ca 100644 --- a/esphomeyaml/__main__.py +++ b/esphomeyaml/__main__.py @@ -451,6 +451,8 @@ def parse_args(argv): default=6052) dashboard.add_argument("--password", help="The optional password to require for all requests.", type=str, default='') + dashboard.add_argument("--open-ui", help="Open the dashboard UI in a browser.", + action='store_true') return parser.parse_args(argv[1:]) diff --git a/esphomeyaml/dashboard/dashboard.py b/esphomeyaml/dashboard/dashboard.py index 4cec13496a..dfa079392b 100644 --- a/esphomeyaml/dashboard/dashboard.py +++ b/esphomeyaml/dashboard/dashboard.py @@ -117,6 +117,13 @@ class EsphomeyamlValidateHandler(EsphomeyamlCommandWebSocket): return ["esphomeyaml", config_file, "config"] +class EsphomeyamlCleanMqttHandler(EsphomeyamlCommandWebSocket): + def build_command(self, message): + js = json.loads(message) + config_file = os.path.join(CONFIG_DIR, js['configuration']) + return ["esphomeyaml", config_file, "clean-mqtt"] + + class SerialPortRequestHandler(BaseHandler): def get(self): if not self.is_authenticated(): @@ -213,6 +220,7 @@ def make_app(debug=False): (r"/run", EsphomeyamlRunHandler), (r"/compile", EsphomeyamlCompileHandler), (r"/validate", EsphomeyamlValidateHandler), + (r"/clean-mqtt", EsphomeyamlCleanMqttHandler), (r"/download.bin", DownloadBinaryRequestHandler), (r"/serial-ports", SerialPortRequestHandler), (r"/wizard.html", WizardRequestHandler), @@ -251,6 +259,12 @@ def start_web_server(args): args.port, CONFIG_DIR) app = make_app(args.verbose) app.listen(args.port) + + if args.open_ui: + import webbrowser + + webbrowser.open('localhost:{}'.format(args.port)) + try: tornado.ioloop.IOLoop.current().start() except KeyboardInterrupt: diff --git a/esphomeyaml/dashboard/templates/index.html b/esphomeyaml/dashboard/templates/index.html index 9a0abdae0b..a13891f16f 100644 --- a/esphomeyaml/dashboard/templates/index.html +++ b/esphomeyaml/dashboard/templates/index.html @@ -159,6 +159,10 @@ margin-right: 24px; width: 350px; } + + .dropdown-trigger { + cursor: pointer; + } @@ -191,7 +195,7 @@ - {% for file, full_path in zip(files, full_path_files) %} + {% for i, (file, full_path) in enumerate(zip(files, full_path_files)) %} @@ -200,7 +204,10 @@ - {{ escape(file) }} + + {{ escape(file) }} + more_vert + Full path: {{ escape(full_path) }} @@ -211,6 +218,9 @@ Show Logs Validate + + Clean MQTT + @@ -462,6 +472,18 @@ + + + Clean MQTT discovery + + + + + + + add @@ -539,6 +561,7 @@ if (allEqual) return; } + const hasNewPort = response.length >= ports.length; ports = response; @@ -559,7 +582,7 @@ } M.FormSelect.init(portSelect, {}); - if (!begin) + if (!begin && hasNewPort) M.toast({html: "Discovered new serial port."}); }); }; @@ -784,6 +807,48 @@ link.click(); }); + const cleanMqttModalElem = document.getElementById("modal-clean-mqtt"); + + document.querySelectorAll(".action-clean-mqtt").forEach((btn) => { + btn.addEventListener('click', (e) => { + configuration = e.target.getAttribute('data-node'); + const modalInstance = M.Modal.getInstance(cleanMqttModalElem); + const log = cleanMqttModalElem.querySelector(".log"); + log.innerHTML = ""; + const stopLogsButton = cleanMqttModalElem.querySelector(".stop-logs"); + let stopped = false; + stopLogsButton.innerHTML = "Stop"; + modalInstance.open(); + + const filenameField = cleanMqttModalElem.querySelector('.filename'); + filenameField.innerHTML = configuration; + + const logSocket = new WebSocket(wsUrl + "/clean-mqtt"); + logSocket.addEventListener('message', (event) => { + const data = JSON.parse(event.data); + if (data.event === "line") { + const msg = data.data; + log.innerHTML += colorReplace(msg); + } else if (data.event === "exit") { + stopLogsButton.innerHTML = "Close"; + stopped = true; + } + }); + logSocket.addEventListener('open', () => { + const msg = JSON.stringify({configuration: configuration}); + logSocket.send(msg); + }); + logSocket.addEventListener('close', () => { + if (!stopped) { + M.toast({html: 'Terminated process.'}); + } + }); + modalInstance.options.onCloseStart = () => { + logSocket.close(); + }; + }); + }); + const modalSetupElem = document.getElementById("modal-wizard"); const setupWizardStart = document.getElementById('setup-wizard-start'); const startWizard = () => { diff --git a/esphomeyaml/mqtt.py b/esphomeyaml/mqtt.py index ca60800a6c..0160d51197 100644 --- a/esphomeyaml/mqtt.py +++ b/esphomeyaml/mqtt.py @@ -83,7 +83,9 @@ def clear_topic(config, topic, username=None, password=None, client_id=None): discovery_prefix = config[CONF_MQTT].get(CONF_DISCOVERY_PREFIX, u'homeassistant') name = config[CONF_ESPHOMEYAML][CONF_NAME] topic = u'{}/+/{}/#'.format(discovery_prefix, name) - _LOGGER.info(u"Clearing messages from %s", topic) + _LOGGER.info(u"Clearing messages from '%s'", topic) + _LOGGER.info(u"Please close this window when no more messages appear and the " + u"MQTT topic has been cleared of retained messages.") def on_message(client, userdata, msg): if not msg.payload or not msg.retain:
Full path: {{ escape(full_path) }}
{{ escape(full_path) }}