mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	Add clean MQTT button to dashboard (#139)
This commit is contained in:
		| @@ -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:]) | ||||
|  | ||||
|   | ||||
| @@ -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: | ||||
|   | ||||
| @@ -159,6 +159,10 @@ | ||||
|       margin-right: 24px; | ||||
|       width: 350px; | ||||
|     } | ||||
|  | ||||
|     .dropdown-trigger { | ||||
|       cursor: pointer; | ||||
|     } | ||||
|   </style> | ||||
|  | ||||
|   <meta name="viewport" content="width=device-width, initial-scale=1.0"/> | ||||
| @@ -191,7 +195,7 @@ | ||||
|  | ||||
| <main> | ||||
| <div class="container"> | ||||
|   {% for file, full_path in zip(files, full_path_files) %} | ||||
|   {% for i, (file, full_path) in enumerate(zip(files, full_path_files)) %} | ||||
|   <div class="row"> | ||||
|     <div class="col s8 offset-s2 m10 offset-m1 l12"> | ||||
|       <div class="card horizontal"> | ||||
| @@ -200,7 +204,10 @@ | ||||
|         </div> | ||||
|         <div class="card-stacked"> | ||||
|           <div class="card-content"> | ||||
|             <span class="card-title">{{ escape(file) }}</span> | ||||
|             <span class="card-title"> | ||||
|               {{ escape(file) }} | ||||
|               <i class="material-icons right dropdown-trigger" data-target="dropdown-{{ i }}">more_vert</i> | ||||
|             </span> | ||||
|             <p> | ||||
|               Full path: <code class="inlinecode">{{ escape(full_path) }}</code> | ||||
|             </p> | ||||
| @@ -211,6 +218,9 @@ | ||||
|             <a href="#" class="action-show-logs" data-node="{{ file }}">Show Logs</a> | ||||
|             <a href="#" class="action-validate" data-node="{{ file }}">Validate</a> | ||||
|           </div> | ||||
|           <ul id="dropdown-{{ i }}" class="dropdown-content"> | ||||
|             <li><a href="#" class="action-clean-mqtt" data-node="{{ file }}">Clean MQTT</a></li> | ||||
|           </ul> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
| @@ -462,6 +472,18 @@ | ||||
|   </div> | ||||
| </div> | ||||
|  | ||||
| <div id="modal-clean-mqtt" class="modal modal-fixed-footer"> | ||||
|   <div class="modal-content"> | ||||
|     <h4>Clean MQTT discovery <code class="inlinecode filename"></code></h4> | ||||
|     <div class="log-container"> | ||||
|       <pre class="log"></pre> | ||||
|     </div> | ||||
|   </div> | ||||
|   <div class="modal-footer"> | ||||
|     <a class="modal-close waves-effect waves-green btn-flat stop-logs">Stop</a> | ||||
|   </div> | ||||
| </div> | ||||
|  | ||||
| <a class="btn-floating btn-large ribbon-fab waves-effect waves-light pink accent-2" id="setup-wizard-start"> | ||||
|   <i class="material-icons">add</i> | ||||
| </a> | ||||
| @@ -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 = () => { | ||||
|   | ||||
| @@ -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: | ||||
|   | ||||
		Reference in New Issue
	
	Block a user