esphome/esphome/dashboard/templates/index.html
Ian Leeder aea2e9a6bb
Add hyphen to supported name characters (#1223)
Co-authored-by: Otto Winter <otto@otto-winter.com>
2020-07-30 00:02:34 +02:00

678 lines
31 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dashboard - ESPHome</title>
<link rel="shortcut icon" href="{{ get_static_file_url('images/favicon.ico') }}">
<link rel="stylesheet" href="{{ get_static_file_url('fonts/material-icons/material-icons.css') }}">
<link rel="stylesheet" href="{{ get_static_file_url('css/vendor/materialize/materialize.min.css') }}">
<link rel="stylesheet" href="{{ get_static_file_url('css/vendor/materialize-stepper/materialize-stepper.min.css') }}">
<link rel="stylesheet" href="{{ get_static_file_url('css/esphome.css') }}">
<script src="{{ get_static_file_url('js/vendor/jquery/jquery.min.js') }}"></script>
<script src="{{ get_static_file_url('js/vendor/jquery-ui/jquery-ui.min.js') }}"></script>
<script src="{{ get_static_file_url('js/vendor/jquery-validate/jquery.validate.min.js') }}"></script>
<script src="{{ get_static_file_url('js/vendor/materialize/materialize.min.js') }}"></script>
<script src="{{ get_static_file_url('js/vendor/materialize-stepper/materialize-stepper.min.js') }}"></script>
{% if streamer_mode %}
<style>
.log-secret {
visibility: hidden !important;
}
</style>
{% end %}
</head>
<body>
<div class="navbar-fixed">
<nav class="grey lighten-2">
<div class="nav-wrapper">
<a href="#" class="black-text logo-wrapper">
<img src="https://esphome.io/_static/logo-text.svg" alt="ESPHome Logo" class="logo">
</a>
<ul class="nav-icons right">
<li>
<a class="dropdown-trigger" href="#!" data-target="nav-dropdown"><i class="material-icons">more_vert</i></a>
</li>
</ul>
<div class="serial-port-select right" id="js-serial-port-select">
<select></select>
</div>
</div>
<ul id="nav-dropdown" class="select-action dropdown-content">
<li><a data-action="update-all" data-filename="{{ escape(config_dir) }}">Update All</a></li>
<li><a data-action="edit" data-filename="secrets.yaml">Secrets Editor</a></li>
<li class="divider"></li>
{% if login_enabled %}
<li><a href="{{ relative_url }}logout">Logout</a></li>
{% end %}
</ul>
</nav>
</div>
<main>
<div id="nodes" class="container">
<div id="grid" class="grid">
{% for i, entry in enumerate(entries) %}
<div class="card status-unknown" data-node-name="{{ entry.name }}" data-filename="{{ entry.filename }}">
<div class="card-content black-text">
<span class="card-title">
<span class="node-name">{{ escape(entry.name) }}</span>
<i class="material-icons right dropdown-trigger" data-target="dropdown-{{ i }}">more_vert</i>
{% if 'web_server' in entry.loaded_integrations %}
<a href="http://{{ escape(entry.address) }}" target="_blank"><i
class="material-icons node-webserver right tooltipped" data-position="left"
data-tooltip="Open Node Web Server Interface">launch</i></a>
{% end %}
{% if entry.update_available %}
<i class="material-icons node-update-avaliable right tooltipped" data-position="left"
data-tooltip="Update Available: {{ entry.update_old }} &#x27A1;&#xFE0F;{{ entry.update_new }}">system_update</i>
{% end %}
</span>
<div class="node-config-path">
Filename:
<code class="inlinecode tooltipped" data-position="bottom"
data-tooltip="Full Path: <code class=&quot;inlinecode&quot;>{{ escape(entry.path) }}</code>">
{{ escape(entry.filename) }}
</code>
</div>
{% if entry.comment %}
<div class="node-card-comment">
{{ escape(entry.comment) }}
</div>
{% end %}
</div>
<div class="card-action">
<a data-action="edit" data-filename="{{ entry.filename }}">Edit</a>
<a data-action="validate" data-filename="{{ entry.filename }}">Validate</a>
<a data-action="upload" data-filename="{{ entry.filename }}">Upload</a>
<a data-action="logs" data-filename="{{ entry.filename }}">Logs</a>
</div>
<ul id="dropdown-{{ i }}" class="select-action dropdown-content card-dropdown-action node-dropdown">
<li><a data-action="clean-mqtt" data-filename="{{ entry.filename }}">Clean MQTT</a></li>
<li><a data-action="clean" data-filename="{{ entry.filename }}">Clean Build Files</a></li>
<li><a data-action="compile" data-filename="{{ entry.filename }}">Compile</a></li>
<li class="divider"></li>
<li><a data-action="delete" data-filename="{{ entry.filename }}">Delete</a></li>
</ul>
</div>
{% end %}
</div>
</div>
{% if len(entries) == 0 %}
<div class="center">
<h5>Welcome to ESPHome</h5>
<p>It looks like you don't yet have any Nodes configured.</p>
<p>Click on the pulsating button at the bottom right of the page to add a Node.</p>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const addNodeButton = document.querySelector("#js-wizard");
addNodeButton.classList.add("pulse");
});
</script>
{% end %}
<!-- Config Editor Modal -->
<div id="js-editor-modal" class="modal modal-fixed-footer no-autoinit">
<div class="modal-content">
<h4>Editing: <code id="js-node-filename" class="inlinecode"></code></h4>
<div id="js-loading-indicator">
<div class="preloader-wrapper big active">
<div class="spinner-layer spinner-blue-only">
<div class="circle-clipper left">
<div class="circle"></div>
</div>
<div class="gap-patch">
<div class="circle"></div>
</div>
<div class="circle-clipper right">
<div class="circle"></div>
</div>
</div>
</div>
</div>
<div id="js-editor-area" class="editor"></div>
</div>
<div class="modal-footer">
<a class="waves-effect waves-green btn-flat" data-action="save">Save</a>
<a class="modal-close waves-effect waves-green btn-flat" data-action="upload">Upload</a>
<a class="modal-close waves-effect waves-green btn-flat" data-action="close">Close</a>
</div>
</div>
<!-- Upload Modal -->
<div id="js-upload-modal" class="modal modal-fixed-footer no-autoinit">
<div class="modal-content">
<h4>Compiling & Uploading: <code id="js-node-filename" class="inlinecode"></code></h4>
<pre id="js-log-area" class="log"></pre>
</div>
<div class="modal-footer">
<a href="https://esphome.io/guides/faq.html#i-can-t-get-flashing-over-usb-to-work" target="_blank"
rel="noreferrer">
<i class="material-icons">help_outline</i>
</a>
<a class="modal-close waves-effect waves-green btn-flat" data-action="edit">Edit</a>
<a class="modal-close waves-effect waves-green btn-flat" data-action="stop-logs">Stop</a>
<div class="btn-flat"><i class="material-icons dropdown-trigger"
data-target="dropdown-upload-actions">more_vert</i>
</div>
</div>
<ul id="dropdown-upload-actions" class="select-action dropdown-content card-dropdown-action">
<li>
<a class="modal-close waves-effect waves-green btn-flat disabled" data-action="download-binary">
Download Binary
</a>
</li>
<li>
<a class="waves-effect waves-green btn-flat disabled action-upload" data-action="upload">Retry Upload</a>
</li>
</ul>
</div>
<!-- Update All Modal -->
<div id="js-update-all-modal" class="modal modal-fixed-footer no-autoinit">
<div class="modal-content">
<h4>Update All <code id="js-node-filename" class="inlinecode"></code></h4>
<pre id="js-log-area" class="log"></pre>
</div>
<div class="modal-footer">
<a class="modal-close waves-effect waves-green btn-flat" data-action="stop-logs">Stop</a>
</div>
</div>
<!-- Validate Modal -->
<div id="js-validate-modal" class="modal modal-fixed-footer no-autoinit">
<div class="modal-content">
<h4>Validate: <code id="js-node-filename" class="inlinecode"></code></h4>
<pre id="js-log-area" class="log"></pre>
</div>
<div class="modal-footer">
<a class="modal-close waves-effect waves-green btn-flat" data-action="edit">Edit</a>
<a class="modal-close waves-effect waves-green btn-flat" data-action="upload">Upload</a>
<a class="modal-close waves-effect waves-green btn-flat" data-action="stop-logs">Stop</a>
</div>
</div>
<!-- Logs Modal -->
<div id="js-logs-modal" class="modal modal-fixed-footer no-autoinit">
<div class="modal-content">
<!-- TODO: Change `node-filename` to `node-name` -->
<h4>Showing Logs For: <code id="js-node-filename" class="inlinecode"></code></h4>
<pre id="js-log-area" class="log"></pre>
</div>
<div class="modal-footer">
<a class="modal-close waves-effect waves-green btn-flat" data-action="stop-logs">Close</a>
</div>
</div>
<!-- Compile Modal -->
<div id="js-compile-modal" class="modal modal-fixed-footer no-autoinit">
<div class="modal-content">
<h4>Compiling: <code id="js-node-filename" class="inlinecode"></code></h4>
<pre id="js-log-area" class="log"></pre>
</div>
<div class="modal-footer">
<a href="https://esphome.io/guides/faq.html#i-can-t-get-flashing-over-usb-to-work" target="_blank"
rel="noreferrer">
<i class="material-icons">help_outline</i>
</a>
<a class="modal-close waves-effect waves-green btn-flat disabled" data-action="download-binary">
Download Binary
</a>
<a class="modal-close waves-effect waves-green btn-flat" data-action="stop-logs">Stop</a>
</div>
</div>
<!-- Clean MQTT Modal -->
<div id="js-clean-mqtt-modal" class="modal modal-fixed-footer no-autoinit">
<div class="modal-content">
<div>
<!-- TODO: Change `node-filename` to `node-name` -->
<h4>Clean MQTT Discovery For: <code id="js-node-filename" class="inlinecode"></code></h4>
<pre id="js-log-area" class="log"></pre>
</div>
</div>
<div class="modal-footer">
<a class="modal-close waves-effect waves-green btn-flat" data-action="stop-logs">Close</a>
</div>
</div>
<!-- Clean Build Files Modal -->
<div id="js-clean-modal" class="modal modal-fixed-footer no-autoinit">
<div class="modal-content">
<div>
<!-- TODO: Change `node-filename` to `node-name` -->
<h4>Clean Build Files For: <code id="js-node-filename" class="inlinecode"></code></h4>
<pre id="js-log-area" class="log"></pre>
</div>
</div>
<div class="modal-footer">
<a class="modal-close waves-effect waves-green btn-flat" data-action="stop-logs">Stop</a>
</div>
</div>
<!-- Add New Node / Launch Wizard Button -->
<div class="fixed-action-btn">
<a class="btn-floating btn-large waves-effect waves-light green js-wizard" id="js-wizard" data-action="wizard">
<i class="large material-icons">add</i>
</a>
</div>
<!-- Wizard Modal -->
<div id="js-wizard-modal" class="modal modal-fixed-footer">
<div class="modal-content">
<h5>Create New Node</h5>
<form action="./wizard.html" method="POST">
<ul class="stepper">
{% if len(entries) == 0 %}
<!-- Step 0 (First Run - No Nodes) - Welcome -->
<li class="step active">
<div class="step-title waves-effect">Welcome</div>
<div class="step-content">
<p>
Welcome to the ESPHome node setup wizard! As there are no nodes setup you will be guided through
setting up your first ESP8266 or ESP32-powered device using ESPHome.
</p>
<p>
<a href="https://www.espressif.com/en/products/hardware/esp8266ex/overview"
target="_blank">ESP8266s</a> and
their successors (the <a href="https://www.espressif.com/en/products/hardware/esp32/overview"
target="_blank">ESP32s</a>)
are great low-cost microcontrollers that can communicate with the outside world using WiFi.
They're found in many devices such as the popular Sonoff/iTead, but also exist as development boards
such as the <a href="https://esphome.io/devices/nodemcu_esp8266.html" rel="noreferrer"
target="_blank">NodeMCU</a>.
</p>
<p>
ESPHome, the tool you're using here, creates custom firmwares for these devices using YAML
configuration files (similar to the ones you might be used to with <a href="https://home-assistant.io"
target="_blank">Home Assistant</a>).
</p>
<p>
This wizard will create a basic YAML configuration file for your "node" (the microcontroller) and
later, you will be able to customize this file with some of ESPHome's many avaliable integrations.
</p>
<p>
When you are ready click "begin" to move onto the next step!
</p>
<div class="step-actions">
<button class="waves-effect waves-dark green btn next-step">Begin</button>
</div>
</div>
</li>
{% end %}
<!-- Step 1 - Node Name -->
{% if len(entries) == 0 %}
<li class="step">
{% end %}
{% if len(entries) >= 1 %}
<li class="step active">
{% end %}
<div class="step-title waves-effect">Node Name</div>
<div class="step-content">
{% if len(entries) == 0 %}
<p>
Firstly, please decide on a name for the node. Choose this name wisely, it should be unique among all
of your ESPHome nodes.
</p>
{% end %}
{% if len(entries) >= 1 %}
<p>
Select a unique name for the node.
</p>
{% end %}
<p>
Names must be all <strong>lowercase</strong> and <strong>must not contain any spaces</strong>!
Characters that are allowed are: <code class="inlinecode">a-z</code>,
<code class="inlinecode">0-9</code>, <code class="inlinecode">_</code> and <code class="inlinecode">-</code>.
</p>
<div class="input-field col s12">
<input id="node_name" class="validate" type="text" name="name" data-rule-nospaces="true"
data-rule-lowercase="true" required>
<label for="node_name">Node Name</label>
</div>
<div class="step-actions">
<button class="waves-effect waves-dark green btn next-step">Next</button>
</div>
</div>
</li>
<!-- Step 2 - Device Type -->
<li class="step">
<div class="step-title waves-effect">Device Type</div>
<div class="step-content">
{% if len(entries) == 0 %}
<p>
Now that you have named your node, please select what type of microcontroller you are using so that
the firmware for your node can be compiled correctly.
</p>
{% end %}
{% if len(entries) >= 1 %}
<p>
Select the type of microcontroller that you are using for the node.
</p>
{% end %}
<p>
<em>If unsure you can also select a similar board or choose the "Generic" option.</em>
</p>
<div class="input-field col s12">
<select class="browser-default" name="board" required>
<optgroup label="ESP8266">
<option value="esp01_1m">Generic ESP8266 (for example Sonoff)</option>
<option value="nodemcuv2">NodeMCU</option>
<option value="d1_mini">Wemos D1 and Wemos D1 mini</option>
<option value="d1_mini_lite">Wemos D1 mini Lite</option>
<option value="d1_mini_pro">Wemos D1 mini Pro</option>
<option value="huzzah">Adafruit HUZZAH ESP8266</option>
<option value="oak">DigiStump Oak</option>
<option value="thing">Sparkfun ESP8266 Thing</option>
<option value="thingdev">Sparkfun ESP8266 Thing - Dev Board</option>
</optgroup>
<optgroup label="ESP32">
<option value="esp-wrover-kit">Generic ESP32 (WROVER Module)</option>
<option value="nodemcu-32s">NodeMCU-32S</option>
<option value="lolin_d32">Wemos Lolin D32</option>
<option value="lolin_d32_pro">Wemos Lolin D32 Pro</option>
<option value="featheresp32">Adafruit ESP32 Feather</option>
<option value="m5stack-core-esp32">M5Stack Core ESP32</option>
</optgroup>
<optgroup label="Other ESP8266s">
<option value="gen4iod">4D Systems gen4 IoD Range</option>
<option value="wifi_slot">Amperka WiFi Slot</option>
<option value="espduino">Doit ESPDuino</option>
<option value="espectro">DycodeX ESPectro Core</option>
<option value="espino">ESPino</option>
<option value="esp_wroom_02">Espressif ESP-WROOM-02 module</option>
<option value="esp12e">Espressif ESP-12E module</option>
<option value="esp01">Espressif ESP-01 512k module</option>
<option value="esp07">Espressif ESP-07 module</option>
<option value="esp8285">Generic ESP8285 module</option>
<option value="espresso_lite_v1">ESPert ESPresso Lite 1.0</option>
<option value="espresso_lite_v2">ESPert ESPresso Lite 2.0</option>
<option value="phoenix_v1">ESPert Phoenix 1.0</option>
<option value="wifinfo">WiFInfo</option>
<option value="heltec_wifi_kit_8">Heltec WiFi kit 8</option>
<option value="nodemcu">NodeMCU 0.9</option>
<option value="modwifi">Olimex MOD-WIFI</option>
<option value="wio_link">SeedStudio Wio Link</option>
<option value="wio_node">SeedStudio Wio Node</option>
<option value="sparkfunBlynk">Sparkfun Blynk Board</option>
<option value="esp210">SweetPea ESP-210</option>
<option value="espinotee">ThaiEasyElec ESPino</option>
<option value="d1">Wemos D1 Revision 1</option>
<option value="wifiduino">WiFiDuino</option>
<option value="xinabox_cw01">XinaBox CW01</option>
</optgroup>
<optgroup label="Other ESP32s">
<option value="lolin32">Wemos Lolin 32</option>
<option value="m5stack-fire">M5Stack FIRE</option>
<option value="wemosbat">Wemos WiFi &amp; Bluetooth Battery</option>
<option value="node32s">Node32s</option>
<option value="alksesp32">ALKS ESP32</option>
<option value="bpi-bit">BPI-Bit</option>
<option value="d-duino-32">D-duino-32</option>
<option value="esp32-devkitlipo">OLIMEX ESP32-DevKit-LiPo</option>
<option value="esp32-evb">OLIMEX ESP32-EVB</option>
<option value="esp32-gateway">OLIMEX ESP32-GATEWAY</option>
<option value="esp32-poe-iso">OLIMEX ESP32-PoE-ISO</option>
<option value="esp32-poe">OLIMEX ESP32-PoE</option>
<option value="esp32-pro">OLIMEX ESP32-PRO</option>
<option value="esp320">Electronic SweetPeas ESP320</option>
<option value="esp32cam">AI Thinker ESP32-CAM</option>
<option value="esp32dev">Espressif ESP32 Dev Module</option>
<option value="esp32doit-devkit-v1">DOIT ESP32 DEVKIT V1</option>
<option value="esp32thing">SparkFun ESP32 Thing</option>
<option value="esp32vn-iot-uno">ESP32vn IoT Uno</option>
<option value="espea32">April Brother ESPea32</option>
<option value="espectro32">ESPectro32</option>
<option value="espino32">ESPino32</option>
<option value="firebeetle32">FireBeetle-ESP32</option>
<option value="fm-devkit">ESP32 FM DevKit</option>
<option value="frogboard">Frog Board ESP32</option>
<option value="heltec_wifi_kit_32">Heltec WiFi Kit 32</option>
<option value="heltec_wifi_lora_32">Heltec WiFi LoRa 32</option>
<option value="heltec_wifi_lora_32_V2">Heltec WiFi LoRa 32 (V2)</option>
<option value="heltec_wireless_stick">Heltec Wireless Stick</option>
<option value="hornbill32dev">Hornbill ESP32 Dev</option>
<option value="hornbill32minima">Hornbill ESP32 Minima</option>
<option value="intorobot">IntoRobot Fig</option>
<option value="iotaap_magnolia">IoTaaP Magnolia</option>
<option value="iotbusio">oddWires IoT-Bus Io</option>
<option value="iotbusproteus">oddWires IoT-Bus Proteus</option>
<option value="lopy">Pycom LoPy</option>
<option value="lopy4">Pycom LoPy4</option>
<option value="m5stack-grey">M5Stack GREY ESP32</option>
<option value="m5stick-c">M5Stick-C</option>
<option value="magicbit">MagicBit</option>
<option value="mhetesp32devkit">MH ET LIVE ESP32DevKIT</option>
<option value="mhetesp32minikit">MH ET LIVE ESP32MiniKit</option>
<option value="microduino-core-esp32">Microduino Core ESP32</option>
<option value="nano32">MakerAsia Nano32</option>
<option value="nina_w10">u-blox NINA-W10 series</option>
<option value="odroid_esp32">ODROID-GO</option>
<option value="onehorse32dev">Onehorse ESP32 Dev Module</option>
<option value="oroca_edubot">OROCA EduBot</option>
<option value="pico32">ESP32 Pico Kit</option>
<option value="pocket_32">Dongsen Tech Pocket 32</option>
<option value="pycom_gpy">Pycom GPy</option>
<option value="quantum">Noduino Quantum</option>
<option value="sparkfun_lora_gateway_1-channel">SparkFun LoRa Gateway 1-Channel</option>
<option value="tinypico">TinyPICO</option>
<option value="ttgo-lora32-v1">TTGO LoRa32-OLED V1</option>
<option value="ttgo-t-beam">TTGO T-Beam</option>
<option value="ttgo-t-watch">TTGO T-Watch</option>
<option value="ttgo-t1">TTGO T1</option>
<option value="turta_iot_node">Turta IoT Node</option>
<option value="vintlabs-devkit-v1">VintLabs ESP32 Devkit</option>
<option value="wemos_d1_mini32">WeMos D1 MINI ESP32</option>
<option value="wesp32">Silicognition wESP32</option>
<option value="widora-air">Widora AIR</option>
<option value="xinabox_cw02">XinaBox CW02</option>
</optgroup>
</select>
</div>
<div class="step-actions">
<button class="waves-effect waves-dark green btn next-step">Next</button>
</div>
</div>
</li>
<!-- Step 3 - WiFi & Updates -->
<li class="step">
<div class="step-title waves-effect">WiFi & Updates</div>
<div class="step-content">
{% if len(entries) == 0 %}
<p>
Finally, please enter the details for the WiFi network you want the node to connect to.
Please enter an SSID (name of the WiFi network) and the password needed to connect (if the network has
no password then this can be left blank):
</p>
{% end %}
{% if len(entries) >= 1 %}
<p>
Enter the details for the WiFi network the node can connect to:
</p>
{% end %}
<div class="input-field col s12">
<input id="wifi_ssid" class="validate" type="text" name="ssid" required>
<label for="wifi_ssid">WiFi SSID</label>
</div>
<div class="input-field col s12">
<input id="wifi_password" name="psk" type="password">
<label for="wifi_password">WiFi Password</label>
</div>
{% if len(entries) == 0 %}
<p>
This wizard will automatically set up an Over-The-Air (OTA) update server on the node so that you only
need
to flash the firmware via USB once.
You can optionally password protect this OTA update server by setting up a password here:
</p>
{% end %}
{% if len(entries) >= 1 %}
<p>
Setup an optional password for the Over-The-Air (OTA) update server:
</p>
{% end %}
<div class="input-field col s12">
<input id="password" class="validate" name="password" type="password">
<label for="password">OTA Access Password</label>
</div>
<div class="step-actions">
<!-- Here goes your actions buttons -->
<button class="waves-effect waves-dark green btn next-step">Next</button>
</div>
</div>
</li>
<!-- Step 3 - Finish -->
<li class="step">
<div class="step-title waves-effect">Finish</div>
<div class="step-content">
{% if len(entries) == 0 %}
<p>
Hooray! 🎉🎉🎉 You have successfully created your first ESPHome configuration file.
When you click Submit, the wizard will save the configuration file as
<code class="inlinecode">{{ escape(config_dir) }}/&lt;NAME_OF_NODE&gt;.yaml</code>.
</p>
<h5>Next steps</h5>
<ul class="browser-default">
<li>
Flash the firmware. This can be done using the “UPLOAD” option in the dashboard. See
<a href="https://esphome.io/index.html#devices" rel="noreferrer" target="_blank">this</a>
for guides on how to flash different types of devices. For newly plugged in serial
devices to be detected, restart the add-on.
</li>
<li>
With the current configuration, your node will only connect to WiFi. To make it
actually <i>do</i> stuff, follow
<a href="https://esphome.io/guides/getting_started_hassio.html#adding-some-basic-features"
rel="noreferrer">
the rest of the getting started guide
</a>.
</li>
<li>
See the <a href="https://esphome.io/index.html" rel="noreferrer" target="_blank">ESPHome
Documentation</a>
for a list of supported sensors/devices.
</li>
<li>
Join the <a href="https://discord.gg/KhAMKrd" target="_blank">Discord server</a> and
say hi! Discord's the best place to ask if you have issues/ideas.
</li>
<li>
Star <a href="https://github.com/esphome/esphome" target="_blank">ESPHome</a> on GitHub
if you find this software awesome and report issues using the bug trackers there.
</li>
</ul>
{% end %}
{% if len(entries) >= 1 %}
<p>Click submit to finish creating the node!</p>
{% end %}
<div class="step-actions">
<!-- Here goes your actions buttons -->
<button class="waves-effect waves-dark green btn" type="submit">Submit</button>
</div>
</div>
</li>
</ul>
</form>
</div>
<div class="modal-footer">
<a class="modal-close waves-effect waves-green btn-flat" onclick="wizardStepperInstace.resetStepper();">Exit
Wizard</a>
</div>
</div>
</main>
<footer class="page-footer grey darken-4">
<div class="container">
<div class="left">
Copyright © 2019-2020 ESPHome | Made with <a href="https://materializecss.com/" target="_blank">Materialize</a>
</div>
<div class="right">
<a href="{{ docs_link }}" target="_blank" rel="noreferrer">v{{ version }}
Documentation</a>
</div>
</div>
</footer>
<script src="{{ get_static_file_url('js/vendor/ace/ace.js') }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ get_static_file_url('js/esphome.js') }}" type="text/javascript"></script>
{% if begin and len(entries) == 1 %}
<script>
window.history.replaceState({}, document.title, "/");
document.addEventListener('DOMContentLoaded', () => {
M.toast({
html: '🎉 Congratulations on adding your first Node!',
displayLength: 10000
})
});
</script>
{% end %}
</body>
</html>