mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	HassIO -> dashboard
This commit is contained in:
		| @@ -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,9 +398,10 @@ 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, | ||||
|                         default=6052) | ||||
|     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,10 +2,10 @@ 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, \ | ||||
|     CONF_MQTT_ID, CONF_MULTIPLY, CONF_NAME, CONF_OFFSET, CONF_ON_RAW_VALUE, CONF_ON_VALUE, \ | ||||
| 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 | ||||
| from esphomeyaml.helpers import App, ArrayInitializer, Pvariable, add, esphomelib_ns, float_, \ | ||||
| @@ -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}`}); | ||||
|           } | ||||
|         } | ||||
|       }); | ||||
		Reference in New Issue
	
	Block a user