mirror of
https://github.com/esphome/esphome.git
synced 2024-11-21 22:48:10 +01:00
HassIO -> dashboard
This commit is contained in:
parent
2e7d8540fb
commit
93d962dd43
15 changed files with 79 additions and 57 deletions
|
@ -1,4 +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
|
||||
include esphomeyaml/dashboard/templates/index.html
|
||||
include esphomeyaml/dashboard/static/materialize-stepper.min.css
|
||||
include esphomeyaml/dashboard/static/materialize-stepper.min.js
|
||||
|
|
|
@ -314,16 +314,16 @@ def command_version(args):
|
|||
return 0
|
||||
|
||||
|
||||
def command_hassio(args):
|
||||
from esphomeyaml.hassio import hassio
|
||||
def command_dashboard(args):
|
||||
from esphomeyaml.dashboard import dashboard
|
||||
|
||||
return hassio.start_web_server(args)
|
||||
return dashboard.start_web_server(args)
|
||||
|
||||
|
||||
PRE_CONFIG_ACTIONS = {
|
||||
'wizard': command_wizard,
|
||||
'version': command_version,
|
||||
'hassio': command_hassio
|
||||
'dashboard': command_dashboard
|
||||
}
|
||||
|
||||
POST_CONFIG_ACTIONS = {
|
||||
|
@ -353,7 +353,7 @@ def parse_args(argv):
|
|||
"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)",
|
||||
help="Use esptool.py for the uploading (only for ESP8266)",
|
||||
action='store_true')
|
||||
|
||||
parser_logs = subparsers.add_parser('logs', help='Validate the configuration '
|
||||
|
@ -364,7 +364,7 @@ def parse_args(argv):
|
|||
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",
|
||||
parser_logs.add_argument('--escape', help="Escape ANSI color codes for running in dashboard",
|
||||
action='store_true')
|
||||
|
||||
parser_run = subparsers.add_parser('run', help='Validate the configuration, create a binary, '
|
||||
|
@ -378,9 +378,10 @@ def parse_args(argv):
|
|||
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",
|
||||
parser_run.add_argument('--escape', help="Escape ANSI color codes for running in dashboard",
|
||||
action='store_true')
|
||||
parser_run.add_argument('--use-esptoolpy', help="Use esptool.py for HassIO (only for ESP8266)",
|
||||
parser_run.add_argument('--use-esptoolpy',
|
||||
help="Use esptool.py for the uploading (only for ESP8266)",
|
||||
action='store_true')
|
||||
|
||||
parser_clean = subparsers.add_parser('clean-mqtt', help="Helper to clear an MQTT topic from "
|
||||
|
@ -397,8 +398,9 @@ def parse_args(argv):
|
|||
|
||||
subparsers.add_parser('version', help="Print the esphomeyaml version and exit.")
|
||||
|
||||
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,
|
||||
dashboard = subparsers.add_parser('dashboard',
|
||||
help="Create a simple webserver for a dashboard.")
|
||||
dashboard.add_argument("--port", help="The HTTP port to open connections on.", type=int,
|
||||
default=6052)
|
||||
|
||||
return parser.parse_args(argv[1:])
|
||||
|
|
|
@ -4,9 +4,9 @@ import esphomeyaml.config_validation as cv
|
|||
from esphomeyaml.components import cover, fan
|
||||
from esphomeyaml.const import CONF_ACTION_ID, CONF_AND, CONF_AUTOMATION_ID, CONF_BLUE, \
|
||||
CONF_BRIGHTNESS, CONF_CONDITION_ID, CONF_DELAY, CONF_EFFECT, CONF_FLASH_LENGTH, CONF_GREEN, \
|
||||
CONF_ID, CONF_IF, CONF_LAMBDA, CONF_MAX, CONF_MIN, CONF_OR, CONF_PAYLOAD, CONF_QOS, \
|
||||
CONF_RANGE, CONF_RED, CONF_RETAIN, CONF_THEN, CONF_TOPIC, CONF_TRANSITION_LENGTH, \
|
||||
CONF_TRIGGER_ID, CONF_WHITE, CONF_OSCILLATING, CONF_SPEED
|
||||
CONF_ID, CONF_IF, CONF_LAMBDA, CONF_OR, CONF_OSCILLATING, CONF_PAYLOAD, \
|
||||
CONF_QOS, CONF_RANGE, CONF_RED, CONF_RETAIN, CONF_SPEED, CONF_THEN, CONF_TOPIC, \
|
||||
CONF_TRANSITION_LENGTH, CONF_TRIGGER_ID, CONF_WHITE, CONF_ABOVE, CONF_BELOW
|
||||
from esphomeyaml.core import ESPHomeYAMLError
|
||||
from esphomeyaml.helpers import App, ArrayInitializer, Pvariable, TemplateArguments, add, \
|
||||
bool_, esphomelib_ns, float_, get_variable, process_lambda, std_string, templatable, uint32, \
|
||||
|
@ -51,11 +51,11 @@ ACTIONS_SCHEMA = vol.All(cv.ensure_list, [vol.All({
|
|||
vol.Required(CONF_ID): cv.variable_id,
|
||||
vol.Optional(CONF_TRANSITION_LENGTH): cv.templatable(cv.positive_time_period_milliseconds),
|
||||
vol.Optional(CONF_FLASH_LENGTH): cv.templatable(cv.positive_time_period_milliseconds),
|
||||
vol.Optional(CONF_BRIGHTNESS): cv.templatable(cv.zero_to_one_float),
|
||||
vol.Optional(CONF_RED): cv.templatable(cv.zero_to_one_float),
|
||||
vol.Optional(CONF_GREEN): cv.templatable(cv.zero_to_one_float),
|
||||
vol.Optional(CONF_BLUE): cv.templatable(cv.zero_to_one_float),
|
||||
vol.Optional(CONF_WHITE): cv.templatable(cv.zero_to_one_float),
|
||||
vol.Optional(CONF_BRIGHTNESS): cv.templatable(cv.percentage),
|
||||
vol.Optional(CONF_RED): cv.templatable(cv.percentage),
|
||||
vol.Optional(CONF_GREEN): cv.templatable(cv.percentage),
|
||||
vol.Optional(CONF_BLUE): cv.templatable(cv.percentage),
|
||||
vol.Optional(CONF_WHITE): cv.templatable(cv.percentage),
|
||||
vol.Optional(CONF_EFFECT): cv.templatable(cv.string),
|
||||
}),
|
||||
vol.Optional(CONF_SWITCH_TOGGLE): vol.Schema({
|
||||
|
@ -116,9 +116,9 @@ CONDITIONS_SCHEMA = vol.All(cv.ensure_list, [vol.All({
|
|||
vol.Optional(CONF_AND): validate_recursive_condition,
|
||||
vol.Optional(CONF_OR): validate_recursive_condition,
|
||||
vol.Optional(CONF_RANGE): vol.All(vol.Schema({
|
||||
vol.Optional(CONF_MIN): vol.Coerce(float),
|
||||
vol.Optional(CONF_MAX): vol.Coerce(float),
|
||||
}), cv.has_at_least_one_key(CONF_MIN, CONF_MAX)),
|
||||
vol.Optional(CONF_ABOVE): vol.Coerce(float),
|
||||
vol.Optional(CONF_BELOW): vol.Coerce(float),
|
||||
}), cv.has_at_least_one_key(CONF_ABOVE, CONF_BELOW)),
|
||||
vol.Optional(CONF_LAMBDA): cv.lambda_,
|
||||
}), cv.has_at_exactly_one_key(*CONDITION_KEYS)])
|
||||
|
||||
|
@ -149,10 +149,10 @@ def build_condition(config, arg_type):
|
|||
conf = config[CONF_RANGE]
|
||||
rhs = RangeCondition.new(template_arg)
|
||||
condition = Pvariable(RangeCondition.template(template_arg), config[CONF_CONDITION_ID], rhs)
|
||||
if CONF_MIN in conf:
|
||||
condition.set_min(templatable(conf[CONF_MIN], arg_type, float_))
|
||||
if CONF_MAX in conf:
|
||||
condition.set_max(templatable(conf[CONF_MAX], arg_type, float_))
|
||||
if CONF_ABOVE in conf:
|
||||
condition.set_min(templatable(conf[CONF_ABOVE], arg_type, float_))
|
||||
if CONF_BELOW in conf:
|
||||
condition.set_max(templatable(conf[CONF_BELOW], arg_type, float_))
|
||||
return condition
|
||||
raise ESPHomeYAMLError(u"Unsupported condition {}".format(config))
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ def validate_voltage(values):
|
|||
value = cv.string(value)
|
||||
if not value.endswith('V'):
|
||||
value += 'V'
|
||||
return cv.one_of(values)(value)
|
||||
return cv.one_of(*values)(value)
|
||||
return validator
|
||||
|
||||
|
||||
|
|
|
@ -14,9 +14,9 @@ PLATFORM_SCHEMA = fan.PLATFORM_SCHEMA.extend({
|
|||
vol.Optional(CONF_SPEED_COMMAND_TOPIC): cv.subscribe_topic,
|
||||
vol.Optional(CONF_OSCILLATION_OUTPUT): cv.variable_id,
|
||||
vol.Optional(CONF_SPEED): vol.Schema({
|
||||
vol.Required(CONF_LOW): cv.zero_to_one_float,
|
||||
vol.Required(CONF_MEDIUM): cv.zero_to_one_float,
|
||||
vol.Required(CONF_HIGH): cv.zero_to_one_float,
|
||||
vol.Required(CONF_LOW): cv.percentage,
|
||||
vol.Required(CONF_MEDIUM): cv.percentage,
|
||||
vol.Required(CONF_HIGH): cv.percentage,
|
||||
}),
|
||||
}).extend(fan.FAN_SCHEMA.schema)
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ BINARY_OUTPUT_SCHEMA = cv.REQUIRED_ID_SCHEMA.extend({
|
|||
})
|
||||
|
||||
FLOAT_OUTPUT_SCHEMA = BINARY_OUTPUT_SCHEMA.extend({
|
||||
vol.Optional(CONF_MAX_POWER): cv.zero_to_one_float,
|
||||
vol.Optional(CONF_MAX_POWER): cv.percentage,
|
||||
})
|
||||
|
||||
output_ns = esphomelib_ns.namespace('output')
|
||||
|
|
|
@ -2,9 +2,9 @@ import voluptuous as vol
|
|||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml import automation
|
||||
from esphomeyaml.const import CONF_ACCURACY_DECIMALS, CONF_ALPHA, CONF_DEBOUNCE, CONF_DELTA, \
|
||||
CONF_EXPIRE_AFTER, CONF_EXPONENTIAL_MOVING_AVERAGE, CONF_FILTERS, CONF_FILTER_NAN, \
|
||||
CONF_FILTER_OUT, CONF_HEARTBEAT, CONF_ICON, CONF_ID, CONF_LAMBDA, CONF_MAX, CONF_MIN, \
|
||||
from esphomeyaml.const import CONF_ABOVE, CONF_ACCURACY_DECIMALS, CONF_ALPHA, CONF_BELOW, \
|
||||
CONF_DEBOUNCE, CONF_DELTA, CONF_EXPIRE_AFTER, CONF_EXPONENTIAL_MOVING_AVERAGE, CONF_FILTERS, \
|
||||
CONF_FILTER_NAN, CONF_FILTER_OUT, CONF_HEARTBEAT, CONF_ICON, CONF_ID, CONF_LAMBDA, \
|
||||
CONF_MQTT_ID, CONF_MULTIPLY, CONF_NAME, CONF_OFFSET, CONF_ON_RAW_VALUE, CONF_ON_VALUE,\
|
||||
CONF_ON_VALUE_RANGE, CONF_OR, CONF_SEND_EVERY, CONF_SLIDING_WINDOW_MOVING_AVERAGE, \
|
||||
CONF_THROTTLE, CONF_TRIGGER_ID, CONF_UNIQUE, CONF_UNIT_OF_MEASUREMENT, CONF_WINDOW_SIZE
|
||||
|
@ -59,9 +59,9 @@ SENSOR_SCHEMA = cv.MQTT_COMPONENT_SCHEMA.extend({
|
|||
vol.Optional(CONF_ON_RAW_VALUE): vol.All(cv.ensure_list, [automation.AUTOMATION_SCHEMA]),
|
||||
vol.Optional(CONF_ON_VALUE_RANGE): vol.All(cv.ensure_list, [vol.All(
|
||||
automation.AUTOMATION_SCHEMA.extend({
|
||||
vol.Optional(CONF_MIN): vol.Coerce(float),
|
||||
vol.Optional(CONF_MAX): vol.Coerce(float),
|
||||
}), cv.has_at_least_one_key(CONF_MIN, CONF_MAX))]),
|
||||
vol.Optional(CONF_ABOVE): vol.Coerce(float),
|
||||
vol.Optional(CONF_BELOW): vol.Coerce(float),
|
||||
}), cv.has_at_least_one_key(CONF_ABOVE, CONF_BELOW))]),
|
||||
})
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
|
@ -144,10 +144,10 @@ def setup_sensor_core_(sensor_var, mqtt_var, config):
|
|||
for conf in config.get(CONF_ON_VALUE_RANGE, []):
|
||||
rhs = sensor_var.make_value_range_trigger()
|
||||
trigger = Pvariable(ValueRangeTrigger, conf[CONF_TRIGGER_ID], rhs)
|
||||
if CONF_MIN in conf:
|
||||
trigger.set_min(templatable(conf[CONF_MIN], float_, float_))
|
||||
if CONF_MAX in conf:
|
||||
trigger.set_max(templatable(conf[CONF_MAX], float_, float_))
|
||||
if CONF_ABOVE in conf:
|
||||
trigger.set_min(templatable(conf[CONF_ABOVE], float_, float_))
|
||||
if CONF_BELOW in conf:
|
||||
trigger.set_max(templatable(conf[CONF_BELOW], float_, float_))
|
||||
automation.build_automation(trigger, float_, conf)
|
||||
|
||||
if CONF_EXPIRE_AFTER in config:
|
||||
|
|
|
@ -36,14 +36,18 @@ def validate_gain(value):
|
|||
elif not isinstance(value, (str, unicode)):
|
||||
raise vol.Invalid('invalid gain "{}"'.format(value))
|
||||
|
||||
if value not in GAIN:
|
||||
raise vol.Invalid("Invalid gain, options are {}".format(', '.join(GAIN.keys())))
|
||||
return value
|
||||
return cv.one_of(*GAIN)(value)
|
||||
|
||||
|
||||
def validate_mux(value):
|
||||
value = cv.string(value).upper()
|
||||
value = value.replace(' ', '_')
|
||||
return cv.one_of(*MUX)(value)
|
||||
|
||||
|
||||
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID('ads1115_sensor'): cv.register_variable_id,
|
||||
vol.Required(CONF_MULTIPLEXER): vol.All(vol.Upper, cv.one_of(*MUX)),
|
||||
vol.Required(CONF_MULTIPLEXER): validate_mux,
|
||||
vol.Required(CONF_GAIN): validate_gain,
|
||||
vol.Optional(CONF_ADS1115_ID): cv.variable_id,
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
|
||||
|
|
|
@ -461,6 +461,12 @@ hex_uint32_t = vol.All(hex_int, vol.Range(min=0, max=4294967295))
|
|||
i2c_address = hex_uint8_t
|
||||
|
||||
|
||||
def percentage(value):
|
||||
if isinstance(value, (str, unicode)) and value.endswith('%'):
|
||||
value = float(value[:-1].rstrip()) / 100.0
|
||||
return zero_to_one_float(value)
|
||||
|
||||
|
||||
def invalid(message):
|
||||
def validator(value):
|
||||
raise vol.Invalid(message)
|
||||
|
|
|
@ -81,8 +81,8 @@ CONF_TRANSITION_LENGTH = 'transition_length'
|
|||
CONF_FLASH_LENGTH = 'flash_length'
|
||||
CONF_BRIGHTNESS = 'brightness'
|
||||
CONF_EFFECT = 'effect'
|
||||
CONF_MIN = 'min'
|
||||
CONF_MAX = 'max'
|
||||
CONF_ABOVE = 'above'
|
||||
CONF_BELOW = 'below'
|
||||
CONF_ON = 'on'
|
||||
CONF_IF = 'if'
|
||||
CONF_THEN = 'then'
|
||||
|
|
|
@ -140,7 +140,7 @@ class DownloadBinaryRequestHandler(tornado.web.RequestHandler):
|
|||
|
||||
class MainRequestHandler(tornado.web.RequestHandler):
|
||||
def get(self):
|
||||
files = [f for f in os.listdir(CONFIG_DIR) if f.endswith('.yaml')]
|
||||
files = sorted([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__)
|
||||
|
@ -157,7 +157,7 @@ def make_app():
|
|||
(r"/serial-ports", SerialPortRequestHandler),
|
||||
(r"/wizard.html", WizardRequestHandler),
|
||||
(r'/static/(.*)', tornado.web.StaticFileHandler, {'path': static_path}),
|
||||
], debug=True)
|
||||
], debug=False)
|
||||
|
||||
|
||||
def start_web_server(args):
|
||||
|
@ -166,7 +166,7 @@ def start_web_server(args):
|
|||
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...",
|
||||
_LOGGER.info("Starting dashboard web server on port %s and configuration dir %s...",
|
||||
args.port, CONFIG_DIR)
|
||||
app = make_app()
|
||||
app.listen(args.port)
|
|
@ -547,7 +547,11 @@
|
|||
const msg = data.data;
|
||||
log.innerHTML += colorReplace(msg);
|
||||
} else if (data.event === "exit") {
|
||||
M.toast({html: `Program exited with code ${data.code}`});
|
||||
if (data.code === 0) {
|
||||
M.toast({html: "Program exited successfully!"});
|
||||
} else {
|
||||
M.toast({html: `Program failed with code ${data.code}`});
|
||||
}
|
||||
}
|
||||
});
|
||||
logSocket.addEventListener('open', () => {
|
||||
|
@ -615,7 +619,11 @@
|
|||
const msg = data.data;
|
||||
log.innerHTML += colorReplace(msg);
|
||||
} else if (data.event === "exit") {
|
||||
M.toast({html: `Program exited with code ${data.code}`});
|
||||
if (data.code === 0) {
|
||||
M.toast({html: "Program exited successfully!"});
|
||||
} else {
|
||||
M.toast({html: `Program failed with code ${data.code}`});
|
||||
}
|
||||
}
|
||||
});
|
||||
logSocket.addEventListener('open', () => {
|
||||
|
@ -665,9 +673,11 @@
|
|||
const msg = data.data;
|
||||
log.innerHTML += colorReplace(msg);
|
||||
} else if (data.event === "exit") {
|
||||
M.toast({html: `Program exited with code ${data.code}`});
|
||||
if (data.code === 0) {
|
||||
M.toast({html: "Program exited successfully!"});
|
||||
downloadButton.classList.remove('disabled');
|
||||
} else {
|
||||
M.toast({html: `Program failed with code ${data.code}`});
|
||||
}
|
||||
}
|
||||
});
|
Loading…
Reference in a new issue