Add update available notice

This commit is contained in:
Otto Winter 2018-11-27 16:54:11 +01:00
parent c3a3c038ac
commit c75edc4880
No known key found for this signature in database
GPG Key ID: DB66C0BE6013F97E
8 changed files with 66 additions and 22 deletions

View File

@ -1,14 +1,14 @@
import voluptuous as vol import voluptuous as vol
from esphomeyaml.components import binary_sensor, switch from esphomeyaml.components import switch
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.const import CONF_BINARY_SENSORS, CONF_ID, CONF_LAMBDA, CONF_SWITCHES from esphomeyaml.const import CONF_ID, CONF_LAMBDA, CONF_SWITCHES
from esphomeyaml.cpp_generator import process_lambda, variable from esphomeyaml.cpp_generator import process_lambda, variable
from esphomeyaml.cpp_types import std_vector from esphomeyaml.cpp_types import std_vector
CustomSwitchConstructor = switch.switch_ns.class_('CustomSwitchConstructor') CustomSwitchConstructor = switch.switch_ns.class_('CustomSwitchConstructor')
PLATFORM_SCHEMA = binary_sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = switch.PLATFORM_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(CustomSwitchConstructor), cv.GenerateID(): cv.declare_variable_id(CustomSwitchConstructor),
vol.Required(CONF_LAMBDA): cv.lambda_, vol.Required(CONF_LAMBDA): cv.lambda_,
vol.Required(CONF_SWITCHES): vol.Required(CONF_SWITCHES):
@ -29,8 +29,8 @@ def to_code(config):
switch.register_switch(custom.get_switch(i), sens) switch.register_switch(custom.get_switch(i), sens)
BUILD_FLAGS = '-DUSE_CUSTOM_BINARY_SENSOR' BUILD_FLAGS = '-DUSE_CUSTOM_SWITCH'
def to_hass_config(data, config): def to_hass_config(data, config):
return [binary_sensor.core_to_hass_config(data, sens) for sens in config[CONF_BINARY_SENSORS]] return [switch.core_to_hass_config(data, swi) for swi in config[CONF_SWITCHES]]

View File

@ -590,10 +590,12 @@ def one_of(*values, **kwargs):
upper = kwargs.get('upper', False) upper = kwargs.get('upper', False)
string_ = kwargs.get('string', False) or lower or upper string_ = kwargs.get('string', False) or lower or upper
to_int = kwargs.get('int', False) to_int = kwargs.get('int', False)
space = kwargs.get('space', ' ')
def validator(value): def validator(value):
if string_: if string_:
value = string(value) value = string(value)
value = value.replace(' ', space)
if to_int: if to_int:
value = int_(value) value = int_(value)
if lower: if lower:

View File

@ -378,6 +378,12 @@ CONF_SWITCHES = 'switches'
CONF_TEXT_SENSORS = 'text_sensors' CONF_TEXT_SENSORS = 'text_sensors'
CONF_INCLUDES = 'includes' CONF_INCLUDES = 'includes'
CONF_LIBRARIES = 'libraries' CONF_LIBRARIES = 'libraries'
CONF_PIN_A = 'pin_a'
CONF_PIN_B = 'pin_b'
CONF_PIN_C = 'pin_c'
CONF_PIN_D = 'pin_d'
CONF_SLEEP_WHEN_DONE = 'sleep_when_done'
CONF_STEP_MODE = 'step_mode'
ALLOWED_NAME_CHARS = u'abcdefghijklmnopqrstuvwxyz0123456789_' ALLOWED_NAME_CHARS = u'abcdefghijklmnopqrstuvwxyz0123456789_'
ARDUINO_VERSION_ESP32_DEV = 'https://github.com/platformio/platform-espressif32.git#feature/stage' ARDUINO_VERSION_ESP32_DEV = 'https://github.com/platformio/platform-espressif32.git#feature/stage'

View File

@ -269,6 +269,12 @@ class DashboardEntry(object):
return None return None
return self.storage.board return self.storage.board
@property
def update_available(self):
if self.storage is None:
return True
return self.storage.esphomeyaml_version != const.__version__
class MainRequestHandler(BaseHandler): class MainRequestHandler(BaseHandler):
def get(self): def get(self):

View File

@ -204,3 +204,11 @@ ul.stepper:not(.horizontal) .step.active::before, ul.stepper:not(.horizontal) .s
border-radius: 3px; border-radius: 3px;
height: 100% height: 100%
} }
.update-available i {
vertical-align: bottom;
font-size: 20px !important;
color: #3F51B5 !important;
margin-right: -4.5px;
margin-left: -5.5px;
}

