mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	Add logger.log action (#198)
* Add logger.log Action * Simple schema * Validate printf * Improve error message * Undo unfix tests :)
This commit is contained in:
		| @@ -86,9 +86,12 @@ def validate_automation(extra_schema=None, extra_validators=None, single=False): | |||||||
|             try: |             try: | ||||||
|                 # First try as a sequence of actions |                 # First try as a sequence of actions | ||||||
|                 return [schema({CONF_THEN: value})] |                 return [schema({CONF_THEN: value})] | ||||||
|             except vol.Invalid: |             except vol.Invalid as err: | ||||||
|                 # Next try as a sequence of automations |                 # Next try as a sequence of automations | ||||||
|                 return vol.Schema([schema])(value) |                 try: | ||||||
|  |                     return vol.Schema([schema])(value) | ||||||
|  |                 except vol.Invalid as err2: | ||||||
|  |                     raise vol.MultipleInvalid([err, err2]) | ||||||
|         elif isinstance(value, dict): |         elif isinstance(value, dict): | ||||||
|             if CONF_THEN in value: |             if CONF_THEN in value: | ||||||
|                 return [schema(value)] |                 return [schema(value)] | ||||||
|   | |||||||
| @@ -1,10 +1,14 @@ | |||||||
|  | import re | ||||||
|  |  | ||||||
| import voluptuous as vol | import voluptuous as vol | ||||||
|  |  | ||||||
|  | from esphomeyaml.automation import ACTION_REGISTRY, LambdaAction | ||||||
| import esphomeyaml.config_validation as cv | import esphomeyaml.config_validation as cv | ||||||
| from esphomeyaml.const import CONF_BAUD_RATE, CONF_ID, CONF_LEVEL, CONF_LOGS, \ | from esphomeyaml.const import CONF_ARGS, CONF_BAUD_RATE, CONF_FORMAT, CONF_ID, CONF_LEVEL, \ | ||||||
|     CONF_TX_BUFFER_SIZE |     CONF_LOGS, CONF_TAG, CONF_TX_BUFFER_SIZE | ||||||
| from esphomeyaml.core import ESPHomeYAMLError | from esphomeyaml.core import ESPHomeYAMLError, Lambda | ||||||
| from esphomeyaml.helpers import App, Pvariable, add, esphomelib_ns, global_ns | from esphomeyaml.helpers import App, Pvariable, TemplateArguments, add, esphomelib_ns, global_ns, \ | ||||||
|  |     process_lambda, RawExpression, statement | ||||||
|  |  | ||||||
| LOG_LEVELS = { | LOG_LEVELS = { | ||||||
|     'NONE': global_ns.ESPHOMELIB_LOG_LEVEL_NONE, |     'NONE': global_ns.ESPHOMELIB_LOG_LEVEL_NONE, | ||||||
| @@ -16,6 +20,15 @@ LOG_LEVELS = { | |||||||
|     'VERY_VERBOSE': global_ns.ESPHOMELIB_LOG_LEVEL_VERY_VERBOSE, |     'VERY_VERBOSE': global_ns.ESPHOMELIB_LOG_LEVEL_VERY_VERBOSE, | ||||||
| } | } | ||||||
|  |  | ||||||
|  | LOG_LEVEL_TO_ESP_LOG = { | ||||||
|  |     'ERROR': global_ns.ESP_LOGE, | ||||||
|  |     'WARN': global_ns.ESP_LOGW, | ||||||
|  |     'INFO': global_ns.ESP_LOGI, | ||||||
|  |     'DEBUG': global_ns.ESP_LOGD, | ||||||
|  |     'VERBOSE': global_ns.ESP_LOGV, | ||||||
|  |     'VERY_VERBOSE': global_ns.ESP_LOGVV, | ||||||
|  | } | ||||||
|  |  | ||||||
| LOG_LEVEL_SEVERITY = ['NONE', 'ERROR', 'WARN', 'INFO', 'DEBUG', 'VERBOSE', 'VERY_VERBOSE'] | LOG_LEVEL_SEVERITY = ['NONE', 'ERROR', 'WARN', 'INFO', 'DEBUG', 'VERBOSE', 'VERY_VERBOSE'] | ||||||
|  |  | ||||||
| # pylint: disable=invalid-name | # pylint: disable=invalid-name | ||||||
| @@ -59,3 +72,57 @@ def required_build_flags(config): | |||||||
|     if CONF_LEVEL in config: |     if CONF_LEVEL in config: | ||||||
|         return u'-DESPHOMELIB_LOG_LEVEL={}'.format(str(LOG_LEVELS[config[CONF_LEVEL]])) |         return u'-DESPHOMELIB_LOG_LEVEL={}'.format(str(LOG_LEVELS[config[CONF_LEVEL]])) | ||||||
|     return None |     return None | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def maybe_simple_message(schema): | ||||||
|  |     def validator(value): | ||||||
|  |         if isinstance(value, dict): | ||||||
|  |             return vol.Schema(schema)(value) | ||||||
|  |         return vol.Schema(schema)({CONF_FORMAT: value}) | ||||||
|  |     return validator | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def validate_printf(value): | ||||||
|  |     # https://stackoverflow.com/questions/30011379/how-can-i-parse-a-c-format-string-in-python | ||||||
|  |     # pylint: disable=anomalous-backslash-in-string | ||||||
|  |     cfmt = u"""\ | ||||||
|  |     (                                  # start of capture group 1 | ||||||
|  |     %                                  # literal "%" | ||||||
|  |     (?:                                # first option | ||||||
|  |     (?:[-+0 #]{0,5})                   # optional flags | ||||||
|  |     (?:\d+|\*)?                        # width | ||||||
|  |     (?:\.(?:\d+|\*))?                  # precision | ||||||
|  |     (?:h|l|ll|w|I|I32|I64)?            # size | ||||||
|  |     [cCdiouxXeEfgGaAnpsSZ]             # type | ||||||
|  |     ) |                                # OR | ||||||
|  |     %%)                                # literal "%%" | ||||||
|  |     """ | ||||||
|  |     matches = re.findall(cfmt, value[CONF_FORMAT], flags=re.X) | ||||||
|  |     if len(matches) != len(value[CONF_ARGS]): | ||||||
|  |         raise vol.Invalid(u"Found {} printf-patterns ({}), but {} args were given!" | ||||||
|  |                           u"".format(len(matches), u', '.join(matches), len(value[CONF_ARGS]))) | ||||||
|  |     return value | ||||||
|  |  | ||||||
|  |  | ||||||
|  | CONF_LOGGER_LOG = 'logger.log' | ||||||
|  | LOGGER_LOG_ACTION_SCHEMA = vol.All(maybe_simple_message({ | ||||||
|  |     vol.Required(CONF_FORMAT): cv.string, | ||||||
|  |     vol.Optional(CONF_ARGS, default=list): vol.All(cv.ensure_list, [cv.lambda_]), | ||||||
|  |     vol.Optional(CONF_LEVEL, default="DEBUG"): vol.All(vol.Upper, cv.one_of(*LOG_LEVEL_TO_ESP_LOG)), | ||||||
|  |     vol.Optional(CONF_TAG, default="main"): cv.string, | ||||||
|  | }), validate_printf) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @ACTION_REGISTRY.register(CONF_LOGGER_LOG, LOGGER_LOG_ACTION_SCHEMA) | ||||||
|  | def logger_log_action_to_code(config, action_id, arg_type): | ||||||
|  |     template_arg = TemplateArguments(arg_type) | ||||||
|  |     esp_log = LOG_LEVEL_TO_ESP_LOG[config[CONF_LEVEL]] | ||||||
|  |     args = [RawExpression(unicode(x)) for x in config[CONF_ARGS]] | ||||||
|  |  | ||||||
|  |     text = unicode(statement(esp_log(config[CONF_TAG], config[CONF_FORMAT], *args))) | ||||||
|  |  | ||||||
|  |     for lambda_ in process_lambda(Lambda(text), [(arg_type, 'x')]): | ||||||
|  |         yield None | ||||||
|  |     rhs = LambdaAction.new(template_arg, lambda_) | ||||||
|  |     type = LambdaAction.template(template_arg) | ||||||
|  |     yield Pvariable(action_id, rhs, type=type) | ||||||
|   | |||||||
| @@ -346,6 +346,8 @@ CONF_PM_2_5 = 'pm_2_5' | |||||||
| CONF_PM_10_0 = 'pm_10_0' | CONF_PM_10_0 = 'pm_10_0' | ||||||
| CONF_FORMALDEHYDE = 'formaldehyde' | CONF_FORMALDEHYDE = 'formaldehyde' | ||||||
| CONF_ON_TAG = 'on_tag' | CONF_ON_TAG = 'on_tag' | ||||||
|  | CONF_ARGS = 'args' | ||||||
|  | CONF_FORMAT = 'format' | ||||||
| CONF_COLOR_CORRECT = 'color_correct' | CONF_COLOR_CORRECT = 'color_correct' | ||||||
| CONF_ON_JSON_MESSAGE = 'on_json_message' | CONF_ON_JSON_MESSAGE = 'on_json_message' | ||||||
|  |  | ||||||
|   | |||||||
| @@ -193,6 +193,11 @@ sensor: | |||||||
|     on_raw_value: |     on_raw_value: | ||||||
|       - lambda: >- |       - lambda: >- | ||||||
|           ESP_LOGD("main", "Got raw value %f", x); |           ESP_LOGD("main", "Got raw value %f", x); | ||||||
|  |       - logger.log: | ||||||
|  |           level: DEBUG | ||||||
|  |           format: "Got raw value %f" | ||||||
|  |           args: ['x'] | ||||||
|  |       - logger.log: "Got raw value NAN" | ||||||
|       - mqtt.publish: |       - mqtt.publish: | ||||||
|           topic: some/topic |           topic: some/topic | ||||||
|           payload: Hello |           payload: Hello | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user