View File

@ -23,6 +23,13 @@ const colorReplace = (input) => {
return input; return input;
}; };
const removeUpdateAvailable = (filename) => {
const p = document.querySelector(`.update-available[data-node="${filename}"]`);
if (p === undefined)
return;
p.remove();
};
let configuration = ""; let configuration = "";
let wsProtocol = "ws:"; let wsProtocol = "ws:";
if (window.location.protocol === "https:") { if (window.location.protocol === "https:") {
@ -202,6 +209,7 @@ document.querySelectorAll(".action-upload").forEach((upload) => {
} else if (data.event === "exit") { } else if (data.event === "exit") {
if (data.code === 0) { if (data.code === 0) {
M.toast({html: "Program exited successfully."}); M.toast({html: "Program exited successfully."});
removeUpdateAvailable(configuration);
} else { } else {
M.toast({html: `Program failed with code ${data.code}`}); M.toast({html: `Program failed with code ${data.code}`});
} }
@ -481,7 +489,6 @@ const editorElem = editModalElem.querySelector("#editor");
const editor = ace.edit(editorElem); const editor = ace.edit(editorElem);
editor.setTheme("ace/theme/dreamweaver"); editor.setTheme("ace/theme/dreamweaver");
editor.session.setMode("ace/mode/yaml"); editor.session.setMode("ace/mode/yaml");
editor.session.setValue("Hello World!");
editor.session.setOption('useSoftTabs', true); editor.session.setOption('useSoftTabs', true);
editor.session.setOption('tabSize', 2); editor.session.setOption('tabSize', 2);

View File

@ -4,17 +4,17 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>esphomeyaml Dashboard</title> <title>esphomeyaml Dashboard</title>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="stylesheet" href="/static/materialize.min.css"> <link rel="stylesheet" href="/static/materialize.min.css?v=1">
<link rel="stylesheet" href="/static/materialize-stepper.min.css"> <link rel="stylesheet" href="/static/materialize-stepper.min.css?v=1">
<link rel="stylesheet" href="/static/esphomeyaml.css"> <link rel="stylesheet" href="/static/esphomeyaml.css?v=1">
<link rel="shortcut icon" href="/static/favicon.ico"> <link rel="shortcut icon" href="/static/favicon.ico?v=1">
<script src="/static/jquery.min.js"></script> <script src="/static/jquery.min.js?v=1"></script>
<script src="/static/jquery-ui.min.js"></script> <script src="/static/jquery-ui.min.js?v=1"></script>
<script src="/static/materialize.min.js"></script> <script src="/static/materialize.min.js?v=1"></script>
<script src="/static/jquery.validate.min.js"></script> <script src="/static/jquery.validate.min.js?v=1"></script>
<script src="/static/materialize-stepper.min.js"></script> <script src="/static/materialize-stepper.min.js?v=1"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
</head> </head>
<body> <body>
@ -61,8 +61,15 @@
<p> <p>
<span class="status-indicator unknown" data-node="{{ entry.filename }}"> <span class="status-indicator unknown" data-node="{{ entry.filename }}">
<span class="status-indicator-icon"></span> <span class="status-indicator-icon"></span>
<span class="status-indicator-text"></span></span>. Full path: <code class="inlinecode">{{ escape(entry.full_path) }}</code> <span class="status-indicator-text"></span></span>.
Full path: <code class="inlinecode">{{ escape(entry.full_path) }}</code>
</p> </p>
{% if entry.update_available %}
<p class="update-available" data-node="{{ entry.filename }}">
<i class="material-icons">system_update</i>
Update Available!
</p>
{% end %}
</div> </div>
<div class="card-action"> <div class="card-action">
<a href="#" class="action-upload" data-node="{{ entry.filename }}">Upload</a> <a href="#" class="action-upload" data-node="{{ entry.filename }}">Upload</a>
@ -500,8 +507,8 @@
</div> </div>
</footer> </footer>
<script src="/static/ace.js" type="text/javascript" charset="utf-8"></script> <script src="/static/ace.js?v=1" type="text/javascript" charset="utf-8"></script>
<script src="/static/esphomeyaml.js" type="text/javascript"></script> <script src="/static/esphomeyaml.js?v=1" type="text/javascript"></script>
{% if len(entries) == 0 %} {% if len(entries) == 0 %}
<script> <script>

View File

@ -2,6 +2,7 @@ import codecs
import json import json
import os import os
from esphomeyaml import const
from esphomeyaml.core import CORE from esphomeyaml.core import CORE
from esphomeyaml.helpers import mkdir_p from esphomeyaml.helpers import mkdir_p
@ -20,8 +21,8 @@ def ext_storage_path(base_path, config_filename): # type: (str, str) -> str
# pylint: disable=too-many-instance-attributes # pylint: disable=too-many-instance-attributes
class StorageJSON(object): class StorageJSON(object):
def __init__(self, storage_version, name, esphomelib_version, src_version, def __init__(self, storage_version, name, esphomelib_version, esphomeyaml_version,
arduino_version, address, esp_platform, board, build_path, src_version, arduino_version, address, esp_platform, board, build_path,
firmware_bin_path): firmware_bin_path):
# Version of the storage JSON schema # Version of the storage JSON schema
assert storage_version is None or isinstance(storage_version, int) assert storage_version is None or isinstance(storage_version, int)
@ -31,6 +32,8 @@ class StorageJSON(object):
# The esphomelib version in use # The esphomelib version in use
assert esphomelib_version is None or isinstance(esphomelib_version, dict) assert esphomelib_version is None or isinstance(esphomelib_version, dict)
self.esphomelib_version = esphomelib_version # type: Dict[str, str] self.esphomelib_version = esphomelib_version # type: Dict[str, str]
# The esphomeyaml version this was compiled with
self.esphomeyaml_version = esphomeyaml_version # type: str
# The version of the file in src/main.cpp - Used to migrate the file # The version of the file in src/main.cpp - Used to migrate the file
assert src_version is None or isinstance(src_version, int) assert src_version is None or isinstance(src_version, int)
self.src_version = src_version # type: int self.src_version = src_version # type: int
@ -53,6 +56,7 @@ class StorageJSON(object):
'storage_version': self.storage_version, 'storage_version': self.storage_version,
'name': self.name, 'name': self.name,
'esphomelib_version': self.esphomelib_version, 'esphomelib_version': self.esphomelib_version,
'esphomeyaml_version': self.esphomeyaml_version,
'src_version': self.src_version, 'src_version': self.src_version,
'arduino_version': self.arduino_version, 'arduino_version': self.arduino_version,
'address': self.address, 'address': self.address,
@ -76,6 +80,7 @@ class StorageJSON(object):
storage_version=1, storage_version=1,
name=esph.name, name=esph.name,
esphomelib_version=esph.esphomelib_version, esphomelib_version=esph.esphomelib_version,
esphomeyaml_version=const.__version__,
src_version=1, src_version=1,
arduino_version=esph.arduino_version, arduino_version=esph.arduino_version,
address=esph.address, address=esph.address,
@ -92,6 +97,7 @@ class StorageJSON(object):
storage_version=1, storage_version=1,
name=name, name=name,
esphomelib_version=None, esphomelib_version=None,
esphomeyaml_version=const.__version__,
src_version=1, src_version=1,
arduino_version=None, arduino_version=None,
address=address, address=address,
@ -109,6 +115,7 @@ class StorageJSON(object):
storage_version = storage['storage_version'] storage_version = storage['storage_version']
name = storage.get('name') name = storage.get('name')
esphomelib_version = storage.get('esphomelib_version') esphomelib_version = storage.get('esphomelib_version')
esphomeyaml_version = storage.get('esphomeyaml_version')
src_version = storage.get('src_version') src_version = storage.get('src_version')
arduino_version = storage.get('arduino_version') arduino_version = storage.get('arduino_version')
address = storage.get('address') address = storage.get('address')
@ -116,8 +123,9 @@ class StorageJSON(object):
board = storage.get('board') board = storage.get('board')
build_path = storage.get('build_path') build_path = storage.get('build_path')
firmware_bin_path = storage.get('firmware_bin_path') firmware_bin_path = storage.get('firmware_bin_path')
return StorageJSON(storage_version, name, esphomelib_version, src_version, arduino_version, return StorageJSON(storage_version, name, esphomelib_version, esphomeyaml_version,
address, esp_platform, board, build_path, firmware_bin_path) src_version, arduino_version, address, esp_platform, board, build_path,
firmware_bin_path)
@staticmethod @staticmethod
def load(path): # type: (str) -> Optional[StorageJSON] def load(path): # type: (str) -> Optional[StorageJSON]