From 822377be8b28a4baafe833b0bf06a10cd1601203 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 4 May 2021 09:21:14 +1200 Subject: [PATCH 001/104] Bump version to v1.17.0 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 90155f30f6..f8b7da0664 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -2,7 +2,7 @@ MAJOR_VERSION = 1 MINOR_VERSION = 17 -PATCH_VERSION = "0b1" +PATCH_VERSION = "0" __short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__ = f"{__short_version__}.{PATCH_VERSION}" From 69c78651d509414daa9f7acd44bd44e262447797 Mon Sep 17 00:00:00 2001 From: buxtronix Date: Tue, 23 Mar 2021 16:21:04 +1100 Subject: [PATCH 002/104] Fix BLE UUID matching (#1637) Co-authored-by: Ben Buxton --- esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp index a8185a8c67..b2d303da15 100644 --- a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +++ b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp @@ -241,7 +241,7 @@ ESPBTUUID ESPBTUUID::as_128bit() const { } bool ESPBTUUID::contains(uint8_t data1, uint8_t data2) const { if (this->uuid_.len == ESP_UUID_LEN_16) { - return (this->uuid_.uuid.uuid16 >> 8) == data2 || (this->uuid_.uuid.uuid16 & 0xFF) == data1; + return (this->uuid_.uuid.uuid16 >> 8) == data2 && (this->uuid_.uuid.uuid16 & 0xFF) == data1; } else if (this->uuid_.len == ESP_UUID_LEN_32) { for (uint8_t i = 0; i < 3; i++) { bool a = ((this->uuid_.uuid.uuid32 >> i * 8) & 0xFF) == data1; From c903eb2d01273719e3deda21d1977fb575eadf8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diego=20Elio=20Petten=C3=B2?= Date: Thu, 25 Mar 2021 18:33:06 +0000 Subject: [PATCH 003/104] Add optional bindkey support for CGG1. (#1407) --- esphome/components/xiaomi_ble/xiaomi_ble.cpp | 7 +++++-- esphome/components/xiaomi_cgg1/sensor.py | 4 ++++ esphome/components/xiaomi_cgg1/xiaomi_cgg1.cpp | 18 ++++++++++++++++-- esphome/components/xiaomi_cgg1/xiaomi_cgg1.h | 2 ++ 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/esphome/components/xiaomi_ble/xiaomi_ble.cpp b/esphome/components/xiaomi_ble/xiaomi_ble.cpp index 033269f66c..29a34be81c 100644 --- a/esphome/components/xiaomi_ble/xiaomi_ble.cpp +++ b/esphome/components/xiaomi_ble/xiaomi_ble.cpp @@ -103,7 +103,7 @@ bool parse_xiaomi_message(const std::vector &message, XiaomiParseResult return false; } - while (payload_length > 0) { + while (payload_length > 3) { if (payload[payload_offset + 1] != 0x10) { ESP_LOGVV(TAG, "parse_xiaomi_message(): fixed byte not found, stop parsing residual data."); break; @@ -171,7 +171,10 @@ optional parse_xiaomi_header(const esp32_ble_tracker::Service result.type = XiaomiParseResult::TYPE_MUE4094RT; result.name = "MUE4094RT"; result.raw_offset -= 6; - } else if ((raw[2] == 0x47) && (raw[3] == 0x03)) { // round body, e-ink display + } else if ((raw[2] == 0x47) && (raw[3] == 0x03)) { // ClearGrass-branded, round body, e-ink display + result.type = XiaomiParseResult::TYPE_CGG1; + result.name = "CGG1"; + } else if ((raw[2] == 0x48) && (raw[3] == 0x0B)) { // Qingping-branded, round body, e-ink display — with bindkeys result.type = XiaomiParseResult::TYPE_CGG1; result.name = "CGG1"; } else if ((raw[2] == 0xbc) && (raw[3] == 0x03)) { // VegTrug Grow Care Garden diff --git a/esphome/components/xiaomi_cgg1/sensor.py b/esphome/components/xiaomi_cgg1/sensor.py index 6201df61b8..cedf04d8a6 100644 --- a/esphome/components/xiaomi_cgg1/sensor.py +++ b/esphome/components/xiaomi_cgg1/sensor.py @@ -3,6 +3,7 @@ import esphome.config_validation as cv from esphome.components import sensor, esp32_ble_tracker from esphome.const import ( CONF_BATTERY_LEVEL, + CONF_BINDKEY, CONF_HUMIDITY, CONF_MAC_ADDRESS, CONF_TEMPERATURE, @@ -27,6 +28,7 @@ CONFIG_SCHEMA = ( cv.Schema( { cv.GenerateID(): cv.declare_id(XiaomiCGG1), + cv.Optional(CONF_BINDKEY): cv.bind_key, cv.Required(CONF_MAC_ADDRESS): cv.mac_address, cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE @@ -50,6 +52,8 @@ def to_code(config): yield esp32_ble_tracker.register_ble_device(var, config) cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) + if CONF_BINDKEY in config: + cg.add(var.set_bindkey(config[CONF_BINDKEY])) if CONF_TEMPERATURE in config: sens = yield sensor.new_sensor(config[CONF_TEMPERATURE]) diff --git a/esphome/components/xiaomi_cgg1/xiaomi_cgg1.cpp b/esphome/components/xiaomi_cgg1/xiaomi_cgg1.cpp index a7c94fafad..86725956e0 100644 --- a/esphome/components/xiaomi_cgg1/xiaomi_cgg1.cpp +++ b/esphome/components/xiaomi_cgg1/xiaomi_cgg1.cpp @@ -10,6 +10,7 @@ static const char *TAG = "xiaomi_cgg1"; void XiaomiCGG1::dump_config() { ESP_LOGCONFIG(TAG, "Xiaomi CGG1"); + ESP_LOGCONFIG(TAG, " Bindkey: %s", hexencode(this->bindkey_, 16).c_str()); LOG_SENSOR(" ", "Temperature", this->temperature_); LOG_SENSOR(" ", "Humidity", this->humidity_); LOG_SENSOR(" ", "Battery Level", this->battery_level_); @@ -31,8 +32,9 @@ bool XiaomiCGG1::parse_device(const esp32_ble_tracker::ESPBTDevice &device) { if (res->is_duplicate) { continue; } - if (res->has_encryption) { - ESP_LOGVV(TAG, "parse_device(): payload decryption is currently not supported on this device."); + if (res->has_encryption && + (!(xiaomi_ble::decrypt_xiaomi_payload(const_cast &>(service_data.data), this->bindkey_, + this->address_)))) { continue; } if (!(xiaomi_ble::parse_xiaomi_message(service_data.data, *res))) { @@ -57,6 +59,18 @@ bool XiaomiCGG1::parse_device(const esp32_ble_tracker::ESPBTDevice &device) { return true; } +void XiaomiCGG1::set_bindkey(const std::string &bindkey) { + memset(bindkey_, 0, 16); + if (bindkey.size() != 32) { + return; + } + char temp[3] = {0}; + for (int i = 0; i < 16; i++) { + strncpy(temp, &(bindkey.c_str()[i * 2]), 2); + bindkey_[i] = std::strtoul(temp, NULL, 16); + } +} + } // namespace xiaomi_cgg1 } // namespace esphome diff --git a/esphome/components/xiaomi_cgg1/xiaomi_cgg1.h b/esphome/components/xiaomi_cgg1/xiaomi_cgg1.h index 57f883405c..e1d812e929 100644 --- a/esphome/components/xiaomi_cgg1/xiaomi_cgg1.h +++ b/esphome/components/xiaomi_cgg1/xiaomi_cgg1.h @@ -13,6 +13,7 @@ namespace xiaomi_cgg1 { class XiaomiCGG1 : public Component, public esp32_ble_tracker::ESPBTDeviceListener { public: void set_address(uint64_t address) { address_ = address; } + void set_bindkey(const std::string &bindkey); bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override; @@ -24,6 +25,7 @@ class XiaomiCGG1 : public Component, public esp32_ble_tracker::ESPBTDeviceListen protected: uint64_t address_; + uint8_t bindkey_[16]; sensor::Sensor *temperature_{nullptr}; sensor::Sensor *humidity_{nullptr}; sensor::Sensor *battery_level_{nullptr}; From 566c1294355ad2f4cc43d8880b6ac819cce90419 Mon Sep 17 00:00:00 2001 From: SenexCrenshaw <35600301+SenexCrenshaw@users.noreply.github.com> Date: Fri, 26 Mar 2021 18:01:37 -0400 Subject: [PATCH 004/104] Buffer allocation and TRUEFALSE templates (#1644) --- esphome/core/helpers.h | 15 +++++++++++++++ esphome/core/log.h | 1 + 2 files changed, 16 insertions(+) diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index 63706e8a19..5f9ab1fdd1 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -319,3 +319,18 @@ template class Parented { uint32_t fnv1_hash(const std::string &str); } // namespace esphome + +template T *new_buffer(size_t length) { + T *buffer; +#ifdef ARDUINO_ARCH_ESP32 + if (psramFound()) { + buffer = (T *) ps_malloc(length); + } else { + buffer = new T[length]; + } +#else + buffer = new T[length]; +#endif + + return buffer; +} // namespace esphome diff --git a/esphome/core/log.h b/esphome/core/log.h index 361fbe1182..0eec28101f 100644 --- a/esphome/core/log.h +++ b/esphome/core/log.h @@ -160,5 +160,6 @@ int esp_idf_log_vprintf_(const char *format, va_list args); // NOLINT ((byte) &0x08 ? '1' : '0'), ((byte) &0x04 ? '1' : '0'), ((byte) &0x02 ? '1' : '0'), ((byte) &0x01 ? '1' : '0') #define YESNO(b) ((b) ? "YES" : "NO") #define ONOFF(b) ((b) ? "ON" : "OFF") +#define TRUEFALSE(b) ((b) ? "TRUE" : "FALSE") } // namespace esphome From 392ed64375a07435ee78c5b011ac6c1ec2683aa5 Mon Sep 17 00:00:00 2001 From: Guillermo Ruffino Date: Sun, 28 Mar 2021 22:35:39 -0300 Subject: [PATCH 005/104] fix servo not reattaching with same target (#1649) --- esphome/components/servo/servo.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/components/servo/servo.cpp b/esphome/components/servo/servo.cpp index 6935c34653..57baf4aecf 100644 --- a/esphome/components/servo/servo.cpp +++ b/esphome/components/servo/servo.cpp @@ -52,6 +52,8 @@ void Servo::loop() { void Servo::write(float value) { value = clamp(value, -1.0f, 1.0f); + if (this->target_value_ == value) + this->internal_write(value); this->target_value_ = value; this->source_value_ = this->current_value_; this->state_ = STATE_ATTACHED; From 5ab2ef40792e0bae937aa1b49d6a8e13f6917c5c Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Thu, 8 Apr 2021 13:58:01 +0200 Subject: [PATCH 006/104] Fix colorlog removing colors and refactor color code (#1671) --- esphome/__main__.py | 57 +++++------------------------- esphome/api/client.py | 5 +-- esphome/config.py | 31 +++++++++------- esphome/helpers.py | 11 ------ esphome/log.py | 82 +++++++++++++++++++++++++++++++++++++++++++ esphome/mqtt.py | 4 +-- esphome/wizard.py | 69 +++++++++++++++++++----------------- requirements.txt | 1 - 8 files changed, 151 insertions(+), 109 deletions(-) create mode 100644 esphome/log.py diff --git a/esphome/__main__.py b/esphome/__main__.py index 20cb44d11c..79a8c708a4 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -19,7 +19,7 @@ from esphome.const import ( CONF_PLATFORMIO_OPTIONS, ) from esphome.core import CORE, EsphomeError, coroutine, coroutine_with_priority -from esphome.helpers import color, indent +from esphome.helpers import indent from esphome.util import ( run_external_command, run_external_process, @@ -27,6 +27,7 @@ from esphome.util import ( list_yaml_files, get_serial_ports, ) +from esphome.log import color, setup_log, Fore _LOGGER = logging.getLogger(__name__) @@ -57,7 +58,7 @@ def choose_prompt(options): raise ValueError break except ValueError: - safe_print(color("red", f"Invalid option: '{opt}'")) + safe_print(color(Fore.RED, f"Invalid option: '{opt}'")) return options[opt - 1][1] @@ -263,46 +264,6 @@ def clean_mqtt(config, args): ) -def setup_log(debug=False, quiet=False): - if debug: - log_level = logging.DEBUG - CORE.verbose = True - elif quiet: - log_level = logging.CRITICAL - else: - log_level = logging.INFO - logging.basicConfig(level=log_level) - fmt = "%(levelname)s %(message)s" - colorfmt = f"%(log_color)s{fmt}%(reset)s" - datefmt = "%H:%M:%S" - - logging.getLogger("urllib3").setLevel(logging.WARNING) - - try: - import colorama - - colorama.init(strip=True) - - from colorlog import ColoredFormatter - - logging.getLogger().handlers[0].setFormatter( - ColoredFormatter( - colorfmt, - datefmt=datefmt, - reset=True, - log_colors={ - "DEBUG": "cyan", - "INFO": "green", - "WARNING": "yellow", - "ERROR": "red", - "CRITICAL": "red", - }, - ) - ) - except ImportError: - pass - - def command_wizard(args): from esphome import wizard @@ -442,30 +403,30 @@ def command_update_all(args): click.echo(f"{half_line}{middle_text}{half_line}") for f in files: - print("Updating {}".format(color("cyan", f))) + print("Updating {}".format(color(Fore.CYAN, f))) print("-" * twidth) print() rc = run_external_process( "esphome", "--dashboard", f, "run", "--no-logs", "--upload-port", "OTA" ) if rc == 0: - print_bar("[{}] {}".format(color("bold_green", "SUCCESS"), f)) + print_bar("[{}] {}".format(color(Fore.BOLD_GREEN, "SUCCESS"), f)) success[f] = True else: - print_bar("[{}] {}".format(color("bold_red", "ERROR"), f)) + print_bar("[{}] {}".format(color(Fore.BOLD_RED, "ERROR"), f)) success[f] = False print() print() print() - print_bar("[{}]".format(color("bold_white", "SUMMARY"))) + print_bar("[{}]".format(color(Fore.BOLD_WHITE, "SUMMARY"))) failed = 0 for f in files: if success[f]: - print(" - {}: {}".format(f, color("green", "SUCCESS"))) + print(" - {}: {}".format(f, color(Fore.GREEN, "SUCCESS"))) else: - print(" - {}: {}".format(f, color("bold_red", "FAILED"))) + print(" - {}: {}".format(f, color(Fore.BOLD_RED, "FAILED"))) failed += 1 return failed diff --git a/esphome/api/client.py b/esphome/api/client.py index 84c9890fe0..dd11f79922 100644 --- a/esphome/api/client.py +++ b/esphome/api/client.py @@ -13,7 +13,8 @@ from esphome import const import esphome.api.api_pb2 as pb from esphome.const import CONF_PASSWORD, CONF_PORT from esphome.core import EsphomeError -from esphome.helpers import resolve_ip_address, indent, color +from esphome.helpers import resolve_ip_address, indent +from esphome.log import color, Fore from esphome.util import safe_print _LOGGER = logging.getLogger(__name__) @@ -488,7 +489,7 @@ def run_logs(config, address): text = msg.message if msg.send_failed: text = color( - "white", + Fore.WHITE, "(Message skipped because it was too big to fit in " "TCP buffer - This is only cosmetic)", ) diff --git a/esphome/config.py b/esphome/config.py index 3317196965..0c8e51fdce 100644 --- a/esphome/config.py +++ b/esphome/config.py @@ -19,13 +19,14 @@ from esphome.const import ( CONF_SUBSTITUTIONS, ) from esphome.core import CORE, EsphomeError # noqa -from esphome.helpers import color, indent +from esphome.helpers import indent from esphome.util import safe_print, OrderedDict from typing import List, Optional, Tuple, Union # noqa from esphome.core import ConfigType # noqa from esphome.yaml_util import is_secret, ESPHomeDataBase, ESPForceValue from esphome.voluptuous_schema import ExtraKeysInvalid +from esphome.log import color, Fore _LOGGER = logging.getLogger(__name__) @@ -790,7 +791,7 @@ def line_info(config, path, highlight=True): if obj: mark = obj.start_mark source = "[source {}:{}]".format(mark.document, mark.line + 1) - return color("cyan", source) + return color(Fore.CYAN, source) return "None" @@ -813,7 +814,9 @@ def dump_dict(config, path, at_root=True): if at_root: error = config.get_error_for_path(path) if error is not None: - ret += "\n" + color("bold_red", _format_vol_invalid(error, config)) + "\n" + ret += ( + "\n" + color(Fore.BOLD_RED, _format_vol_invalid(error, config)) + "\n" + ) if isinstance(conf, (list, tuple)): multiline = True @@ -826,12 +829,14 @@ def dump_dict(config, path, at_root=True): error = config.get_error_for_path(path_) if error is not None: ret += ( - "\n" + color("bold_red", _format_vol_invalid(error, config)) + "\n" + "\n" + + color(Fore.BOLD_RED, _format_vol_invalid(error, config)) + + "\n" ) sep = "- " if config.is_in_error_path(path_): - sep = color("red", sep) + sep = color(Fore.RED, sep) msg, _ = dump_dict(config, path_, at_root=False) msg = indent(msg) inf = line_info(config, path_, highlight=config.is_in_error_path(path_)) @@ -851,12 +856,14 @@ def dump_dict(config, path, at_root=True): error = config.get_error_for_path(path_) if error is not None: ret += ( - "\n" + color("bold_red", _format_vol_invalid(error, config)) + "\n" + "\n" + + color(Fore.BOLD_RED, _format_vol_invalid(error, config)) + + "\n" ) st = f"{k}: " if config.is_in_error_path(path_): - st = color("red", st) + st = color(Fore.RED, st) msg, m = dump_dict(config, path_, at_root=False) inf = line_info(config, path_, highlight=config.is_in_error_path(path_)) @@ -878,7 +885,7 @@ def dump_dict(config, path, at_root=True): if len(conf) > 80: conf = "|-\n" + indent(conf) error = config.get_error_for_path(path) - col = "bold_red" if error else "white" + col = Fore.BOLD_RED if error else Fore.KEEP ret += color(col, str(conf)) elif isinstance(conf, core.Lambda): if is_secret(conf): @@ -886,13 +893,13 @@ def dump_dict(config, path, at_root=True): conf = "!lambda |-\n" + indent(str(conf.value)) error = config.get_error_for_path(path) - col = "bold_red" if error else "white" + col = Fore.BOLD_RED if error else Fore.KEEP ret += color(col, conf) elif conf is None: pass else: error = config.get_error_for_path(path) - col = "bold_red" if error else "white" + col = Fore.BOLD_RED if error else Fore.KEEP ret += color(col, str(conf)) multiline = "\n" in ret @@ -934,13 +941,13 @@ def read_config(command_line_substitutions): if not CORE.verbose: res = strip_default_ids(res) - safe_print(color("bold_red", "Failed config")) + safe_print(color(Fore.BOLD_RED, "Failed config")) safe_print("") for path, domain in res.output_paths: if not res.is_in_error_path(path): continue - errstr = color("bold_red", f"{domain}:") + errstr = color(Fore.BOLD_RED, f"{domain}:") errline = line_info(res, path) if errline: errstr += " " + errline diff --git a/esphome/helpers.py b/esphome/helpers.py index 780a2aa88e..b80d338eef 100644 --- a/esphome/helpers.py +++ b/esphome/helpers.py @@ -57,17 +57,6 @@ def cpp_string_escape(string, encoding="utf-8"): return '"' + result + '"' -def color(the_color, message=""): - from colorlog.escape_codes import escape_codes, parse_colors - - if not message: - res = parse_colors(the_color) - else: - res = parse_colors(the_color) + message + escape_codes["reset"] - - return res - - def run_system_command(*args): import subprocess diff --git a/esphome/log.py b/esphome/log.py new file mode 100644 index 0000000000..fa79efa833 --- /dev/null +++ b/esphome/log.py @@ -0,0 +1,82 @@ +import logging + +from esphome.core import CORE + + +class AnsiFore: + KEEP = "" + BLACK = "\033[30m" + RED = "\033[31m" + GREEN = "\033[32m" + YELLOW = "\033[33m" + BLUE = "\033[34m" + MAGENTA = "\033[35m" + CYAN = "\033[36m" + WHITE = "\033[37m" + RESET = "\033[39m" + + BOLD_BLACK = "\033[1;30m" + BOLD_RED = "\033[1;31m" + BOLD_GREEN = "\033[1;32m" + BOLD_YELLOW = "\033[1;33m" + BOLD_BLUE = "\033[1;34m" + BOLD_MAGENTA = "\033[1;35m" + BOLD_CYAN = "\033[1;36m" + BOLD_WHITE = "\033[1;37m" + BOLD_RESET = "\033[1;39m" + + +class AnsiStyle: + BRIGHT = "\033[1m" + BOLD = "\033[1m" + DIM = "\033[2m" + THIN = "\033[2m" + NORMAL = "\033[22m" + RESET_ALL = "\033[0m" + + +Fore = AnsiFore() +Style = AnsiStyle() + + +def color(col: str, msg: str, reset: bool = True) -> bool: + if col and not col.startswith("\033["): + raise ValueError("Color must be value from esphome.log.Fore") + s = str(col) + msg + if reset and col: + s += str(Style.RESET_ALL) + return s + + +class ESPHomeLogFormatter(logging.Formatter): + def __init__(self): + super().__init__(fmt="%(levelname)s %(message)s", datefmt="%H:%M:%S", style="%") + + def format(self, record): + formatted = super().format(record) + prefix = { + "DEBUG": Fore.CYAN, + "INFO": Fore.GREEN, + "WARNING": Fore.YELLOW, + "ERROR": Fore.RED, + "CRITICAL": Fore.RED, + }.get(record.levelname, "") + return f"{prefix}{formatted}{Style.RESET_ALL}" + + +def setup_log(debug=False, quiet=False): + import colorama + + if debug: + log_level = logging.DEBUG + CORE.verbose = True + elif quiet: + log_level = logging.CRITICAL + else: + log_level = logging.INFO + logging.basicConfig(level=log_level) + + logging.getLogger("urllib3").setLevel(logging.WARNING) + + colorama.init() + logging.getLogger().handlers[0].setFormatter(ESPHomeLogFormatter()) diff --git a/esphome/mqtt.py b/esphome/mqtt.py index 86937ba37e..9be87b5c5d 100644 --- a/esphome/mqtt.py +++ b/esphome/mqtt.py @@ -22,7 +22,7 @@ from esphome.const import ( CONF_USERNAME, ) from esphome.core import CORE, EsphomeError -from esphome.helpers import color +from esphome.log import color, Fore from esphome.util import safe_print _LOGGER = logging.getLogger(__name__) @@ -158,7 +158,7 @@ def get_fingerprint(config): sha1 = hashlib.sha1(cert_der).hexdigest() - safe_print("SHA1 Fingerprint: " + color("cyan", sha1)) + safe_print("SHA1 Fingerprint: " + color(Fore.CYAN, sha1)) safe_print( "Copy the string above into mqtt.ssl_fingerprints section of {}" "".format(CORE.config_path) diff --git a/esphome/wizard.py b/esphome/wizard.py index 620ceb9b59..4ad5c63216 100644 --- a/esphome/wizard.py +++ b/esphome/wizard.py @@ -6,7 +6,8 @@ import unicodedata import voluptuous as vol import esphome.config_validation as cv -from esphome.helpers import color, get_bool_env, write_file +from esphome.helpers import get_bool_env, write_file +from esphome.log import color, Fore # pylint: disable=anomalous-backslash-in-string from esphome.pins import ESP32_BOARD_PINS, ESP8266_BOARD_PINS @@ -148,13 +149,13 @@ def wizard(path): if not path.endswith(".yaml") and not path.endswith(".yml"): safe_print( "Please make your configuration file {} have the extension .yaml or .yml" - "".format(color("cyan", path)) + "".format(color(Fore.CYAN, path)) ) return 1 if os.path.exists(path): safe_print( "Uh oh, it seems like {} already exists, please delete that file first " - "or chose another configuration file.".format(color("cyan", path)) + "or chose another configuration file.".format(color(Fore.CYAN, path)) ) return 2 safe_print("Hi there!") @@ -171,7 +172,7 @@ def wizard(path): safe_print() safe_print_step(1, CORE_BIG) safe_print( - "First up, please choose a " + color("green", "name") + " for your node." + "First up, please choose a " + color(Fore.GREEN, "name") + " for your node." ) safe_print( "It should be a unique name that can be used to identify the device later." @@ -179,12 +180,12 @@ def wizard(path): sleep(1) safe_print( "For example, I like calling the node in my living room {}.".format( - color("bold_white", "livingroom") + color(Fore.BOLD_WHITE, "livingroom") ) ) safe_print() sleep(1) - name = input(color("bold_white", "(name): ")) + name = input(color(Fore.BOLD_WHITE, "(name): ")) while True: try: @@ -193,7 +194,7 @@ def wizard(path): except vol.Invalid: safe_print( color( - "red", + Fore.RED, f'Oh noes, "{name}" isn\'t a valid name. Names can only ' f"include numbers, lower-case letters, underscores and " f"hyphens.", @@ -202,12 +203,12 @@ def wizard(path): name = strip_accents(name).lower().replace(" ", "_") name = "".join(c for c in name if c in ALLOWED_NAME_CHARS) safe_print( - 'Shall I use "{}" as the name instead?'.format(color("cyan", name)) + 'Shall I use "{}" as the name instead?'.format(color(Fore.CYAN, name)) ) sleep(0.5) name = default_input("(name [{}]): ", name) - safe_print('Great! Your node is now called "{}".'.format(color("cyan", name))) + safe_print('Great! Your node is now called "{}".'.format(color(Fore.CYAN, name))) sleep(1) safe_print_step(2, ESP_BIG) safe_print( @@ -216,16 +217,16 @@ def wizard(path): ) safe_print( "Are you using an " - + color("green", "ESP32") + + color(Fore.GREEN, "ESP32") + " or " - + color("green", "ESP8266") + + color(Fore.GREEN, "ESP8266") + " platform? (Choose ESP8266 for Sonoff devices)" ) while True: sleep(0.5) safe_print() safe_print("Please enter either ESP32 or ESP8266.") - platform = input(color("bold_white", "(ESP32/ESP8266): ")) + platform = input(color(Fore.BOLD_WHITE, "(ESP32/ESP8266): ")) try: platform = vol.All(vol.Upper, vol.Any("ESP32", "ESP8266"))(platform) break @@ -235,7 +236,7 @@ def wizard(path): '"{}". Please try again.'.format(platform) ) safe_print( - "Thanks! You've chosen {} as your platform.".format(color("cyan", platform)) + "Thanks! You've chosen {} as your platform.".format(color(Fore.CYAN, platform)) ) safe_print() sleep(1) @@ -250,37 +251,39 @@ def wizard(path): ) safe_print( - "Next, I need to know what " + color("green", "board") + " you're using." + "Next, I need to know what " + color(Fore.GREEN, "board") + " you're using." ) sleep(0.5) - safe_print("Please go to {} and choose a board.".format(color("green", board_link))) + safe_print( + "Please go to {} and choose a board.".format(color(Fore.GREEN, board_link)) + ) if platform == "ESP32": - safe_print("(Type " + color("green", "esp01_1m") + " for Sonoff devices)") + safe_print("(Type " + color(Fore.GREEN, "esp01_1m") + " for Sonoff devices)") safe_print() # Don't sleep because user needs to copy link if platform == "ESP32": - safe_print('For example "{}".'.format(color("bold_white", "nodemcu-32s"))) + safe_print('For example "{}".'.format(color(Fore.BOLD_WHITE, "nodemcu-32s"))) boards = list(ESP32_BOARD_PINS.keys()) else: - safe_print('For example "{}".'.format(color("bold_white", "nodemcuv2"))) + safe_print('For example "{}".'.format(color(Fore.BOLD_WHITE, "nodemcuv2"))) boards = list(ESP8266_BOARD_PINS.keys()) safe_print("Options: {}".format(", ".join(sorted(boards)))) while True: - board = input(color("bold_white", "(board): ")) + board = input(color(Fore.BOLD_WHITE, "(board): ")) try: board = vol.All(vol.Lower, vol.Any(*boards))(board) break except vol.Invalid: safe_print( - color("red", f'Sorry, I don\'t think the board "{board}" exists.') + color(Fore.RED, f'Sorry, I don\'t think the board "{board}" exists.') ) safe_print() sleep(0.25) safe_print() safe_print( - "Way to go! You've chosen {} as your board.".format(color("cyan", board)) + "Way to go! You've chosen {} as your board.".format(color(Fore.CYAN, board)) ) safe_print() sleep(1) @@ -291,20 +294,20 @@ def wizard(path): sleep(1) safe_print( "First, what's the " - + color("green", "SSID") + + color(Fore.GREEN, "SSID") + f" (the name) of the WiFi network {name} I should connect to?" ) sleep(1.5) - safe_print('For example "{}".'.format(color("bold_white", "Abraham Linksys"))) + safe_print('For example "{}".'.format(color(Fore.BOLD_WHITE, "Abraham Linksys"))) while True: - ssid = input(color("bold_white", "(ssid): ")) + ssid = input(color(Fore.BOLD_WHITE, "(ssid): ")) try: ssid = cv.ssid(ssid) break except vol.Invalid: safe_print( color( - "red", + Fore.RED, 'Unfortunately, "{}" doesn\'t seem to be a valid SSID. ' "Please try again.".format(ssid), ) @@ -314,20 +317,20 @@ def wizard(path): safe_print( 'Thank you very much! You\'ve just chosen "{}" as your SSID.' - "".format(color("cyan", ssid)) + "".format(color(Fore.CYAN, ssid)) ) safe_print() sleep(0.75) safe_print( "Now please state the " - + color("green", "password") + + color(Fore.GREEN, "password") + " of the WiFi network so that I can connect to it (Leave empty for no password)" ) safe_print() - safe_print('For example "{}"'.format(color("bold_white", "PASSWORD42"))) + safe_print('For example "{}"'.format(color(Fore.BOLD_WHITE, "PASSWORD42"))) sleep(0.5) - psk = input(color("bold_white", "(PSK): ")) + psk = input(color(Fore.BOLD_WHITE, "(PSK): ")) safe_print( "Perfect! WiFi is now set up (you can create static IPs and so on later)." ) @@ -340,12 +343,12 @@ def wizard(path): ) safe_print( "This can be insecure if you do not trust the WiFi network. Do you want to set " - "a " + color("green", "password") + " for connecting to this ESP?" + "a " + color(Fore.GREEN, "password") + " for connecting to this ESP?" ) safe_print() sleep(0.25) safe_print("Press ENTER for no password") - password = input(color("bold_white", "(password): ")) + password = input(color(Fore.BOLD_WHITE, "(password): ")) wizard_write( path=path, @@ -359,8 +362,8 @@ def wizard(path): safe_print() safe_print( - color("cyan", "DONE! I've now written a new configuration file to ") - + color("bold_cyan", path) + color(Fore.CYAN, "DONE! I've now written a new configuration file to ") + + color(Fore.BOLD_CYAN, path) ) safe_print() safe_print("Next steps:") diff --git a/requirements.txt b/requirements.txt index 9ab99e0bb4..9cb8a91f5f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,6 @@ voluptuous==0.12.1 PyYAML==5.4.1 paho-mqtt==1.5.1 colorama==0.4.4 -colorlog==4.7.2 tornado==6.1 protobuf==3.15.6 tzlocal==2.1 From b680649113c3e6cb20672cbd4ef35a26e53cdd54 Mon Sep 17 00:00:00 2001 From: Guillermo Ruffino Date: Thu, 8 Apr 2021 09:22:30 -0300 Subject: [PATCH 007/104] Fix servo detach chopped PWM (#1650) --- esphome/components/esp8266_pwm/esp8266_pwm.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/esphome/components/esp8266_pwm/esp8266_pwm.cpp b/esphome/components/esp8266_pwm/esp8266_pwm.cpp index 96290871e0..b3fd2398f3 100644 --- a/esphome/components/esp8266_pwm/esp8266_pwm.cpp +++ b/esphome/components/esp8266_pwm/esp8266_pwm.cpp @@ -37,6 +37,11 @@ void HOT ESP8266PWM::write_state(float state) { uint32_t duty_off = total_time_us - duty_on; if (duty_on == 0) { + // This is a hacky fix for servos: Servo PWM high time is maximum 2.4ms by default + // The frequency check is to affect this fix for servos mostly as the frequency is usually 50-300 hz + if (this->pin_->digital_read() && 50 <= this->frequency_ && this->frequency_ <= 300) { + delay(3); + } stopWaveform(this->pin_->get_pin()); this->pin_->digital_write(this->pin_->is_inverted()); } else if (duty_off == 0) { From 06f566346daefd0eeecbe68019a5af1ffdb533f8 Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Thu, 8 Apr 2021 14:37:55 +0200 Subject: [PATCH 008/104] Fix sensor.sensor_schema interface changed (#1659) --- esphome/components/sensor/__init__.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py index a10c5d7326..c5df0ca97c 100644 --- a/esphome/components/sensor/__init__.py +++ b/esphome/components/sensor/__init__.py @@ -1,4 +1,5 @@ import math +from typing import Optional import esphome.codegen as cg import esphome.config_validation as cv @@ -180,8 +181,12 @@ SENSOR_SCHEMA = cv.MQTT_COMPONENT_SCHEMA.extend( ) -def sensor_schema(unit_of_measurement_, icon_, accuracy_decimals_, device_class_): - # type: (str, str, int, str) -> cv.Schema +def sensor_schema( + unit_of_measurement_: str, + icon_: str, + accuracy_decimals_: int, + device_class_: Optional[str] = DEVICE_CLASS_EMPTY, +) -> cv.Schema: schema = SENSOR_SCHEMA if unit_of_measurement_ != UNIT_EMPTY: schema = schema.extend( From 6ec0f80b765f721ec064a0b1403b01cc4414876f Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Fri, 9 Apr 2021 10:27:18 +0200 Subject: [PATCH 009/104] Sensor Average Filter Fix Floating Pointer Error Accumulating (#1624) --- esphome/components/sensor/filter.cpp | 18 +++++++++++++----- esphome/components/sensor/filter.h | 2 +- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/esphome/components/sensor/filter.cpp b/esphome/components/sensor/filter.cpp index 6dfb11b9c9..57ffe9b482 100644 --- a/esphome/components/sensor/filter.cpp +++ b/esphome/components/sensor/filter.cpp @@ -148,10 +148,10 @@ void SlidingWindowMovingAverageFilter::set_window_size(size_t window_size) { thi optional SlidingWindowMovingAverageFilter::new_value(float value) { if (!isnan(value)) { if (this->queue_.size() == this->window_size_) { - this->sum_ -= this->queue_.front(); - this->queue_.pop(); + this->sum_ -= this->queue_[0]; + this->queue_.pop_front(); } - this->queue_.push(value); + this->queue_.push_back(value); this->sum_ += value; } float average; @@ -161,8 +161,16 @@ optional SlidingWindowMovingAverageFilter::new_value(float value) { average = this->sum_ / this->queue_.size(); ESP_LOGVV(TAG, "SlidingWindowMovingAverageFilter(%p)::new_value(%f) -> %f", this, value, average); - if (++this->send_at_ >= this->send_every_) { - this->send_at_ = 0; + if (++this->send_at_ % this->send_every_ == 0) { + if (this->send_at_ >= 10000) { + // Recalculate to prevent floating point error accumulating + this->sum_ = 0; + for (auto v : this->queue_) + this->sum_ += v; + average = this->sum_ / this->queue_.size(); + this->send_at_ = 0; + } + ESP_LOGVV(TAG, "SlidingWindowMovingAverageFilter(%p)::new_value(%f) SENDING", this, value); return average; } diff --git a/esphome/components/sensor/filter.h b/esphome/components/sensor/filter.h index 651d2a8986..5b06d002fa 100644 --- a/esphome/components/sensor/filter.h +++ b/esphome/components/sensor/filter.h @@ -162,7 +162,7 @@ class SlidingWindowMovingAverageFilter : public Filter { protected: float sum_{0.0}; - std::queue queue_; + std::deque queue_; size_t send_every_; size_t send_at_; size_t window_size_; From d83d214497d42142fcf11cf42417d346dc45a967 Mon Sep 17 00:00:00 2001 From: Richard Klingler Date: Wed, 21 Apr 2021 12:10:45 +0200 Subject: [PATCH 010/104] Added / to default glyphs (#1691) Co-authored-by: Charlie Root --- esphome/components/font/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/font/__init__.py b/esphome/components/font/__init__.py index e79d311dab..c414d37c40 100644 --- a/esphome/components/font/__init__.py +++ b/esphome/components/font/__init__.py @@ -72,7 +72,7 @@ def validate_truetype_file(value): DEFAULT_GLYPHS = ( - ' !"%()+,-.:0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz°' + ' !"%()+,-.:/0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz°' ) CONF_RAW_DATA_ID = "raw_data_id" From be70a96651e3a67da300c74e687cc7d34e0be496 Mon Sep 17 00:00:00 2001 From: Guillermo Ruffino Date: Wed, 28 Apr 2021 19:50:24 -0300 Subject: [PATCH 011/104] RC522 fixes (#1479) --- esphome/components/rc522/rc522.cpp | 792 +++++++-------------- esphome/components/rc522/rc522.h | 109 ++- esphome/components/rc522_i2c/rc522_i2c.cpp | 30 - esphome/components/rc522_spi/rc522_spi.cpp | 19 +- 4 files changed, 330 insertions(+), 620 deletions(-) diff --git a/esphome/components/rc522/rc522.cpp b/esphome/components/rc522/rc522.cpp index 8182c1e8c9..ced58760ad 100644 --- a/esphome/components/rc522/rc522.cpp +++ b/esphome/components/rc522/rc522.cpp @@ -7,22 +7,38 @@ namespace esphome { namespace rc522 { +static const uint8_t WAIT_I_RQ = 0x30; // RxIRq and IdleIRq + static const char *TAG = "rc522"; static const uint8_t RESET_COUNT = 5; -void format_uid(char *buf, const uint8_t *uid, uint8_t uid_length) { +std::string format_buffer(uint8_t *b, uint8_t len) { + char buf[32]; int offset = 0; - for (uint8_t i = 0; i < uid_length; i++) { + for (uint8_t i = 0; i < len; i++) { const char *format = "%02X"; - if (i + 1 < uid_length) + if (i + 1 < len) + format = "%02X-"; + offset += sprintf(buf + offset, format, b[i]); + } + return std::string(buf); +} + +std::string format_uid(std::vector &uid) { + char buf[32]; + int offset = 0; + for (uint8_t i = 0; i < uid.size(); i++) { + const char *format = "%02X"; + if (i + 1 < uid.size()) format = "%02X-"; offset += sprintf(buf + offset, format, uid[i]); } + return std::string(buf); } void RC522::setup() { - initialize_pending_ = true; + state_ = STATE_SETUP; // Pull device out of power down / reset state. // First set the resetPowerDownPin as digital input, to check the MFRC522 power down mode. @@ -48,7 +64,7 @@ void RC522::setup() { } void RC522::initialize_() { - // Per originall code, wait 50 ms + // Per original code, wait 50 ms if (millis() - reset_timeout_ < 50) return; @@ -75,9 +91,8 @@ void RC522::initialize_() { pcd_write_register(TX_ASK_REG, 0x40); pcd_write_register(MODE_REG, 0x3D); // Default 0x3F. Set the preset value for the CRC coprocessor for the CalcCRC // command to 0x6363 (ISO 14443-3 part 6.2.4) - pcd_antenna_on_(); // Enable the antenna driver pins TX1 and TX2 (they were disabled by the reset) - initialize_pending_ = false; + state_ = STATE_INIT; } void RC522::dump_config() { @@ -99,76 +114,163 @@ void RC522::dump_config() { } } +void RC522::update() { + if (state_ == STATE_INIT) { + pcd_antenna_on_(); + pcd_clear_register_bit_mask_(COLL_REG, 0x80); // ValuesAfterColl=1 => Bits received after collision are cleared. + buffer_[0] = PICC_CMD_REQA; + pcd_transceive_data_(1); + state_ = STATE_PICC_REQUEST_A; + } else { + ESP_LOGW(TAG, "Communication takes longer than update interval: %d", state_); + } +} + void RC522::loop() { // First check reset is needed if (reset_count_ > 0) { pcd_reset_(); return; } - if (initialize_pending_) { + if (state_ == STATE_SETUP) { initialize_(); return; } - if (millis() - update_wait_ < this->update_interval_) - return; + StatusCode status = STATUS_ERROR; // For lint passing. TODO: refactor this + if (awaiting_comm_) { + if (state_ == STATE_SELECT_SERIAL_DONE) + status = await_crc_(); + else + status = await_transceive_(); - auto status = picc_is_new_card_present_(); - - static StatusCode LAST_STATUS = StatusCode::STATUS_OK; - - if (status != LAST_STATUS) { - ESP_LOGD(TAG, "Status is now: %d", status); - LAST_STATUS = status; - } - - if (status == STATUS_ERROR) // No card - { - // ESP_LOGE(TAG, "Error"); - // mark_failed(); - return; - } - - if (status != STATUS_OK) // We can receive STATUS_TIMEOUT when no card, or unexpected status. - return; - - // Try process card - if (!picc_read_card_serial_()) { - ESP_LOGW(TAG, "Requesting tag read failed!"); - return; - }; - - if (uid_.size < 4) { - return; - ESP_LOGW(TAG, "Read serial size: %d", uid_.size); - } - - update_wait_ = millis(); - - bool report = true; - // 1. Go through all triggers - for (auto *trigger : this->triggers_) - trigger->process(uid_.uiduint8_t, uid_.size); - - // 2. Find a binary sensor - for (auto *tag : this->binary_sensors_) { - if (tag->process(uid_.uiduint8_t, uid_.size)) { - // 2.1 if found, do not dump - report = false; + if (status == STATUS_WAITING) { + return; } + awaiting_comm_ = false; + ESP_LOGV(TAG, "finished communication status: %d, state: %d", status, state_); } - if (report) { - char buf[32]; - format_uid(buf, uid_.uiduint8_t, uid_.size); - ESP_LOGD(TAG, "Found new tag '%s'", buf); - } -} + switch (state_) { + case STATE_PICC_REQUEST_A: { + if (status == STATUS_TIMEOUT) { // no tag present + for (auto *obj : this->binary_sensors_) + obj->on_scan_end(); // reset the binary sensors + ESP_LOGV(TAG, "CMD_REQA -> TIMEOUT (no tag present) %d", status); + state_ = STATE_DONE; + } else if (status != STATUS_OK) { + ESP_LOGW(TAG, "CMD_REQA -> Not OK %d", status); + state_ = STATE_DONE; + } else if (back_length_ != 2) { // || *valid_bits_ != 0) { // ATQA must be exactly 16 bits. + ESP_LOGW(TAG, "CMD_REQA -> OK, but unexpacted back_length_ of %d", back_length_); + state_ = STATE_DONE; + } else { + state_ = STATE_READ_SERIAL; + } + if (state_ == STATE_DONE) { + // Don't wait another loop cycle + pcd_antenna_off_(); + } + break; + } + case STATE_READ_SERIAL: { + ESP_LOGV(TAG, "STATE_READ_SERIAL (%d)", status); + switch (uid_idx_) { + case 0: + buffer_[0] = PICC_CMD_SEL_CL1; + break; + case 3: + buffer_[0] = PICC_CMD_SEL_CL2; + break; + case 6: + buffer_[0] = PICC_CMD_SEL_CL3; + break; + default: + ESP_LOGE(TAG, "uid_idx_ invalid, uid_idx_ = %d", uid_idx_); + state_ = STATE_DONE; + } + buffer_[1] = 32; + pcd_transceive_data_(2); + state_ = STATE_SELECT_SERIAL; + break; + } + case STATE_SELECT_SERIAL: { + buffer_[1] = 0x70; // select + // todo: set CRC + buffer_[6] = buffer_[2] ^ buffer_[3] ^ buffer_[4] ^ buffer_[5]; + pcd_calculate_crc_(buffer_, 7); + state_ = STATE_SELECT_SERIAL_DONE; + break; + } + case STATE_SELECT_SERIAL_DONE: { + send_len_ = 6; + pcd_transceive_data_(9); + state_ = STATE_READ_SERIAL_DONE; + break; + } + case STATE_READ_SERIAL_DONE: { + if (status != STATUS_OK || back_length_ != 3) { + if (status == STATUS_TIMEOUT) + ESP_LOGV(TAG, "STATE_READ_SERIAL_DONE -> TIMEOUT (no tag present) %d", status); + else + ESP_LOGW(TAG, "Unexpected response. Read status is %d. Read bytes: %d (%s)", status, back_length_, + format_buffer(buffer_, 9).c_str()); -void RC522::update() { - for (auto *obj : this->binary_sensors_) - obj->on_scan_end(); -} + state_ = STATE_DONE; + uid_idx_ = 0; + + pcd_antenna_off_(); + return; + } + + // copy the uid + bool cascade = buffer_[2] == PICC_CMD_CT; // todo: should be determined based on select response (buffer[6]) + for (uint8_t i = 2 + cascade; i < 6; i++) + uid_buffer_[uid_idx_++] = buffer_[i]; + ESP_LOGVV(TAG, "copied uid to idx %d last byte is 0x%x, cascade is %d", uid_idx_, uid_buffer_[uid_idx_ - 1], + cascade); + + if (cascade) { // there is more bytes in the UID + state_ = STATE_READ_SERIAL; + return; + } + + std::vector rfid_uid(std::begin(uid_buffer_), std::begin(uid_buffer_) + uid_idx_); + uid_idx_ = 0; + // ESP_LOGD(TAG, "Processing '%s'", format_uid(rfid_uid).c_str()); + pcd_antenna_off_(); + state_ = STATE_INIT; // scan again on next update + bool report = true; + + for (auto *tag : this->binary_sensors_) { + if (tag->process(rfid_uid)) { + report = false; + } + } + + if (this->current_uid_ == rfid_uid) { + return; + } + + this->current_uid_ = rfid_uid; + + for (auto *trigger : this->triggers_) + trigger->process(rfid_uid); + + if (report) { + ESP_LOGD(TAG, "Found new tag '%s'", format_uid(rfid_uid).c_str()); + } + break; + } + case STATE_DONE: { + this->current_uid_ = {}; + state_ = STATE_INIT; + break; + } + default: + break; + } +} // namespace rc522 /** * Performs a soft reset on the MFRC522 chip and waits for it to be ready again. @@ -176,14 +278,14 @@ void RC522::update() { void RC522::pcd_reset_() { // The datasheet does not mention how long the SoftRest command takes to complete. // But the MFRC522 might have been in soft power-down mode (triggered by bit 4 of CommandReg) - // Section 8.8.2 in the datasheet says the oscillator start-up time is the start up time of the crystal + 37,74μs. Let - // us be generous: 50ms. + // Section 8.8.2 in the datasheet says the oscillator start-up time is the start up time of the crystal + 37,74μs. + // Let us be generous: 50ms. if (millis() - reset_timeout_ < 50) return; if (reset_count_ == RESET_COUNT) { - ESP_LOGV(TAG, "Soft reset..."); + ESP_LOGI(TAG, "Soft reset..."); // Issue the SoftReset command. pcd_write_register(COMMAND_REG, PCD_SOFT_RESET); } @@ -199,6 +301,7 @@ void RC522::pcd_reset_() { if (--reset_count_ == 0) { ESP_LOGE(TAG, "Unable to reset RC522."); + this->error_code_ = RESET_FAILED; mark_failed(); } } @@ -215,49 +318,13 @@ void RC522::pcd_antenna_on_() { } /** - * Transmits a REQuest command, Type A. Invites PICCs in state IDLE to go to READY and prepare for anticollision or - * selection. 7 bit frame. Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - - * probably due do bad antenna design. - * - * @return STATUS_OK on success, STATUS_??? otherwise. + * Turns the antenna off by disabling pins TX1 and TX2. */ -RC522::StatusCode RC522::picc_request_a_( - uint8_t *buffer_atqa, ///< The buffer to store the ATQA (Answer to request) in - uint8_t *buffer_size ///< Buffer size, at least two uint8_ts. Also number of uint8_ts returned if STATUS_OK. -) { - return picc_reqa_or_wupa_(PICC_CMD_REQA, buffer_atqa, buffer_size); -} - -/** - * Transmits REQA or WUPA commands. - * Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna - * design. - * - * @return STATUS_OK on success, STATUS_??? otherwise. - */ -RC522::StatusCode RC522::picc_reqa_or_wupa_( - uint8_t command, ///< The command to send - PICC_CMD_REQA or PICC_CMD_WUPA - uint8_t *buffer_atqa, ///< The buffer to store the ATQA (Answer to request) in - uint8_t *buffer_size ///< Buffer size, at least two uint8_ts. Also number of uint8_ts returned if STATUS_OK. -) { - uint8_t valid_bits; - RC522::StatusCode status; - - if (buffer_atqa == nullptr || *buffer_size < 2) { // The ATQA response is 2 uint8_ts long. - return STATUS_NO_ROOM; +void RC522::pcd_antenna_off_() { + uint8_t value = pcd_read_register(TX_CONTROL_REG); + if ((value & 0x03) != 0x00) { + pcd_write_register(TX_CONTROL_REG, value & ~0x03); } - pcd_clear_register_bit_mask_(COLL_REG, 0x80); // ValuesAfterColl=1 => Bits received after collision are cleared. - valid_bits = 7; // For REQA and WUPA we need the short frame format - transmit only 7 bits of the last (and only) - // uint8_t. TxLastBits = BitFramingReg[2..0] - status = pcd_transceive_data_(&command, 1, buffer_atqa, buffer_size, &valid_bits); - if (status != STATUS_OK) - return status; - if (*buffer_size != 2 || valid_bits != 0) { // ATQA must be exactly 16 bits. - ESP_LOGVV(TAG, "picc_reqa_or_wupa_() -> STATUS_ERROR"); - return STATUS_ERROR; - } - - return STATUS_OK; } /** @@ -280,140 +347,86 @@ void RC522::pcd_clear_register_bit_mask_(PcdRegister reg, ///< The register to pcd_write_register(reg, tmp & (~mask)); // clear bit mask } -/** - * Executes the Transceive command. - * CRC validation can only be done if backData and backLen are specified. - * - * @return STATUS_OK on success, STATUS_??? otherwise. - */ -RC522::StatusCode RC522::pcd_transceive_data_( - uint8_t *send_data, ///< Pointer to the data to transfer to the FIFO. - uint8_t send_len, ///< Number of uint8_ts to transfer to the FIFO. - uint8_t *back_data, ///< nullptr or pointer to buffer if data should be read back after executing the command. - uint8_t *back_len, ///< In: Max number of uint8_ts to write to *backData. Out: The number of uint8_ts returned. - uint8_t - *valid_bits, ///< In/Out: The number of valid bits in the last uint8_t. 0 for 8 valid bits. Default nullptr. - uint8_t rx_align, ///< In: Defines the bit position in backData[0] for the first bit received. Default 0. - bool check_crc ///< In: True => The last two uint8_ts of the response is assumed to be a CRC_A that must be - ///< validated. -) { - uint8_t wait_i_rq = 0x30; // RxIRq and IdleIRq - auto ret = pcd_communicate_with_picc_(PCD_TRANSCEIVE, wait_i_rq, send_data, send_len, back_data, back_len, valid_bits, - rx_align, check_crc); - - if (ret == STATUS_OK && *back_len == 5) - ESP_LOGVV(TAG, "pcd_transceive_data_(..., %d, ) -> %d [%x, %x, %x, %x, %x]", send_len, ret, back_data[0], - back_data[1], back_data[2], back_data[3], back_data[4]); - else - ESP_LOGVV(TAG, "pcd_transceive_data_(..., %d, ... ) -> %d", send_len, ret); - return ret; -} - /** * Transfers data to the MFRC522 FIFO, executes a command, waits for completion and transfers data back from the FIFO. * CRC validation can only be done if backData and backLen are specified. * * @return STATUS_OK on success, STATUS_??? otherwise. */ -RC522::StatusCode RC522::pcd_communicate_with_picc_( - uint8_t command, ///< The command to execute. One of the PCD_Command enums. - uint8_t wait_i_rq, ///< The bits in the ComIrqReg register that signals successful completion of the command. - uint8_t *send_data, ///< Pointer to the data to transfer to the FIFO. - uint8_t send_len, ///< Number of uint8_ts to transfer to the FIFO. - uint8_t *back_data, ///< nullptr or pointer to buffer if data should be read back after executing the command. - uint8_t *back_len, ///< In: Max number of uint8_ts to write to *backData. Out: The number of uint8_ts returned. - uint8_t *valid_bits, ///< In/Out: The number of valid bits in the last uint8_t. 0 for 8 valid bits. - uint8_t rx_align, ///< In: Defines the bit position in backData[0] for the first bit received. Default 0. - bool check_crc ///< In: True => The last two uint8_ts of the response is assumed to be a CRC_A that must be - ///< validated. -) { - ESP_LOGVV(TAG, "pcd_communicate_with_picc_(%d, %d,... %d)", command, wait_i_rq, check_crc); - +void RC522::pcd_transceive_data_(uint8_t send_len) { + ESP_LOGV(TAG, "PCD TRANSCEIVE: RX: %s", format_buffer(buffer_, send_len).c_str()); + delayMicroseconds(1000); // we need 1 ms delay between antenna on and those communication commands + send_len_ = send_len; // Prepare values for BitFramingReg - uint8_t tx_last_bits = valid_bits ? *valid_bits : 0; - uint8_t bit_framing = - (rx_align << 4) + tx_last_bits; // RxAlign = BitFramingReg[6..4]. TxLastBits = BitFramingReg[2..0] + // For REQA and WUPA we need the short frame format - transmit only 7 bits of the last (and only) + // uint8_t. TxLastBits = BitFramingReg[2..0] + uint8_t bit_framing = (buffer_[0] == PICC_CMD_REQA) ? 7 : 0; - pcd_write_register(COMMAND_REG, PCD_IDLE); // Stop any active command. - pcd_write_register(COM_IRQ_REG, 0x7F); // Clear all seven interrupt request bits - pcd_write_register(FIFO_LEVEL_REG, 0x80); // FlushBuffer = 1, FIFO initialization - pcd_write_register(FIFO_DATA_REG, send_len, send_data); // Write sendData to the FIFO - pcd_write_register(BIT_FRAMING_REG, bit_framing); // Bit adjustments - pcd_write_register(COMMAND_REG, command); // Execute the command - if (command == PCD_TRANSCEIVE) { - pcd_set_register_bit_mask_(BIT_FRAMING_REG, 0x80); // StartSend=1, transmission of data starts - } + pcd_write_register(COMMAND_REG, PCD_IDLE); // Stop any active command. + pcd_write_register(COM_IRQ_REG, 0x7F); // Clear all seven interrupt request bits + pcd_write_register(FIFO_LEVEL_REG, 0x80); // FlushBuffer = 1, FIFO initialization + pcd_write_register(FIFO_DATA_REG, send_len_, buffer_); // Write sendData to the FIFO + pcd_write_register(BIT_FRAMING_REG, bit_framing); // Bit adjustments + pcd_write_register(COMMAND_REG, PCD_TRANSCEIVE); // Execute the command + pcd_set_register_bit_mask_(BIT_FRAMING_REG, 0x80); // StartSend=1, transmission of data starts + awaiting_comm_ = true; + awaiting_comm_time_ = millis(); +} - // Wait for the command to complete. - // In PCD_Init() we set the TAuto flag in TModeReg. This means the timer automatically starts when the PCD stops - // transmitting. Each iteration of the do-while-loop takes 17.86μs. - // TODO check/modify for other architectures than Arduino Uno 16bit - uint16_t i; - for (i = 2000; i > 0; i--) { - uint8_t n = pcd_read_register( - COM_IRQ_REG); // ComIrqReg[7..0] bits are: Set1 TxIRq RxIRq IdleIRq HiAlertIRq LoAlertIRq ErrIRq TimerIRq - if (n & wait_i_rq) { // One of the interrupts that signal success has been set. - break; - } - if (n & 0x01) { // Timer interrupt - nothing received in 25ms - return STATUS_TIMEOUT; - } - } - // 35.7ms and nothing happend. Communication with the MFRC522 might be down. - if (i == 0) { +RC522::StatusCode RC522::await_transceive_() { + if (millis() - awaiting_comm_time_ < 2) // wait at least 2 ms + return STATUS_WAITING; + uint8_t n = pcd_read_register( + COM_IRQ_REG); // ComIrqReg[7..0] bits are: Set1 TxIRq RxIRq IdleIRq HiAlertIRq LoAlertIRq ErrIRq TimerIRq + if (n & 0x01) { // Timer interrupt - nothing received in 25ms + back_length_ = 0; + error_counter_ = 0; // reset the error counter return STATUS_TIMEOUT; } + if (!(n & WAIT_I_RQ)) { // None of the interrupts that signal success has been set. + // Wait for the command to complete. + if (millis() - awaiting_comm_time_ < 40) + return STATUS_WAITING; + back_length_ = 0; + ESP_LOGW(TAG, "Communication with the MFRC522 might be down, reset in %d", + 10 - error_counter_); // todo: trigger reset? + if (error_counter_++ > 10) + setup(); + return STATUS_TIMEOUT; + } // Stop now if any errors except collisions were detected. uint8_t error_reg_value = pcd_read_register( ERROR_REG); // ErrorReg[7..0] bits are: WrErr TempErr reserved BufferOvfl CollErr CRCErr ParityErr ProtocolErr if (error_reg_value & 0x13) { // BufferOvfl ParityErr ProtocolErr return STATUS_ERROR; } + error_counter_ = 0; // reset the error counter - uint8_t valid_bits_local = 0; - - // If the caller wants data back, get it from the MFRC522. - if (back_data && back_len) { - uint8_t n = pcd_read_register(FIFO_LEVEL_REG); // Number of uint8_ts in the FIFO - if (n > *back_len) { - return STATUS_NO_ROOM; - } - *back_len = n; // Number of uint8_ts returned - pcd_read_register(FIFO_DATA_REG, n, back_data, rx_align); // Get received data from FIFO - valid_bits_local = - pcd_read_register(CONTROL_REG) & 0x07; // RxLastBits[2:0] indicates the number of valid bits in the last - // received uint8_t. If this value is 000b, the whole uint8_t is valid. - if (valid_bits) { - *valid_bits = valid_bits_local; - } - } + n = pcd_read_register(FIFO_LEVEL_REG); // Number of uint8_ts in the FIFO + if (n > sizeof(buffer_)) + return STATUS_NO_ROOM; + if (n > sizeof(buffer_) - send_len_) + send_len_ = sizeof(buffer_) - n; // simply overwrite the sent values + back_length_ = n; // Number of uint8_ts returned + pcd_read_register(FIFO_DATA_REG, n, buffer_ + send_len_, rx_align_); // Get received data from FIFO + uint8_t valid_bits_local = + pcd_read_register(CONTROL_REG) & 0x07; // RxLastBits[2:0] indicates the number of valid bits in the last + // received uint8_t. If this value is 000b, the whole uint8_t is valid. // Tell about collisions if (error_reg_value & 0x08) { // CollErr + ESP_LOGW(TAG, "collision error, received %d bytes + %d bits (but anticollision not implemented)", + back_length_ - (valid_bits_local > 0), valid_bits_local); return STATUS_COLLISION; } - - // Perform CRC_A validation if requested. - if (back_data && back_len && check_crc) { - // In this case a MIFARE Classic NAK is not OK. - if (*back_len == 1 && valid_bits_local == 4) { - return STATUS_MIFARE_NACK; - } - // We need at least the CRC_A value and all 8 bits of the last uint8_t must be received. - if (*back_len < 2 || valid_bits_local != 0) { - return STATUS_CRC_WRONG; - } - // Verify CRC_A - do our own calculation and store the control in controlBuffer. - uint8_t control_buffer[2]; - RC522::StatusCode status = pcd_calculate_crc_(&back_data[0], *back_len - 2, &control_buffer[0]); - if (status != STATUS_OK) { - return status; - } - if ((back_data[*back_len - 2] != control_buffer[0]) || (back_data[*back_len - 1] != control_buffer[1])) { - return STATUS_CRC_WRONG; - } + // Tell about collisions + if (valid_bits_local) { + ESP_LOGW(TAG, "only %d valid bits received, tag distance to high? Error code is 0x%x", valid_bits_local, + error_reg_value); // TODO: is this always due to collissions? + return STATUS_ERROR; } + ESP_LOGV(TAG, "received %d bytes: %s", back_length_, format_buffer(buffer_ + send_len_, back_length_).c_str()); return STATUS_OK; } @@ -424,10 +437,8 @@ RC522::StatusCode RC522::pcd_communicate_with_picc_( * @return STATUS_OK on success, STATUS_??? otherwise. */ -RC522::StatusCode RC522::pcd_calculate_crc_( - uint8_t *data, ///< In: Pointer to the data to transfer to the FIFO for CRC calculation. - uint8_t length, ///< In: The number of uint8_ts to transfer. - uint8_t *result ///< Out: Pointer to result buffer. Result is written to result[0..1], low uint8_t first. +void RC522::pcd_calculate_crc_(uint8_t *data, ///< In: Pointer to the data to transfer to the FIFO for CRC calculation. + uint8_t length ///< In: The number of uint8_ts to transfer. ) { ESP_LOGVV(TAG, "pcd_calculate_crc_(..., %d, ...)", length); pcd_write_register(COMMAND_REG, PCD_IDLE); // Stop any active command. @@ -436,323 +447,50 @@ RC522::StatusCode RC522::pcd_calculate_crc_( pcd_write_register(FIFO_DATA_REG, length, data); // Write data to the FIFO pcd_write_register(COMMAND_REG, PCD_CALC_CRC); // Start the calculation - // Wait for the CRC calculation to complete. Each iteration of the while-loop takes 17.73μs. - // TODO check/modify for other architectures than Arduino Uno 16bit + awaiting_comm_ = true; + awaiting_comm_time_ = millis(); +} - // Wait for the CRC calculation to complete. Each iteration of the while-loop takes 17.73us. - for (uint16_t i = 5000; i > 0; i--) { - // DivIrqReg[7..0] bits are: Set2 reserved reserved MfinActIRq reserved CRCIRq reserved reserved - uint8_t n = pcd_read_register(DIV_IRQ_REG); - if (n & 0x04) { // CRCIRq bit set - calculation done - pcd_write_register(COMMAND_REG, PCD_IDLE); // Stop calculating CRC for new content in the FIFO. - // Transfer the result from the registers to the result buffer - result[0] = pcd_read_register(CRC_RESULT_REG_L); - result[1] = pcd_read_register(CRC_RESULT_REG_H); +RC522::StatusCode RC522::await_crc_() { + if (millis() - awaiting_comm_time_ < 2) // wait at least 2 ms + return STATUS_WAITING; - ESP_LOGVV(TAG, "pcd_calculate_crc_() STATUS_OK"); - return STATUS_OK; - } + // DivIrqReg[7..0] bits are: Set2 reserved reserved MfinActIRq reserved CRCIRq reserved reserved + uint8_t n = pcd_read_register(DIV_IRQ_REG); + if (n & 0x04) { // CRCIRq bit set - calculation done + pcd_write_register(COMMAND_REG, PCD_IDLE); // Stop calculating CRC for new content in the FIFO. + // Transfer the result from the registers to the result buffer + buffer_[7] = pcd_read_register(CRC_RESULT_REG_L); + buffer_[8] = pcd_read_register(CRC_RESULT_REG_H); + + ESP_LOGVV(TAG, "pcd_calculate_crc_() STATUS_OK"); + return STATUS_OK; } - ESP_LOGVV(TAG, "pcd_calculate_crc_() TIMEOUT"); + if (millis() - awaiting_comm_time_ < 89) + return STATUS_WAITING; + + ESP_LOGD(TAG, "pcd_calculate_crc_() TIMEOUT"); // 89ms passed and nothing happend. Communication with the MFRC522 might be down. return STATUS_TIMEOUT; } -/** - * Returns STATUS_OK if a PICC responds to PICC_CMD_REQA. - * Only "new" cards in state IDLE are invited. Sleeping cards in state HALT are ignored. - * - * @return STATUS_OK on success, STATUS_??? otherwise. - */ -RC522::StatusCode RC522::picc_is_new_card_present_() { - uint8_t buffer_atqa[2]; - uint8_t buffer_size = sizeof(buffer_atqa); - - // Reset baud rates - pcd_write_register(TX_MODE_REG, 0x00); - pcd_write_register(RX_MODE_REG, 0x00); - // Reset ModWidthReg - pcd_write_register(MOD_WIDTH_REG, 0x26); - - auto result = picc_request_a_(buffer_atqa, &buffer_size); - - ESP_LOGV(TAG, "picc_is_new_card_present_() -> %d", result); +bool RC522BinarySensor::process(std::vector &data) { + bool result = true; + if (data.size() != this->uid_.size()) + result = false; + else { + for (uint8_t i = 0; i < data.size(); i++) { + if (data[i] != this->uid_[i]) { + result = false; + break; + } + } + } + this->publish_state(result); + this->found_ = result; return result; } - -/** - * Simple wrapper around PICC_Select. - * Returns true if a UID could be read. - * Remember to call PICC_IsNewCardPresent(), PICC_RequestA() or PICC_WakeupA() first. - * The read UID is available in the class variable uid. - * - * @return bool - */ -bool RC522::picc_read_card_serial_() { - RC522::StatusCode result = picc_select_(&this->uid_); - ESP_LOGVV(TAG, "picc_select_(...) -> %d", result); - return (result == STATUS_OK); -} - -/** - * Transmits SELECT/ANTICOLLISION commands to select a single PICC. - * Before calling this function the PICCs must be placed in the READY(*) state by calling PICC_RequestA() or - * PICC_WakeupA(). On success: - * - The chosen PICC is in state ACTIVE(*) and all other PICCs have returned to state IDLE/HALT. (Figure 7 of the - * ISO/IEC 14443-3 draft.) - * - The UID size and value of the chosen PICC is returned in *uid along with the SAK. - * - * A PICC UID consists of 4, 7 or 10 uint8_ts. - * Only 4 uint8_ts can be specified in a SELECT command, so for the longer UIDs two or three iterations are used: - * UID size Number of UID uint8_ts Cascade levels Example of PICC - * ======== =================== ============== =============== - * single 4 1 MIFARE Classic - * double 7 2 MIFARE Ultralight - * triple 10 3 Not currently in use? - * - * @return STATUS_OK on success, STATUS_??? otherwise. - */ -RC522::StatusCode RC522::picc_select_( - Uid *uid, ///< Pointer to Uid struct. Normally output, but can also be used to supply a known UID. - uint8_t valid_bits ///< The number of known UID bits supplied in *uid. Normally 0. If set you must also supply - ///< uid->size. -) { - bool uid_complete; - bool select_done; - bool use_cascade_tag; - uint8_t cascade_level = 1; - RC522::StatusCode result; - uint8_t count; - uint8_t check_bit; - uint8_t index; - uint8_t uid_index; // The first index in uid->uiduint8_t[] that is used in the current Cascade Level. - int8_t current_level_known_bits; // The number of known UID bits in the current Cascade Level. - uint8_t buffer[9]; // The SELECT/ANTICOLLISION commands uses a 7 uint8_t standard frame + 2 uint8_ts CRC_A - uint8_t buffer_used; // The number of uint8_ts used in the buffer, ie the number of uint8_ts to transfer to the FIFO. - uint8_t rx_align; // Used in BitFramingReg. Defines the bit position for the first bit received. - uint8_t tx_last_bits; // Used in BitFramingReg. The number of valid bits in the last transmitted uint8_t. - uint8_t *response_buffer; - uint8_t response_length; - - // Description of buffer structure: - // uint8_t 0: SEL Indicates the Cascade Level: PICC_CMD_SEL_CL1, PICC_CMD_SEL_CL2 or PICC_CMD_SEL_CL3 - // uint8_t 1: NVB Number of Valid Bits (in complete command, not just the UID): High nibble: complete - // uint8_ts, - // Low nibble: Extra bits. uint8_t 2: UID-data or CT See explanation below. CT means Cascade Tag. uint8_t - // 3: UID-data uint8_t 4: UID-data uint8_t 5: UID-data uint8_t 6: BCC Block Check Character - XOR of - // uint8_ts 2-5 uint8_t 7: CRC_A uint8_t 8: CRC_A The BCC and CRC_A are only transmitted if we know all the UID bits - // of the current Cascade Level. - // - // Description of uint8_ts 2-5: (Section 6.5.4 of the ISO/IEC 14443-3 draft: UID contents and cascade levels) - // UID size Cascade level uint8_t2 uint8_t3 uint8_t4 uint8_t5 - // ======== ============= ===== ===== ===== ===== - // 4 uint8_ts 1 uid0 uid1 uid2 uid3 - // 7 uint8_ts 1 CT uid0 uid1 uid2 - // 2 uid3 uid4 uid5 uid6 - // 10 uint8_ts 1 CT uid0 uid1 uid2 - // 2 CT uid3 uid4 uid5 - // 3 uid6 uid7 uid8 uid9 - - // Sanity checks - if (valid_bits > 80) { - return STATUS_INVALID; - } - - ESP_LOGVV(TAG, "picc_select_(&, %d)", valid_bits); - - // Prepare MFRC522 - pcd_clear_register_bit_mask_(COLL_REG, 0x80); // ValuesAfterColl=1 => Bits received after collision are cleared. - - // Repeat Cascade Level loop until we have a complete UID. - uid_complete = false; - while (!uid_complete) { - // Set the Cascade Level in the SEL uint8_t, find out if we need to use the Cascade Tag in uint8_t 2. - switch (cascade_level) { - case 1: - buffer[0] = PICC_CMD_SEL_CL1; - uid_index = 0; - use_cascade_tag = valid_bits && uid->size > 4; // When we know that the UID has more than 4 uint8_ts - break; - - case 2: - buffer[0] = PICC_CMD_SEL_CL2; - uid_index = 3; - use_cascade_tag = valid_bits && uid->size > 7; // When we know that the UID has more than 7 uint8_ts - break; - - case 3: - buffer[0] = PICC_CMD_SEL_CL3; - uid_index = 6; - use_cascade_tag = false; // Never used in CL3. - break; - - default: - return STATUS_INTERNAL_ERROR; - break; - } - - // How many UID bits are known in this Cascade Level? - current_level_known_bits = valid_bits - (8 * uid_index); - if (current_level_known_bits < 0) { - current_level_known_bits = 0; - } - // Copy the known bits from uid->uiduint8_t[] to buffer[] - index = 2; // destination index in buffer[] - if (use_cascade_tag) { - buffer[index++] = PICC_CMD_CT; - } - uint8_t uint8_ts_to_copy = current_level_known_bits / 8 + - (current_level_known_bits % 8 - ? 1 - : 0); // The number of uint8_ts needed to represent the known bits for this level. - if (uint8_ts_to_copy) { - uint8_t maxuint8_ts = - use_cascade_tag ? 3 : 4; // Max 4 uint8_ts in each Cascade Level. Only 3 left if we use the Cascade Tag - if (uint8_ts_to_copy > maxuint8_ts) { - uint8_ts_to_copy = maxuint8_ts; - } - for (count = 0; count < uint8_ts_to_copy; count++) { - buffer[index++] = uid->uiduint8_t[uid_index + count]; - } - } - // Now that the data has been copied we need to include the 8 bits in CT in currentLevelKnownBits - if (use_cascade_tag) { - current_level_known_bits += 8; - } - - // Repeat anti collision loop until we can transmit all UID bits + BCC and receive a SAK - max 32 iterations. - select_done = false; - while (!select_done) { - // Find out how many bits and uint8_ts to send and receive. - if (current_level_known_bits >= 32) { // All UID bits in this Cascade Level are known. This is a SELECT. - - if (response_length < 4) { - ESP_LOGW(TAG, "Not enough data received."); - return STATUS_INVALID; - } - - // Serial.print(F("SELECT: currentLevelKnownBits=")); Serial.println(currentLevelKnownBits, DEC); - buffer[1] = 0x70; // NVB - Number of Valid Bits: Seven whole uint8_ts - // Calculate BCC - Block Check Character - buffer[6] = buffer[2] ^ buffer[3] ^ buffer[4] ^ buffer[5]; - // Calculate CRC_A - result = pcd_calculate_crc_(buffer, 7, &buffer[7]); - if (result != STATUS_OK) { - return result; - } - tx_last_bits = 0; // 0 => All 8 bits are valid. - buffer_used = 9; - // Store response in the last 3 uint8_ts of buffer (BCC and CRC_A - not needed after tx) - response_buffer = &buffer[6]; - response_length = 3; - } else { // This is an ANTICOLLISION. - // Serial.print(F("ANTICOLLISION: currentLevelKnownBits=")); Serial.println(currentLevelKnownBits, DEC); - tx_last_bits = current_level_known_bits % 8; - count = current_level_known_bits / 8; // Number of whole uint8_ts in the UID part. - index = 2 + count; // Number of whole uint8_ts: SEL + NVB + UIDs - buffer[1] = (index << 4) + tx_last_bits; // NVB - Number of Valid Bits - buffer_used = index + (tx_last_bits ? 1 : 0); - // Store response in the unused part of buffer - response_buffer = &buffer[index]; - response_length = sizeof(buffer) - index; - } - - // Set bit adjustments - rx_align = tx_last_bits; // Having a separate variable is overkill. But it makes the next line easier to read. - pcd_write_register( - BIT_FRAMING_REG, - (rx_align << 4) + tx_last_bits); // RxAlign = BitFramingReg[6..4]. TxLastBits = BitFramingReg[2..0] - - // Transmit the buffer and receive the response. - result = pcd_transceive_data_(buffer, buffer_used, response_buffer, &response_length, &tx_last_bits, rx_align); - if (result == STATUS_COLLISION) { // More than one PICC in the field => collision. - uint8_t value_of_coll_reg = pcd_read_register( - COLL_REG); // CollReg[7..0] bits are: ValuesAfterColl reserved CollPosNotValid CollPos[4:0] - if (value_of_coll_reg & 0x20) { // CollPosNotValid - return STATUS_COLLISION; // Without a valid collision position we cannot continue - } - uint8_t collision_pos = value_of_coll_reg & 0x1F; // Values 0-31, 0 means bit 32. - if (collision_pos == 0) { - collision_pos = 32; - } - if (collision_pos <= current_level_known_bits) { // No progress - should not happen - return STATUS_INTERNAL_ERROR; - } - // Choose the PICC with the bit set. - current_level_known_bits = collision_pos; - count = current_level_known_bits % 8; // The bit to modify - check_bit = (current_level_known_bits - 1) % 8; - index = 1 + (current_level_known_bits / 8) + (count ? 1 : 0); // First uint8_t is index 0. - if (response_length > 2) // Note: Otherwise buffer[index] might be not initialized - buffer[index] |= (1 << check_bit); - } else if (result != STATUS_OK) { - return result; - } else { // STATUS_OK - if (current_level_known_bits >= 32) { // This was a SELECT. - select_done = true; // No more anticollision - // We continue below outside the while. - } else { // This was an ANTICOLLISION. - // We now have all 32 bits of the UID in this Cascade Level - current_level_known_bits = 32; - // Run loop again to do the SELECT. - } - } - } // End of while (!selectDone) - - // We do not check the CBB - it was constructed by us above. - - // Copy the found UID uint8_ts from buffer[] to uid->uiduint8_t[] - index = (buffer[2] == PICC_CMD_CT) ? 3 : 2; // source index in buffer[] - uint8_ts_to_copy = (buffer[2] == PICC_CMD_CT) ? 3 : 4; - for (count = 0; count < uint8_ts_to_copy; count++) { - uid->uiduint8_t[uid_index + count] = buffer[index++]; - } - - // Check response SAK (Select Acknowledge) - if (response_length != 3 || tx_last_bits != 0) { // SAK must be exactly 24 bits (1 uint8_t + CRC_A). - return STATUS_ERROR; - } - // Verify CRC_A - do our own calculation and store the control in buffer[2..3] - those uint8_ts are not needed - // anymore. - result = pcd_calculate_crc_(response_buffer, 1, &buffer[2]); - if (result != STATUS_OK) { - return result; - } - if ((buffer[2] != response_buffer[1]) || (buffer[3] != response_buffer[2])) { - return STATUS_CRC_WRONG; - } - if (response_buffer[0] & 0x04) { // Cascade bit set - UID not complete yes - cascade_level++; - } else { - uid_complete = true; - uid->sak = response_buffer[0]; - } - } // End of while (!uidComplete) - - // Set correct uid->size - uid->size = 3 * cascade_level + 1; - - return STATUS_OK; -} - -bool RC522BinarySensor::process(const uint8_t *data, uint8_t len) { - if (len != this->uid_.size()) - return false; - - for (uint8_t i = 0; i < len; i++) { - if (data[i] != this->uid_[i]) - return false; - } - - this->publish_state(true); - this->found_ = true; - return true; -} -void RC522Trigger::process(const uint8_t *uid, uint8_t uid_length) { - char buf[32]; - format_uid(buf, uid, uid_length); - this->trigger(std::string(buf)); -} +void RC522Trigger::process(std::vector &data) { this->trigger(format_uid(data)); } } // namespace rc522 } // namespace esphome diff --git a/esphome/components/rc522/rc522.h b/esphome/components/rc522/rc522.h index cabcf8db0b..7fb49e97fd 100644 --- a/esphome/components/rc522/rc522.h +++ b/esphome/components/rc522/rc522.h @@ -26,6 +26,33 @@ class RC522 : public PollingComponent { void set_reset_pin(GPIOPin *reset) { this->reset_pin_ = reset; } protected: + // Return codes from the functions in this class. Remember to update GetStatusCodeName() if you add more. + // last value set to 0xff, then compiler uses less ram, it seems some optimisations are triggered + enum StatusCode : uint8_t { + STATUS_OK, // Success + STATUS_WAITING, // Waiting result from RC522 chip + STATUS_ERROR, // Error in communication + STATUS_COLLISION, // Collission detected + STATUS_TIMEOUT, // Timeout in communication. + STATUS_NO_ROOM, // A buffer is not big enough. + STATUS_INTERNAL_ERROR, // Internal error in the code. Should not happen ;-) + STATUS_INVALID, // Invalid argument. + STATUS_CRC_WRONG, // The CRC_A does not match + STATUS_MIFARE_NACK = 0xff // A MIFARE PICC responded with NAK. + }; + + enum State { + STATE_NONE = 0, + STATE_SETUP, + STATE_INIT, + STATE_PICC_REQUEST_A, + STATE_READ_SERIAL, + STATE_SELECT_SERIAL, + STATE_SELECT_SERIAL_DONE, + STATE_READ_SERIAL_DONE, + STATE_DONE, + } state_{STATE_NONE}; + enum PcdRegister : uint8_t { // Page 0: Command and status // 0x00 // reserved for future use @@ -150,33 +177,11 @@ class RC522 : public PollingComponent { PICC_CMD_UL_WRITE = 0xA2 // Writes one 4 uint8_t page to the PICC. }; - // Return codes from the functions in this class. Remember to update GetStatusCodeName() if you add more. - // last value set to 0xff, then compiler uses less ram, it seems some optimisations are triggered - enum StatusCode : uint8_t { - STATUS_OK, // Success - STATUS_ERROR, // Error in communication - STATUS_COLLISION, // Collission detected - STATUS_TIMEOUT, // Timeout in communication. - STATUS_NO_ROOM, // A buffer is not big enough. - STATUS_INTERNAL_ERROR, // Internal error in the code. Should not happen ;-) - STATUS_INVALID, // Invalid argument. - STATUS_CRC_WRONG, // The CRC_A does not match - STATUS_MIFARE_NACK = 0xff // A MIFARE PICC responded with NAK. - }; - - // A struct used for passing the UID of a PICC. - using Uid = struct { - uint8_t size; // Number of uint8_ts in the UID. 4, 7 or 10. - uint8_t uiduint8_t[10]; - uint8_t sak; // The SAK (Select acknowledge) uint8_t returned from the PICC after successful selection. - }; - - Uid uid_; - uint32_t update_wait_{0}; - void pcd_reset_(); void initialize_(); void pcd_antenna_on_(); + void pcd_antenna_off_(); + virtual uint8_t pcd_read_register(PcdRegister reg ///< The register to read from. One of the PCD_Register enums. ) = 0; @@ -202,15 +207,6 @@ class RC522 : public PollingComponent { uint8_t *values ///< The values to write. uint8_t array. ) = 0; - StatusCode picc_request_a_( - uint8_t *buffer_atqa, ///< The buffer to store the ATQA (Answer to request) in - uint8_t *buffer_size ///< Buffer size, at least two uint8_ts. Also number of uint8_ts returned if STATUS_OK. - ); - StatusCode picc_reqa_or_wupa_( - uint8_t command, ///< The command to send - PICC_CMD_REQA or PICC_CMD_WUPA - uint8_t *buffer_atqa, ///< The buffer to store the ATQA (Answer to request) in - uint8_t *buffer_size ///< Buffer size, at least two uint8_ts. Also number of uint8_ts returned if STATUS_OK. - ); void pcd_set_register_bit_mask_(PcdRegister reg, ///< The register to update. One of the PCD_Register enums. uint8_t mask ///< The bits to set. ); @@ -218,38 +214,33 @@ class RC522 : public PollingComponent { uint8_t mask ///< The bits to clear. ); - StatusCode pcd_transceive_data_(uint8_t *send_data, uint8_t send_len, uint8_t *back_data, uint8_t *back_len, - uint8_t *valid_bits = nullptr, uint8_t rx_align = 0, bool check_crc = false); - StatusCode pcd_communicate_with_picc_(uint8_t command, uint8_t wait_i_rq, uint8_t *send_data, uint8_t send_len, - uint8_t *back_data = nullptr, uint8_t *back_len = nullptr, - uint8_t *valid_bits = nullptr, uint8_t rx_align = 0, bool check_crc = false); - StatusCode pcd_calculate_crc_( - uint8_t *data, ///< In: Pointer to the data to transfer to the FIFO for CRC calculation. - uint8_t length, ///< In: The number of uint8_ts to transfer. - uint8_t *result ///< Out: Pointer to result buffer. Result is written to result[0..1], low uint8_t first. - ); - RC522::StatusCode picc_is_new_card_present_(); - bool picc_read_card_serial_(); - StatusCode picc_select_( - Uid *uid, ///< Pointer to Uid struct. Normally output, but can also be used to supply a known UID. - uint8_t valid_bits = 0 ///< The number of known UID bits supplied in *uid. Normally 0. If set you must also - ///< supply uid->size. + void pcd_transceive_data_(uint8_t send_len); + + void pcd_calculate_crc_(uint8_t *data, ///< In: Pointer to the data to transfer to the FIFO for CRC calculation. + uint8_t length ///< In: The number of uint8_ts to transfer. ); - /** Read a data frame from the RC522 and return the result as a vector. - * - * Note that is_ready needs to be checked first before requesting this method. - * - * On failure, an empty vector is returned. - */ - std::vector r_c522_read_data_(); + bool awaiting_comm_; + uint32_t awaiting_comm_time_; + StatusCode await_transceive_(); + StatusCode await_crc_(); + + uint8_t buffer_[9]; ///< buffer for communication, the first bits [0..back_idx-1] are for tx , + ///< [back_idx..back_idx+back_len] for rx + uint8_t send_len_; // index of first byte for RX + uint8_t back_length_; ///< In: Max number of uint8_ts to write to *backData. Out: The number of uint8_ts returned. + uint8_t uid_buffer_[10]; // buffer to construct the uid (for 7 and 10 bit uids) + uint8_t uid_idx_ = 0; // number of read uid bytes e.g. index of the next available position in uid_buffer + uint8_t error_counter_ = 0; // to reset if unresponsive + uint8_t rx_align_; + uint8_t *valid_bits_; GPIOPin *reset_pin_{nullptr}; uint8_t reset_count_{0}; uint32_t reset_timeout_{0}; - bool initialize_pending_{false}; std::vector binary_sensors_; std::vector triggers_; + std::vector current_uid_; enum RC522Error { NONE = 0, @@ -261,7 +252,7 @@ class RC522BinarySensor : public binary_sensor::BinarySensor { public: void set_uid(const std::vector &uid) { uid_ = uid; } - bool process(const uint8_t *data, uint8_t len); + bool process(std::vector &data); void on_scan_end() { if (!this->found_) { @@ -277,7 +268,7 @@ class RC522BinarySensor : public binary_sensor::BinarySensor { class RC522Trigger : public Trigger { public: - void process(const uint8_t *uid, uint8_t uid_length); + void process(std::vector &data); }; } // namespace rc522 diff --git a/esphome/components/rc522_i2c/rc522_i2c.cpp b/esphome/components/rc522_i2c/rc522_i2c.cpp index 8248e79b50..fe88f567c0 100644 --- a/esphome/components/rc522_i2c/rc522_i2c.cpp +++ b/esphome/components/rc522_i2c/rc522_i2c.cpp @@ -36,10 +36,6 @@ void RC522I2C::pcd_read_register(PcdRegister reg, ///< The register to read fro return; } - std::string buf; - buf = "Rx"; - char cstrb[20]; - uint8_t b = values[0]; read_bytes(reg >> 1, values, count); @@ -69,31 +65,5 @@ void RC522I2C::pcd_write_register(PcdRegister reg, ///< The register to write t write_bytes(reg >> 1, values, count); } -// bool RC522I2C::write_data(const std::vector &data) { -// return this->write_bytes_raw(data.data(), data.size()); } - -// bool RC522I2C::read_data(std::vector &data, uint8_t len) { -// delay(5); - -// std::vector ready; -// ready.resize(1); -// uint32_t start_time = millis(); -// while (true) { -// if (this->read_bytes_raw(ready.data(), 1)) { -// if (ready[0] == 0x01) -// break; -// } - -// if (millis() - start_time > 100) { -// ESP_LOGV(TAG, "Timed out waiting for readiness from RC522!"); -// return false; -// } -// } - -// data.resize(len + 1); -// this->read_bytes_raw(data.data(), len + 1); -// return true; -// } - } // namespace rc522_i2c } // namespace esphome diff --git a/esphome/components/rc522_spi/rc522_spi.cpp b/esphome/components/rc522_spi/rc522_spi.cpp index 61236393e4..1865b36da6 100644 --- a/esphome/components/rc522_spi/rc522_spi.cpp +++ b/esphome/components/rc522_spi/rc522_spi.cpp @@ -32,7 +32,7 @@ uint8_t RC522Spi::pcd_read_register(PcdRegister reg ///< The register to read f transfer_byte(0x80 | reg); value = read_byte(); disable(); - ESP_LOGV(TAG, "read_register_(%x) -> %x", reg, value); + ESP_LOGVV(TAG, "read_register_(%d) -> %d", reg, value); return value; } @@ -45,9 +45,11 @@ void RC522Spi::pcd_read_register(PcdRegister reg, ///< The register to read fro uint8_t *values, ///< uint8_t array to store the values in. uint8_t rx_align ///< Only bit positions rxAlign..7 in values[0] are updated. ) { +#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE std::string buf; buf = "Rx"; char cstrb[20]; +#endif if (count == 0) { return; } @@ -68,25 +70,30 @@ void RC522Spi::pcd_read_register(PcdRegister reg, ///< The register to read fro values[0] = (values[0] & ~mask) | (value & mask); index++; +#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE sprintf(cstrb, " %x", values[0]); buf.append(cstrb); +#endif } while (index < count) { values[index] = transfer_byte(address); // Read value and tell that we want to read the same address again. +#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE sprintf(cstrb, " %x", values[index]); buf.append(cstrb); +#endif index++; } values[index] = transfer_byte(0); // Read the final uint8_t. Send 0 to stop reading. +#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE buf = buf + " "; sprintf(cstrb, "%x", values[index]); buf.append(cstrb); ESP_LOGVV(TAG, "read_register_array_(%x, %d, , %d) -> %s", reg, count, rx_align, buf.c_str()); - +#endif disable(); } @@ -108,21 +115,25 @@ void RC522Spi::pcd_write_register(PcdRegister reg, ///< The register to write t uint8_t count, ///< The number of uint8_ts to write to the register uint8_t *values ///< The values to write. uint8_t array. ) { +#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE std::string buf; buf = "Tx"; + char cstrb[20]; +#endif enable(); transfer_byte(reg); - char cstrb[20]; for (uint8_t index = 0; index < count; index++) { transfer_byte(values[index]); +#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE sprintf(cstrb, " %x", values[index]); buf.append(cstrb); +#endif } disable(); - ESP_LOGVV(TAG, "write_register_(%x, %d) -> %s", reg, count, buf.c_str()); + ESP_LOGVV(TAG, "write_register_(%d, %d) -> %s", reg, count, buf.c_str()); } } // namespace rc522_spi From 37bc0b3b5a3020b2aa4b6beaa2f722f340c46115 Mon Sep 17 00:00:00 2001 From: Alex <33379584+alexyao2015@users.noreply.github.com> Date: Tue, 4 May 2021 21:31:38 -0500 Subject: [PATCH 012/104] Do not call component update on failed components (#1392) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/core/base_automation.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/esphome/core/base_automation.h b/esphome/core/base_automation.h index d2656290bc..fa49786d1d 100644 --- a/esphome/core/base_automation.h +++ b/esphome/core/base_automation.h @@ -266,7 +266,11 @@ template class UpdateComponentAction : public Action { public: UpdateComponentAction(PollingComponent *component) : component_(component) {} - void play(Ts... x) override { this->component_->update(); } + void play(Ts... x) override { + if (this->component_->is_failed()) + return; + this->component_->update(); + } protected: PollingComponent *component_; From 13dbdd9b16ea081db7239cfdd094f7a614cf6dce Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 5 May 2021 22:35:18 +1200 Subject: [PATCH 013/104] Bump version to v1.17.1 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index f8b7da0664..237a356c74 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -2,7 +2,7 @@ MAJOR_VERSION = 1 MINOR_VERSION = 17 -PATCH_VERSION = "0" +PATCH_VERSION = "1" __short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__ = f"{__short_version__}.{PATCH_VERSION}" From 403b6e32e3fbfb1201e6680177b6332c84884ce2 Mon Sep 17 00:00:00 2001 From: Vegetto Date: Tue, 6 Apr 2021 14:31:38 +0200 Subject: [PATCH 014/104] fixes #858 - esphome crashes with neolightbus and RMT (#1667) Co-authored-by: Otto Winter --- esphome/components/neopixelbus/neopixelbus_light.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/esphome/components/neopixelbus/neopixelbus_light.h b/esphome/components/neopixelbus/neopixelbus_light.h index 46601d8345..2f279e1c9b 100644 --- a/esphome/components/neopixelbus/neopixelbus_light.h +++ b/esphome/components/neopixelbus/neopixelbus_light.h @@ -68,7 +68,8 @@ class NeoPixelBusLightOutputBase : public light::AddressableLight { void add_leds(uint16_t count_pixels) { this->add_leds(new NeoPixelBus(count_pixels)); } void add_leds(NeoPixelBus *controller) { this->controller_ = controller; - this->controller_->Begin(); + // controller gets initialised in setup() - avoid calling twice (crashes with RMT) + // this->controller_->Begin(); } // ========== INTERNAL METHODS ========== From 3b4ea0ed0ae01a31310596095a140513e822513c Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Sun, 9 May 2021 22:37:31 +1200 Subject: [PATCH 015/104] Bump version to v1.17.2 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 237a356c74..8f9c80e2e3 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -2,7 +2,7 @@ MAJOR_VERSION = 1 MINOR_VERSION = 17 -PATCH_VERSION = "1" +PATCH_VERSION = "2" __short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__ = f"{__short_version__}.{PATCH_VERSION}" From 076124eb715748525372d33b6459610784c04fd5 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 10 May 2021 07:54:06 +1200 Subject: [PATCH 016/104] Bump version to v1.19.0-dev --- esphome/const.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/const.py b/esphome/const.py index a8f8aa81f5..4a3857f1e0 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,8 +1,8 @@ """Constants used by esphome.""" MAJOR_VERSION = 1 -MINOR_VERSION = 18 -PATCH_VERSION = "0-dev" +MINOR_VERSION = 19 +PATCH_VERSION = '0-dev' __short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__ = f"{__short_version__}.{PATCH_VERSION}" From 96ded4e402beb41d0b4739e41bef701c4f3e498b Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 10 May 2021 08:05:08 +1200 Subject: [PATCH 017/104] Fix quotes --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 4a3857f1e0..8c8a1c7102 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -2,7 +2,7 @@ MAJOR_VERSION = 1 MINOR_VERSION = 19 -PATCH_VERSION = '0-dev' +PATCH_VERSION = "0-dev" __short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__ = f"{__short_version__}.{PATCH_VERSION}" From 33bf78c369471f25cd5727c00cebdb32c759c788 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 May 2021 17:25:37 -0300 Subject: [PATCH 018/104] Bump black from 20.8b1 to 21.5b0 (#1745) Bumps [black](https://github.com/psf/black) from 20.8b1 to 21.5b0. - [Release notes](https://github.com/psf/black/releases) - [Changelog](https://github.com/psf/black/blob/master/CHANGES.md) - [Commits](https://github.com/psf/black/commits) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements_test.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_test.txt b/requirements_test.txt index fdd1e91b20..9e4f175852 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -1,6 +1,6 @@ pylint==2.7.2 flake8==3.9.0 -black==20.8b1 +black==21.5b0 pillow>4.0.0 cryptography>=2.0.0,<4 pexpect==4.8.0 From 73252ccd256739deedb9d50d294561b83c4a1434 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 May 2021 17:57:25 -0300 Subject: [PATCH 019/104] Bump pylint from 2.7.2 to 2.8.2 (#1729) * Bump pylint from 2.7.2 to 2.8.2 Bumps [pylint](https://github.com/PyCQA/pylint) from 2.7.2 to 2.8.2. - [Release notes](https://github.com/PyCQA/pylint/releases) - [Changelog](https://github.com/PyCQA/pylint/blob/master/ChangeLog) - [Commits](https://github.com/PyCQA/pylint/compare/pylint-2.7.2...v2.8.2) Signed-off-by: dependabot[bot] * fix pylint Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Guillermo Ruffino --- esphome/dashboard/dashboard.py | 64 +++++++++++++++++----------------- esphome/espota2.py | 17 +++++---- esphome/helpers.py | 8 ++--- requirements_test.txt | 2 +- 4 files changed, 45 insertions(+), 46 deletions(-) diff --git a/esphome/dashboard/dashboard.py b/esphome/dashboard/dashboard.py index 1575d9f9b1..f0e9604141 100644 --- a/esphome/dashboard/dashboard.py +++ b/esphome/dashboard/dashboard.py @@ -515,45 +515,45 @@ class MDNSStatusThread(threading.Thread): class PingStatusThread(threading.Thread): def run(self): - pool = multiprocessing.Pool(processes=8) - while not STOP_EVENT.is_set(): - # Only do pings if somebody has the dashboard open + with multiprocessing.Pool(processes=8) as pool: + while not STOP_EVENT.is_set(): + # Only do pings if somebody has the dashboard open - def callback(ret): - PING_RESULT[ret[0]] = ret[1] + def callback(ret): + PING_RESULT[ret[0]] = ret[1] - entries = _list_dashboard_entries() - queue = collections.deque() - for entry in entries: - if entry.address is None: - PING_RESULT[entry.filename] = None - continue + entries = _list_dashboard_entries() + queue = collections.deque() + for entry in entries: + if entry.address is None: + PING_RESULT[entry.filename] = None + continue - result = pool.apply_async( - _ping_func, (entry.filename, entry.address), callback=callback - ) - queue.append(result) + result = pool.apply_async( + _ping_func, (entry.filename, entry.address), callback=callback + ) + queue.append(result) - while queue: - item = queue[0] - if item.ready(): - queue.popleft() - continue + while queue: + item = queue[0] + if item.ready(): + queue.popleft() + continue - try: - item.get(0.1) - except OSError: - # ping not installed - pass - except multiprocessing.TimeoutError: - pass + try: + item.get(0.1) + except OSError: + # ping not installed + pass + except multiprocessing.TimeoutError: + pass - if STOP_EVENT.is_set(): - pool.terminate() - return + if STOP_EVENT.is_set(): + pool.terminate() + return - PING_REQUEST.wait() - PING_REQUEST.clear() + PING_REQUEST.wait() + PING_REQUEST.clear() class PingRequestHandler(BaseHandler): diff --git a/esphome/espota2.py b/esphome/espota2.py index 785cb155df..351f6feda9 100644 --- a/esphome/espota2.py +++ b/esphome/espota2.py @@ -296,15 +296,14 @@ def run_ota_impl_(remote_host, remote_port, password, filename): _LOGGER.error("Connecting to %s:%s failed: %s", remote_host, remote_port, err) return 1 - file_handle = open(filename, "rb") - try: - perform_ota(sock, password, file_handle, filename) - except OTAError as err: - _LOGGER.error(str(err)) - return 1 - finally: - sock.close() - file_handle.close() + with open(filename, "rb") as file_handle: + try: + perform_ota(sock, password, file_handle, filename) + except OTAError as err: + _LOGGER.error(str(err)) + return 1 + finally: + sock.close() return 0 diff --git a/esphome/helpers.py b/esphome/helpers.py index d9730f96a7..ad7b8272b2 100644 --- a/esphome/helpers.py +++ b/esphome/helpers.py @@ -60,10 +60,10 @@ def cpp_string_escape(string, encoding="utf-8"): def run_system_command(*args): import subprocess - p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - stdout, stderr = p.communicate() - rc = p.returncode - return rc, stdout, stderr + with subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) as p: + stdout, stderr = p.communicate() + rc = p.returncode + return rc, stdout, stderr def mkdir_p(path): diff --git a/requirements_test.txt b/requirements_test.txt index 9e4f175852..e612d5871b 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -1,4 +1,4 @@ -pylint==2.7.2 +pylint==2.8.2 flake8==3.9.0 black==21.5b0 pillow>4.0.0 From 4250af4dd92877c899891ecaffa4cf0380a27327 Mon Sep 17 00:00:00 2001 From: Guillermo Ruffino Date: Tue, 11 May 2021 12:05:49 -0300 Subject: [PATCH 020/104] Switch to esphome/AsyncTCP-esphome v1.2.2. (#1762) --- esphome/components/async_tcp/__init__.py | 4 ++-- platformio.ini | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/esphome/components/async_tcp/__init__.py b/esphome/components/async_tcp/__init__.py index b07db9ed7c..8532f349e6 100644 --- a/esphome/components/async_tcp/__init__.py +++ b/esphome/components/async_tcp/__init__.py @@ -8,8 +8,8 @@ CODEOWNERS = ["@OttoWinter"] @coroutine_with_priority(200.0) def to_code(config): if CORE.is_esp32: - # https://github.com/OttoWinter/AsyncTCP/blob/master/library.json - cg.add_library("AsyncTCP-esphome", "1.1.1") + # https://github.com/esphome/AsyncTCP/blob/master/library.json + cg.add_library("esphome/AsyncTCP-esphome", "1.2.2") elif CORE.is_esp8266: # https://github.com/OttoWinter/ESPAsyncTCP cg.add_library("ESPAsyncTCP-esphome", "1.2.3") diff --git a/platformio.ini b/platformio.ini index 1dbc88cfde..7a63ea67a9 100644 --- a/platformio.ini +++ b/platformio.ini @@ -10,7 +10,7 @@ include_dir = include [common] lib_deps = - AsyncTCP-esphome@1.1.1 + esphome/AsyncTCP-esphome@1.2.2 AsyncMqttClient-esphome@0.8.4 ArduinoJson-esphomelib@5.13.3 ESPAsyncWebServer-esphome@1.2.7 From 7665a220a0e18c19d35a4a476e15e3e828ecb08f Mon Sep 17 00:00:00 2001 From: Maurice Makaay Date: Tue, 11 May 2021 17:15:29 +0200 Subject: [PATCH 021/104] Fix error when using %% in printf format. (#1713) For printf formatting, a check is done to see if the number of arguments matches the number of printf formatting placeholders. The escape code `%%` that is used for representing a literal `%` is also counted as a placeholder, but no argument will be provided for that one. This makes it impossible to use something like `("%f%%", percentage)` in the code. In such case, one gets the error: `Found 2 printf-patterns (%f, %%), but 1 args were given!` This commit fixes this behavior by omitting the `%%` from the matches. Co-authored-by: Maurice Makaay --- esphome/components/logger/__init__.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/esphome/components/logger/__init__.py b/esphome/components/logger/__init__.py index 5e7383cca7..d865be856b 100644 --- a/esphome/components/logger/__init__.py +++ b/esphome/components/logger/__init__.py @@ -209,14 +209,12 @@ def validate_printf(value): cfmt = """\ ( # 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 "%%" + ) """ # noqa matches = re.findall(cfmt, value[CONF_FORMAT], flags=re.X) if len(matches) != len(value[CONF_ARGS]): From 66b0b6feeb1b5391e06087a2fe063e081206549e Mon Sep 17 00:00:00 2001 From: Ciprian Constantinescu Date: Tue, 11 May 2021 18:16:51 +0300 Subject: [PATCH 022/104] Update const.py (#1748) * Update const.py Added cubic meter for https://github.com/esphome/feature-requests/issues/1185 * Update const.py ordered alphabetically --- esphome/const.py | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/const.py b/esphome/const.py index 8c8a1c7102..e6ce4a6ba2 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -679,6 +679,7 @@ ICON_WIFI = "mdi:wifi" UNIT_AMPERE = "A" UNIT_CELSIUS = "°C" UNIT_COUNTS_PER_CUBIC_METER = "#/m³" +UNIT_CUBIC_METER = "m³" UNIT_DECIBEL = "dB" UNIT_DECIBEL_MILLIWATT = "dBm" UNIT_DEGREE_PER_SECOND = "°/s" From 5c3af1d3f66c73c0a0ea01df55fc3a065340bb38 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 12 May 2021 03:36:14 +1200 Subject: [PATCH 023/104] Allow duration for deep_sleep.enter to be templateable (#1765) --- esphome/components/deep_sleep/__init__.py | 4 +++- tests/test2.yaml | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/esphome/components/deep_sleep/__init__.py b/esphome/components/deep_sleep/__init__.py index 793d6b2ebb..c0d035987d 100644 --- a/esphome/components/deep_sleep/__init__.py +++ b/esphome/components/deep_sleep/__init__.py @@ -108,7 +108,9 @@ def to_code(config): DEEP_SLEEP_ENTER_SCHEMA = automation.maybe_simple_id( { cv.GenerateID(): cv.use_id(DeepSleepComponent), - cv.Optional(CONF_SLEEP_DURATION): cv.positive_time_period_milliseconds, + cv.Optional(CONF_SLEEP_DURATION): cv.templatable( + cv.positive_time_period_milliseconds + ), } ) diff --git a/tests/test2.yaml b/tests/test2.yaml index 34724ee955..9b4db1477f 100644 --- a/tests/test2.yaml +++ b/tests/test2.yaml @@ -346,6 +346,8 @@ text_sensor: - homeassistant.tag_scanned: 1234-abcd - deep_sleep.enter: sleep_duration: 30min + - deep_sleep.enter: + sleep_duration: !lambda "return 30 * 60 * 1000;" - platform: template name: 'Template Text Sensor' lambda: |- From a546677b08b7631d6f16a3bf7b1d6356509b2c03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Klitzing?= Date: Tue, 11 May 2021 22:31:40 +0200 Subject: [PATCH 024/104] Fix build issues for idf 4.2 (Support ESP32-S2) (#1433) Co-authored-by: Otto winter --- esphome/components/logger/logger.cpp | 4 ++ esphome/components/wifi/wifi_component.h | 4 ++ .../components/wifi/wifi_component_esp32.cpp | 58 ++++++++++++++++++- 3 files changed, 63 insertions(+), 3 deletions(-) diff --git a/esphome/components/logger/logger.cpp b/esphome/components/logger/logger.cpp index 140b8f26c1..8e7bd2ee49 100644 --- a/esphome/components/logger/logger.cpp +++ b/esphome/components/logger/logger.cpp @@ -136,7 +136,11 @@ void Logger::pre_setup() { break; #ifdef ARDUINO_ARCH_ESP32 case UART_SELECTION_UART2: +#if !CONFIG_IDF_TARGET_ESP32S2 + // FIXME: Validate in config that UART2 can't be set for ESP32-S2 (only has + // UART0-UART1) this->hw_serial_ = &Serial2; +#endif break; #endif } diff --git a/esphome/components/wifi/wifi_component.h b/esphome/components/wifi/wifi_component.h index 536d914a36..ee8fd208b2 100644 --- a/esphome/components/wifi/wifi_component.h +++ b/esphome/components/wifi/wifi_component.h @@ -261,7 +261,11 @@ class WiFiComponent : public Component { #endif #ifdef ARDUINO_ARCH_ESP32 +#if ESP_IDF_VERSION_MAJOR >= 4 + void wifi_event_callback_(arduino_event_id_t event, arduino_event_info_t info); +#else void wifi_event_callback_(system_event_id_t event, system_event_info_t info); +#endif void wifi_scan_done_callback_(); #endif diff --git a/esphome/components/wifi/wifi_component_esp32.cpp b/esphome/components/wifi/wifi_component_esp32.cpp index 09b8433a0e..cf65ed3725 100644 --- a/esphome/components/wifi/wifi_component_esp32.cpp +++ b/esphome/components/wifi/wifi_component_esp32.cpp @@ -265,7 +265,14 @@ const char *get_auth_mode_str(uint8_t mode) { return "UNKNOWN"; } } -std::string format_ip4_addr(const ip4_addr_t &ip) { + +#if ESP_IDF_VERSION_MAJOR >= 4 +using esphome_ip4_addr_t = esp_ip4_addr_t; +#else +using esphome_ip4_addr_t = ip4_addr_t; +#endif + +std::string format_ip4_addr(const esphome_ip4_addr_t &ip) { char buf[20]; sprintf(buf, "%u.%u.%u.%u", uint8_t(ip.addr >> 0), uint8_t(ip.addr >> 8), uint8_t(ip.addr >> 16), uint8_t(ip.addr >> 24)); @@ -346,14 +353,22 @@ const char *get_disconnect_reason_str(uint8_t reason) { return "Unspecified"; } } +#if ESP_IDF_VERSION_MAJOR >= 4 +void WiFiComponent::wifi_event_callback_(arduino_event_id_t event, arduino_event_info_t info) { +#else void WiFiComponent::wifi_event_callback_(system_event_id_t event, system_event_info_t info) { +#endif switch (event) { case SYSTEM_EVENT_WIFI_READY: { ESP_LOGV(TAG, "Event: WiFi ready"); break; } case SYSTEM_EVENT_SCAN_DONE: { +#if ESP_IDF_VERSION_MAJOR >= 4 + auto it = info.wifi_scan_done; +#else auto it = info.scan_done; +#endif ESP_LOGV(TAG, "Event: WiFi Scan Done status=%u number=%u scan_id=%u", it.status, it.number, it.scan_id); break; } @@ -366,7 +381,11 @@ void WiFiComponent::wifi_event_callback_(system_event_id_t event, system_event_i break; } case SYSTEM_EVENT_STA_CONNECTED: { +#if ESP_IDF_VERSION_MAJOR >= 4 + auto it = info.wifi_sta_connected; +#else auto it = info.connected; +#endif char buf[33]; memcpy(buf, it.ssid, it.ssid_len); buf[it.ssid_len] = '\0'; @@ -375,7 +394,11 @@ void WiFiComponent::wifi_event_callback_(system_event_id_t event, system_event_i break; } case SYSTEM_EVENT_STA_DISCONNECTED: { +#if ESP_IDF_VERSION_MAJOR >= 4 + auto it = info.wifi_sta_disconnected; +#else auto it = info.disconnected; +#endif char buf[33]; memcpy(buf, it.ssid, it.ssid_len); buf[it.ssid_len] = '\0'; @@ -388,7 +411,11 @@ void WiFiComponent::wifi_event_callback_(system_event_id_t event, system_event_i break; } case SYSTEM_EVENT_STA_AUTHMODE_CHANGE: { +#if ESP_IDF_VERSION_MAJOR >= 4 + auto it = info.wifi_sta_authmode_change; +#else auto it = info.auth_change; +#endif ESP_LOGV(TAG, "Event: Authmode Change old=%s new=%s", get_auth_mode_str(it.old_mode), get_auth_mode_str(it.new_mode)); // Mitigate CVE-2020-12638 @@ -424,13 +451,25 @@ void WiFiComponent::wifi_event_callback_(system_event_id_t event, system_event_i break; } case SYSTEM_EVENT_AP_STACONNECTED: { +#if ESP_IDF_VERSION_MAJOR >= 4 + auto it = info.wifi_sta_connected; + auto &mac = it.bssid; +#else auto it = info.sta_connected; - ESP_LOGV(TAG, "Event: AP client connected MAC=%s aid=%u", format_mac_addr(it.mac).c_str(), it.aid); + auto &mac = it.mac; +#endif + ESP_LOGV(TAG, "Event: AP client connected MAC=%s", format_mac_addr(mac).c_str()); break; } case SYSTEM_EVENT_AP_STADISCONNECTED: { +#if ESP_IDF_VERSION_MAJOR >= 4 + auto it = info.wifi_sta_disconnected; + auto &mac = it.bssid; +#else auto it = info.sta_disconnected; - ESP_LOGV(TAG, "Event: AP client disconnected MAC=%s aid=%u", format_mac_addr(it.mac).c_str(), it.aid); + auto &mac = it.mac; +#endif + ESP_LOGV(TAG, "Event: AP client disconnected MAC=%s", format_mac_addr(mac).c_str()); break; } case SYSTEM_EVENT_AP_STAIPASSIGNED: { @@ -438,7 +477,11 @@ void WiFiComponent::wifi_event_callback_(system_event_id_t event, system_event_i break; } case SYSTEM_EVENT_AP_PROBEREQRECVED: { +#if ESP_IDF_VERSION_MAJOR >= 4 + auto it = info.wifi_ap_probereqrecved; +#else auto it = info.ap_probereqrecved; +#endif ESP_LOGVV(TAG, "Event: AP receive Probe Request MAC=%s RSSI=%d", format_mac_addr(it.mac).c_str(), it.rssi); break; } @@ -446,8 +489,13 @@ void WiFiComponent::wifi_event_callback_(system_event_id_t event, system_event_i break; } +#if ESP_IDF_VERSION_MAJOR >= 4 + if (event == ARDUINO_EVENT_WIFI_STA_DISCONNECTED) { + uint8_t reason = info.wifi_sta_disconnected.reason; +#else if (event == SYSTEM_EVENT_STA_DISCONNECTED) { uint8_t reason = info.disconnected.reason; +#endif if (reason == WIFI_REASON_AUTH_EXPIRE || reason == WIFI_REASON_BEACON_TIMEOUT || reason == WIFI_REASON_NO_AP_FOUND || reason == WIFI_REASON_ASSOC_FAIL || reason == WIFI_REASON_HANDSHAKE_TIMEOUT) { @@ -458,7 +506,11 @@ void WiFiComponent::wifi_event_callback_(system_event_id_t event, system_event_i this->error_from_callback_ = true; } } +#if ESP_IDF_VERSION_MAJOR >= 4 + if (event == ARDUINO_EVENT_WIFI_SCAN_DONE) { +#else if (event == SYSTEM_EVENT_SCAN_DONE) { +#endif this->wifi_scan_done_callback_(); } } From cdc9c99d4087b3ddac62c74f1ec3c7a964d4961c Mon Sep 17 00:00:00 2001 From: Yuval Aboulafia Date: Wed, 12 May 2021 01:16:59 +0300 Subject: [PATCH 025/104] Use core constants for sample duration on bh1750 (#1764) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/bh1750/bh1750.cpp | 6 +++--- esphome/components/bh1750/bh1750.h | 4 ++-- esphome/components/bh1750/sensor.py | 8 ++++++-- tests/test1.yaml | 2 +- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/esphome/components/bh1750/bh1750.cpp b/esphome/components/bh1750/bh1750.cpp index 2ec297a6f4..799440fdfc 100644 --- a/esphome/components/bh1750/bh1750.cpp +++ b/esphome/components/bh1750/bh1750.cpp @@ -17,8 +17,8 @@ void BH1750Sensor::setup() { return; } - uint8_t mtreg_hi = (this->measurement_time_ >> 5) & 0b111; - uint8_t mtreg_lo = (this->measurement_time_ >> 0) & 0b11111; + uint8_t mtreg_hi = (this->measurement_duration_ >> 5) & 0b111; + uint8_t mtreg_lo = (this->measurement_duration_ >> 0) & 0b11111; this->write_bytes(BH1750_COMMAND_MT_REG_HI | mtreg_hi, nullptr, 0); this->write_bytes(BH1750_COMMAND_MT_REG_LO | mtreg_lo, nullptr, 0); } @@ -77,7 +77,7 @@ void BH1750Sensor::read_data_() { } float lx = float(raw_value) / 1.2f; - lx *= 69.0f / this->measurement_time_; + lx *= 69.0f / this->measurement_duration_; ESP_LOGD(TAG, "'%s': Got illuminance=%.1flx", this->get_name().c_str(), lx); this->publish_state(lx); this->status_clear_warning(); diff --git a/esphome/components/bh1750/bh1750.h b/esphome/components/bh1750/bh1750.h index 00abd53e92..c88fa10832 100644 --- a/esphome/components/bh1750/bh1750.h +++ b/esphome/components/bh1750/bh1750.h @@ -28,7 +28,7 @@ class BH1750Sensor : public sensor::Sensor, public PollingComponent, public i2c: * @param resolution The new resolution of the sensor. */ void set_resolution(BH1750Resolution resolution); - void set_measurement_time(uint8_t measurement_time) { measurement_time_ = measurement_time; } + void set_measurement_duration(uint8_t measurement_duration) { measurement_duration_ = measurement_duration; } // ========== INTERNAL METHODS ========== // (In most use cases you won't need these) @@ -41,7 +41,7 @@ class BH1750Sensor : public sensor::Sensor, public PollingComponent, public i2c: void read_data_(); BH1750Resolution resolution_{BH1750_RESOLUTION_0P5_LX}; - uint8_t measurement_time_; + uint8_t measurement_duration_; }; } // namespace bh1750 diff --git a/esphome/components/bh1750/sensor.py b/esphome/components/bh1750/sensor.py index 9ad1b7eadb..0e37b2b865 100644 --- a/esphome/components/bh1750/sensor.py +++ b/esphome/components/bh1750/sensor.py @@ -7,6 +7,7 @@ from esphome.const import ( DEVICE_CLASS_ILLUMINANCE, ICON_EMPTY, UNIT_LUX, + CONF_MEASUREMENT_DURATION, ) DEPENDENCIES = ["i2c"] @@ -32,9 +33,12 @@ CONFIG_SCHEMA = ( cv.Optional(CONF_RESOLUTION, default=0.5): cv.enum( BH1750_RESOLUTIONS, float=True ), - cv.Optional(CONF_MEASUREMENT_TIME, default=69): cv.int_range( + cv.Optional(CONF_MEASUREMENT_DURATION, default=69): cv.int_range( min=31, max=254 ), + cv.Optional(CONF_MEASUREMENT_TIME): cv.invalid( + "The 'measurement_time' option has been replaced with 'measurement_duration' in 1.18.0" + ), } ) .extend(cv.polling_component_schema("60s")) @@ -49,4 +53,4 @@ def to_code(config): yield i2c.register_i2c_device(var, config) cg.add(var.set_resolution(config[CONF_RESOLUTION])) - cg.add(var.set_measurement_time(config[CONF_MEASUREMENT_TIME])) + cg.add(var.set_measurement_duration(config[CONF_MEASUREMENT_DURATION])) diff --git a/tests/test1.yaml b/tests/test1.yaml index c5c39fb52d..885495b949 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -412,7 +412,7 @@ sensor: retain: False availability: state_topic: livingroom/custom_state_topic - measurement_time: 31 + measurement_duration: 31 - platform: bme280 temperature: name: 'Outside Temperature' From 6aa61dbce752ec08fc5ee047ebc01d58f25f7e39 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 May 2021 15:25:23 +1200 Subject: [PATCH 026/104] Bump black from 21.5b0 to 21.5b1 (#1768) Bumps [black](https://github.com/psf/black) from 21.5b0 to 21.5b1. - [Release notes](https://github.com/psf/black/releases) - [Changelog](https://github.com/psf/black/blob/main/CHANGES.md) - [Commits](https://github.com/psf/black/commits) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements_test.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_test.txt b/requirements_test.txt index e612d5871b..2efc27c113 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -1,6 +1,6 @@ pylint==2.8.2 flake8==3.9.0 -black==21.5b0 +black==21.5b1 pillow>4.0.0 cryptography>=2.0.0,<4 pexpect==4.8.0 From ea80cb751b4645d4b4aca0877956eea93008e0ca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 May 2021 15:33:20 +1200 Subject: [PATCH 027/104] Bump flake8 from 3.9.0 to 3.9.2 (#1763) Bumps [flake8](https://gitlab.com/pycqa/flake8) from 3.9.0 to 3.9.2. - [Release notes](https://gitlab.com/pycqa/flake8/tags) - [Commits](https://gitlab.com/pycqa/flake8/compare/3.9.0...3.9.2) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements_test.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_test.txt b/requirements_test.txt index 2efc27c113..2ca45c2252 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -1,5 +1,5 @@ pylint==2.8.2 -flake8==3.9.0 +flake8==3.9.2 black==21.5b1 pillow>4.0.0 cryptography>=2.0.0,<4 From 4030a2e253333685729bc112f0e550db76e9a732 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 May 2021 15:44:33 +1200 Subject: [PATCH 028/104] Bump pytest from 6.2.3 to 6.2.4 (#1769) Bumps [pytest](https://github.com/pytest-dev/pytest) from 6.2.3 to 6.2.4. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/6.2.3...6.2.4) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements_test.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_test.txt b/requirements_test.txt index 2ca45c2252..ecfaed5d05 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -7,7 +7,7 @@ pexpect==4.8.0 pre-commit # Unit tests -pytest==6.2.3 +pytest==6.2.4 pytest-cov==2.11.1 pytest-mock==3.5.1 asyncmock==0.4.2 From 29fc4af0fce5d19dcdbf6abe5fb139157022d959 Mon Sep 17 00:00:00 2001 From: krunkel Date: Wed, 12 May 2021 05:50:26 +0200 Subject: [PATCH 029/104] Add delay to aht10.cpp (#1498) --- esphome/components/aht10/aht10.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/aht10/aht10.cpp b/esphome/components/aht10/aht10.cpp index 6951254e0d..d3a77fee5f 100644 --- a/esphome/components/aht10/aht10.cpp +++ b/esphome/components/aht10/aht10.cpp @@ -60,6 +60,7 @@ void AHT10Component::update() { delay = AHT10_HUMIDITY_DELAY; for (int i = 0; i < AHT10_ATTEMPS; ++i) { ESP_LOGVV(TAG, "Attemps %u at %6ld", i, millis()); + delay_microseconds_accurate(4); if (!this->read_bytes(0, data, 6, delay)) { ESP_LOGD(TAG, "Communication with AHT10 failed, waiting..."); } else if ((data[0] & 0x80) == 0x80) { // Bit[7] = 0b1, device is busy From 1e46b4073f30292059bd530c19798ec0978ac6a7 Mon Sep 17 00:00:00 2001 From: RubyBailey <60991881+RubyBailey@users.noreply.github.com> Date: Tue, 11 May 2021 21:07:28 -0700 Subject: [PATCH 030/104] Mitsubishi Heat Pump - Fixed default transmit_state to be generic instead of for a specific type of heat pump (#1414) Co-authored-by: RubyBailey Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/mitsubishi/climate.py | 1 + esphome/components/mitsubishi/mitsubishi.cpp | 4 ++-- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index e15de721b9..7a9677cb53 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -63,6 +63,7 @@ esphome/components/mcp2515/* @danielschramm @mvturnho esphome/components/mcp9808/* @k7hpn esphome/components/midea_ac/* @dudanov esphome/components/midea_dongle/* @dudanov +esphome/components/mitsubishi/* @RubyBailey esphome/components/network/* @esphome/core esphome/components/nfc/* @jesserockz esphome/components/ota/* @esphome/core diff --git a/esphome/components/mitsubishi/climate.py b/esphome/components/mitsubishi/climate.py index c08baf7e54..f150985d28 100644 --- a/esphome/components/mitsubishi/climate.py +++ b/esphome/components/mitsubishi/climate.py @@ -3,6 +3,7 @@ import esphome.config_validation as cv from esphome.components import climate_ir from esphome.const import CONF_ID +CODEOWNERS = ["@RubyBailey"] AUTO_LOAD = ["climate_ir"] mitsubishi_ns = cg.esphome_ns.namespace("mitsubishi") diff --git a/esphome/components/mitsubishi/mitsubishi.cpp b/esphome/components/mitsubishi/mitsubishi.cpp index b70aa6d394..dbc70af75c 100644 --- a/esphome/components/mitsubishi/mitsubishi.cpp +++ b/esphome/components/mitsubishi/mitsubishi.cpp @@ -23,8 +23,8 @@ const uint16_t MITSUBISHI_HEADER_SPACE = 1700; const uint16_t MITSUBISHI_MIN_GAP = 17500; void MitsubishiClimate::transmit_state() { - uint32_t remote_state[18] = {0x23, 0xCB, 0x26, 0x01, 0x00, 0x20, 0x48, 0x00, 0x30, - 0x58, 0x61, 0x00, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00}; + uint32_t remote_state[18] = {0x23, 0xCB, 0x26, 0x01, 0x00, 0x20, 0x08, 0x00, 0x30, + 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; switch (this->mode) { case climate::CLIMATE_MODE_COOL: From 5dc40049bead0db592a9217d605497eb59d48326 Mon Sep 17 00:00:00 2001 From: onde2rock Date: Wed, 12 May 2021 06:38:29 +0200 Subject: [PATCH 031/104] Add function to set SDS011 sensor in sleeping state (#1416) Co-authored-by: aurelien --- esphome/components/sds011/sds011.cpp | 15 +++++++++++++++ esphome/components/sds011/sds011.h | 1 + 2 files changed, 16 insertions(+) diff --git a/esphome/components/sds011/sds011.cpp b/esphome/components/sds011/sds011.cpp index 1a5be0adc3..ddcbdbb712 100644 --- a/esphome/components/sds011/sds011.cpp +++ b/esphome/components/sds011/sds011.cpp @@ -50,6 +50,21 @@ void SDS011Component::setup() { this->sds011_write_command_(command_data); } +void SDS011Component::set_working_state(bool working_state) { + if (this->rx_mode_only_) { + // In RX-only mode we do not setup the sensor, it is assumed to be setup + // already + return; + } + uint8_t command_data[SDS011_DATA_REQUEST_LENGTH] = {0}; + command_data[0] = SDS011_COMMAND_SLEEP; + command_data[1] = SDS011_SET_MODE; + command_data[2] = working_state ? SDS011_MODE_WORK : SDS011_MODE_SLEEP; + command_data[13] = 0xff; + command_data[14] = 0xff; + this->sds011_write_command_(command_data); +} + void SDS011Component::dump_config() { ESP_LOGCONFIG(TAG, "SDS011:"); ESP_LOGCONFIG(TAG, " Update Interval: %u min", this->update_interval_min_); diff --git a/esphome/components/sds011/sds011.h b/esphome/components/sds011/sds011.h index 83f89df237..19e0cd3efe 100644 --- a/esphome/components/sds011/sds011.h +++ b/esphome/components/sds011/sds011.h @@ -25,6 +25,7 @@ class SDS011Component : public Component, public uart::UARTDevice { void set_update_interval(uint32_t val) { /* ignore */ } void set_update_interval_min(uint8_t update_interval_min); + void set_working_state(bool working_state); protected: void sds011_write_command_(const uint8_t *command); From 54660300e94c52819506c058d00828ee84de914e Mon Sep 17 00:00:00 2001 From: BoukeHaarsma23 Date: Wed, 12 May 2021 21:14:01 +0200 Subject: [PATCH 032/104] Add sm2135 component (#1736) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/sm2135/__init__.py | 33 +++++++++++ esphome/components/sm2135/output.py | 28 +++++++++ esphome/components/sm2135/sm2135.cpp | 81 ++++++++++++++++++++++++++ esphome/components/sm2135/sm2135.h | 82 +++++++++++++++++++++++++++ tests/test3.yaml | 19 +++++++ 6 files changed, 244 insertions(+) create mode 100644 esphome/components/sm2135/__init__.py create mode 100644 esphome/components/sm2135/output.py create mode 100644 esphome/components/sm2135/sm2135.cpp create mode 100644 esphome/components/sm2135/sm2135.h diff --git a/CODEOWNERS b/CODEOWNERS index 7a9677cb53..356cf07e2b 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -86,6 +86,7 @@ esphome/components/sgp40/* @SenexCrenshaw esphome/components/sht4x/* @sjtrny esphome/components/shutdown/* @esphome/core esphome/components/sim800l/* @glmnet +esphome/components/sm2135/* @BoukeHaarsma23 esphome/components/spi/* @esphome/core esphome/components/ssd1322_base/* @kbx81 esphome/components/ssd1322_spi/* @kbx81 diff --git a/esphome/components/sm2135/__init__.py b/esphome/components/sm2135/__init__.py new file mode 100644 index 0000000000..019a1c68c1 --- /dev/null +++ b/esphome/components/sm2135/__init__.py @@ -0,0 +1,33 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome import pins +from esphome.const import ( + CONF_CLOCK_PIN, + CONF_DATA_PIN, + CONF_ID, +) + +AUTO_LOAD = ["output"] +CODEOWNERS = ["@BoukeHaarsma23"] + +sm2135_ns = cg.esphome_ns.namespace("sm2135") +SM2135 = sm2135_ns.class_("SM2135", cg.Component) + +MULTI_CONF = True +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(): cv.declare_id(SM2135), + cv.Required(CONF_DATA_PIN): pins.gpio_output_pin_schema, + cv.Required(CONF_CLOCK_PIN): pins.gpio_output_pin_schema, + } +).extend(cv.COMPONENT_SCHEMA) + + +def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + yield cg.register_component(var, config) + + data = yield cg.gpio_pin_expression(config[CONF_DATA_PIN]) + cg.add(var.set_data_pin(data)) + clock = yield cg.gpio_pin_expression(config[CONF_CLOCK_PIN]) + cg.add(var.set_clock_pin(clock)) diff --git a/esphome/components/sm2135/output.py b/esphome/components/sm2135/output.py new file mode 100644 index 0000000000..86f6db1bb4 --- /dev/null +++ b/esphome/components/sm2135/output.py @@ -0,0 +1,28 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import output +from esphome.const import CONF_CHANNEL, CONF_ID +from . import SM2135 + +DEPENDENCIES = ["sm2135"] +CODEOWNERS = ["@BoukeHaarsma23"] + +Channel = SM2135.class_("Channel", output.FloatOutput) + +CONF_SM2135_ID = "sm2135_id" +CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( + { + cv.GenerateID(CONF_SM2135_ID): cv.use_id(SM2135), + cv.Required(CONF_ID): cv.declare_id(Channel), + cv.Required(CONF_CHANNEL): cv.int_range(min=0, max=65535), + } +).extend(cv.COMPONENT_SCHEMA) + + +def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + yield output.register_output(var, config) + + parent = yield cg.get_variable(config[CONF_SM2135_ID]) + cg.add(var.set_parent(parent)) + cg.add(var.set_channel(config[CONF_CHANNEL])) diff --git a/esphome/components/sm2135/sm2135.cpp b/esphome/components/sm2135/sm2135.cpp new file mode 100644 index 0000000000..3991c220ec --- /dev/null +++ b/esphome/components/sm2135/sm2135.cpp @@ -0,0 +1,81 @@ +#include "sm2135.h" +#include "esphome/core/log.h" + +// Tnx to the work of https://github.com/arendst (Tasmota) for making the initial version of the driver + +namespace esphome { +namespace sm2135 { + +static const char *TAG = "sm2135"; + +static const uint8_t SM2135_ADDR_MC = 0xC0; // Max current register +static const uint8_t SM2135_ADDR_CH = 0xC1; // RGB or CW channel select register +static const uint8_t SM2135_ADDR_R = 0xC2; // Red color +static const uint8_t SM2135_ADDR_G = 0xC3; // Green color +static const uint8_t SM2135_ADDR_B = 0xC4; // Blue color +static const uint8_t SM2135_ADDR_C = 0xC5; // Cold +static const uint8_t SM2135_ADDR_W = 0xC6; // Warm + +static const uint8_t SM2135_RGB = 0x00; // RGB channel +static const uint8_t SM2135_CW = 0x80; // CW channel (Chip default) + +static const uint8_t SM2135_10MA = 0x00; +static const uint8_t SM2135_15MA = 0x01; +static const uint8_t SM2135_20MA = 0x02; // RGB max current (Chip default) +static const uint8_t SM2135_25MA = 0x03; +static const uint8_t SM2135_30MA = 0x04; // CW max current (Chip default) +static const uint8_t SM2135_35MA = 0x05; +static const uint8_t SM2135_40MA = 0x06; +static const uint8_t SM2135_45MA = 0x07; // Max value for RGB +static const uint8_t SM2135_50MA = 0x08; +static const uint8_t SM2135_55MA = 0x09; +static const uint8_t SM2135_60MA = 0x0A; + +static const uint8_t SM2135_CURRENT = (SM2135_20MA << 4) | SM2135_10MA; + +void SM2135::setup() { + ESP_LOGCONFIG(TAG, "Setting up SM2135OutputComponent..."); + this->data_pin_->setup(); + this->data_pin_->digital_write(true); + this->clock_pin_->setup(); + this->clock_pin_->digital_write(true); + this->pwm_amounts_.resize(5, 0); +} +void SM2135::dump_config() { + ESP_LOGCONFIG(TAG, "SM2135:"); + LOG_PIN(" Data Pin: ", this->data_pin_); + LOG_PIN(" Clock Pin: ", this->clock_pin_); +} + +void SM2135::loop() { + if (!this->update_) + return; + + uint8_t data[6]; + if (this->update_channel_ == 3 || this->update_channel_ == 4) { + // No color so must be Cold/Warm + data[0] = SM2135_ADDR_MC; + data[1] = SM2135_CURRENT; + data[2] = SM2135_CW; + this->write_buffer_(data, 3); + delay(1); + data[0] = SM2135_ADDR_C; + data[1] = this->pwm_amounts_[4]; // Warm + data[2] = this->pwm_amounts_[3]; // Cold + this->write_buffer_(data, 3); + } else { + // Color + data[0] = SM2135_ADDR_MC; + data[1] = SM2135_CURRENT; + data[2] = SM2135_RGB; + data[3] = this->pwm_amounts_[1]; // Green + data[4] = this->pwm_amounts_[0]; // Red + data[5] = this->pwm_amounts_[2]; // Blue + this->write_buffer_(data, 6); + } + + this->update_ = false; +} + +} // namespace sm2135 +} // namespace esphome diff --git a/esphome/components/sm2135/sm2135.h b/esphome/components/sm2135/sm2135.h new file mode 100644 index 0000000000..e39730579f --- /dev/null +++ b/esphome/components/sm2135/sm2135.h @@ -0,0 +1,82 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/esphal.h" +#include "esphome/components/output/float_output.h" + +namespace esphome { +namespace sm2135 { + +class SM2135 : public Component { + public: + class Channel; + + void set_data_pin(GPIOPin *data_pin) { data_pin_ = data_pin; } + void set_clock_pin(GPIOPin *clock_pin) { clock_pin_ = clock_pin; } + + void setup() override; + + void dump_config() override; + + float get_setup_priority() const override { return setup_priority::HARDWARE; } + + /// Send new values if they were updated. + void loop() override; + + class Channel : public output::FloatOutput { + public: + void set_parent(SM2135 *parent) { parent_ = parent; } + void set_channel(uint8_t channel) { channel_ = channel; } + + protected: + void write_state(float state) override { + auto amount = static_cast(state * 0xff); + this->parent_->set_channel_value_(this->channel_, amount); + } + + SM2135 *parent_; + uint8_t channel_; + }; + + protected: + void set_channel_value_(uint8_t channel, uint8_t value) { + if (this->pwm_amounts_[channel] != value) { + this->update_ = true; + this->update_channel_ = channel; + } + this->pwm_amounts_[channel] = value; + } + void write_bit_(bool value) { + this->clock_pin_->digital_write(false); + this->data_pin_->digital_write(value); + this->clock_pin_->digital_write(true); + } + + void write_byte_(uint8_t data) { + for (uint8_t mask = 0x80; mask; mask >>= 1) { + this->write_bit_(data & mask); + } + this->clock_pin_->digital_write(false); + this->data_pin_->digital_write(true); + this->clock_pin_->digital_write(true); + } + + void write_buffer_(uint8_t *buffer, uint8_t size) { + this->data_pin_->digital_write(false); + for (uint32_t i = 0; i < size; i++) { + this->write_byte_(buffer[i]); + } + this->clock_pin_->digital_write(false); + this->clock_pin_->digital_write(true); + this->data_pin_->digital_write(true); + } + + GPIOPin *data_pin_; + GPIOPin *clock_pin_; + uint8_t update_channel_; + std::vector pwm_amounts_; + bool update_{true}; +}; + +} // namespace sm2135 +} // namespace esphome diff --git a/tests/test3.yaml b/tests/test3.yaml index 8781c935a1..8104c70fbf 100644 --- a/tests/test3.yaml +++ b/tests/test3.yaml @@ -586,6 +586,10 @@ script: then: - lambda: 'ESP_LOGD("main", "Hello World!");' +sm2135: + data_pin: GPIO12 + clock_pin: GPIO14 + switch: - platform: template name: 'mpr121_toggle' @@ -828,6 +832,21 @@ output: pin: GPIO5 id: my_slow_pwm period: 15s + - platform: sm2135 + id: sm2135_0 + channel: 0 + - platform: sm2135 + id: sm2135_1 + channel: 1 + - platform: sm2135 + id: sm2135_2 + channel: 2 + - platform: sm2135 + id: sm2135_3 + channel: 3 + - platform: sm2135 + id: sm2135_4 + channel: 4 mcp23017: id: mcp23017_hub From 00c144daeb8c7ef3129947509b5f2b2fd9467fd1 Mon Sep 17 00:00:00 2001 From: Stanislav Meduna Date: Thu, 13 May 2021 22:36:53 +0200 Subject: [PATCH 033/104] Autorepeat filter for the binary sensors (#1681) * add the autorepeat filter * add a test for the autorepeat filter * make no timing equivalent to a single default one --- esphome/components/binary_sensor/__init__.py | 47 ++++++++++++++++++++ esphome/components/binary_sensor/filter.cpp | 44 ++++++++++++++++++ esphome/components/binary_sensor/filter.h | 27 +++++++++++ tests/test4.yaml | 14 ++++++ 4 files changed, 132 insertions(+) diff --git a/esphome/components/binary_sensor/__init__.py b/esphome/components/binary_sensor/__init__.py index 56e6b7dc97..5d4b227d70 100644 --- a/esphome/components/binary_sensor/__init__.py +++ b/esphome/components/binary_sensor/__init__.py @@ -4,6 +4,7 @@ from esphome import automation, core from esphome.automation import Condition, maybe_simple_id from esphome.components import mqtt from esphome.const import ( + CONF_DELAY, CONF_DEVICE_CLASS, CONF_FILTERS, CONF_ID, @@ -120,6 +121,7 @@ DelayedOnOffFilter = binary_sensor_ns.class_("DelayedOnOffFilter", Filter, cg.Co DelayedOnFilter = binary_sensor_ns.class_("DelayedOnFilter", Filter, cg.Component) DelayedOffFilter = binary_sensor_ns.class_("DelayedOffFilter", Filter, cg.Component) InvertFilter = binary_sensor_ns.class_("InvertFilter", Filter) +AutorepeatFilter = binary_sensor_ns.class_("AutorepeatFilter", Filter, cg.Component) LambdaFilter = binary_sensor_ns.class_("LambdaFilter", Filter) FILTER_REGISTRY = Registry() @@ -158,6 +160,51 @@ def delayed_off_filter_to_code(config, filter_id): yield var +CONF_TIME_OFF = "time_off" +CONF_TIME_ON = "time_on" + +DEFAULT_DELAY = "1s" +DEFAULT_TIME_OFF = "100ms" +DEFAULT_TIME_ON = "900ms" + + +@FILTER_REGISTRY.register( + "autorepeat", + AutorepeatFilter, + cv.All( + cv.ensure_list( + { + cv.Optional( + CONF_DELAY, default=DEFAULT_DELAY + ): cv.positive_time_period_milliseconds, + cv.Optional( + CONF_TIME_OFF, default=DEFAULT_TIME_OFF + ): cv.positive_time_period_milliseconds, + cv.Optional( + CONF_TIME_ON, default=DEFAULT_TIME_ON + ): cv.positive_time_period_milliseconds, + } + ), + ), +) +def autorepeat_filter_to_code(config, filter_id): + timings = [] + if len(config) > 0: + for conf in config: + timings.append((conf[CONF_DELAY], conf[CONF_TIME_OFF], conf[CONF_TIME_ON])) + else: + timings.append( + ( + cv.time_period_str_unit(DEFAULT_DELAY).total_milliseconds, + cv.time_period_str_unit(DEFAULT_TIME_OFF).total_milliseconds, + cv.time_period_str_unit(DEFAULT_TIME_ON).total_milliseconds, + ) + ) + var = cg.new_Pvariable(filter_id, timings) + yield cg.register_component(var, {}) + yield var + + @FILTER_REGISTRY.register("lambda", LambdaFilter, cv.returning_lambda) def lambda_filter_to_code(config, filter_id): lambda_ = yield cg.process_lambda( diff --git a/esphome/components/binary_sensor/filter.cpp b/esphome/components/binary_sensor/filter.cpp index f4612d62e9..c6ca3e2f79 100644 --- a/esphome/components/binary_sensor/filter.cpp +++ b/esphome/components/binary_sensor/filter.cpp @@ -64,6 +64,50 @@ float DelayedOffFilter::get_setup_priority() const { return setup_priority::HARD optional InvertFilter::new_value(bool value, bool is_initial) { return !value; } +AutorepeatFilter::AutorepeatFilter(const std::vector &timings) : timings_(timings) {} + +optional AutorepeatFilter::new_value(bool value, bool is_initial) { + if (value) { + // Ignore if already running + if (this->active_timing_ != 0) + return {}; + + this->next_timing_(); + return true; + } else { + this->cancel_timeout("TIMING"); + this->cancel_timeout("ON_OFF"); + this->active_timing_ = 0; + return false; + } +} + +void AutorepeatFilter::next_timing_() { + // Entering this method + // 1st time: starts waiting the first delay + // 2nd time: starts waiting the second delay and starts toggling with the first time_off / _on + // last time: no delay to start but have to bump the index to reflect the last + if (this->active_timing_ < this->timings_.size()) + this->set_timeout("TIMING", this->timings_[this->active_timing_].delay, [this]() { this->next_timing_(); }); + + if (this->active_timing_ <= this->timings_.size()) { + this->active_timing_++; + } + + if (this->active_timing_ == 2) + this->next_value_(false); + + // Leaving this method: if the toggling is started, it has to use [active_timing_ - 2] for the intervals +} + +void AutorepeatFilter::next_value_(bool val) { + const AutorepeatFilterTiming &timing = this->timings_[this->active_timing_ - 2]; + this->output(val, false); // This is at least the second one so not initial + this->set_timeout("ON_OFF", val ? timing.time_on : timing.time_off, [this, val]() { this->next_value_(!val); }); +} + +float AutorepeatFilter::get_setup_priority() const { return setup_priority::HARDWARE; } + LambdaFilter::LambdaFilter(const std::function(bool)> &f) : f_(f) {} optional LambdaFilter::new_value(bool value, bool is_initial) { return this->f_(value); } diff --git a/esphome/components/binary_sensor/filter.h b/esphome/components/binary_sensor/filter.h index 0b54251cda..8528e74a9f 100644 --- a/esphome/components/binary_sensor/filter.h +++ b/esphome/components/binary_sensor/filter.h @@ -66,6 +66,33 @@ class InvertFilter : public Filter { optional new_value(bool value, bool is_initial) override; }; +struct AutorepeatFilterTiming { + AutorepeatFilterTiming(uint32_t delay, uint32_t off, uint32_t on) { + this->delay = delay; + this->time_off = off; + this->time_on = on; + } + uint32_t delay; + uint32_t time_off; + uint32_t time_on; +}; + +class AutorepeatFilter : public Filter, public Component { + public: + explicit AutorepeatFilter(const std::vector &timings); + + optional new_value(bool value, bool is_initial) override; + + float get_setup_priority() const override; + + protected: + void next_timing_(); + void next_value_(bool val); + + std::vector timings_; + uint8_t active_timing_{0}; +}; + class LambdaFilter : public Filter { public: explicit LambdaFilter(const std::function(bool)> &f); diff --git a/tests/test4.yaml b/tests/test4.yaml index e85cdfbc19..d2dcb8b682 100644 --- a/tests/test4.yaml +++ b/tests/test4.yaml @@ -86,6 +86,20 @@ binary_sensor: - platform: tuya id: tuya_binary_sensor sensor_datapoint: 1 + - platform: template + id: ar1 + lambda: 'return {};' + filters: + - autorepeat: + - delay: 2s + time_off: 100ms + time_on: 900ms + - delay: 4s + time_off: 100ms + time_on: 400ms + on_state: + then: + - lambda: 'ESP_LOGI("ar1:", "%d", x);' climate: - platform: tuya From 4f6982fbc5130ad288749ce2386a205ca891e3d6 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 14 May 2021 20:06:31 +1200 Subject: [PATCH 034/104] Add action to set total pulses on pulse_meter (#1757) --- esphome/components/pulse_meter/automation.h | 24 +++++++++++++++++++ .../pulse_meter/pulse_meter_sensor.cpp | 2 ++ .../pulse_meter/pulse_meter_sensor.h | 2 ++ esphome/components/pulse_meter/sensor.py | 23 +++++++++++++++++- tests/test1.yaml | 12 ++++++---- 5 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 esphome/components/pulse_meter/automation.h diff --git a/esphome/components/pulse_meter/automation.h b/esphome/components/pulse_meter/automation.h new file mode 100644 index 0000000000..3112ded680 --- /dev/null +++ b/esphome/components/pulse_meter/automation.h @@ -0,0 +1,24 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/automation.h" +#include "esphome/components/pulse_meter/pulse_meter_sensor.h" + +namespace esphome { + +namespace pulse_meter { + +template class SetTotalPulsesAction : public Action { + public: + SetTotalPulsesAction(PulseMeterSensor *pulse_meter) : pulse_meter_(pulse_meter) {} + + TEMPLATABLE_VALUE(uint32_t, total_pulses) + + void play(Ts... x) override { this->pulse_meter_->set_total_pulses(this->total_pulses_.value(x...)); } + + protected: + PulseMeterSensor *pulse_meter_; +}; + +} // namespace pulse_meter +} // namespace esphome diff --git a/esphome/components/pulse_meter/pulse_meter_sensor.cpp b/esphome/components/pulse_meter/pulse_meter_sensor.cpp index 8cf341c8a1..7728930ec1 100644 --- a/esphome/components/pulse_meter/pulse_meter_sensor.cpp +++ b/esphome/components/pulse_meter/pulse_meter_sensor.cpp @@ -48,6 +48,8 @@ void PulseMeterSensor::loop() { } } +void PulseMeterSensor::set_total_pulses(uint32_t pulses) { this->total_pulses_ = pulses; } + void PulseMeterSensor::dump_config() { LOG_SENSOR("", "Pulse Meter", this); LOG_PIN(" Pin: ", this->pin_); diff --git a/esphome/components/pulse_meter/pulse_meter_sensor.h b/esphome/components/pulse_meter/pulse_meter_sensor.h index 7d3adbbbcb..d02cff6123 100644 --- a/esphome/components/pulse_meter/pulse_meter_sensor.h +++ b/esphome/components/pulse_meter/pulse_meter_sensor.h @@ -15,6 +15,8 @@ class PulseMeterSensor : public sensor::Sensor, public Component { void set_timeout_us(uint32_t timeout) { this->timeout_us_ = timeout; } void set_total_sensor(sensor::Sensor *sensor) { this->total_sensor_ = sensor; } + void set_total_pulses(uint32_t pulses); + void setup() override; void loop() override; float get_setup_priority() const override { return setup_priority::DATA; } diff --git a/esphome/components/pulse_meter/sensor.py b/esphome/components/pulse_meter/sensor.py index 37827b735d..c7256b2987 100644 --- a/esphome/components/pulse_meter/sensor.py +++ b/esphome/components/pulse_meter/sensor.py @@ -1,6 +1,6 @@ import esphome.codegen as cg import esphome.config_validation as cv -from esphome import pins +from esphome import automation, pins from esphome.components import sensor from esphome.const import ( CONF_ID, @@ -9,6 +9,7 @@ from esphome.const import ( CONF_NUMBER, CONF_TIMEOUT, CONF_TOTAL, + CONF_VALUE, ICON_PULSE, UNIT_PULSES, UNIT_PULSES_PER_MINUTE, @@ -24,6 +25,8 @@ PulseMeterSensor = pulse_meter_ns.class_( "PulseMeterSensor", sensor.Sensor, cg.Component ) +SetTotalPulsesAction = pulse_meter_ns.class_("SetTotalPulsesAction", automation.Action) + def validate_internal_filter(value): return cv.positive_time_period_microseconds(value) @@ -73,3 +76,21 @@ def to_code(config): if CONF_TOTAL in config: sens = yield sensor.new_sensor(config[CONF_TOTAL]) cg.add(var.set_total_sensor(sens)) + + +@automation.register_action( + "pulse_meter.set_total_pulses", + SetTotalPulsesAction, + cv.Schema( + { + cv.Required(CONF_ID): cv.use_id(PulseMeterSensor), + cv.Required(CONF_VALUE): cv.templatable(cv.uint32_t), + } + ), +) +def set_total_action_to_code(config, action_id, template_arg, args): + paren = yield cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, paren) + template_ = yield cg.templatable(config[CONF_VALUE], args, int) + cg.add(var.set_total_pulses(template_)) + yield var diff --git a/tests/test1.yaml b/tests/test1.yaml index 885495b949..5695183f74 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -247,10 +247,10 @@ ble_client: id: ble_blah on_connect: then: - - switch.turn_on: ble1_status + - switch.turn_on: ble1_status on_disconnect: then: - - switch.turn_on: ble1_status + - switch.turn_on: ble1_status mcp23s08: - id: 'mcp23s08_hub' cs_pin: GPIO12 @@ -264,7 +264,7 @@ mcp23s17: sensor: - platform: ble_client ble_client_id: ble_foo - name: "Green iTag btn" + name: 'Green iTag btn' service_uuid: 'ffe0' characteristic_uuid: 'ffe1' descriptor_uuid: 'ffe2' @@ -658,9 +658,14 @@ sensor: update_interval: 15s - platform: pulse_meter name: 'Pulse Meter' + id: pulse_meter_sensor pin: GPIO12 internal_filter: 100ms timeout: 2 min + on_value: + - pulse_meter.set_total_pulses: + id: pulse_meter_sensor + value: 12345 total: name: 'Pulse Meter Total' - platform: rotary_encoder @@ -2037,7 +2042,6 @@ tca9548a: multiplexer: id: multiplex0 channel: 0 - pcf8574: - id: 'pcf8574_hub' From 3d6dcc9eeec5c5a8c0cd651ff88e4c01975c2a87 Mon Sep 17 00:00:00 2001 From: Guillermo Ruffino Date: Fri, 14 May 2021 20:35:39 -0300 Subject: [PATCH 035/104] Add more json schema generation features (#1690) * some enums * extract enums, light effects remote_receiver etc * more pins schema * update to core changes --- esphome/components/light/effects.py | 5 ++++ esphome/config_validation.py | 18 ++++++++++- script/build_jsonschema.py | 46 ++++++++++++++++++++++++----- 3 files changed, 60 insertions(+), 9 deletions(-) diff --git a/esphome/components/light/effects.py b/esphome/components/light/effects.py index 08a78d90ed..48785df523 100644 --- a/esphome/components/light/effects.py +++ b/esphome/components/light/effects.py @@ -1,3 +1,4 @@ +from esphome.jsonschema import jschema_extractor import esphome.codegen as cg import esphome.config_validation as cv from esphome import automation @@ -452,7 +453,11 @@ def addressable_flicker_effect_to_code(config, effect_id): def validate_effects(allowed_effects): + @jschema_extractor("effects") def validator(value): + # pylint: disable=comparison-with-callable + if value == jschema_extractor: + return (allowed_effects, EFFECTS_REGISTRY) value = cv.validate_registry("effect", EFFECTS_REGISTRY)(value) errors = [] names = set() diff --git a/esphome/config_validation.py b/esphome/config_validation.py index 24c86e6713..dcc0da8b2b 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -46,7 +46,13 @@ from esphome.core import ( TimePeriodMinutes, ) from esphome.helpers import list_starts_with, add_class_to_obj -from esphome.jsonschema import jschema_composite, jschema_registry, jschema_typed +from esphome.jsonschema import ( + jschema_composite, + jschema_extractor, + jschema_registry, + jschema_typed, +) + from esphome.voluptuous_schema import _Schema from esphome.yaml_util import make_data_base @@ -1121,7 +1127,12 @@ def one_of(*values, **kwargs): if kwargs: raise ValueError + @jschema_extractor("one_of") def validator(value): + # pylint: disable=comparison-with-callable + if value == jschema_extractor: + return values + if string_: value = string(value) value = value.replace(" ", space) @@ -1161,7 +1172,12 @@ def enum(mapping, **kwargs): assert isinstance(mapping, dict) one_of_validator = one_of(*mapping, **kwargs) + @jschema_extractor("enum") def validator(value): + # pylint: disable=comparison-with-callable + if value == jschema_extractor: + return mapping + value = one_of_validator(value) value = add_class_to_obj(value, core.EnumValue) value.enum_value = mapping[value] diff --git a/script/build_jsonschema.py b/script/build_jsonschema.py index 6d19e25e29..89d621fd5a 100644 --- a/script/build_jsonschema.py +++ b/script/build_jsonschema.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 +from esphome.cpp_generator import MockObj import json import argparse import os @@ -54,7 +55,7 @@ def is_ref(jschema): def unref(jschema): - return definitions[jschema[JSC_REF][len("#/definitions/") :]] + return definitions.get(jschema[JSC_REF][len("#/definitions/") :]) def add_definition_array_or_single_object(ref): @@ -104,8 +105,11 @@ def add_registry(registry_name, registry): for name in registry.keys(): schema = get_jschema(str(name), registry[name].schema, create_return_ref=False) if not schema: - schema = {"type": "string"} + schema = {"type": "null"} o_schema = {"type": "object", JSC_PROPERTIES: {name: schema}} + o_schema = create_ref( + registry_name + "-" + name, str(registry[name].schema) + "x", o_schema + ) validators.append(o_schema) definitions[registry_name] = {JSC_ANYOF: validators} @@ -134,7 +138,7 @@ def add_module_schemas(name, module): def get_dirs(): - from esphome.config import CORE_COMPONENTS_PATH + from esphome.loader import CORE_COMPONENTS_PATH dir_names = [ d @@ -146,7 +150,7 @@ def get_dirs(): def get_logger_tags(): - from esphome.config import CORE_COMPONENTS_PATH + from esphome.loader import CORE_COMPONENTS_PATH import glob pattern = re.compile(r'^static const char(\*\s|\s\*)TAG = "(\w.*)";', re.MULTILINE) @@ -241,7 +245,7 @@ def add_components(): elif c.config_schema is not None: # adds root components which are not platforms, e.g. api: logger: - if c.is_multi_conf: + if c.multi_conf: schema = get_jschema(domain, c.config_schema) schema = add_definition_array_or_single_object(schema) else: @@ -322,7 +326,6 @@ def get_entry(parent_key, vschema): elif str(vschema) in ejs.list_schemas: ref = get_jschema(parent_key, ejs.list_schemas[str(vschema)][0]) entry = {JSC_ANYOF: [ref, {"type": "array", "items": ref}]} - elif str(vschema) in ejs.typed_schemas: schema_types = [{"type": "object", "properties": {"type": {"type": "string"}}}] entry = {"allOf": schema_types} @@ -342,6 +345,22 @@ def get_entry(parent_key, vschema): entry = get_automation_schema(parent_key, inner_vschema) elif type == "maybe": entry = get_jschema(parent_key, inner_vschema) + elif type == "one_of": + entry = {"enum": list(inner_vschema)} + elif type == "enum": + entry = {"enum": list(inner_vschema.keys())} + elif type == "effects": + # Like list schema but subset from list. + subset_list = inner_vschema[0] + # get_jschema('strobex', registry['strobe'].schema) + registry_schemas = [] + for name in subset_list: + registry_schemas.append(get_ref("light.EFFECTS_REGISTRY-" + name)) + + entry = { + JSC_ANYOF: [{"type": "array", "items": {JSC_ANYOF: registry_schemas}}] + } + else: raise ValueError("Unknown extracted schema type") elif str(vschema).startswith(" Date: Sat, 15 May 2021 17:02:52 +1200 Subject: [PATCH 036/104] Allow RC522 components to have multiple configurations (#1782) --- esphome/components/rc522/__init__.py | 1 - esphome/components/rc522_i2c/__init__.py | 2 +- esphome/components/rc522_spi/__init__.py | 1 + tests/test1.yaml | 13 +++++++++---- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/esphome/components/rc522/__init__.py b/esphome/components/rc522/__init__.py index 970b867e79..7858213f06 100644 --- a/esphome/components/rc522/__init__.py +++ b/esphome/components/rc522/__init__.py @@ -7,7 +7,6 @@ from esphome.core import coroutine CODEOWNERS = ["@glmnet"] AUTO_LOAD = ["binary_sensor"] -MULTI_CONF = True CONF_RC522_ID = "rc522_id" diff --git a/esphome/components/rc522_i2c/__init__.py b/esphome/components/rc522_i2c/__init__.py index 532adfce79..081536b6b1 100644 --- a/esphome/components/rc522_i2c/__init__.py +++ b/esphome/components/rc522_i2c/__init__.py @@ -6,7 +6,7 @@ from esphome.const import CONF_ID CODEOWNERS = ["@glmnet"] DEPENDENCIES = ["i2c"] AUTO_LOAD = ["rc522"] - +MULTI_CONF = True rc522_i2c_ns = cg.esphome_ns.namespace("rc522_i2c") RC522I2C = rc522_i2c_ns.class_("RC522I2C", rc522.RC522, i2c.I2CDevice) diff --git a/esphome/components/rc522_spi/__init__.py b/esphome/components/rc522_spi/__init__.py index 6ae163bcb4..2e5630f46d 100644 --- a/esphome/components/rc522_spi/__init__.py +++ b/esphome/components/rc522_spi/__init__.py @@ -6,6 +6,7 @@ from esphome.const import CONF_ID CODEOWNERS = ["@glmnet"] DEPENDENCIES = ["spi"] AUTO_LOAD = ["rc522"] +MULTI_CONF = True rc522_spi_ns = cg.esphome_ns.namespace("rc522_spi") RC522Spi = rc522_spi_ns.class_("RC522Spi", rc522.RC522, spi.SPIDevice) diff --git a/tests/test1.yaml b/tests/test1.yaml index 5695183f74..c2a79085b5 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -1982,10 +1982,15 @@ rc522_spi: ESP_LOGD("main", "Found tag %s", x.c_str()); rc522_i2c: - update_interval: 1s - on_tag: - - lambda: |- - ESP_LOGD("main", "Found tag %s", x.c_str()); + - update_interval: 1s + on_tag: + - lambda: |- + ESP_LOGD("main", "Found tag %s", x.c_str()); + + - update_interval: 1s + on_tag: + - lambda: |- + ESP_LOGD("main", "Found tag %s", x.c_str()); gps: uart_id: uart0 From 9a7a2055107ccc828d464c8491dfdcaeee03e80f Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 17 May 2021 10:54:17 +1200 Subject: [PATCH 037/104] Generate protobuf code closer to formatted files (#1790) --- esphome/components/api/api_pb2.h | 436 ++++++++++++++-------------- script/api_protobuf/api_protobuf.py | 71 +++-- 2 files changed, 267 insertions(+), 240 deletions(-) diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index f70ac74a79..2ef92ce6f5 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -89,7 +89,7 @@ enum ClimateAction : uint32_t { class HelloRequest : public ProtoMessage { public: - std::string client_info{}; // NOLINT + std::string client_info{}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -98,9 +98,9 @@ class HelloRequest : public ProtoMessage { }; class HelloResponse : public ProtoMessage { public: - uint32_t api_version_major{0}; // NOLINT - uint32_t api_version_minor{0}; // NOLINT - std::string server_info{}; // NOLINT + uint32_t api_version_major{0}; + uint32_t api_version_minor{0}; + std::string server_info{}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -110,7 +110,7 @@ class HelloResponse : public ProtoMessage { }; class ConnectRequest : public ProtoMessage { public: - std::string password{}; // NOLINT + std::string password{}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -119,7 +119,7 @@ class ConnectRequest : public ProtoMessage { }; class ConnectResponse : public ProtoMessage { public: - bool invalid_password{false}; // NOLINT + bool invalid_password{false}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -163,13 +163,13 @@ class DeviceInfoRequest : public ProtoMessage { }; class DeviceInfoResponse : public ProtoMessage { public: - bool uses_password{false}; // NOLINT - std::string name{}; // NOLINT - std::string mac_address{}; // NOLINT - std::string esphome_version{}; // NOLINT - std::string compilation_time{}; // NOLINT - std::string model{}; // NOLINT - bool has_deep_sleep{false}; // NOLINT + bool uses_password{false}; + std::string name{}; + std::string mac_address{}; + std::string esphome_version{}; + std::string compilation_time{}; + std::string model{}; + bool has_deep_sleep{false}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -200,12 +200,12 @@ class SubscribeStatesRequest : public ProtoMessage { }; class ListEntitiesBinarySensorResponse : public ProtoMessage { public: - std::string object_id{}; // NOLINT - uint32_t key{0}; // NOLINT - std::string name{}; // NOLINT - std::string unique_id{}; // NOLINT - std::string device_class{}; // NOLINT - bool is_status_binary_sensor{false}; // NOLINT + std::string object_id{}; + uint32_t key{0}; + std::string name{}; + std::string unique_id{}; + std::string device_class{}; + bool is_status_binary_sensor{false}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -216,9 +216,9 @@ class ListEntitiesBinarySensorResponse : public ProtoMessage { }; class BinarySensorStateResponse : public ProtoMessage { public: - uint32_t key{0}; // NOLINT - bool state{false}; // NOLINT - bool missing_state{false}; // NOLINT + uint32_t key{0}; + bool state{false}; + bool missing_state{false}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -228,14 +228,14 @@ class BinarySensorStateResponse : public ProtoMessage { }; class ListEntitiesCoverResponse : public ProtoMessage { public: - std::string object_id{}; // NOLINT - uint32_t key{0}; // NOLINT - std::string name{}; // NOLINT - std::string unique_id{}; // NOLINT - bool assumed_state{false}; // NOLINT - bool supports_position{false}; // NOLINT - bool supports_tilt{false}; // NOLINT - std::string device_class{}; // NOLINT + std::string object_id{}; + uint32_t key{0}; + std::string name{}; + std::string unique_id{}; + bool assumed_state{false}; + bool supports_position{false}; + bool supports_tilt{false}; + std::string device_class{}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -246,11 +246,11 @@ class ListEntitiesCoverResponse : public ProtoMessage { }; class CoverStateResponse : public ProtoMessage { public: - uint32_t key{0}; // NOLINT - enums::LegacyCoverState legacy_state{}; // NOLINT - float position{0.0f}; // NOLINT - float tilt{0.0f}; // NOLINT - enums::CoverOperation current_operation{}; // NOLINT + uint32_t key{0}; + enums::LegacyCoverState legacy_state{}; + float position{0.0f}; + float tilt{0.0f}; + enums::CoverOperation current_operation{}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -260,14 +260,14 @@ class CoverStateResponse : public ProtoMessage { }; class CoverCommandRequest : public ProtoMessage { public: - uint32_t key{0}; // NOLINT - bool has_legacy_command{false}; // NOLINT - enums::LegacyCoverCommand legacy_command{}; // NOLINT - bool has_position{false}; // NOLINT - float position{0.0f}; // NOLINT - bool has_tilt{false}; // NOLINT - float tilt{0.0f}; // NOLINT - bool stop{false}; // NOLINT + uint32_t key{0}; + bool has_legacy_command{false}; + enums::LegacyCoverCommand legacy_command{}; + bool has_position{false}; + float position{0.0f}; + bool has_tilt{false}; + float tilt{0.0f}; + bool stop{false}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -277,14 +277,14 @@ class CoverCommandRequest : public ProtoMessage { }; class ListEntitiesFanResponse : public ProtoMessage { public: - std::string object_id{}; // NOLINT - uint32_t key{0}; // NOLINT - std::string name{}; // NOLINT - std::string unique_id{}; // NOLINT - bool supports_oscillation{false}; // NOLINT - bool supports_speed{false}; // NOLINT - bool supports_direction{false}; // NOLINT - int32_t supported_speed_count{0}; // NOLINT + std::string object_id{}; + uint32_t key{0}; + std::string name{}; + std::string unique_id{}; + bool supports_oscillation{false}; + bool supports_speed{false}; + bool supports_direction{false}; + int32_t supported_speed_count{0}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -295,12 +295,12 @@ class ListEntitiesFanResponse : public ProtoMessage { }; class FanStateResponse : public ProtoMessage { public: - uint32_t key{0}; // NOLINT - bool state{false}; // NOLINT - bool oscillating{false}; // NOLINT - enums::FanSpeed speed{}; // NOLINT - enums::FanDirection direction{}; // NOLINT - int32_t speed_level{0}; // NOLINT + uint32_t key{0}; + bool state{false}; + bool oscillating{false}; + enums::FanSpeed speed{}; + enums::FanDirection direction{}; + int32_t speed_level{0}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -310,17 +310,17 @@ class FanStateResponse : public ProtoMessage { }; class FanCommandRequest : public ProtoMessage { public: - uint32_t key{0}; // NOLINT - bool has_state{false}; // NOLINT - bool state{false}; // NOLINT - bool has_speed{false}; // NOLINT - enums::FanSpeed speed{}; // NOLINT - bool has_oscillating{false}; // NOLINT - bool oscillating{false}; // NOLINT - bool has_direction{false}; // NOLINT - enums::FanDirection direction{}; // NOLINT - bool has_speed_level{false}; // NOLINT - int32_t speed_level{0}; // NOLINT + uint32_t key{0}; + bool has_state{false}; + bool state{false}; + bool has_speed{false}; + enums::FanSpeed speed{}; + bool has_oscillating{false}; + bool oscillating{false}; + bool has_direction{false}; + enums::FanDirection direction{}; + bool has_speed_level{false}; + int32_t speed_level{0}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -330,17 +330,17 @@ class FanCommandRequest : public ProtoMessage { }; class ListEntitiesLightResponse : public ProtoMessage { public: - std::string object_id{}; // NOLINT - uint32_t key{0}; // NOLINT - std::string name{}; // NOLINT - std::string unique_id{}; // NOLINT - bool supports_brightness{false}; // NOLINT - bool supports_rgb{false}; // NOLINT - bool supports_white_value{false}; // NOLINT - bool supports_color_temperature{false}; // NOLINT - float min_mireds{0.0f}; // NOLINT - float max_mireds{0.0f}; // NOLINT - std::vector effects{}; // NOLINT + std::string object_id{}; + uint32_t key{0}; + std::string name{}; + std::string unique_id{}; + bool supports_brightness{false}; + bool supports_rgb{false}; + bool supports_white_value{false}; + bool supports_color_temperature{false}; + float min_mireds{0.0f}; + float max_mireds{0.0f}; + std::vector effects{}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -351,15 +351,15 @@ class ListEntitiesLightResponse : public ProtoMessage { }; class LightStateResponse : public ProtoMessage { public: - uint32_t key{0}; // NOLINT - bool state{false}; // NOLINT - float brightness{0.0f}; // NOLINT - float red{0.0f}; // NOLINT - float green{0.0f}; // NOLINT - float blue{0.0f}; // NOLINT - float white{0.0f}; // NOLINT - float color_temperature{0.0f}; // NOLINT - std::string effect{}; // NOLINT + uint32_t key{0}; + bool state{false}; + float brightness{0.0f}; + float red{0.0f}; + float green{0.0f}; + float blue{0.0f}; + float white{0.0f}; + float color_temperature{0.0f}; + std::string effect{}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -370,25 +370,25 @@ class LightStateResponse : public ProtoMessage { }; class LightCommandRequest : public ProtoMessage { public: - uint32_t key{0}; // NOLINT - bool has_state{false}; // NOLINT - bool state{false}; // NOLINT - bool has_brightness{false}; // NOLINT - float brightness{0.0f}; // NOLINT - bool has_rgb{false}; // NOLINT - float red{0.0f}; // NOLINT - float green{0.0f}; // NOLINT - float blue{0.0f}; // NOLINT - bool has_white{false}; // NOLINT - float white{0.0f}; // NOLINT - bool has_color_temperature{false}; // NOLINT - float color_temperature{0.0f}; // NOLINT - bool has_transition_length{false}; // NOLINT - uint32_t transition_length{0}; // NOLINT - bool has_flash_length{false}; // NOLINT - uint32_t flash_length{0}; // NOLINT - bool has_effect{false}; // NOLINT - std::string effect{}; // NOLINT + uint32_t key{0}; + bool has_state{false}; + bool state{false}; + bool has_brightness{false}; + float brightness{0.0f}; + bool has_rgb{false}; + float red{0.0f}; + float green{0.0f}; + float blue{0.0f}; + bool has_white{false}; + float white{0.0f}; + bool has_color_temperature{false}; + float color_temperature{0.0f}; + bool has_transition_length{false}; + uint32_t transition_length{0}; + bool has_flash_length{false}; + uint32_t flash_length{0}; + bool has_effect{false}; + std::string effect{}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -399,15 +399,15 @@ class LightCommandRequest : public ProtoMessage { }; class ListEntitiesSensorResponse : public ProtoMessage { public: - std::string object_id{}; // NOLINT - uint32_t key{0}; // NOLINT - std::string name{}; // NOLINT - std::string unique_id{}; // NOLINT - std::string icon{}; // NOLINT - std::string unit_of_measurement{}; // NOLINT - int32_t accuracy_decimals{0}; // NOLINT - bool force_update{false}; // NOLINT - std::string device_class{}; // NOLINT + std::string object_id{}; + uint32_t key{0}; + std::string name{}; + std::string unique_id{}; + std::string icon{}; + std::string unit_of_measurement{}; + int32_t accuracy_decimals{0}; + bool force_update{false}; + std::string device_class{}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -418,9 +418,9 @@ class ListEntitiesSensorResponse : public ProtoMessage { }; class SensorStateResponse : public ProtoMessage { public: - uint32_t key{0}; // NOLINT - float state{0.0f}; // NOLINT - bool missing_state{false}; // NOLINT + uint32_t key{0}; + float state{0.0f}; + bool missing_state{false}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -430,12 +430,12 @@ class SensorStateResponse : public ProtoMessage { }; class ListEntitiesSwitchResponse : public ProtoMessage { public: - std::string object_id{}; // NOLINT - uint32_t key{0}; // NOLINT - std::string name{}; // NOLINT - std::string unique_id{}; // NOLINT - std::string icon{}; // NOLINT - bool assumed_state{false}; // NOLINT + std::string object_id{}; + uint32_t key{0}; + std::string name{}; + std::string unique_id{}; + std::string icon{}; + bool assumed_state{false}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -446,8 +446,8 @@ class ListEntitiesSwitchResponse : public ProtoMessage { }; class SwitchStateResponse : public ProtoMessage { public: - uint32_t key{0}; // NOLINT - bool state{false}; // NOLINT + uint32_t key{0}; + bool state{false}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -457,8 +457,8 @@ class SwitchStateResponse : public ProtoMessage { }; class SwitchCommandRequest : public ProtoMessage { public: - uint32_t key{0}; // NOLINT - bool state{false}; // NOLINT + uint32_t key{0}; + bool state{false}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -468,11 +468,11 @@ class SwitchCommandRequest : public ProtoMessage { }; class ListEntitiesTextSensorResponse : public ProtoMessage { public: - std::string object_id{}; // NOLINT - uint32_t key{0}; // NOLINT - std::string name{}; // NOLINT - std::string unique_id{}; // NOLINT - std::string icon{}; // NOLINT + std::string object_id{}; + uint32_t key{0}; + std::string name{}; + std::string unique_id{}; + std::string icon{}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -482,9 +482,9 @@ class ListEntitiesTextSensorResponse : public ProtoMessage { }; class TextSensorStateResponse : public ProtoMessage { public: - uint32_t key{0}; // NOLINT - std::string state{}; // NOLINT - bool missing_state{false}; // NOLINT + uint32_t key{0}; + std::string state{}; + bool missing_state{false}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -495,8 +495,8 @@ class TextSensorStateResponse : public ProtoMessage { }; class SubscribeLogsRequest : public ProtoMessage { public: - enums::LogLevel level{}; // NOLINT - bool dump_config{false}; // NOLINT + enums::LogLevel level{}; + bool dump_config{false}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -505,10 +505,10 @@ class SubscribeLogsRequest : public ProtoMessage { }; class SubscribeLogsResponse : public ProtoMessage { public: - enums::LogLevel level{}; // NOLINT - std::string tag{}; // NOLINT - std::string message{}; // NOLINT - bool send_failed{false}; // NOLINT + enums::LogLevel level{}; + std::string tag{}; + std::string message{}; + bool send_failed{false}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -525,8 +525,8 @@ class SubscribeHomeassistantServicesRequest : public ProtoMessage { }; class HomeassistantServiceMap : public ProtoMessage { public: - std::string key{}; // NOLINT - std::string value{}; // NOLINT + std::string key{}; + std::string value{}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -535,11 +535,11 @@ class HomeassistantServiceMap : public ProtoMessage { }; class HomeassistantServiceResponse : public ProtoMessage { public: - std::string service{}; // NOLINT - std::vector data{}; // NOLINT - std::vector data_template{}; // NOLINT - std::vector variables{}; // NOLINT - bool is_event{false}; // NOLINT + std::string service{}; + std::vector data{}; + std::vector data_template{}; + std::vector variables{}; + bool is_event{false}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -556,7 +556,7 @@ class SubscribeHomeAssistantStatesRequest : public ProtoMessage { }; class SubscribeHomeAssistantStateResponse : public ProtoMessage { public: - std::string entity_id{}; // NOLINT + std::string entity_id{}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -565,8 +565,8 @@ class SubscribeHomeAssistantStateResponse : public ProtoMessage { }; class HomeAssistantStateResponse : public ProtoMessage { public: - std::string entity_id{}; // NOLINT - std::string state{}; // NOLINT + std::string entity_id{}; + std::string state{}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -582,7 +582,7 @@ class GetTimeRequest : public ProtoMessage { }; class GetTimeResponse : public ProtoMessage { public: - uint32_t epoch_seconds{0}; // NOLINT + uint32_t epoch_seconds{0}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -591,8 +591,8 @@ class GetTimeResponse : public ProtoMessage { }; class ListEntitiesServicesArgument : public ProtoMessage { public: - std::string name{}; // NOLINT - enums::ServiceArgType type{}; // NOLINT + std::string name{}; + enums::ServiceArgType type{}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -602,9 +602,9 @@ class ListEntitiesServicesArgument : public ProtoMessage { }; class ListEntitiesServicesResponse : public ProtoMessage { public: - std::string name{}; // NOLINT - uint32_t key{0}; // NOLINT - std::vector args{}; // NOLINT + std::string name{}; + uint32_t key{0}; + std::vector args{}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -614,15 +614,15 @@ class ListEntitiesServicesResponse : public ProtoMessage { }; class ExecuteServiceArgument : public ProtoMessage { public: - bool bool_{false}; // NOLINT - int32_t legacy_int{0}; // NOLINT - float float_{0.0f}; // NOLINT - std::string string_{}; // NOLINT - int32_t int_{0}; // NOLINT - std::vector bool_array{}; // NOLINT - std::vector int_array{}; // NOLINT - std::vector float_array{}; // NOLINT - std::vector string_array{}; // NOLINT + bool bool_{false}; + int32_t legacy_int{0}; + float float_{0.0f}; + std::string string_{}; + int32_t int_{0}; + std::vector bool_array{}; + std::vector int_array{}; + std::vector float_array{}; + std::vector string_array{}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -633,8 +633,8 @@ class ExecuteServiceArgument : public ProtoMessage { }; class ExecuteServiceRequest : public ProtoMessage { public: - uint32_t key{0}; // NOLINT - std::vector args{}; // NOLINT + uint32_t key{0}; + std::vector args{}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -644,10 +644,10 @@ class ExecuteServiceRequest : public ProtoMessage { }; class ListEntitiesCameraResponse : public ProtoMessage { public: - std::string object_id{}; // NOLINT - uint32_t key{0}; // NOLINT - std::string name{}; // NOLINT - std::string unique_id{}; // NOLINT + std::string object_id{}; + uint32_t key{0}; + std::string name{}; + std::string unique_id{}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -657,9 +657,9 @@ class ListEntitiesCameraResponse : public ProtoMessage { }; class CameraImageResponse : public ProtoMessage { public: - uint32_t key{0}; // NOLINT - std::string data{}; // NOLINT - bool done{false}; // NOLINT + uint32_t key{0}; + std::string data{}; + bool done{false}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -670,8 +670,8 @@ class CameraImageResponse : public ProtoMessage { }; class CameraImageRequest : public ProtoMessage { public: - bool single{false}; // NOLINT - bool stream{false}; // NOLINT + bool single{false}; + bool stream{false}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -680,20 +680,20 @@ class CameraImageRequest : public ProtoMessage { }; class ListEntitiesClimateResponse : public ProtoMessage { public: - std::string object_id{}; // NOLINT - uint32_t key{0}; // NOLINT - std::string name{}; // NOLINT - std::string unique_id{}; // NOLINT - bool supports_current_temperature{false}; // NOLINT - bool supports_two_point_target_temperature{false}; // NOLINT - std::vector supported_modes{}; // NOLINT - float visual_min_temperature{0.0f}; // NOLINT - float visual_max_temperature{0.0f}; // NOLINT - float visual_temperature_step{0.0f}; // NOLINT - bool supports_away{false}; // NOLINT - bool supports_action{false}; // NOLINT - std::vector supported_fan_modes{}; // NOLINT - std::vector supported_swing_modes{}; // NOLINT + std::string object_id{}; + uint32_t key{0}; + std::string name{}; + std::string unique_id{}; + bool supports_current_temperature{false}; + bool supports_two_point_target_temperature{false}; + std::vector supported_modes{}; + float visual_min_temperature{0.0f}; + float visual_max_temperature{0.0f}; + float visual_temperature_step{0.0f}; + bool supports_away{false}; + bool supports_action{false}; + std::vector supported_fan_modes{}; + std::vector supported_swing_modes{}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -704,16 +704,16 @@ class ListEntitiesClimateResponse : public ProtoMessage { }; class ClimateStateResponse : public ProtoMessage { public: - uint32_t key{0}; // NOLINT - enums::ClimateMode mode{}; // NOLINT - float current_temperature{0.0f}; // NOLINT - float target_temperature{0.0f}; // NOLINT - float target_temperature_low{0.0f}; // NOLINT - float target_temperature_high{0.0f}; // NOLINT - bool away{false}; // NOLINT - enums::ClimateAction action{}; // NOLINT - enums::ClimateFanMode fan_mode{}; // NOLINT - enums::ClimateSwingMode swing_mode{}; // NOLINT + uint32_t key{0}; + enums::ClimateMode mode{}; + float current_temperature{0.0f}; + float target_temperature{0.0f}; + float target_temperature_low{0.0f}; + float target_temperature_high{0.0f}; + bool away{false}; + enums::ClimateAction action{}; + enums::ClimateFanMode fan_mode{}; + enums::ClimateSwingMode swing_mode{}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -723,21 +723,21 @@ class ClimateStateResponse : public ProtoMessage { }; class ClimateCommandRequest : public ProtoMessage { public: - uint32_t key{0}; // NOLINT - bool has_mode{false}; // NOLINT - enums::ClimateMode mode{}; // NOLINT - bool has_target_temperature{false}; // NOLINT - float target_temperature{0.0f}; // NOLINT - bool has_target_temperature_low{false}; // NOLINT - float target_temperature_low{0.0f}; // NOLINT - bool has_target_temperature_high{false}; // NOLINT - float target_temperature_high{0.0f}; // NOLINT - bool has_away{false}; // NOLINT - bool away{false}; // NOLINT - bool has_fan_mode{false}; // NOLINT - enums::ClimateFanMode fan_mode{}; // NOLINT - bool has_swing_mode{false}; // NOLINT - enums::ClimateSwingMode swing_mode{}; // NOLINT + uint32_t key{0}; + bool has_mode{false}; + enums::ClimateMode mode{}; + bool has_target_temperature{false}; + float target_temperature{0.0f}; + bool has_target_temperature_low{false}; + float target_temperature_low{0.0f}; + bool has_target_temperature_high{false}; + float target_temperature_high{0.0f}; + bool has_away{false}; + bool away{false}; + bool has_fan_mode{false}; + enums::ClimateFanMode fan_mode{}; + bool has_swing_mode{false}; + enums::ClimateSwingMode swing_mode{}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; diff --git a/script/api_protobuf/api_protobuf.py b/script/api_protobuf/api_protobuf.py index f86145df2f..97cc95e556 100644 --- a/script/api_protobuf/api_protobuf.py +++ b/script/api_protobuf/api_protobuf.py @@ -40,7 +40,16 @@ d = descriptor.FileDescriptorSet.FromString(content) def indent_list(text, padding=" "): - return [padding + line for line in text.splitlines()] + lines = [] + for line in text.splitlines(): + if line == "": + p = "" + elif line.startswith("#ifdef") or line.startswith("#endif"): + p = "" + else: + p = padding + lines.append(p + line) + return lines def indent(text, padding=" "): @@ -103,7 +112,7 @@ class TypeInfo: @property def class_member(self) -> str: - return f"{self.cpp_type} {self.field_name}{{{self.default_value}}}; // NOLINT" + return f"{self.cpp_type} {self.field_name}{{{self.default_value}}};" @property def decode_varint_content(self) -> str: @@ -432,7 +441,7 @@ class SInt64Type(TypeInfo): decode_varint = "value.as_sint64()" encode_func = "encode_sin64" - def dump(self): + def dump(self, name): o = f'sprintf(buffer, "%ll", {name});\n' o += f"out.append(buffer);" return o @@ -514,10 +523,10 @@ class RepeatedTypeInfo(TypeInfo): @property def encode_content(self): - return f"""\ - for (auto {'' if self._ti_is_bool else '&'}it : this->{self.field_name}) {{ - buffer.{self._ti.encode_func}({self.number}, it, true); - }}""" + o = f"for (auto {'' if self._ti_is_bool else '&'}it : this->{self.field_name}) {{\n" + o += f" buffer.{self._ti.encode_func}({self.number}, it, true);\n" + o += f"}}" + return o @property def dump_content(self): @@ -536,12 +545,13 @@ def build_enum_type(desc): out += f" {v.name} = {v.number},\n" out += "};\n" - cpp = f"template<>\n" - cpp += f"const char *proto_enum_to_string(enums::{name} value) {{\n" + cpp = f"template<> const char *proto_enum_to_string(enums::{name} value) {{\n" cpp += f" switch (value) {{\n" for v in desc.value: - cpp += f' case enums::{v.name}: return "{v.name}";\n' - cpp += f' default: return "UNKNOWN";\n' + cpp += f" case enums::{v.name}:\n" + cpp += f' return "{v.name}";\n' + cpp += f" default:\n" + cpp += f' return "UNKNOWN";\n' cpp += f" }}\n" cpp += f"}}\n" @@ -620,21 +630,35 @@ def build_message_type(desc): prot = "bool decode_64bit(uint32_t field_id, Proto64bit value) override;" protected_content.insert(0, prot) - o = f"void {desc.name}::encode(ProtoWriteBuffer buffer) const {{\n" - o += indent("\n".join(encode)) + "\n" + o = f"void {desc.name}::encode(ProtoWriteBuffer buffer) const {{" + if encode: + if len(encode) == 1 and len(encode[0]) + len(o) + 3 < 120: + o += f" {encode[0]} " + else: + o += "\n" + o += indent("\n".join(encode)) + "\n" o += "}\n" cpp += o prot = "void encode(ProtoWriteBuffer buffer) const override;" public_content.append(prot) - o = f"void {desc.name}::dump_to(std::string &out) const {{\n" + o = f"void {desc.name}::dump_to(std::string &out) const {{" if dump: - o += f" char buffer[64];\n" - o += f' out.append("{desc.name} {{\\n");\n' - o += indent("\n".join(dump)) + "\n" - o += f' out.append("}}");\n' + if len(dump) == 1 and len(dump[0]) + len(o) + 3 < 120: + o += f" {dump[0]} " + else: + o += "\n" + o += f" char buffer[64];\n" + o += f' out.append("{desc.name} {{\\n");\n' + o += indent("\n".join(dump)) + "\n" + o += f' out.append("}}");\n' else: - o += f' out.append("{desc.name} {{}}");\n' + o2 = f'out.append("{desc.name} {{}}");' + if len(o) + len(o2) + 3 < 120: + o += f" {o2} " + else: + o += "\n" + o += f" {o2}\n" o += "}\n" cpp += o prot = "void dump_to(std::string &out) const override;" @@ -643,8 +667,11 @@ def build_message_type(desc): out = f"class {desc.name} : public ProtoMessage {{\n" out += " public:\n" out += indent("\n".join(public_content)) + "\n" + out += "\n" out += " protected:\n" - out += indent("\n".join(protected_content)) + "\n" + out += indent("\n".join(protected_content)) + if len(protected_content) > 0: + out += "\n" out += "};\n" return out, cpp @@ -814,13 +841,13 @@ cases.sort() hpp += " protected:\n" hpp += f" bool read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) override;\n" out = f"bool {class_name}::read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) {{\n" -out += f" switch(msg_type) {{\n" +out += f" switch (msg_type) {{\n" for i, case in cases: c = f"case {i}: {{\n" c += indent(case) + "\n" c += f"}}" out += indent(c, " ") + "\n" -out += " default: \n" +out += " default:\n" out += " return false;\n" out += " }\n" out += " return true;\n" From 5645be4e0f8ab88026aad03340a846d65602839c Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Mon, 17 May 2021 01:16:22 +0200 Subject: [PATCH 038/104] Add attribute support to Home Assistant sensors (#1770) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/api/api.proto | 2 ++ esphome/components/api/api_connection.cpp | 4 +++- esphome/components/api/api_pb2.cpp | 18 +++++++++++++++ esphome/components/api/api_pb2.h | 2 ++ esphome/components/api/api_server.cpp | 4 +++- esphome/components/api/api_server.h | 4 +++- esphome/components/api/custom_api_device.h | 20 ++++++++++------- .../homeassistant/binary_sensor/__init__.py | 5 ++++- .../homeassistant_binary_sensor.cpp | 12 ++++++++-- .../homeassistant_binary_sensor.h | 2 ++ .../homeassistant/sensor/__init__.py | 4 ++++ .../sensor/homeassistant_sensor.cpp | 12 ++++++++-- .../sensor/homeassistant_sensor.h | 2 ++ .../homeassistant/text_sensor/__init__.py | 5 ++++- .../text_sensor/homeassistant_text_sensor.cpp | 22 +++++++++++++------ .../text_sensor/homeassistant_text_sensor.h | 5 ++++- esphome/const.py | 1 + tests/custom.h | 2 ++ tests/test2.yaml | 12 ++++++++++ 19 files changed, 113 insertions(+), 25 deletions(-) diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index ede2cc6205..e228fe6874 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -561,6 +561,7 @@ message SubscribeHomeAssistantStateResponse { option (id) = 39; option (source) = SOURCE_SERVER; string entity_id = 1; + string attribute = 2; } message HomeAssistantStateResponse { @@ -570,6 +571,7 @@ message HomeAssistantStateResponse { string entity_id = 1; string state = 2; + string attribute = 3; } // ==================== IMPORT TIME ==================== diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 8098c93781..ac04e1f09f 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -642,8 +642,9 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) { } void APIConnection::on_home_assistant_state_response(const HomeAssistantStateResponse &msg) { for (auto &it : this->parent_->get_state_subs()) - if (it.entity_id == msg.entity_id) + if (it.entity_id == msg.entity_id && it.attribute.value() == msg.attribute) { it.callback(msg.state); + } } void APIConnection::execute_service(const ExecuteServiceRequest &msg) { bool found = false; @@ -660,6 +661,7 @@ void APIConnection::subscribe_home_assistant_states(const SubscribeHomeAssistant for (auto &it : this->parent_->get_state_subs()) { SubscribeHomeAssistantStateResponse resp; resp.entity_id = it.entity_id; + resp.attribute = it.attribute.value(); if (!this->send_subscribe_home_assistant_state_response(resp)) { this->on_fatal_error(); return; diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 23538b77bf..8f8e2abf58 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -2123,12 +2123,17 @@ bool SubscribeHomeAssistantStateResponse::decode_length(uint32_t field_id, Proto this->entity_id = value.as_string(); return true; } + case 2: { + this->attribute = value.as_string(); + return true; + } default: return false; } } void SubscribeHomeAssistantStateResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_string(1, this->entity_id); + buffer.encode_string(2, this->attribute); } void SubscribeHomeAssistantStateResponse::dump_to(std::string &out) const { char buffer[64]; @@ -2136,6 +2141,10 @@ void SubscribeHomeAssistantStateResponse::dump_to(std::string &out) const { out.append(" entity_id: "); out.append("'").append(this->entity_id).append("'"); out.append("\n"); + + out.append(" attribute: "); + out.append("'").append(this->attribute).append("'"); + out.append("\n"); out.append("}"); } bool HomeAssistantStateResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) { @@ -2148,6 +2157,10 @@ bool HomeAssistantStateResponse::decode_length(uint32_t field_id, ProtoLengthDel this->state = value.as_string(); return true; } + case 3: { + this->attribute = value.as_string(); + return true; + } default: return false; } @@ -2155,6 +2168,7 @@ bool HomeAssistantStateResponse::decode_length(uint32_t field_id, ProtoLengthDel void HomeAssistantStateResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_string(1, this->entity_id); buffer.encode_string(2, this->state); + buffer.encode_string(3, this->attribute); } void HomeAssistantStateResponse::dump_to(std::string &out) const { char buffer[64]; @@ -2166,6 +2180,10 @@ void HomeAssistantStateResponse::dump_to(std::string &out) const { out.append(" state: "); out.append("'").append(this->state).append("'"); out.append("\n"); + + out.append(" attribute: "); + out.append("'").append(this->attribute).append("'"); + out.append("\n"); out.append("}"); } void GetTimeRequest::encode(ProtoWriteBuffer buffer) const {} diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index 2ef92ce6f5..5715a7f50f 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -557,6 +557,7 @@ class SubscribeHomeAssistantStatesRequest : public ProtoMessage { class SubscribeHomeAssistantStateResponse : public ProtoMessage { public: std::string entity_id{}; + std::string attribute{}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -567,6 +568,7 @@ class HomeAssistantStateResponse : public ProtoMessage { public: std::string entity_id{}; std::string state{}; + std::string attribute{}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; diff --git a/esphome/components/api/api_server.cpp b/esphome/components/api/api_server.cpp index 25ae9a98a3..dd77f2004f 100644 --- a/esphome/components/api/api_server.cpp +++ b/esphome/components/api/api_server.cpp @@ -208,9 +208,11 @@ void APIServer::send_homeassistant_service_call(const HomeassistantServiceRespon } } APIServer::APIServer() { global_api_server = this; } -void APIServer::subscribe_home_assistant_state(std::string entity_id, std::function f) { +void APIServer::subscribe_home_assistant_state(std::string entity_id, optional attribute, + std::function f) { this->state_subs_.push_back(HomeAssistantStateSubscription{ .entity_id = std::move(entity_id), + .attribute = std::move(attribute), .callback = std::move(f), }); } diff --git a/esphome/components/api/api_server.h b/esphome/components/api/api_server.h index db826c55c2..538a385efb 100644 --- a/esphome/components/api/api_server.h +++ b/esphome/components/api/api_server.h @@ -71,10 +71,12 @@ class APIServer : public Component, public Controller { struct HomeAssistantStateSubscription { std::string entity_id; + optional attribute; std::function callback; }; - void subscribe_home_assistant_state(std::string entity_id, std::function f); + void subscribe_home_assistant_state(std::string entity_id, optional attribute, + std::function f); const std::vector &get_state_subs() const; const std::vector &get_user_services() const { return this->user_services_; } diff --git a/esphome/components/api/custom_api_device.h b/esphome/components/api/custom_api_device.h index aac91244b6..74343904eb 100644 --- a/esphome/components/api/custom_api_device.h +++ b/esphome/components/api/custom_api_device.h @@ -76,13 +76,13 @@ class CustomAPIDevice { global_api_server->register_user_service(service); } - /** Subscribe to the state of an entity from Home Assistant. + /** Subscribe to the state (or attribute state) of an entity from Home Assistant. * * Usage: * * ```cpp * void setup() override { - * subscribe_homeassistant_state(&CustomNativeAPI::on_state_changed, "sensor.weather_forecast"); + * subscribe_homeassistant_state(&CustomNativeAPI::on_state_changed, "climate.kitchen", "current_temperature"); * } * * void on_state_changed(std::string state) { @@ -93,17 +93,19 @@ class CustomAPIDevice { * @tparam T The class type creating the service, automatically deduced from the function pointer. * @param callback The member function to call when the entity state changes. * @param entity_id The entity_id to track. + * @param attribute The entity state attribute to track. */ template - void subscribe_homeassistant_state(void (T::*callback)(std::string), const std::string &entity_id) { + void subscribe_homeassistant_state(void (T::*callback)(std::string), const std::string &entity_id, + const std::string &attribute = "") { auto f = std::bind(callback, (T *) this, std::placeholders::_1); - global_api_server->subscribe_home_assistant_state(entity_id, f); + global_api_server->subscribe_home_assistant_state(entity_id, optional(attribute), f); } - /** Subscribe to the state of an entity from Home Assistant. + /** Subscribe to the state (or attribute state) of an entity from Home Assistant. * * Usage: - * + *å * ```cpp * void setup() override { * subscribe_homeassistant_state(&CustomNativeAPI::on_state_changed, "sensor.weather_forecast"); @@ -117,11 +119,13 @@ class CustomAPIDevice { * @tparam T The class type creating the service, automatically deduced from the function pointer. * @param callback The member function to call when the entity state changes. * @param entity_id The entity_id to track. + * @param attribute The entity state attribute to track. */ template - void subscribe_homeassistant_state(void (T::*callback)(std::string, std::string), const std::string &entity_id) { + void subscribe_homeassistant_state(void (T::*callback)(std::string, std::string), const std::string &entity_id, + const std::string &attribute = "") { auto f = std::bind(callback, (T *) this, entity_id, std::placeholders::_1); - global_api_server->subscribe_home_assistant_state(entity_id, f); + global_api_server->subscribe_home_assistant_state(entity_id, optional(attribute), f); } /** Call a Home Assistant service from ESPHome. diff --git a/esphome/components/homeassistant/binary_sensor/__init__.py b/esphome/components/homeassistant/binary_sensor/__init__.py index 850f239d6f..cf2f3092af 100644 --- a/esphome/components/homeassistant/binary_sensor/__init__.py +++ b/esphome/components/homeassistant/binary_sensor/__init__.py @@ -1,7 +1,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import binary_sensor -from esphome.const import CONF_ENTITY_ID, CONF_ID +from esphome.const import CONF_ATTRIBUTE, CONF_ENTITY_ID, CONF_ID from .. import homeassistant_ns DEPENDENCIES = ["api"] @@ -13,6 +13,7 @@ CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend( { cv.GenerateID(): cv.declare_id(HomeassistantBinarySensor), cv.Required(CONF_ENTITY_ID): cv.entity_id, + cv.Optional(CONF_ATTRIBUTE): cv.string, } ).extend(cv.COMPONENT_SCHEMA) @@ -23,3 +24,5 @@ def to_code(config): yield binary_sensor.register_binary_sensor(var, config) cg.add(var.set_entity_id(config[CONF_ENTITY_ID])) + if CONF_ATTRIBUTE in config: + cg.add(var.set_attribute(config[CONF_ATTRIBUTE])) diff --git a/esphome/components/homeassistant/binary_sensor/homeassistant_binary_sensor.cpp b/esphome/components/homeassistant/binary_sensor/homeassistant_binary_sensor.cpp index 203f6d8a24..cf2415d9c0 100644 --- a/esphome/components/homeassistant/binary_sensor/homeassistant_binary_sensor.cpp +++ b/esphome/components/homeassistant/binary_sensor/homeassistant_binary_sensor.cpp @@ -8,7 +8,7 @@ namespace homeassistant { static const char *TAG = "homeassistant.binary_sensor"; void HomeassistantBinarySensor::setup() { - api::global_api_server->subscribe_home_assistant_state(this->entity_id_, [this](std::string state) { + api::global_api_server->subscribe_home_assistant_state(this->entity_id_, this->attribute_, [this](std::string state) { auto val = parse_on_off(state.c_str()); switch (val) { case PARSE_NONE: @@ -18,7 +18,12 @@ void HomeassistantBinarySensor::setup() { case PARSE_ON: case PARSE_OFF: bool new_state = val == PARSE_ON; - ESP_LOGD(TAG, "'%s': Got state %s", this->entity_id_.c_str(), ONOFF(new_state)); + if (this->attribute_.has_value()) { + ESP_LOGD(TAG, "'%s::%s': Got attribute state %s", this->entity_id_.c_str(), this->attribute_.value().c_str(), + ONOFF(new_state)); + } else { + ESP_LOGD(TAG, "'%s': Got state %s", this->entity_id_.c_str(), ONOFF(new_state)); + } if (this->initial_) this->publish_initial_state(new_state); else @@ -31,6 +36,9 @@ void HomeassistantBinarySensor::setup() { void HomeassistantBinarySensor::dump_config() { LOG_BINARY_SENSOR("", "Homeassistant Binary Sensor", this); ESP_LOGCONFIG(TAG, " Entity ID: '%s'", this->entity_id_.c_str()); + if (this->attribute_.has_value()) { + ESP_LOGCONFIG(TAG, " Attribute: '%s'", this->attribute_.value().c_str()); + } } float HomeassistantBinarySensor::get_setup_priority() const { return setup_priority::AFTER_WIFI; } diff --git a/esphome/components/homeassistant/binary_sensor/homeassistant_binary_sensor.h b/esphome/components/homeassistant/binary_sensor/homeassistant_binary_sensor.h index e468fd00eb..7026496295 100644 --- a/esphome/components/homeassistant/binary_sensor/homeassistant_binary_sensor.h +++ b/esphome/components/homeassistant/binary_sensor/homeassistant_binary_sensor.h @@ -9,12 +9,14 @@ namespace homeassistant { class HomeassistantBinarySensor : public binary_sensor::BinarySensor, public Component { public: void set_entity_id(const std::string &entity_id) { entity_id_ = entity_id; } + void set_attribute(const std::string &attribute) { attribute_ = attribute; } void setup() override; void dump_config() override; float get_setup_priority() const override; protected: std::string entity_id_; + optional attribute_; bool initial_{true}; }; diff --git a/esphome/components/homeassistant/sensor/__init__.py b/esphome/components/homeassistant/sensor/__init__.py index 9c19c7867f..c754ae295b 100644 --- a/esphome/components/homeassistant/sensor/__init__.py +++ b/esphome/components/homeassistant/sensor/__init__.py @@ -2,6 +2,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import sensor from esphome.const import ( + CONF_ATTRIBUTE, CONF_ENTITY_ID, CONF_ID, ICON_EMPTY, @@ -22,6 +23,7 @@ CONFIG_SCHEMA = sensor.sensor_schema( { cv.GenerateID(): cv.declare_id(HomeassistantSensor), cv.Required(CONF_ENTITY_ID): cv.entity_id, + cv.Optional(CONF_ATTRIBUTE): cv.string, } ) @@ -32,3 +34,5 @@ def to_code(config): yield sensor.register_sensor(var, config) cg.add(var.set_entity_id(config[CONF_ENTITY_ID])) + if CONF_ATTRIBUTE in config: + cg.add(var.set_attribute(config[CONF_ATTRIBUTE])) diff --git a/esphome/components/homeassistant/sensor/homeassistant_sensor.cpp b/esphome/components/homeassistant/sensor/homeassistant_sensor.cpp index 6b1299f70e..5f7916403e 100644 --- a/esphome/components/homeassistant/sensor/homeassistant_sensor.cpp +++ b/esphome/components/homeassistant/sensor/homeassistant_sensor.cpp @@ -8,7 +8,7 @@ namespace homeassistant { static const char *TAG = "homeassistant.sensor"; void HomeassistantSensor::setup() { - api::global_api_server->subscribe_home_assistant_state(this->entity_id_, [this](std::string state) { + api::global_api_server->subscribe_home_assistant_state(this->entity_id_, this->attribute_, [this](std::string state) { auto val = parse_float(state); if (!val.has_value()) { ESP_LOGW(TAG, "Can't convert '%s' to number!", state.c_str()); @@ -16,13 +16,21 @@ void HomeassistantSensor::setup() { return; } - ESP_LOGD(TAG, "'%s': Got state %.2f", this->entity_id_.c_str(), *val); + if (this->attribute_.has_value()) { + ESP_LOGD(TAG, "'%s::%s': Got attribute state %.2f", this->entity_id_.c_str(), this->attribute_.value().c_str(), + *val); + } else { + ESP_LOGD(TAG, "'%s': Got state %.2f", this->entity_id_.c_str(), *val); + } this->publish_state(*val); }); } void HomeassistantSensor::dump_config() { LOG_SENSOR("", "Homeassistant Sensor", this); ESP_LOGCONFIG(TAG, " Entity ID: '%s'", this->entity_id_.c_str()); + if (this->attribute_.has_value()) { + ESP_LOGCONFIG(TAG, " Attribute: '%s'", this->attribute_.value().c_str()); + } } float HomeassistantSensor::get_setup_priority() const { return setup_priority::AFTER_CONNECTION; } diff --git a/esphome/components/homeassistant/sensor/homeassistant_sensor.h b/esphome/components/homeassistant/sensor/homeassistant_sensor.h index baca6594c1..53b288d7d4 100644 --- a/esphome/components/homeassistant/sensor/homeassistant_sensor.h +++ b/esphome/components/homeassistant/sensor/homeassistant_sensor.h @@ -9,12 +9,14 @@ namespace homeassistant { class HomeassistantSensor : public sensor::Sensor, public Component { public: void set_entity_id(const std::string &entity_id) { entity_id_ = entity_id; } + void set_attribute(const std::string &attribute) { attribute_ = attribute; } void setup() override; void dump_config() override; float get_setup_priority() const override; protected: std::string entity_id_; + optional attribute_; }; } // namespace homeassistant diff --git a/esphome/components/homeassistant/text_sensor/__init__.py b/esphome/components/homeassistant/text_sensor/__init__.py index 478bd1c3d2..ed14615b80 100644 --- a/esphome/components/homeassistant/text_sensor/__init__.py +++ b/esphome/components/homeassistant/text_sensor/__init__.py @@ -1,7 +1,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import text_sensor -from esphome.const import CONF_ENTITY_ID, CONF_ID +from esphome.const import CONF_ATTRIBUTE, CONF_ENTITY_ID, CONF_ID from .. import homeassistant_ns DEPENDENCIES = ["api"] @@ -14,6 +14,7 @@ CONFIG_SCHEMA = text_sensor.TEXT_SENSOR_SCHEMA.extend( { cv.GenerateID(): cv.declare_id(HomeassistantTextSensor), cv.Required(CONF_ENTITY_ID): cv.entity_id, + cv.Optional(CONF_ATTRIBUTE): cv.string, } ) @@ -24,3 +25,5 @@ def to_code(config): yield text_sensor.register_text_sensor(var, config) cg.add(var.set_entity_id(config[CONF_ENTITY_ID])) + if CONF_ATTRIBUTE in config: + cg.add(var.set_attribute(config[CONF_ATTRIBUTE])) diff --git a/esphome/components/homeassistant/text_sensor/homeassistant_text_sensor.cpp b/esphome/components/homeassistant/text_sensor/homeassistant_text_sensor.cpp index 67fbf3cd5d..07b06cad3c 100644 --- a/esphome/components/homeassistant/text_sensor/homeassistant_text_sensor.cpp +++ b/esphome/components/homeassistant/text_sensor/homeassistant_text_sensor.cpp @@ -7,16 +7,24 @@ namespace homeassistant { static const char *TAG = "homeassistant.text_sensor"; -void HomeassistantTextSensor::dump_config() { - LOG_TEXT_SENSOR("", "Homeassistant Text Sensor", this); - ESP_LOGCONFIG(TAG, " Entity ID: '%s'", this->entity_id_.c_str()); -} void HomeassistantTextSensor::setup() { - api::global_api_server->subscribe_home_assistant_state(this->entity_id_, [this](std::string state) { - ESP_LOGD(TAG, "'%s': Got state '%s'", this->entity_id_.c_str(), state.c_str()); + api::global_api_server->subscribe_home_assistant_state(this->entity_id_, this->attribute_, [this](std::string state) { + if (this->attribute_.has_value()) { + ESP_LOGD(TAG, "'%s::%s': Got attribute state '%s'", this->entity_id_.c_str(), this->attribute_.value().c_str(), + state.c_str()); + } else { + ESP_LOGD(TAG, "'%s': Got state '%s'", this->entity_id_.c_str(), state.c_str()); + } this->publish_state(state); }); } - +void HomeassistantTextSensor::dump_config() { + LOG_TEXT_SENSOR("", "Homeassistant Text Sensor", this); + ESP_LOGCONFIG(TAG, " Entity ID: '%s'", this->entity_id_.c_str()); + if (this->attribute_.has_value()) { + ESP_LOGCONFIG(TAG, " Attribute: '%s'", this->attribute_.value().c_str()); + } +} +float HomeassistantTextSensor::get_setup_priority() const { return setup_priority::AFTER_CONNECTION; } } // namespace homeassistant } // namespace esphome diff --git a/esphome/components/homeassistant/text_sensor/homeassistant_text_sensor.h b/esphome/components/homeassistant/text_sensor/homeassistant_text_sensor.h index 02a74af1db..ce6b2c2c3f 100644 --- a/esphome/components/homeassistant/text_sensor/homeassistant_text_sensor.h +++ b/esphome/components/homeassistant/text_sensor/homeassistant_text_sensor.h @@ -9,11 +9,14 @@ namespace homeassistant { class HomeassistantTextSensor : public text_sensor::TextSensor, public Component { public: void set_entity_id(const std::string &entity_id) { entity_id_ = entity_id; } - void dump_config() override; + void set_attribute(const std::string &attribute) { attribute_ = attribute; } void setup() override; + void dump_config() override; + float get_setup_priority() const override; protected: std::string entity_id_; + optional attribute_; }; } // namespace homeassistant diff --git a/esphome/const.py b/esphome/const.py index e6ce4a6ba2..a83e090285 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -66,6 +66,7 @@ CONF_ARGS = "args" CONF_ASSUMED_STATE = "assumed_state" CONF_AT = "at" CONF_ATTENUATION = "attenuation" +CONF_ATTRIBUTE = "attribute" CONF_AUTH = "auth" CONF_AUTO_MODE = "auto_mode" CONF_AUTOMATION_ID = "automation_id" diff --git a/tests/custom.h b/tests/custom.h index 278e300785..f1a35b9b3c 100644 --- a/tests/custom.h +++ b/tests/custom.h @@ -49,6 +49,7 @@ class CustomNativeAPI : public Component, public CustomAPIDevice { register_service(&CustomNativeAPI::on_start_dryer, "start_dryer", {"value"}); register_service(&CustomNativeAPI::on_many_values, "many_values", {"bool", "int", "float", "str1", "str2"}); subscribe_homeassistant_state(&CustomNativeAPI::on_light_state, "light.my_light"); + subscribe_homeassistant_state(&CustomNativeAPI::on_brightness_state, "light.my_light", "brightness"); } void on_hello_world() { ESP_LOGD("custom_api", "Hello World from native API service!"); } @@ -69,4 +70,5 @@ class CustomNativeAPI : public Component, public CustomAPIDevice { call_homeassistant_service("homeassistant.restart"); } void on_light_state(std::string state) { ESP_LOGD("custom_api", "Got state %s", state.c_str()); } + void on_brightness_state(std::string state) { ESP_LOGD("custom_api", "Got attribute state %s", state.c_str()); } }; diff --git a/tests/test2.yaml b/tests/test2.yaml index 9b4db1477f..faa76300cc 100644 --- a/tests/test2.yaml +++ b/tests/test2.yaml @@ -63,6 +63,10 @@ sensor: - platform: homeassistant entity_id: sensor.hello_world id: ha_hello_world + - platform: homeassistant + entity_id: climate.living_room + attribute: temperature + id: ha_hello_world_temperature - platform: ble_rssi mac_address: AC:37:43:77:5F:4C name: 'BLE Google Home Mini RSSI value' @@ -246,6 +250,10 @@ binary_sensor: - platform: homeassistant entity_id: binary_sensor.hello_world id: ha_hello_world_binary + - platform: homeassistant + entity_id: binary_sensor.hello + attribute: world + id: ha_hello_world_binary_attribute - platform: ble_presence mac_address: AC:37:43:77:5F:4C name: 'ESP32 BLE Tracker Google Home Mini' @@ -355,6 +363,10 @@ text_sensor: - platform: homeassistant entity_id: sensor.hello_world2 id: ha_hello_world2 + - platform: homeassistant + entity_id: sensor.hello_world3 + id: ha_hello_world3 + attribute: some_attribute - platform: ble_scanner name: Scanner From 98166dfa66d6601ebf6a22150a80f807b2c24694 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Mon, 17 May 2021 01:38:26 +0200 Subject: [PATCH 039/104] Bump Arduino SDK for ESP32 to 1.0.6 (#1789) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .../components/ethernet/ethernet_component.cpp | 15 +++++++++++---- esphome/core/config.py | 2 +- esphome/core/util.h | 5 +++++ 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/esphome/components/ethernet/ethernet_component.cpp b/esphome/components/ethernet/ethernet_component.cpp index 005712420f..8c96cca951 100644 --- a/esphome/components/ethernet/ethernet_component.cpp +++ b/esphome/components/ethernet/ethernet_component.cpp @@ -224,10 +224,17 @@ void EthernetComponent::dump_connect_params_() { ESP_LOGCONFIG(TAG, " Subnet: %s", IPAddress(ip.netmask.addr).toString().c_str()); ESP_LOGCONFIG(TAG, " Gateway: %s", IPAddress(ip.gw.addr).toString().c_str()); - ip_addr_t dns_ip = dns_getserver(0); - ESP_LOGCONFIG(TAG, " DNS1: %s", IPAddress(dns_ip.u_addr.ip4.addr).toString().c_str()); - dns_ip = dns_getserver(1); - ESP_LOGCONFIG(TAG, " DNS2: %s", IPAddress(dns_ip.u_addr.ip4.addr).toString().c_str()); +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(3, 3, 4) + const ip_addr_t *dns_ip1 = dns_getserver(0); + const ip_addr_t *dns_ip2 = dns_getserver(1); +#else + ip_addr_t tmp_ip1 = dns_getserver(0); + const ip_addr_t *dns_ip1 = &tmp_ip1; + ip_addr_t tmp_ip2 = dns_getserver(1); + const ip_addr_t *dns_ip2 = &tmp_ip2; +#endif + ESP_LOGCONFIG(TAG, " DNS1: %s", IPAddress(dns_ip1->u_addr.ip4.addr).toString().c_str()); + ESP_LOGCONFIG(TAG, " DNS2: %s", IPAddress(dns_ip2->u_addr.ip4.addr).toString().c_str()); uint8_t mac[6]; esp_eth_get_mac(mac); ESP_LOGCONFIG(TAG, " MAC Address: %02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); diff --git a/esphome/core/config.py b/esphome/core/config.py index 1dbe2ec33a..5893f086f2 100644 --- a/esphome/core/config.py +++ b/esphome/core/config.py @@ -76,7 +76,7 @@ PLATFORMIO_ESP8266_LUT = { PLATFORMIO_ESP32_LUT = { **ARDUINO_VERSION_ESP32, - "RECOMMENDED": ARDUINO_VERSION_ESP32["1.0.4"], + "RECOMMENDED": ARDUINO_VERSION_ESP32["1.0.6"], "LATEST": "espressif32", "DEV": ARDUINO_VERSION_ESP32["dev"], } diff --git a/esphome/core/util.h b/esphome/core/util.h index 8e30211be6..4b3e79353a 100644 --- a/esphome/core/util.h +++ b/esphome/core/util.h @@ -5,6 +5,11 @@ namespace esphome { +/// Macro for IDF version comparision +#ifndef ESP_IDF_VERSION_VAL +#define ESP_IDF_VERSION_VAL(major, minor, patch) ((major << 16) | (minor << 8) | (patch)) +#endif + /// Return whether the node is connected to the network (through wifi, eth, ...) bool network_is_connected(); /// Get the active network hostname From 9ecead26455679a6637b1ee5c31810447a08cbe8 Mon Sep 17 00:00:00 2001 From: testbughub <30836300+testbughub@users.noreply.github.com> Date: Mon, 17 May 2021 01:38:49 +0200 Subject: [PATCH 040/104] Added bottom segment to digit 9 (#1787) --- esphome/components/tm1637/tm1637.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/tm1637/tm1637.cpp b/esphome/components/tm1637/tm1637.cpp index 833e3caecd..653a9657f4 100644 --- a/esphome/components/tm1637/tm1637.cpp +++ b/esphome/components/tm1637/tm1637.cpp @@ -46,7 +46,7 @@ const uint8_t TM1637_ASCII_TO_RAW[] PROGMEM = { 0b01011111, // '6', ord 0x36 0b01110000, // '7', ord 0x37 0b01111111, // '8', ord 0x38 - 0b01110011, // '9', ord 0x39 + 0b01111011, // '9', ord 0x39 0b01001000, // ':', ord 0x3A 0b01011000, // ';', ord 0x3B TM1637_UNKNOWN_CHAR, // '<', ord 0x3C From d0eaebe19fe91c5f0d10df57df7af6d1c179e6cc Mon Sep 17 00:00:00 2001 From: Stanislav Meduna Date: Mon, 17 May 2021 03:03:58 +0200 Subject: [PATCH 041/104] Add support for the XPT2046 touchscreen controller (#1542) --- CODEOWNERS | 1 + esphome/components/xpt2046/__init__.py | 129 ++++++++++++ esphome/components/xpt2046/binary_sensor.py | 57 +++++ esphome/components/xpt2046/xpt2046.cpp | 217 ++++++++++++++++++++ esphome/components/xpt2046/xpt2046.h | 124 +++++++++++ tests/test4.yaml | 34 +++ 6 files changed, 562 insertions(+) create mode 100644 esphome/components/xpt2046/__init__.py create mode 100644 esphome/components/xpt2046/binary_sensor.py create mode 100644 esphome/components/xpt2046/xpt2046.cpp create mode 100644 esphome/components/xpt2046/xpt2046.h diff --git a/CODEOWNERS b/CODEOWNERS index 356cf07e2b..b8f00aa368 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -123,3 +123,4 @@ esphome/components/web_server_base/* @OttoWinter esphome/components/whirlpool/* @glmnet esphome/components/xiaomi_lywsd03mmc/* @ahpohl esphome/components/xiaomi_mhoc401/* @vevsvevs +esphome/components/xpt2046/* @numo68 diff --git a/esphome/components/xpt2046/__init__.py b/esphome/components/xpt2046/__init__.py new file mode 100644 index 0000000000..fc440bcbba --- /dev/null +++ b/esphome/components/xpt2046/__init__.py @@ -0,0 +1,129 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome import automation +from esphome import pins +from esphome.components import spi +from esphome.const import CONF_ID, CONF_ON_STATE, CONF_THRESHOLD, CONF_TRIGGER_ID + +CODEOWNERS = ["@numo68"] +AUTO_LOAD = ["binary_sensor"] +DEPENDENCIES = ["spi"] +MULTI_CONF = True + +CONF_REPORT_INTERVAL = "report_interval" +CONF_CALIBRATION_X_MIN = "calibration_x_min" +CONF_CALIBRATION_X_MAX = "calibration_x_max" +CONF_CALIBRATION_Y_MIN = "calibration_y_min" +CONF_CALIBRATION_Y_MAX = "calibration_y_max" +CONF_DIMENSION_X = "dimension_x" +CONF_DIMENSION_Y = "dimension_y" +CONF_SWAP_X_Y = "swap_x_y" +CONF_IRQ_PIN = "irq_pin" + +xpt2046_ns = cg.esphome_ns.namespace("xpt2046") +CONF_XPT2046_ID = "xpt2046_id" + +XPT2046Component = xpt2046_ns.class_( + "XPT2046Component", cg.PollingComponent, spi.SPIDevice +) + +XPT2046OnStateTrigger = xpt2046_ns.class_( + "XPT2046OnStateTrigger", automation.Trigger.template(cg.int_, cg.int_, cg.bool_) +) + + +def validate_xpt2046(config): + if ( + abs( + cv.int_(config[CONF_CALIBRATION_X_MAX]) + - cv.int_(config[CONF_CALIBRATION_X_MIN]) + ) + < 1000 + ): + raise cv.Invalid("Calibration X values difference < 1000") + + if ( + abs( + cv.int_(config[CONF_CALIBRATION_Y_MAX]) + - cv.int_(config[CONF_CALIBRATION_Y_MIN]) + ) + < 1000 + ): + raise cv.Invalid("Calibration Y values difference < 1000") + + return config + + +def report_interval(value): + if value == "never": + return 4294967295 # uint32_t max + return cv.positive_time_period_milliseconds(value) + + +CONFIG_SCHEMA = cv.All( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(XPT2046Component), + cv.Optional(CONF_IRQ_PIN): pins.gpio_input_pin_schema, + cv.Optional(CONF_CALIBRATION_X_MIN, default=0): cv.int_range( + min=0, max=4095 + ), + cv.Optional(CONF_CALIBRATION_X_MAX, default=4095): cv.int_range( + min=0, max=4095 + ), + cv.Optional(CONF_CALIBRATION_Y_MIN, default=0): cv.int_range( + min=0, max=4095 + ), + cv.Optional(CONF_CALIBRATION_Y_MAX, default=4095): cv.int_range( + min=0, max=4095 + ), + cv.Optional(CONF_DIMENSION_X, default=100): cv.positive_not_null_int, + cv.Optional(CONF_DIMENSION_Y, default=100): cv.positive_not_null_int, + cv.Optional(CONF_THRESHOLD, default=400): cv.int_range(min=0, max=4095), + cv.Optional(CONF_REPORT_INTERVAL, default="never"): report_interval, + cv.Optional(CONF_SWAP_X_Y, default=False): cv.boolean, + cv.Optional(CONF_ON_STATE): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id( + XPT2046OnStateTrigger + ), + } + ), + } + ) + .extend(cv.polling_component_schema("50ms")) + .extend(spi.spi_device_schema()), + validate_xpt2046, +) + + +def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + yield cg.register_component(var, config) + yield spi.register_spi_device(var, config) + + cg.add(var.set_threshold(config[CONF_THRESHOLD])) + cg.add(var.set_report_interval(config[CONF_REPORT_INTERVAL])) + cg.add(var.set_dimensions(config[CONF_DIMENSION_X], config[CONF_DIMENSION_Y])) + cg.add( + var.set_calibration( + config[CONF_CALIBRATION_X_MIN], + config[CONF_CALIBRATION_X_MAX], + config[CONF_CALIBRATION_Y_MIN], + config[CONF_CALIBRATION_Y_MAX], + ) + ) + + if CONF_SWAP_X_Y in config: + cg.add(var.set_swap_x_y(config[CONF_SWAP_X_Y])) + + if CONF_IRQ_PIN in config: + pin = yield cg.gpio_pin_expression(config[CONF_IRQ_PIN]) + cg.add(var.set_irq_pin(pin)) + + for conf in config.get(CONF_ON_STATE, []): + yield automation.build_automation( + var.get_on_state_trigger(), + [(cg.int_, "x"), (cg.int_, "y"), (cg.bool_, "touched")], + conf, + ) diff --git a/esphome/components/xpt2046/binary_sensor.py b/esphome/components/xpt2046/binary_sensor.py new file mode 100644 index 0000000000..457b706caf --- /dev/null +++ b/esphome/components/xpt2046/binary_sensor.py @@ -0,0 +1,57 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import binary_sensor +from esphome.const import CONF_ID +from . import ( + xpt2046_ns, + XPT2046Component, + CONF_XPT2046_ID, +) + +CONF_X_MIN = "x_min" +CONF_X_MAX = "x_max" +CONF_Y_MIN = "y_min" +CONF_Y_MAX = "y_max" + +DEPENDENCIES = ["xpt2046"] +XPT2046Button = xpt2046_ns.class_("XPT2046Button", binary_sensor.BinarySensor) + + +def validate_xpt2046_button(config): + if cv.int_(config[CONF_X_MAX]) < cv.int_(config[CONF_X_MIN]) or cv.int_( + config[CONF_Y_MAX] + ) < cv.int_(config[CONF_Y_MIN]): + raise cv.Invalid("x_max is less than x_min or y_max is less than y_min") + + return config + + +CONFIG_SCHEMA = cv.All( + binary_sensor.BINARY_SENSOR_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(XPT2046Button), + cv.GenerateID(CONF_XPT2046_ID): cv.use_id(XPT2046Component), + cv.Required(CONF_X_MIN): cv.int_range(min=0, max=4095), + cv.Required(CONF_X_MAX): cv.int_range(min=0, max=4095), + cv.Required(CONF_Y_MIN): cv.int_range(min=0, max=4095), + cv.Required(CONF_Y_MAX): cv.int_range(min=0, max=4095), + } + ), + validate_xpt2046_button, +) + + +def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + yield binary_sensor.register_binary_sensor(var, config) + hub = yield cg.get_variable(config[CONF_XPT2046_ID]) + cg.add( + var.set_area( + config[CONF_X_MIN], + config[CONF_X_MAX], + config[CONF_Y_MIN], + config[CONF_Y_MAX], + ) + ) + + cg.add(hub.register_button(var)) diff --git a/esphome/components/xpt2046/xpt2046.cpp b/esphome/components/xpt2046/xpt2046.cpp new file mode 100644 index 0000000000..3e22e82859 --- /dev/null +++ b/esphome/components/xpt2046/xpt2046.cpp @@ -0,0 +1,217 @@ +#include "xpt2046.h" +#include "esphome/core/log.h" +#include "esphome/core/helpers.h" + +#include + +namespace esphome { +namespace xpt2046 { + +static const char *TAG = "xpt2046"; + +void XPT2046Component::setup() { + if (this->irq_pin_ != nullptr) { + // The pin reports a touch with a falling edge. Unfortunately the pin goes also changes state + // while the channels are read and wiring it as an interrupt is not straightforward and would + // need careful masking. A GPIO poll is cheap so we'll just use that. + this->irq_pin_->setup(); // INPUT + } + spi_setup(); + read_adc_(0xD0); // ADC powerdown, enable PENIRQ pin +} + +void XPT2046Component::loop() { + if (this->irq_pin_ != nullptr) { + // Force immediate update if a falling edge (= touched is seen) Ignore if still active + // (that would mean that we missed the release because of a too long update interval) + bool val = this->irq_pin_->digital_read(); + if (!val && this->last_irq_ && !this->touched) { + ESP_LOGD(TAG, "Falling penirq edge, forcing update"); + update(); + } + this->last_irq_ = val; + } +} + +void XPT2046Component::update() { + int16_t data[6]; + bool touch = false; + unsigned long now = millis(); + + this->z_raw = 0; + + // In case the penirq pin is present only do the SPI transaction if it reports a touch (is low). + // The touch has to be also confirmed with checking the pressure over threshold + if (this->irq_pin_ == nullptr || !this->irq_pin_->digital_read()) { + enable(); + + int16_t z1 = read_adc_(0xB1 /* Z1 */); + int16_t z2 = read_adc_(0xC1 /* Z2 */); + + this->z_raw = z1 + 4095 - z2; + + touch = (this->z_raw >= this->threshold_); + if (touch) { + read_adc_(0x91 /* Y */); // dummy Y measure, 1st is always noisy + data[0] = read_adc_(0xD1 /* X */); + data[1] = read_adc_(0x91 /* Y */); // make 3 x-y measurements + data[2] = read_adc_(0xD1 /* X */); + data[3] = read_adc_(0x91 /* Y */); + data[4] = read_adc_(0xD1 /* X */); + } + + data[5] = read_adc_(0x90 /* Y */); // Last Y touch power down + + disable(); + } + + if (touch) { + this->x_raw = best_two_avg(data[0], data[2], data[4]); + this->y_raw = best_two_avg(data[1], data[3], data[5]); + } else { + this->x_raw = this->y_raw = 0; + } + + ESP_LOGV(TAG, "Update [x, y] = [%d, %d], z = %d%s", this->x_raw, this->y_raw, this->z_raw, (touch ? " touched" : "")); + + if (touch) { + // Normalize raw data according to calibration min and max + + int16_t x_val = normalize(this->x_raw, this->x_raw_min_, this->x_raw_max_); + int16_t y_val = normalize(this->y_raw, this->y_raw_min_, this->y_raw_max_); + + if (this->swap_x_y_) { + std::swap(x_val, y_val); + } + + if (this->invert_x_) { + x_val = 0x7fff - x_val; + } + + if (this->invert_y_) { + y_val = 0x7fff - y_val; + } + + x_val = (int16_t)((int) x_val * this->x_dim_ / 0x7fff); + y_val = (int16_t)((int) y_val * this->y_dim_ / 0x7fff); + + if (!this->touched || (now - this->last_pos_ms_) >= this->report_millis_) { + ESP_LOGD(TAG, "Raw [x, y] = [%d, %d], transformed = [%d, %d]", this->x_raw, this->y_raw, x_val, y_val); + + this->x = x_val; + this->y = y_val; + this->touched = true; + this->last_pos_ms_ = now; + + this->on_state_trigger_->process(this->x, this->y, true); + for (auto *button : this->buttons_) + button->touch(this->x, this->y); + } + } else { + if (this->touched) { + ESP_LOGD(TAG, "Released [%d, %d]", this->x, this->y); + + this->touched = false; + + this->on_state_trigger_->process(this->x, this->y, false); + for (auto *button : this->buttons_) + button->release(); + } + } +} + +void XPT2046Component::set_calibration(int16_t x_min, int16_t x_max, int16_t y_min, int16_t y_max) { + this->x_raw_min_ = std::min(x_min, x_max); + this->x_raw_max_ = std::max(x_min, x_max); + this->y_raw_min_ = std::min(y_min, y_max); + this->y_raw_max_ = std::max(y_min, y_max); + this->invert_x_ = (x_min > x_max); + this->invert_y_ = (y_min > y_max); +} + +void XPT2046Component::dump_config() { + ESP_LOGCONFIG(TAG, "XPT2046:"); + + LOG_PIN(" IRQ Pin: ", this->irq_pin_); + ESP_LOGCONFIG(TAG, " X min: %d", this->x_raw_min_); + ESP_LOGCONFIG(TAG, " X max: %d", this->x_raw_max_); + ESP_LOGCONFIG(TAG, " Y min: %d", this->y_raw_min_); + ESP_LOGCONFIG(TAG, " Y max: %d", this->y_raw_max_); + ESP_LOGCONFIG(TAG, " X dim: %d", this->x_dim_); + ESP_LOGCONFIG(TAG, " Y dim: %d", this->y_dim_); + if (this->swap_x_y_) { + ESP_LOGCONFIG(TAG, " Swap X/Y"); + } + ESP_LOGCONFIG(TAG, " threshold: %d", this->threshold_); + ESP_LOGCONFIG(TAG, " Report interval: %u", this->report_millis_); + + LOG_UPDATE_INTERVAL(this); +} + +float XPT2046Component::get_setup_priority() const { return setup_priority::DATA; } + +int16_t XPT2046Component::best_two_avg(int16_t x, int16_t y, int16_t z) { + int16_t da, db, dc; + int16_t reta = 0; + + da = (x > y) ? x - y : y - x; + db = (x > z) ? x - z : z - x; + dc = (z > y) ? z - y : y - z; + + if (da <= db && da <= dc) { + reta = (x + y) >> 1; + } else if (db <= da && db <= dc) { + reta = (x + z) >> 1; + } else { + reta = (y + z) >> 1; + } + + return reta; +} + +int16_t XPT2046Component::normalize(int16_t val, int16_t min_val, int16_t max_val) { + int16_t ret; + + if (val <= min_val) { + ret = 0; + } else if (val >= max_val) { + ret = 0x7fff; + } else { + ret = (int16_t)((int) 0x7fff * (val - min_val) / (max_val - min_val)); + } + + return ret; +} + +int16_t XPT2046Component::read_adc_(uint8_t ctrl) { + uint8_t data[2]; + + write_byte(ctrl); + data[0] = read_byte(); + data[1] = read_byte(); + + return ((data[0] << 8) | data[1]) >> 3; +} + +void XPT2046OnStateTrigger::process(int x, int y, bool touched) { this->trigger(x, y, touched); } + +void XPT2046Button::touch(int16_t x, int16_t y) { + bool touched = (x >= this->x_min_ && x <= this->x_max_ && y >= this->y_min_ && y <= this->y_max_); + + if (touched) { + this->publish_state(true); + this->state_ = true; + } else { + release(); + } +} + +void XPT2046Button::release() { + if (this->state_) { + this->publish_state(false); + this->state_ = false; + } +} + +} // namespace xpt2046 +} // namespace esphome diff --git a/esphome/components/xpt2046/xpt2046.h b/esphome/components/xpt2046/xpt2046.h new file mode 100644 index 0000000000..7fd80c3228 --- /dev/null +++ b/esphome/components/xpt2046/xpt2046.h @@ -0,0 +1,124 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/automation.h" +#include "esphome/components/spi/spi.h" +#include "esphome/components/binary_sensor/binary_sensor.h" + +namespace esphome { +namespace xpt2046 { + +class XPT2046OnStateTrigger : public Trigger { + public: + void process(int x, int y, bool touched); +}; + +class XPT2046Button : public binary_sensor::BinarySensor { + public: + /// Set the touch screen area where the button will detect the touch. + void set_area(int16_t x_min, int16_t x_max, int16_t y_min, int16_t y_max) { + this->x_min_ = x_min; + this->x_max_ = x_max; + this->y_min_ = y_min; + this->y_max_ = y_max; + } + + void touch(int16_t x, int16_t y); + void release(); + + protected: + int16_t x_min_, x_max_, y_min_, y_max_; + bool state_{false}; +}; + +class XPT2046Component : public PollingComponent, + public spi::SPIDevice { + public: + /// Set the logical touch screen dimensions. + void set_dimensions(int16_t x, int16_t y) { + this->x_dim_ = x; + this->y_dim_ = y; + } + /// Set the coordinates for the touch screen edges. + void set_calibration(int16_t x_min, int16_t x_max, int16_t y_min, int16_t y_max); + /// If true the x and y axes will be swapped + void set_swap_x_y(bool val) { this->swap_x_y_ = val; } + + /// Set the interval to report the touch point perodically. + void set_report_interval(uint32_t interval) { this->report_millis_ = interval; } + /// Set the threshold for the touch detection. + void set_threshold(int16_t threshold) { this->threshold_ = threshold; } + /// Set the pin used to detect the touch. + void set_irq_pin(GPIOPin *pin) { this->irq_pin_ = pin; } + /// Get an access to the on_state automation trigger + XPT2046OnStateTrigger *get_on_state_trigger() const { return this->on_state_trigger_; } + /// Register a virtual button to the component. + void register_button(XPT2046Button *button) { this->buttons_.push_back(button); } + + void setup() override; + void dump_config() override; + float get_setup_priority() const override; + + /** Detect the touch if the irq pin is specified. + * + * If the touch is detected and the component does not already know about it + * the update() is called immediately. If the irq pin is not specified + * the loop() is a no-op. + */ + void loop() override; + + /** Read and process the values from the hardware. + * + * Read the raw x, y and touch pressure values from the chip, detect the touch, + * and if touched, transform to the user x and y coordinates. If the state has + * changed or if the value should be reported again due to the + * report interval, run the action and inform the virtual buttons. + */ + void update() override; + + /**@{*/ + /** Coordinates of the touch position. + * + * The values are set immediately before the on_state action with touched == true + * is triggered. The action with touched == false sends the coordinates of the last + * reported touch. + */ + int16_t x{0}, y{0}; + /**@}*/ + + /// True if the component currently detects the touch + bool touched{false}; + + /**@{*/ + /** Raw sensor values of the coordinates and the pressure. + * + * The values are set each time the update() method is called. + */ + int16_t x_raw{0}, y_raw{0}, z_raw{0}; + /**@}*/ + + protected: + static int16_t best_two_avg(int16_t x, int16_t y, int16_t z); + static int16_t normalize(int16_t val, int16_t min_val, int16_t max_val); + + int16_t read_adc_(uint8_t ctrl); + + int16_t threshold_; + int16_t x_raw_min_, x_raw_max_, y_raw_min_, y_raw_max_; + int16_t x_dim_, y_dim_; + bool invert_x_, invert_y_; + bool swap_x_y_; + + uint32_t report_millis_; + unsigned long last_pos_ms_{0}; + + GPIOPin *irq_pin_{nullptr}; + bool last_irq_{true}; + + XPT2046OnStateTrigger *on_state_trigger_{new XPT2046OnStateTrigger()}; + std::vector buttons_{}; +}; + +} // namespace xpt2046 +} // namespace esphome diff --git a/tests/test4.yaml b/tests/test4.yaml index d2dcb8b682..fb2bce82a4 100644 --- a/tests/test4.yaml +++ b/tests/test4.yaml @@ -100,6 +100,15 @@ binary_sensor: on_state: then: - lambda: 'ESP_LOGI("ar1:", "%d", x);' + - platform: xpt2046 + xpt2046_id: touchscreen + id: touch_key0 + x_min: 80 + x_max: 160 + y_min: 106 + y_max: 212 + on_state: + - lambda: 'ESP_LOGI("main", "key0: %s", (x ? "touch" : "release"));' climate: - platform: tuya @@ -180,3 +189,28 @@ external_components: components: ["bh1750"] - source: ../esphome/components components: ["sntp"] +xpt2046: + id: touchscreen + cs_pin: 17 + irq_pin: 16 + update_interval: 50ms + report_interval: 1s + threshold: 400 + dimension_x: 240 + dimension_y: 320 + calibration_x_min: 3860 + calibration_x_max: 280 + calibration_y_min: 340 + calibration_y_max: 3860 + swap_x_y: False + on_state: + - lambda: |- + ESP_LOGI("main", "args x=%d, y=%d, touched=%s", x, y, (touched ? "touch" : "release")); + ESP_LOGI("main", "member x=%d, y=%d, touched=%d, x_raw=%d, y_raw=%d, z_raw=%d", + id(touchscreen).x, + id(touchscreen).y, + (int) id(touchscreen).touched, + id(touchscreen).x_raw, + id(touchscreen).y_raw, + id(touchscreen).z_raw + ); From 95ed3e9d469cdea9e1948a132b2db3b9ec11a6f7 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 17 May 2021 13:22:49 +1200 Subject: [PATCH 042/104] Revert "Added bottom segment to digit 9 (#1787)" (#1791) This reverts commit 9ecead26455679a6637b1ee5c31810447a08cbe8. --- esphome/components/tm1637/tm1637.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/tm1637/tm1637.cpp b/esphome/components/tm1637/tm1637.cpp index 653a9657f4..833e3caecd 100644 --- a/esphome/components/tm1637/tm1637.cpp +++ b/esphome/components/tm1637/tm1637.cpp @@ -46,7 +46,7 @@ const uint8_t TM1637_ASCII_TO_RAW[] PROGMEM = { 0b01011111, // '6', ord 0x36 0b01110000, // '7', ord 0x37 0b01111111, // '8', ord 0x38 - 0b01111011, // '9', ord 0x39 + 0b01110011, // '9', ord 0x39 0b01001000, // ':', ord 0x3A 0b01011000, // ';', ord 0x3B TM1637_UNKNOWN_CHAR, // '<', ord 0x3C From d4686c0fb146fd0fe1d764d1848d4bed3b3a6fc3 Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Mon, 17 May 2021 07:14:15 +0200 Subject: [PATCH 043/104] Introduce new async-def coroutine syntax (#1657) --- esphome/__main__.py | 13 +- esphome/automation.py | 114 ++++++------ esphome/components/ota/__init__.py | 4 +- esphome/core/__init__.py | 166 ++++-------------- esphome/core/config.py | 20 +-- esphome/coroutine.py | 252 +++++++++++++++++++++++++++ esphome/cpp_generator.py | 17 +- requirements_test.txt | 1 + tests/unit_tests/test_core.py | 8 +- tests/unit_tests/test_cpp_helpers.py | 34 ++-- 10 files changed, 391 insertions(+), 238 deletions(-) create mode 100644 esphome/coroutine.py diff --git a/esphome/__main__.py b/esphome/__main__.py index 1ec72d9255..b78962c2c0 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -18,7 +18,7 @@ from esphome.const import ( CONF_ESPHOME, CONF_PLATFORMIO_OPTIONS, ) -from esphome.core import CORE, EsphomeError, coroutine, coroutine_with_priority +from esphome.core import CORE, EsphomeError, coroutine from esphome.helpers import indent from esphome.util import ( run_external_command, @@ -127,15 +127,16 @@ def wrap_to_code(name, comp): coro = coroutine(comp.to_code) @functools.wraps(comp.to_code) - @coroutine_with_priority(coro.priority) - def wrapped(conf): + async def wrapped(conf): cg.add(cg.LineComment(f"{name}:")) if comp.config_schema is not None: conf_str = yaml_util.dump(conf) conf_str = conf_str.replace("//", "") cg.add(cg.LineComment(indent(conf_str))) - yield coro(conf) + await coro(conf) + if hasattr(coro, "priority"): + wrapped.priority = coro.priority return wrapped @@ -610,7 +611,7 @@ def run_esphome(argv): try: return PRE_CONFIG_ACTIONS[args.command](args) except EsphomeError as e: - _LOGGER.error(e) + _LOGGER.error(e, exc_info=args.verbose) return 1 for conf_path in args.configuration: @@ -628,7 +629,7 @@ def run_esphome(argv): try: rc = POST_CONFIG_ACTIONS[args.command](args, config) except EsphomeError as e: - _LOGGER.error(e) + _LOGGER.error(e, exc_info=args.verbose) return 1 if rc != 0: return rc diff --git a/esphome/automation.py b/esphome/automation.py index eb6cb02532..1cf6bbf542 100644 --- a/esphome/automation.py +++ b/esphome/automation.py @@ -10,7 +10,6 @@ from esphome.const import ( CONF_TYPE_ID, CONF_TIME, ) -from esphome.core import coroutine from esphome.jsonschema import jschema_extractor from esphome.util import Registry @@ -142,27 +141,27 @@ NotCondition = cg.esphome_ns.class_("NotCondition", Condition) @register_condition("and", AndCondition, validate_condition_list) -def and_condition_to_code(config, condition_id, template_arg, args): - conditions = yield build_condition_list(config, template_arg, args) - yield cg.new_Pvariable(condition_id, template_arg, conditions) +async def and_condition_to_code(config, condition_id, template_arg, args): + conditions = await build_condition_list(config, template_arg, args) + return cg.new_Pvariable(condition_id, template_arg, conditions) @register_condition("or", OrCondition, validate_condition_list) -def or_condition_to_code(config, condition_id, template_arg, args): - conditions = yield build_condition_list(config, template_arg, args) - yield cg.new_Pvariable(condition_id, template_arg, conditions) +async def or_condition_to_code(config, condition_id, template_arg, args): + conditions = await build_condition_list(config, template_arg, args) + return cg.new_Pvariable(condition_id, template_arg, conditions) @register_condition("not", NotCondition, validate_potentially_and_condition) -def not_condition_to_code(config, condition_id, template_arg, args): - condition = yield build_condition(config, template_arg, args) - yield cg.new_Pvariable(condition_id, template_arg, condition) +async def not_condition_to_code(config, condition_id, template_arg, args): + condition = await build_condition(config, template_arg, args) + return cg.new_Pvariable(condition_id, template_arg, condition) @register_condition("lambda", LambdaCondition, cv.lambda_) -def lambda_condition_to_code(config, condition_id, template_arg, args): - lambda_ = yield cg.process_lambda(config, args, return_type=bool) - yield cg.new_Pvariable(condition_id, template_arg, lambda_) +async def lambda_condition_to_code(config, condition_id, template_arg, args): + lambda_ = await cg.process_lambda(config, args, return_type=bool) + return cg.new_Pvariable(condition_id, template_arg, lambda_) @register_condition( @@ -177,26 +176,26 @@ def lambda_condition_to_code(config, condition_id, template_arg, args): } ).extend(cv.COMPONENT_SCHEMA), ) -def for_condition_to_code(config, condition_id, template_arg, args): - condition = yield build_condition( +async def for_condition_to_code(config, condition_id, template_arg, args): + condition = await build_condition( config[CONF_CONDITION], cg.TemplateArguments(), [] ) var = cg.new_Pvariable(condition_id, template_arg, condition) - yield cg.register_component(var, config) - templ = yield cg.templatable(config[CONF_TIME], args, cg.uint32) + await cg.register_component(var, config) + templ = await cg.templatable(config[CONF_TIME], args, cg.uint32) cg.add(var.set_time(templ)) - yield var + return var @register_action( "delay", DelayAction, cv.templatable(cv.positive_time_period_milliseconds) ) -def delay_action_to_code(config, action_id, template_arg, args): +async def delay_action_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) - yield cg.register_component(var, {}) - template_ = yield cg.templatable(config, args, cg.uint32) + await cg.register_component(var, {}) + template_ = await cg.templatable(config, args, cg.uint32) cg.add(var.set_delay(template_)) - yield var + return var @register_action( @@ -211,16 +210,16 @@ def delay_action_to_code(config, action_id, template_arg, args): cv.has_at_least_one_key(CONF_THEN, CONF_ELSE), ), ) -def if_action_to_code(config, action_id, template_arg, args): - conditions = yield build_condition(config[CONF_CONDITION], template_arg, args) +async def if_action_to_code(config, action_id, template_arg, args): + conditions = await build_condition(config[CONF_CONDITION], template_arg, args) var = cg.new_Pvariable(action_id, template_arg, conditions) if CONF_THEN in config: - actions = yield build_action_list(config[CONF_THEN], template_arg, args) + actions = await build_action_list(config[CONF_THEN], template_arg, args) cg.add(var.add_then(actions)) if CONF_ELSE in config: - actions = yield build_action_list(config[CONF_ELSE], template_arg, args) + actions = await build_action_list(config[CONF_ELSE], template_arg, args) cg.add(var.add_else(actions)) - yield var + return var @register_action( @@ -233,12 +232,12 @@ def if_action_to_code(config, action_id, template_arg, args): } ), ) -def while_action_to_code(config, action_id, template_arg, args): - conditions = yield build_condition(config[CONF_CONDITION], template_arg, args) +async def while_action_to_code(config, action_id, template_arg, args): + conditions = await build_condition(config[CONF_CONDITION], template_arg, args) var = cg.new_Pvariable(action_id, template_arg, conditions) - actions = yield build_action_list(config[CONF_THEN], template_arg, args) + actions = await build_action_list(config[CONF_THEN], template_arg, args) cg.add(var.add_then(actions)) - yield var + return var def validate_wait_until(value): @@ -253,17 +252,17 @@ def validate_wait_until(value): @register_action("wait_until", WaitUntilAction, validate_wait_until) -def wait_until_action_to_code(config, action_id, template_arg, args): - conditions = yield build_condition(config[CONF_CONDITION], template_arg, args) +async def wait_until_action_to_code(config, action_id, template_arg, args): + conditions = await build_condition(config[CONF_CONDITION], template_arg, args) var = cg.new_Pvariable(action_id, template_arg, conditions) - yield cg.register_component(var, {}) - yield var + await cg.register_component(var, {}) + return var @register_action("lambda", LambdaAction, cv.lambda_) -def lambda_action_to_code(config, action_id, template_arg, args): - lambda_ = yield cg.process_lambda(config, args, return_type=cg.void) - yield cg.new_Pvariable(action_id, template_arg, lambda_) +async def lambda_action_to_code(config, action_id, template_arg, args): + lambda_ = await cg.process_lambda(config, args, return_type=cg.void) + return cg.new_Pvariable(action_id, template_arg, lambda_) @register_action( @@ -275,54 +274,51 @@ def lambda_action_to_code(config, action_id, template_arg, args): } ), ) -def component_update_action_to_code(config, action_id, template_arg, args): - comp = yield cg.get_variable(config[CONF_ID]) - yield cg.new_Pvariable(action_id, template_arg, comp) +async def component_update_action_to_code(config, action_id, template_arg, args): + comp = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, comp) -@coroutine -def build_action(full_config, template_arg, args): +async def build_action(full_config, template_arg, args): registry_entry, config = cg.extract_registry_entry_config( ACTION_REGISTRY, full_config ) action_id = full_config[CONF_TYPE_ID] builder = registry_entry.coroutine_fun - yield builder(config, action_id, template_arg, args) + ret = await builder(config, action_id, template_arg, args) + return ret -@coroutine -def build_action_list(config, templ, arg_type): +async def build_action_list(config, templ, arg_type): actions = [] for conf in config: - action = yield build_action(conf, templ, arg_type) + action = await build_action(conf, templ, arg_type) actions.append(action) - yield actions + return actions -@coroutine -def build_condition(full_config, template_arg, args): +async def build_condition(full_config, template_arg, args): registry_entry, config = cg.extract_registry_entry_config( CONDITION_REGISTRY, full_config ) action_id = full_config[CONF_TYPE_ID] builder = registry_entry.coroutine_fun - yield builder(config, action_id, template_arg, args) + ret = await builder(config, action_id, template_arg, args) + return ret -@coroutine -def build_condition_list(config, templ, args): +async def build_condition_list(config, templ, args): conditions = [] for conf in config: - condition = yield build_condition(conf, templ, args) + condition = await build_condition(conf, templ, args) conditions.append(condition) - yield conditions + return conditions -@coroutine -def build_automation(trigger, args, config): +async def build_automation(trigger, args, config): arg_types = [arg[0] for arg in args] templ = cg.TemplateArguments(*arg_types) obj = cg.new_Pvariable(config[CONF_AUTOMATION_ID], templ, trigger) - actions = yield build_action_list(config[CONF_THEN], templ, args) + actions = await build_action_list(config[CONF_THEN], templ, args) cg.add(obj.add_actions(actions)) - yield obj + return obj diff --git a/esphome/components/ota/__init__.py b/esphome/components/ota/__init__.py index 25a278f5bf..7ee7ef47ca 100644 --- a/esphome/components/ota/__init__.py +++ b/esphome/components/ota/__init__.py @@ -32,12 +32,12 @@ CONFIG_SCHEMA = cv.Schema( @coroutine_with_priority(50.0) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) cg.add(var.set_port(config[CONF_PORT])) cg.add(var.set_auth_password(config[CONF_PASSWORD])) - yield cg.register_component(var, config) + await cg.register_component(var, config) if config[CONF_SAFE_MODE]: condition = var.should_enter_safe_mode( diff --git a/esphome/core/__init__.py b/esphome/core/__init__.py index 47048478ef..1841dfd8be 100644 --- a/esphome/core/__init__.py +++ b/esphome/core/__init__.py @@ -1,24 +1,23 @@ -import functools -import heapq -import inspect import logging - import math import os import re - -# pylint: disable=unused-import, wrong-import-order -from typing import Any, Dict, List, Optional, Set, TYPE_CHECKING # noqa +from typing import TYPE_CHECKING, Any, Dict, List, Optional, Set, Tuple from esphome.const import ( CONF_ARDUINO_VERSION, - SOURCE_FILE_EXTENSIONS, CONF_COMMENT, CONF_ESPHOME, CONF_USE_ADDRESS, CONF_ETHERNET, CONF_WIFI, + SOURCE_FILE_EXTENSIONS, ) +from esphome.coroutine import FakeAwaitable as _FakeAwaitable +from esphome.coroutine import FakeEventLoop as _FakeEventLoop + +# pylint: disable=unused-import +from esphome.coroutine import coroutine, coroutine_with_priority # noqa from esphome.helpers import ensure_unique_string, is_hassio from esphome.util import OrderedDict @@ -431,64 +430,6 @@ class Library: return NotImplemented -def coroutine(func): - return coroutine_with_priority(0.0)(func) - - -def coroutine_with_priority(priority): - def decorator(func): - if getattr(func, "_esphome_coroutine", False): - # If func is already a coroutine, do not re-wrap it (performance) - return func - - @functools.wraps(func) - def _wrapper_generator(*args, **kwargs): - instance_id = kwargs.pop("__esphome_coroutine_instance__") - if not inspect.isgeneratorfunction(func): - # If func is not a generator, return result immediately - yield func(*args, **kwargs) - # pylint: disable=protected-access - CORE._remove_coroutine(instance_id) - return - gen = func(*args, **kwargs) - var = None - try: - while True: - var = gen.send(var) - if inspect.isgenerator(var): - # Yielded generator, equivalent to 'yield from' - x = None - for x in var: - yield None - # Last yield value is the result - var = x - else: - yield var - except StopIteration: - # Stopping iteration - yield var - # pylint: disable=protected-access - CORE._remove_coroutine(instance_id) - - @functools.wraps(func) - def wrapper(*args, **kwargs): - import random - - instance_id = random.randint(0, 2 ** 32) - kwargs["__esphome_coroutine_instance__"] = instance_id - gen = _wrapper_generator(*args, **kwargs) - # pylint: disable=protected-access - CORE._add_active_coroutine(instance_id, gen) - return gen - - # pylint: disable=protected-access - wrapper._esphome_coroutine = True - wrapper.priority = priority - return wrapper - - return decorator - - def find_source_files(file): files = set() directory = os.path.abspath(os.path.dirname(file)) @@ -527,7 +468,7 @@ class EsphomeCore: # The pending tasks in the task queue (mostly for C++ generation) # This is a priority queue (with heapq) # Each item is a tuple of form: (-priority, unique number, task) - self.pending_tasks = [] + self.event_loop = _FakeEventLoop() # Task counter for pending tasks self.task_counter = 0 # The variable cache, for each ID this holds a MockObj of the variable obj @@ -542,9 +483,6 @@ class EsphomeCore: self.build_flags: Set[str] = set() # A set of defines to set for the compile process in esphome/core/defines.h self.defines: Set["Define"] = set() - # A dictionary of started coroutines, used to warn when a coroutine was not - # awaited. - self.active_coroutines: Dict[int, Any] = {} # A set of strings of names of loaded integrations, used to find namespace ID conflicts self.loaded_integrations = set() # A set of component IDs to track what Component subclasses are declared @@ -561,7 +499,7 @@ class EsphomeCore: self.board = None self.raw_config = None self.config = None - self.pending_tasks = [] + self.event_loop = _FakeEventLoop() self.task_counter = 0 self.variables = {} self.main_statements = [] @@ -569,7 +507,6 @@ class EsphomeCore: self.libraries = [] self.build_flags = set() self.defines = set() - self.active_coroutines = {} self.loaded_integrations = set() self.component_ids = set() @@ -596,12 +533,6 @@ class EsphomeCore: return None - def _add_active_coroutine(self, instance_id, obj): - self.active_coroutines[instance_id] = obj - - def _remove_coroutine(self, instance_id): - self.active_coroutines.pop(instance_id) - @property def arduino_version(self) -> str: if self.config is None: @@ -657,50 +588,13 @@ class EsphomeCore: return self.esp_platform == "ESP32" def add_job(self, func, *args, **kwargs): - coro = coroutine(func) - task = coro(*args, **kwargs) - item = (-coro.priority, self.task_counter, task) - self.task_counter += 1 - heapq.heappush(self.pending_tasks, item) - return task + self.event_loop.add_job(func, *args, **kwargs) def flush_tasks(self): - i = 0 - while self.pending_tasks: - i += 1 - if i > 1000000: - raise EsphomeError("Circular dependency detected!") - - inv_priority, num, task = heapq.heappop(self.pending_tasks) - priority = -inv_priority - _LOGGER.debug("Running %s (num %s)", task, num) - try: - next(task) - # Decrease priority over time, so that if this task is blocked - # due to a dependency others will clear the dependency - # This could be improved with a less naive approach - priority -= 1 - item = (-priority, num, task) - heapq.heappush(self.pending_tasks, item) - except StopIteration: - _LOGGER.debug(" -> finished") - - # Print not-awaited coroutines - for obj in self.active_coroutines.values(): - _LOGGER.warning( - "Coroutine '%s' %s was never awaited with 'yield'.", obj.__name__, obj - ) - _LOGGER.warning("Please file a bug report with your configuration.") - if self.active_coroutines: - raise EsphomeError() - if self.component_ids: - comps = ", ".join(f"'{x}'" for x in self.component_ids) - _LOGGER.warning( - "Components %s were never registered. Please create a bug report", comps - ) - _LOGGER.warning("with your configuration.") - raise EsphomeError() - self.active_coroutines.clear() + try: + self.event_loop.flush_tasks() + except RuntimeError as e: + raise EsphomeError(str(e)) from e def add(self, expression): from esphome.cpp_generator import Expression, Statement, statement @@ -779,25 +673,35 @@ class EsphomeCore: _LOGGER.debug("Adding define: %s", define) return define - def get_variable(self, id): + def _get_variable_generator(self, id): + while True: + try: + return self.variables[id] + except KeyError: + _LOGGER.debug("Waiting for variable %s (%r)", id, id) + yield + + async def get_variable(self, id) -> "MockObj": if not isinstance(id, ID): raise ValueError(f"ID {id!r} must be of type ID!") - while True: - if id in self.variables: - yield self.variables[id] - return - _LOGGER.debug("Waiting for variable %s (%r)", id, id) - yield None + # Fast path, check if already registered without awaiting + if id in self.variables: + return self.variables[id] + return await _FakeAwaitable(self._get_variable_generator(id)) - def get_variable_with_full_id(self, id): + def _get_variable_with_full_id_generator(self, id): while True: if id in self.variables: for k, v in self.variables.items(): if k == id: - yield (k, v) - return + return (k, v) _LOGGER.debug("Waiting for variable %s", id) - yield None, None + yield + + async def get_variable_with_full_id(self, id: ID) -> Tuple[ID, "MockObj"]: + if not isinstance(id, ID): + raise ValueError(f"ID {id!r} must be of type ID!") + return await _FakeAwaitable(self._get_variable_with_full_id_generator(id)) def register_variable(self, id, obj): if id in self.variables: diff --git a/esphome/core/config.py b/esphome/core/config.py index 5893f086f2..6bd8c6be0e 100644 --- a/esphome/core/config.py +++ b/esphome/core/config.py @@ -233,7 +233,7 @@ def include_file(path, basename): @coroutine_with_priority(-1000.0) -def add_includes(includes): +async def add_includes(includes): # Add includes at the very end, so that the included files can access global variables for include in includes: path = CORE.relative_config_path(include) @@ -249,7 +249,7 @@ def add_includes(includes): @coroutine_with_priority(-1000.0) -def _esp8266_add_lwip_type(): +async def _esp8266_add_lwip_type(): # If any component has already set this, do not change it if any( flag.startswith("-DPIO_FRAMEWORK_ARDUINO_LWIP2_") for flag in CORE.build_flags @@ -271,25 +271,25 @@ def _esp8266_add_lwip_type(): @coroutine_with_priority(30.0) -def _add_automations(config): +async def _add_automations(config): for conf in config.get(CONF_ON_BOOT, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], conf.get(CONF_PRIORITY)) - yield cg.register_component(trigger, conf) - yield automation.build_automation(trigger, [], conf) + await cg.register_component(trigger, conf) + await automation.build_automation(trigger, [], conf) for conf in config.get(CONF_ON_SHUTDOWN, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID]) - yield cg.register_component(trigger, conf) - yield automation.build_automation(trigger, [], conf) + await cg.register_component(trigger, conf) + await automation.build_automation(trigger, [], conf) for conf in config.get(CONF_ON_LOOP, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID]) - yield cg.register_component(trigger, conf) - yield automation.build_automation(trigger, [], conf) + await cg.register_component(trigger, conf) + await automation.build_automation(trigger, [], conf) @coroutine_with_priority(100.0) -def to_code(config): +async def to_code(config): cg.add_global(cg.global_ns.namespace("esphome").using) cg.add( cg.App.pre_setup( diff --git a/esphome/coroutine.py b/esphome/coroutine.py new file mode 100644 index 0000000000..58f79c6b36 --- /dev/null +++ b/esphome/coroutine.py @@ -0,0 +1,252 @@ +""" +ESPHome's coroutine system. + +The Problem: When running the code generationg, components can depend on variables being registered. +For example, an i2c-based sensor would need the i2c bus component to first be declared before the +codegen can emit code using that variable (or otherwise the C++ won't compile). + +ESPHome's codegen system solves this by using coroutine-like methods. When a component depends on +a variable, it waits for it to be registered using `await cg.get_variable()`. If the variable +hasn't been registered yet, control will be yielded back to another component until the variable +is registered. This leads to a topological sort, solving the dependency problem. + +Importantly, ESPHome only uses the coroutine *syntax*, no actual asyncio event loop is running in +the background. This is so that we can ensure the order of execution is constant for the same +YAML configuration, thus main.cpp only has to be recompiled if the configuration actually changes. + +There are two syntaxes for ESPHome coroutines ("old style" vs "new style" coroutines). + +"new style" - This is very much like coroutines you might be used to: + +```py +async def my_coroutine(config): + var = await cg.get_variable(config[CONF_ID]) + await some_other_coroutine(xyz) + return var +``` + +new style coroutines are `async def` methods that use `await` to await the result of another coroutine, +and can return values using a `return` statement. + +"old style" - This was a hack for when ESPHome still had to run on python 2, but is still compatible + +```py +@coroutine +def my_coroutine(config): + var = yield cg.get_variable(config[CONF_ID]) + yield some_other_coroutine(xyz) + yield var +``` + +Here everything is combined in `yield` expressions. You await other coroutines using `yield` and +the last `yield` expression defines what is returned. +""" + +import collections +import functools +import heapq +import inspect +import logging +import types +from typing import Any, Awaitable, Callable, Generator, Iterator, List, Tuple + +_LOGGER = logging.getLogger(__name__) + + +def coroutine(func: Callable[..., Any]) -> Callable[..., Awaitable[Any]]: + """Decorator to apply to methods to convert them to ESPHome coroutines.""" + if getattr(func, "_esphome_coroutine", False): + # If func is already a coroutine, do not re-wrap it (performance) + return func + if inspect.isasyncgenfunction(func): + # Trade-off: In ESPHome, there's not really a use-case for async generators. + # and during the transition to new-style syntax it will happen that a `yield` + # is not replaced properly, so don't accept async generators. + raise ValueError( + f"Async generator functions are not allowed. " + f"Please check whether you've replaced all yields with awaits/returns. " + f"See {func} in {func.__module__}" + ) + if inspect.iscoroutinefunction(func): + # A new-style async-def coroutine function, no conversion needed. + return func + + if inspect.isgeneratorfunction(func): + + @functools.wraps(func) + def coro(*args, **kwargs): + gen = func(*args, **kwargs) + ret = yield from _flatten_generator(gen) + return ret + + else: + # A "normal" function with no `yield` statements, convert to generator + # that includes a yield just so it's also a generator function + @functools.wraps(func) + def coro(*args, **kwargs): + res = func(*args, **kwargs) + yield + return res + + # Add coroutine internal python flag so that it can be awaited from new-style coroutines. + coro = types.coroutine(coro) + # pylint: disable=protected-access + coro._esphome_coroutine = True + return coro + + +def coroutine_with_priority(priority: float): + """Decorator to apply to functions to convert them to ESPHome coroutines. + + :param priority: priority with which to schedule the coroutine, higher priorities run first. + """ + + def decorator(func): + coro = coroutine(func) + coro.priority = priority + return coro + + return decorator + + +def _flatten_generator(gen: Generator[Any, Any, Any]): + to_send = None + while True: + try: + # Run until next yield expression + val = gen.send(to_send) + except StopIteration as e: + # return statement or end of function + + # From py3.3, return with a value is allowed in generators, + # and return value is transported in the value field of the exception. + # If we find a value in the exception, use that as the return value, + # otherwise use the value from the last yield statement ("old style") + ret = to_send if e.value is None else e.value + return ret + + if isinstance(val, collections.abc.Awaitable): + # yielded object that is awaitable (like `yield some_new_style_method()`) + # yield from __await__() like actual coroutines would. + to_send = yield from val.__await__() + elif inspect.isgenerator(val): + # Old style, like `yield cg.get_variable()` + to_send = yield from _flatten_generator(val) + else: + # Could be the last expression from this generator, record this as the return value + to_send = val + # perform a yield so that expressions like `while some_condition(): yield None` + # do not run without yielding control back to the top + yield + + +class FakeAwaitable: + """Convert a generator to an awaitable object. + + Needed for internals of `cg.get_variable`. There we can't use @coroutine because + native coroutines await from types.coroutine() directly without yielding back control to the top + (likely as a performance enhancement). + + If we instead wrap the generator in this FakeAwaitable, control is yielded back to the top + (reason unknown). + """ + + def __init__(self, gen: Generator[Any, Any, Any]) -> None: + self._gen = gen + + def __await__(self): + ret = yield from self._gen + return ret + + +@functools.total_ordering +class _Task: + def __init__( + self, + priority: float, + id_number: int, + iterator: Iterator[None], + original_function: Any, + ): + self.priority = priority + self.id_number = id_number + self.iterator = iterator + self.original_function = original_function + + def with_priority(self, priority: float) -> "_Task": + return _Task(priority, self.id_number, self.iterator, self.original_function) + + @property + def _cmp_tuple(self) -> Tuple[float, int]: + return (-self.priority, self.id_number) + + def __eq__(self, other): + return self._cmp_tuple == other._cmp_tuple + + def __ne__(self, other): + return not (self == other) + + def __lt__(self, other): + return self._cmp_tuple < other._cmp_tuple + + +class FakeEventLoop: + """Emulate an asyncio EventLoop to run some registered coroutine jobs in sequence.""" + + def __init__(self): + self._pending_tasks: List[_Task] = [] + self._task_counter = 0 + + def add_job(self, func, *args, **kwargs): + """Add a job to the task queue, + + Optionally retrieves priority from the function object, and schedules according to that. + """ + if inspect.iscoroutine(func): + raise ValueError("Can only add coroutine functions, not coroutine objects") + if inspect.iscoroutinefunction(func): + coro = func + gen = coro(*args, **kwargs).__await__() + else: + coro = coroutine(func) + gen = coro(*args, **kwargs) + prio = getattr(coro, "priority", 0.0) + task = _Task(prio, self._task_counter, gen, func) + self._task_counter += 1 + heapq.heappush(self._pending_tasks, task) + + def flush_tasks(self): + """Run until all tasks have been completed. + + :raises RuntimeError: if a deadlock is detected. + """ + i = 0 + while self._pending_tasks: + i += 1 + if i > 1000000: + # Detect deadlock/circular dependency by measuring how many times tasks have been + # executed. On the big tests/test1.yaml we only get to a fraction of this, so + # this shouldn't be a problem. + raise RuntimeError( + "Circular dependency detected! " + "Please run with -v option to see what functions failed to " + "complete." + ) + + task: _Task = heapq.heappop(self._pending_tasks) + _LOGGER.debug( + "Running %s in %s (num %s)", + task.original_function.__qualname__, + task.original_function.__module__, + task.id_number, + ) + + try: + next(task.iterator) + # Decrease priority over time, so that if this task is blocked + # due to a dependency others will clear the dependency + # This could be improved with a less naive approach + new_task = task.with_priority(task.priority - 1) + heapq.heappush(self._pending_tasks, new_task) + except StopIteration: + _LOGGER.debug(" -> finished") diff --git a/esphome/cpp_generator.py b/esphome/cpp_generator.py index 999b252dde..d71e0df4d2 100644 --- a/esphome/cpp_generator.py +++ b/esphome/cpp_generator.py @@ -549,8 +549,7 @@ def add_define(name: str, value: SafeExpType = None): CORE.add_define(Define(name, safe_exp(value))) -@coroutine -def get_variable(id_: ID) -> Generator["MockObj", None, None]: +async def get_variable(id_: ID) -> "MockObj": """ Wait for the given ID to be defined in the code generation and return it as a MockObj. @@ -560,12 +559,10 @@ def get_variable(id_: ID) -> Generator["MockObj", None, None]: :param id_: The ID to retrieve :return: The variable as a MockObj. """ - var = yield CORE.get_variable(id_) - yield var + return await CORE.get_variable(id_) -@coroutine -def get_variable_with_full_id(id_: ID) -> Generator[Tuple[ID, "MockObj"], None, None]: +async def get_variable_with_full_id(id_: ID) -> Tuple[ID, "MockObj"]: """ Wait for the given ID to be defined in the code generation and return it as a MockObj. @@ -575,8 +572,7 @@ def get_variable_with_full_id(id_: ID) -> Generator[Tuple[ID, "MockObj"], None, :param id_: The ID to retrieve :return: The variable as a MockObj. """ - full_id, var = yield CORE.get_variable_with_full_id(id_) - yield full_id, var + return await CORE.get_variable_with_full_id(id_) @coroutine @@ -604,7 +600,7 @@ def process_lambda( return parts = value.parts[:] for i, id in enumerate(value.requires_ids): - full_id, var = yield CORE.get_variable_with_full_id(id) + full_id, var = yield get_variable_with_full_id(id) if ( full_id is not None and isinstance(full_id.type, MockObjClass) @@ -675,6 +671,9 @@ class MockObj(Expression): self.op = op def __getattr__(self, attr: str) -> "MockObj": + # prevent python dunder methods being replaced by mock objects + if attr.startswith("__"): + raise AttributeError() next_op = "." if attr.startswith("P") and self.op not in ["::", ""]: attr = attr[1:] diff --git a/requirements_test.txt b/requirements_test.txt index ecfaed5d05..b5cf617fee 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -10,5 +10,6 @@ pre-commit pytest==6.2.4 pytest-cov==2.11.1 pytest-mock==3.5.1 +pytest-asyncio==0.14.0 asyncmock==0.4.2 hypothesis==5.21.0 diff --git a/tests/unit_tests/test_core.py b/tests/unit_tests/test_core.py index 37a4920224..4e60880033 100644 --- a/tests/unit_tests/test_core.py +++ b/tests/unit_tests/test_core.py @@ -490,11 +490,15 @@ class TestEsphomeCore: def test_reset(self, target): """Call reset on target and compare to new instance""" - other = core.EsphomeCore() + other = core.EsphomeCore().__dict__ target.reset() + t = target.__dict__ + # ignore event loop + del other["event_loop"] + del t["event_loop"] - assert target.__dict__ == other.__dict__ + assert t == other def test_address__none(self, target): target.config = {} diff --git a/tests/unit_tests/test_cpp_helpers.py b/tests/unit_tests/test_cpp_helpers.py index c6f37f6b5d..3e317589a9 100644 --- a/tests/unit_tests/test_cpp_helpers.py +++ b/tests/unit_tests/test_cpp_helpers.py @@ -6,25 +6,24 @@ from esphome import const from esphome.cpp_generator import MockObj -def test_gpio_pin_expression__conf_is_none(monkeypatch): - target = ch.gpio_pin_expression(None) - - actual = next(target) +@pytest.mark.asyncio +async def test_gpio_pin_expression__conf_is_none(monkeypatch): + actual = await ch.gpio_pin_expression(None) assert actual is None -def test_gpio_pin_expression__new_pin(monkeypatch): - target = ch.gpio_pin_expression( +@pytest.mark.asyncio +async def test_gpio_pin_expression__new_pin(monkeypatch): + actual = await ch.gpio_pin_expression( {const.CONF_NUMBER: 42, const.CONF_MODE: "input", const.CONF_INVERTED: False} ) - actual = next(target) - assert isinstance(actual, MockObj) -def test_register_component(monkeypatch): +@pytest.mark.asyncio +async def test_register_component(monkeypatch): var = Mock(base="foo.bar") app_mock = Mock(register_component=Mock(return_value=var)) @@ -36,9 +35,7 @@ def test_register_component(monkeypatch): add_mock = Mock() monkeypatch.setattr(ch, "add", add_mock) - target = ch.register_component(var, {}) - - actual = next(target) + actual = await ch.register_component(var, {}) assert actual is var add_mock.assert_called_once() @@ -46,18 +43,19 @@ def test_register_component(monkeypatch): assert core_mock.component_ids == [] -def test_register_component__no_component_id(monkeypatch): +@pytest.mark.asyncio +async def test_register_component__no_component_id(monkeypatch): var = Mock(base="foo.eek") core_mock = Mock(component_ids=["foo.bar"]) monkeypatch.setattr(ch, "CORE", core_mock) with pytest.raises(ValueError, match="Component ID foo.eek was not declared to"): - target = ch.register_component(var, {}) - next(target) + await ch.register_component(var, {}) -def test_register_component__with_setup_priority(monkeypatch): +@pytest.mark.asyncio +async def test_register_component__with_setup_priority(monkeypatch): var = Mock(base="foo.bar") app_mock = Mock(register_component=Mock(return_value=var)) @@ -69,7 +67,7 @@ def test_register_component__with_setup_priority(monkeypatch): add_mock = Mock() monkeypatch.setattr(ch, "add", add_mock) - target = ch.register_component( + actual = await ch.register_component( var, { const.CONF_SETUP_PRIORITY: "123", @@ -77,8 +75,6 @@ def test_register_component__with_setup_priority(monkeypatch): }, ) - actual = next(target) - assert actual is var add_mock.assert_called() assert add_mock.call_count == 3 From d3e291b442f47a943a9cdf2e38f9d6c8fee14483 Mon Sep 17 00:00:00 2001 From: romerod Date: Tue, 18 May 2021 01:54:09 +0200 Subject: [PATCH 044/104] Add on_tag_removed trigger to pn532 (#1436) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/pn532/__init__.py | 16 ++++++++++++++-- esphome/components/pn532/pn532.cpp | 12 +++++++++++- esphome/components/pn532/pn532.h | 6 ++++-- esphome/const.py | 1 + tests/test1.yaml | 6 ++++++ 5 files changed, 36 insertions(+), 5 deletions(-) diff --git a/esphome/components/pn532/__init__.py b/esphome/components/pn532/__init__.py index 5403ebe5cd..83e6409f54 100644 --- a/esphome/components/pn532/__init__.py +++ b/esphome/components/pn532/__init__.py @@ -2,7 +2,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import automation from esphome.components import nfc -from esphome.const import CONF_ID, CONF_ON_TAG, CONF_TRIGGER_ID +from esphome.const import CONF_ID, CONF_ON_TAG_REMOVED, CONF_ON_TAG, CONF_TRIGGER_ID from esphome.core import coroutine CODEOWNERS = ["@OttoWinter", "@jesserockz"] @@ -41,6 +41,11 @@ PN532_SCHEMA = cv.Schema( ), } ), + cv.Optional(CONF_ON_TAG_REMOVED): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(PN532OnTagTrigger), + } + ), } ).extend(cv.polling_component_schema("1s")) @@ -59,7 +64,14 @@ def setup_pn532(var, config): for conf in config.get(CONF_ON_TAG, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID]) - cg.add(var.register_trigger(trigger)) + cg.add(var.register_ontag_trigger(trigger)) + yield automation.build_automation( + trigger, [(cg.std_string, "x"), (nfc.NfcTag, "tag")], conf + ) + + for conf in config.get(CONF_ON_TAG_REMOVED, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID]) + cg.add(var.register_ontagremoved_trigger(trigger)) yield automation.build_automation( trigger, [(cg.std_string, "x"), (nfc.NfcTag, "tag")], conf ) diff --git a/esphome/components/pn532/pn532.cpp b/esphome/components/pn532/pn532.cpp index 1cc2b19c2e..5e0ec458ab 100644 --- a/esphome/components/pn532/pn532.cpp +++ b/esphome/components/pn532/pn532.cpp @@ -103,6 +103,11 @@ void PN532::loop() { if (!success) { // Something failed + if (!this->current_uid_.empty()) { + auto tag = new nfc::NfcTag(this->current_uid_); + for (auto *trigger : this->triggers_ontagremoved_) + trigger->process(tag); + } this->current_uid_ = {}; this->turn_off_rf_(); return; @@ -111,6 +116,11 @@ void PN532::loop() { uint8_t num_targets = read[0]; if (num_targets != 1) { // no tags found or too many + if (!this->current_uid_.empty()) { + auto tag = new nfc::NfcTag(this->current_uid_); + for (auto *trigger : this->triggers_ontagremoved_) + trigger->process(tag); + } this->current_uid_ = {}; this->turn_off_rf_(); return; @@ -142,7 +152,7 @@ void PN532::loop() { if (next_task_ == READ) { auto tag = this->read_tag_(nfcid); - for (auto *trigger : this->triggers_) + for (auto *trigger : this->triggers_ontag_) trigger->process(tag); if (report) { diff --git a/esphome/components/pn532/pn532.h b/esphome/components/pn532/pn532.h index 95a2e0dd2a..c4854cf7f2 100644 --- a/esphome/components/pn532/pn532.h +++ b/esphome/components/pn532/pn532.h @@ -30,7 +30,8 @@ class PN532 : public PollingComponent { void loop() override; void register_tag(PN532BinarySensor *tag) { this->binary_sensors_.push_back(tag); } - void register_trigger(PN532OnTagTrigger *trig) { this->triggers_.push_back(trig); } + void register_ontag_trigger(PN532OnTagTrigger *trig) { this->triggers_ontag_.push_back(trig); } + void register_ontagremoved_trigger(PN532OnTagTrigger *trig) { this->triggers_ontagremoved_.push_back(trig); } void add_on_finished_write_callback(std::function callback) { this->on_finished_write_callback_.add(std::move(callback)); @@ -78,7 +79,8 @@ class PN532 : public PollingComponent { bool requested_read_{false}; std::vector binary_sensors_; - std::vector triggers_; + std::vector triggers_ontag_; + std::vector triggers_ontagremoved_; std::vector current_uid_; nfc::NdefMessage *next_task_message_to_write_; enum NfcTask { diff --git a/esphome/const.py b/esphome/const.py index a83e090285..a70fefa648 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -380,6 +380,7 @@ CONF_ON_RELEASE = "on_release" CONF_ON_SHUTDOWN = "on_shutdown" CONF_ON_STATE = "on_state" CONF_ON_TAG = "on_tag" +CONF_ON_TAG_REMOVED = "on_tag_removed" CONF_ON_TIME = "on_time" CONF_ON_TIME_SYNC = "on_time_sync" CONF_ON_TURN_OFF = "on_turn_off" diff --git a/tests/test1.yaml b/tests/test1.yaml index c2a79085b5..df1c340228 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -1968,6 +1968,12 @@ pn532_spi: - mqtt.publish: topic: the/topic payload: !lambda 'return x;' + on_tag_removed: + - lambda: |- + ESP_LOGD("main", "Removed tag %s", x.c_str()); + - mqtt.publish: + topic: the/topic + payload: !lambda 'return x;' pn532_i2c: From dce9d59dfe6a7e9a3f1914234a02a01c9bdf021e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Klitzing?= Date: Tue, 18 May 2021 09:16:51 +0200 Subject: [PATCH 045/104] Do not use Serial2 for ESP32C3, too (#1798) src/esphome/components/logger/logger.cpp: In member function 'void esphome::logger::Logger::pre_setup()': src/esphome/components/logger/logger.cpp:142:29: error: 'Serial2' was not declared in this scope this->hw_serial_ = &Serial2; --- esphome/components/logger/logger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/logger/logger.cpp b/esphome/components/logger/logger.cpp index 8e7bd2ee49..9c65f494f0 100644 --- a/esphome/components/logger/logger.cpp +++ b/esphome/components/logger/logger.cpp @@ -136,7 +136,7 @@ void Logger::pre_setup() { break; #ifdef ARDUINO_ARCH_ESP32 case UART_SELECTION_UART2: -#if !CONFIG_IDF_TARGET_ESP32S2 +#if !CONFIG_IDF_TARGET_ESP32S2 && !CONFIG_IDF_TARGET_ESP32C3 // FIXME: Validate in config that UART2 can't be set for ESP32-S2 (only has // UART0-UART1) this->hw_serial_ = &Serial2; From 557a622f714663b9fc2a9752277ed9d5eab4269e Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 19 May 2021 11:43:47 +1200 Subject: [PATCH 046/104] Bump version to v1.18.0 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index fdecf0ecb7..a0a3ff3dcf 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -2,7 +2,7 @@ MAJOR_VERSION = 1 MINOR_VERSION = 18 -PATCH_VERSION = "0b4" +PATCH_VERSION = "0" __short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__ = f"{__short_version__}.{PATCH_VERSION}" From 76f78877f6ef0f8a18d3073613b20a7d659c6ec0 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Wed, 19 May 2021 04:55:49 +0200 Subject: [PATCH 047/104] Use latest version of the NeoPixelBus-esphome library (#1701) --- esphome/components/neopixelbus/light.py | 2 +- platformio.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/neopixelbus/light.py b/esphome/components/neopixelbus/light.py index 0cf8057b8e..ae3a941bf9 100644 --- a/esphome/components/neopixelbus/light.py +++ b/esphome/components/neopixelbus/light.py @@ -205,4 +205,4 @@ def to_code(config): cg.add(var.set_pixel_order(getattr(ESPNeoPixelOrder, config[CONF_TYPE]))) # https://github.com/Makuna/NeoPixelBus/blob/master/library.json - cg.add_library("NeoPixelBus-esphome", "2.5.7") + cg.add_library("NeoPixelBus-esphome", "2.6.2") diff --git a/platformio.ini b/platformio.ini index 7a63ea67a9..002e0d4695 100644 --- a/platformio.ini +++ b/platformio.ini @@ -15,7 +15,7 @@ lib_deps = ArduinoJson-esphomelib@5.13.3 ESPAsyncWebServer-esphome@1.2.7 fastled/FastLED@3.3.2 - NeoPixelBus-esphome@2.5.7 + NeoPixelBus-esphome@2.6.2 ESPAsyncTCP-esphome@1.2.3 1655@1.0.2 ; TinyGPSPlus (has name conflict) 6865@1.0.0 ; TM1651 Battery Display From 96e46db272839a2408337e44f77c634cf7337cf1 Mon Sep 17 00:00:00 2001 From: Anthony Uk <1492471+dataway@users.noreply.github.com> Date: Wed, 19 May 2021 06:12:43 +0200 Subject: [PATCH 048/104] Added fan triggers on_turn_on and on_turn_off (#1726) --- esphome/components/fan/__init__.py | 23 ++++++++++++++++++ esphome/components/fan/automation.h | 36 +++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/esphome/components/fan/__init__.py b/esphome/components/fan/__init__.py index 10e38682e7..43d9297f96 100644 --- a/esphome/components/fan/__init__.py +++ b/esphome/components/fan/__init__.py @@ -14,6 +14,9 @@ from esphome.const import ( CONF_SPEED_COMMAND_TOPIC, CONF_SPEED_STATE_TOPIC, CONF_NAME, + CONF_ON_TURN_OFF, + CONF_ON_TURN_ON, + CONF_TRIGGER_ID, ) from esphome.core import CORE, coroutine, coroutine_with_priority @@ -28,6 +31,9 @@ TurnOnAction = fan_ns.class_("TurnOnAction", automation.Action) TurnOffAction = fan_ns.class_("TurnOffAction", automation.Action) ToggleAction = fan_ns.class_("ToggleAction", automation.Action) +FanTurnOnTrigger = fan_ns.class_("FanTurnOnTrigger", automation.Trigger.template()) +FanTurnOffTrigger = fan_ns.class_("FanTurnOffTrigger", automation.Trigger.template()) + FAN_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend( { cv.GenerateID(): cv.declare_id(FanState), @@ -44,6 +50,16 @@ FAN_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend( cv.Optional(CONF_SPEED_COMMAND_TOPIC): cv.All( cv.requires_component("mqtt"), cv.subscribe_topic ), + cv.Optional(CONF_ON_TURN_ON): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(FanTurnOnTrigger), + } + ), + cv.Optional(CONF_ON_TURN_OFF): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(FanTurnOffTrigger), + } + ), } ) @@ -77,6 +93,13 @@ def setup_fan_core_(var, config): mqtt_.set_custom_speed_command_topic(config[CONF_SPEED_COMMAND_TOPIC]) ) + for conf in config.get(CONF_ON_TURN_ON, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + yield automation.build_automation(trigger, [], conf) + for conf in config.get(CONF_ON_TURN_OFF, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + yield automation.build_automation(trigger, [], conf) + @coroutine def register_fan(var, config): diff --git a/esphome/components/fan/automation.h b/esphome/components/fan/automation.h index 25c92075ba..fbfc71c720 100644 --- a/esphome/components/fan/automation.h +++ b/esphome/components/fan/automation.h @@ -46,5 +46,41 @@ template class ToggleAction : public Action { FanState *state_; }; +class FanTurnOnTrigger : public Trigger<> { + public: + FanTurnOnTrigger(FanState *state) { + state->add_on_state_callback([this, state]() { + auto is_on = state->state; + auto should_trigger = is_on && !this->last_on_; + this->last_on_ = is_on; + if (should_trigger) { + this->trigger(); + } + }); + this->last_on_ = state->state; + } + + protected: + bool last_on_; +}; + +class FanTurnOffTrigger : public Trigger<> { + public: + FanTurnOffTrigger(FanState *state) { + state->add_on_state_callback([this, state]() { + auto is_on = state->state; + auto should_trigger = !is_on && this->last_on_; + this->last_on_ = is_on; + if (should_trigger) { + this->trigger(); + } + }); + this->last_on_ = state->state; + } + + protected: + bool last_on_; +}; + } // namespace fan } // namespace esphome From 514d11d46ffc049927b076d285d8034e5d986266 Mon Sep 17 00:00:00 2001 From: Anthony Uk <1492471+dataway@users.noreply.github.com> Date: Sat, 22 May 2021 01:04:25 +0200 Subject: [PATCH 049/104] tm1637 - support 6 character displays (#1803) --- esphome/components/tm1637/tm1637.cpp | 2 +- esphome/components/tm1637/tm1637.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/tm1637/tm1637.cpp b/esphome/components/tm1637/tm1637.cpp index 833e3caecd..b58cec4748 100644 --- a/esphome/components/tm1637/tm1637.cpp +++ b/esphome/components/tm1637/tm1637.cpp @@ -253,7 +253,7 @@ uint8_t TM1637Display::print(uint8_t start_pos, const char* str) { pos--; this->buffer_[pos] |= 0b10000000; } else { - if (pos >= 4) { + if (pos >= 6) { ESP_LOGE(TAG, "String is too long for the display!"); break; } diff --git a/esphome/components/tm1637/tm1637.h b/esphome/components/tm1637/tm1637.h index 91e8ba66c0..003344eae9 100644 --- a/esphome/components/tm1637/tm1637.h +++ b/esphome/components/tm1637/tm1637.h @@ -63,7 +63,7 @@ class TM1637Display : public PollingComponent { GPIOPin *clk_pin_; uint8_t intensity_; optional writer_{}; - uint8_t buffer_[4] = {0}; + uint8_t buffer_[6] = {0}; }; } // namespace tm1637 From aebad04c0be3c2c797b1c30326be8f94cf000e43 Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Sun, 23 May 2021 22:10:30 +0200 Subject: [PATCH 050/104] Convert core components to async-def coroutine syntax (#1658) Co-authored-by: Guillermo Ruffino Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/api/__init__.py | 46 ++++++++--------- esphome/components/as3935/__init__.py | 8 ++- esphome/components/async_tcp/__init__.py | 2 +- esphome/components/binary_sensor/__init__.py | 37 +++++++------- esphome/components/captive_portal/__init__.py | 6 +-- esphome/components/climate/__init__.py | 34 ++++++------- esphome/components/climate_ir/__init__.py | 14 +++-- esphome/components/cover/__init__.py | 46 ++++++++--------- esphome/components/display/__init__.py | 34 ++++++------- esphome/components/fan/__init__.py | 49 +++++++++--------- esphome/components/globals/__init__.py | 12 ++--- esphome/components/i2c/__init__.py | 13 +++-- esphome/components/json/__init__.py | 2 +- esphome/components/light/__init__.py | 24 ++++----- esphome/components/logger/__init__.py | 12 ++--- esphome/components/mqtt/__init__.py | 51 +++++++++---------- esphome/components/output/__init__.py | 32 ++++++------ esphome/components/sensor/__init__.py | 46 ++++++++--------- esphome/components/spi/__init__.py | 19 ++++--- esphome/components/status_led/__init__.py | 6 +-- esphome/components/switch/__init__.py | 36 +++++++------ esphome/components/text_sensor/__init__.py | 24 ++++----- esphome/components/time/__init__.py | 26 +++++----- esphome/components/uart/__init__.py | 19 ++++--- esphome/components/web_server/__init__.py | 6 +-- .../components/web_server_base/__init__.py | 4 +- esphome/components/wifi/__init__.py | 8 +-- esphome/cpp_generator.py | 26 ++++------ esphome/cpp_helpers.py | 30 +++++------ 29 files changed, 313 insertions(+), 359 deletions(-) diff --git a/esphome/components/api/__init__.py b/esphome/components/api/__init__.py index d12c01e614..559f8f649c 100644 --- a/esphome/components/api/__init__.py +++ b/esphome/components/api/__init__.py @@ -68,9 +68,9 @@ CONFIG_SCHEMA = cv.Schema( @coroutine_with_priority(40.0) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) + await cg.register_component(var, config) cg.add(var.set_port(config[CONF_PORT])) cg.add(var.set_password(config[CONF_PASSWORD])) @@ -90,7 +90,7 @@ def to_code(config): conf[CONF_TRIGGER_ID], templ, conf[CONF_SERVICE], service_arg_names ) cg.add(var.register_user_service(trigger)) - yield automation.build_automation(trigger, func_args, conf) + await automation.build_automation(trigger, func_args, conf) cg.add_define("USE_API") cg.add_global(api_ns.using) @@ -116,21 +116,21 @@ HOMEASSISTANT_SERVICE_ACTION_SCHEMA = cv.Schema( HomeAssistantServiceCallAction, HOMEASSISTANT_SERVICE_ACTION_SCHEMA, ) -def homeassistant_service_to_code(config, action_id, template_arg, args): - serv = yield cg.get_variable(config[CONF_ID]) +async def homeassistant_service_to_code(config, action_id, template_arg, args): + serv = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, serv, False) - templ = yield cg.templatable(config[CONF_SERVICE], args, None) + templ = await cg.templatable(config[CONF_SERVICE], args, None) cg.add(var.set_service(templ)) for key, value in config[CONF_DATA].items(): - templ = yield cg.templatable(value, args, None) + templ = await cg.templatable(value, args, None) cg.add(var.add_data(key, templ)) for key, value in config[CONF_DATA_TEMPLATE].items(): - templ = yield cg.templatable(value, args, None) + templ = await cg.templatable(value, args, None) cg.add(var.add_data_template(key, templ)) for key, value in config[CONF_VARIABLES].items(): - templ = yield cg.templatable(value, args, None) + templ = await cg.templatable(value, args, None) cg.add(var.add_variable(key, templ)) - yield var + return var def validate_homeassistant_event(value): @@ -159,21 +159,21 @@ HOMEASSISTANT_EVENT_ACTION_SCHEMA = cv.Schema( HomeAssistantServiceCallAction, HOMEASSISTANT_EVENT_ACTION_SCHEMA, ) -def homeassistant_event_to_code(config, action_id, template_arg, args): - serv = yield cg.get_variable(config[CONF_ID]) +async def homeassistant_event_to_code(config, action_id, template_arg, args): + serv = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, serv, True) - templ = yield cg.templatable(config[CONF_EVENT], args, None) + templ = await cg.templatable(config[CONF_EVENT], args, None) cg.add(var.set_service(templ)) for key, value in config[CONF_DATA].items(): - templ = yield cg.templatable(value, args, None) + templ = await cg.templatable(value, args, None) cg.add(var.add_data(key, templ)) for key, value in config[CONF_DATA_TEMPLATE].items(): - templ = yield cg.templatable(value, args, None) + templ = await cg.templatable(value, args, None) cg.add(var.add_data_template(key, templ)) for key, value in config[CONF_VARIABLES].items(): - templ = yield cg.templatable(value, args, None) + templ = await cg.templatable(value, args, None) cg.add(var.add_variable(key, templ)) - yield var + return var HOMEASSISTANT_TAG_SCANNED_ACTION_SCHEMA = cv.maybe_simple_value( @@ -190,15 +190,15 @@ HOMEASSISTANT_TAG_SCANNED_ACTION_SCHEMA = cv.maybe_simple_value( HomeAssistantServiceCallAction, HOMEASSISTANT_TAG_SCANNED_ACTION_SCHEMA, ) -def homeassistant_tag_scanned_to_code(config, action_id, template_arg, args): - serv = yield cg.get_variable(config[CONF_ID]) +async def homeassistant_tag_scanned_to_code(config, action_id, template_arg, args): + serv = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, serv, True) cg.add(var.set_service("esphome.tag_scanned")) - templ = yield cg.templatable(config[CONF_TAG], args, cg.std_string) + templ = await cg.templatable(config[CONF_TAG], args, cg.std_string) cg.add(var.add_data("tag_id", templ)) - yield var + return var @automation.register_condition("api.connected", APIConnectedCondition, {}) -def api_connected_to_code(config, condition_id, template_arg, args): - yield cg.new_Pvariable(condition_id, template_arg) +async def api_connected_to_code(config, condition_id, template_arg, args): + return cg.new_Pvariable(condition_id, template_arg) diff --git a/esphome/components/as3935/__init__.py b/esphome/components/as3935/__init__.py index 337f0a9081..0951d01e68 100644 --- a/esphome/components/as3935/__init__.py +++ b/esphome/components/as3935/__init__.py @@ -11,7 +11,6 @@ from esphome.const import ( CONF_DIV_RATIO, CONF_CAPACITANCE, ) -from esphome.core import coroutine AUTO_LOAD = ["sensor", "binary_sensor"] MULTI_CONF = True @@ -40,11 +39,10 @@ AS3935_SCHEMA = cv.Schema( ) -@coroutine -def setup_as3935(var, config): - yield cg.register_component(var, config) +async def setup_as3935(var, config): + await cg.register_component(var, config) - irq_pin = yield cg.gpio_pin_expression(config[CONF_IRQ_PIN]) + irq_pin = await cg.gpio_pin_expression(config[CONF_IRQ_PIN]) cg.add(var.set_irq_pin(irq_pin)) cg.add(var.set_indoor(config[CONF_INDOOR])) cg.add(var.set_noise_level(config[CONF_NOISE_LEVEL])) diff --git a/esphome/components/async_tcp/__init__.py b/esphome/components/async_tcp/__init__.py index 8532f349e6..8938dc4671 100644 --- a/esphome/components/async_tcp/__init__.py +++ b/esphome/components/async_tcp/__init__.py @@ -6,7 +6,7 @@ CODEOWNERS = ["@OttoWinter"] @coroutine_with_priority(200.0) -def to_code(config): +async def to_code(config): if CORE.is_esp32: # https://github.com/esphome/AsyncTCP/blob/master/library.json cg.add_library("esphome/AsyncTCP-esphome", "1.2.2") diff --git a/esphome/components/binary_sensor/__init__.py b/esphome/components/binary_sensor/__init__.py index 5d4b227d70..c31a14996f 100644 --- a/esphome/components/binary_sensor/__init__.py +++ b/esphome/components/binary_sensor/__init__.py @@ -51,7 +51,7 @@ from esphome.const import ( DEVICE_CLASS_VIBRATION, DEVICE_CLASS_WINDOW, ) -from esphome.core import CORE, coroutine, coroutine_with_priority +from esphome.core import CORE, coroutine_with_priority from esphome.util import Registry CODEOWNERS = ["@esphome/core"] @@ -381,8 +381,7 @@ BINARY_SENSOR_SCHEMA = cv.MQTT_COMPONENT_SCHEMA.extend( ) -@coroutine -def setup_binary_sensor_core_(var, config): +async def setup_binary_sensor_core_(var, config): cg.add(var.set_name(config[CONF_NAME])) if CONF_INTERNAL in config: cg.add(var.set_internal(config[CONF_INTERNAL])) @@ -391,28 +390,28 @@ def setup_binary_sensor_core_(var, config): if CONF_INVERTED in config: cg.add(var.set_inverted(config[CONF_INVERTED])) if CONF_FILTERS in config: - filters = yield cg.build_registry_list(FILTER_REGISTRY, config[CONF_FILTERS]) + filters = await cg.build_registry_list(FILTER_REGISTRY, config[CONF_FILTERS]) cg.add(var.add_filters(filters)) for conf in config.get(CONF_ON_PRESS, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) - yield automation.build_automation(trigger, [], conf) + await automation.build_automation(trigger, [], conf) for conf in config.get(CONF_ON_RELEASE, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) - yield automation.build_automation(trigger, [], conf) + await automation.build_automation(trigger, [], conf) for conf in config.get(CONF_ON_CLICK, []): trigger = cg.new_Pvariable( conf[CONF_TRIGGER_ID], var, conf[CONF_MIN_LENGTH], conf[CONF_MAX_LENGTH] ) - yield automation.build_automation(trigger, [], conf) + await automation.build_automation(trigger, [], conf) for conf in config.get(CONF_ON_DOUBLE_CLICK, []): trigger = cg.new_Pvariable( conf[CONF_TRIGGER_ID], var, conf[CONF_MIN_LENGTH], conf[CONF_MAX_LENGTH] ) - yield automation.build_automation(trigger, [], conf) + await automation.build_automation(trigger, [], conf) for conf in config.get(CONF_ON_MULTI_CLICK, []): timings = [] @@ -428,31 +427,29 @@ def setup_binary_sensor_core_(var, config): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var, timings) if CONF_INVALID_COOLDOWN in conf: cg.add(trigger.set_invalid_cooldown(conf[CONF_INVALID_COOLDOWN])) - yield cg.register_component(trigger, conf) - yield automation.build_automation(trigger, [], conf) + await cg.register_component(trigger, conf) + await automation.build_automation(trigger, [], conf) for conf in config.get(CONF_ON_STATE, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) - yield automation.build_automation(trigger, [(bool, "x")], conf) + await automation.build_automation(trigger, [(bool, "x")], conf) if CONF_MQTT_ID in config: mqtt_ = cg.new_Pvariable(config[CONF_MQTT_ID], var) - yield mqtt.register_mqtt_component(mqtt_, config) + await mqtt.register_mqtt_component(mqtt_, config) -@coroutine -def register_binary_sensor(var, config): +async def register_binary_sensor(var, config): if not CORE.has_id(config[CONF_ID]): var = cg.Pvariable(config[CONF_ID], var) cg.add(cg.App.register_binary_sensor(var)) - yield setup_binary_sensor_core_(var, config) + await setup_binary_sensor_core_(var, config) -@coroutine -def new_binary_sensor(config): +async def new_binary_sensor(config): var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME]) - yield register_binary_sensor(var, config) - yield var + await register_binary_sensor(var, config) + return var BINARY_SENSOR_CONDITION_SCHEMA = maybe_simple_id( @@ -483,6 +480,6 @@ def binary_sensor_is_off_to_code(config, condition_id, template_arg, args): @coroutine_with_priority(100.0) -def to_code(config): +async def to_code(config): cg.add_define("USE_BINARY_SENSOR") cg.add_global(binary_sensor_ns.using) diff --git a/esphome/components/captive_portal/__init__.py b/esphome/components/captive_portal/__init__.py index e158db6746..102bfd370e 100644 --- a/esphome/components/captive_portal/__init__.py +++ b/esphome/components/captive_portal/__init__.py @@ -23,9 +23,9 @@ CONFIG_SCHEMA = cv.Schema( @coroutine_with_priority(64.0) -def to_code(config): - paren = yield cg.get_variable(config[CONF_WEB_SERVER_BASE_ID]) +async def to_code(config): + paren = await cg.get_variable(config[CONF_WEB_SERVER_BASE_ID]) var = cg.new_Pvariable(config[CONF_ID], paren) - yield cg.register_component(var, config) + await cg.register_component(var, config) cg.add_define("USE_CAPTIVE_PORTAL") diff --git a/esphome/components/climate/__init__.py b/esphome/components/climate/__init__.py index 7f74b62c61..fb163c96ae 100644 --- a/esphome/components/climate/__init__.py +++ b/esphome/components/climate/__init__.py @@ -19,7 +19,7 @@ from esphome.const import ( CONF_FAN_MODE, CONF_SWING_MODE, ) -from esphome.core import CORE, coroutine, coroutine_with_priority +from esphome.core import CORE, coroutine_with_priority IS_PLATFORM_COMPONENT = True @@ -85,8 +85,7 @@ CLIMATE_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend( ) -@coroutine -def setup_climate_core_(var, config): +async def setup_climate_core_(var, config): cg.add(var.set_name(config[CONF_NAME])) if CONF_INTERNAL in config: cg.add(var.set_internal(config[CONF_INTERNAL])) @@ -100,15 +99,14 @@ def setup_climate_core_(var, config): if CONF_MQTT_ID in config: mqtt_ = cg.new_Pvariable(config[CONF_MQTT_ID], var) - yield mqtt.register_mqtt_component(mqtt_, config) + await mqtt.register_mqtt_component(mqtt_, config) -@coroutine -def register_climate(var, config): +async def register_climate(var, config): if not CORE.has_id(config[CONF_ID]): var = cg.Pvariable(config[CONF_ID], var) cg.add(cg.App.register_climate(var)) - yield setup_climate_core_(var, config) + await setup_climate_core_(var, config) CLIMATE_CONTROL_ACTION_SCHEMA = cv.Schema( @@ -128,40 +126,40 @@ CLIMATE_CONTROL_ACTION_SCHEMA = cv.Schema( @automation.register_action( "climate.control", ControlAction, CLIMATE_CONTROL_ACTION_SCHEMA ) -def climate_control_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def climate_control_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) if CONF_MODE in config: - template_ = yield cg.templatable(config[CONF_MODE], args, ClimateMode) + template_ = await cg.templatable(config[CONF_MODE], args, ClimateMode) cg.add(var.set_mode(template_)) if CONF_TARGET_TEMPERATURE in config: - template_ = yield cg.templatable(config[CONF_TARGET_TEMPERATURE], args, float) + template_ = await cg.templatable(config[CONF_TARGET_TEMPERATURE], args, float) cg.add(var.set_target_temperature(template_)) if CONF_TARGET_TEMPERATURE_LOW in config: - template_ = yield cg.templatable( + template_ = await cg.templatable( config[CONF_TARGET_TEMPERATURE_LOW], args, float ) cg.add(var.set_target_temperature_low(template_)) if CONF_TARGET_TEMPERATURE_HIGH in config: - template_ = yield cg.templatable( + template_ = await cg.templatable( config[CONF_TARGET_TEMPERATURE_HIGH], args, float ) cg.add(var.set_target_temperature_high(template_)) if CONF_AWAY in config: - template_ = yield cg.templatable(config[CONF_AWAY], args, bool) + template_ = await cg.templatable(config[CONF_AWAY], args, bool) cg.add(var.set_away(template_)) if CONF_FAN_MODE in config: - template_ = yield cg.templatable(config[CONF_FAN_MODE], args, ClimateFanMode) + template_ = await cg.templatable(config[CONF_FAN_MODE], args, ClimateFanMode) cg.add(var.set_fan_mode(template_)) if CONF_SWING_MODE in config: - template_ = yield cg.templatable( + template_ = await cg.templatable( config[CONF_SWING_MODE], args, ClimateSwingMode ) cg.add(var.set_swing_mode(template_)) - yield var + return var @coroutine_with_priority(100.0) -def to_code(config): +async def to_code(config): cg.add_define("USE_CLIMATE") cg.add_global(climate_ns.using) diff --git a/esphome/components/climate_ir/__init__.py b/esphome/components/climate_ir/__init__.py index 8dcd75c31f..1389ebfc6d 100644 --- a/esphome/components/climate_ir/__init__.py +++ b/esphome/components/climate_ir/__init__.py @@ -9,7 +9,6 @@ from esphome.components import ( ) from esphome.components.remote_base import CONF_RECEIVER_ID, CONF_TRANSMITTER_ID from esphome.const import CONF_SUPPORTS_COOL, CONF_SUPPORTS_HEAT, CONF_SENSOR -from esphome.core import coroutine AUTO_LOAD = ["sensor", "remote_base"] CODEOWNERS = ["@glmnet"] @@ -39,19 +38,18 @@ CLIMATE_IR_WITH_RECEIVER_SCHEMA = CLIMATE_IR_SCHEMA.extend( ) -@coroutine -def register_climate_ir(var, config): - yield cg.register_component(var, config) - yield climate.register_climate(var, config) +async def register_climate_ir(var, config): + await cg.register_component(var, config) + await climate.register_climate(var, config) cg.add(var.set_supports_cool(config[CONF_SUPPORTS_COOL])) cg.add(var.set_supports_heat(config[CONF_SUPPORTS_HEAT])) if CONF_SENSOR in config: - sens = yield cg.get_variable(config[CONF_SENSOR]) + sens = await cg.get_variable(config[CONF_SENSOR]) cg.add(var.set_sensor(sens)) if CONF_RECEIVER_ID in config: - receiver = yield cg.get_variable(config[CONF_RECEIVER_ID]) + receiver = await cg.get_variable(config[CONF_RECEIVER_ID]) cg.add(receiver.register_listener(var)) - transmitter = yield cg.get_variable(config[CONF_TRANSMITTER_ID]) + transmitter = await cg.get_variable(config[CONF_TRANSMITTER_ID]) cg.add(var.set_transmitter(transmitter)) diff --git a/esphome/components/cover/__init__.py b/esphome/components/cover/__init__.py index e731c18333..4a7266303d 100644 --- a/esphome/components/cover/__init__.py +++ b/esphome/components/cover/__init__.py @@ -14,7 +14,7 @@ from esphome.const import ( CONF_MQTT_ID, CONF_NAME, ) -from esphome.core import CORE, coroutine, coroutine_with_priority +from esphome.core import CORE, coroutine_with_priority IS_PLATFORM_COMPONENT = True @@ -73,8 +73,7 @@ COVER_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend( ) -@coroutine -def setup_cover_core_(var, config): +async def setup_cover_core_(var, config): cg.add(var.set_name(config[CONF_NAME])) if CONF_INTERNAL in config: cg.add(var.set_internal(config[CONF_INTERNAL])) @@ -83,15 +82,14 @@ def setup_cover_core_(var, config): if CONF_MQTT_ID in config: mqtt_ = cg.new_Pvariable(config[CONF_MQTT_ID], var) - yield mqtt.register_mqtt_component(mqtt_, config) + await mqtt.register_mqtt_component(mqtt_, config) -@coroutine -def register_cover(var, config): +async def register_cover(var, config): if not CORE.has_id(config[CONF_ID]): var = cg.Pvariable(config[CONF_ID], var) cg.add(cg.App.register_cover(var)) - yield setup_cover_core_(var, config) + await setup_cover_core_(var, config) COVER_ACTION_SCHEMA = maybe_simple_id( @@ -102,21 +100,21 @@ COVER_ACTION_SCHEMA = maybe_simple_id( @automation.register_action("cover.open", OpenAction, COVER_ACTION_SCHEMA) -def cover_open_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) - yield cg.new_Pvariable(action_id, template_arg, paren) +async def cover_open_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, paren) @automation.register_action("cover.close", CloseAction, COVER_ACTION_SCHEMA) -def cover_close_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) - yield cg.new_Pvariable(action_id, template_arg, paren) +async def cover_close_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, paren) @automation.register_action("cover.stop", StopAction, COVER_ACTION_SCHEMA) -def cover_stop_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) - yield cg.new_Pvariable(action_id, template_arg, paren) +async def cover_stop_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, paren) COVER_CONTROL_ACTION_SCHEMA = cv.Schema( @@ -131,25 +129,25 @@ COVER_CONTROL_ACTION_SCHEMA = cv.Schema( @automation.register_action("cover.control", ControlAction, COVER_CONTROL_ACTION_SCHEMA) -def cover_control_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def cover_control_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) if CONF_STOP in config: - template_ = yield cg.templatable(config[CONF_STOP], args, bool) + template_ = await cg.templatable(config[CONF_STOP], args, bool) cg.add(var.set_stop(template_)) if CONF_STATE in config: - template_ = yield cg.templatable(config[CONF_STATE], args, float) + template_ = await cg.templatable(config[CONF_STATE], args, float) cg.add(var.set_position(template_)) if CONF_POSITION in config: - template_ = yield cg.templatable(config[CONF_POSITION], args, float) + template_ = await cg.templatable(config[CONF_POSITION], args, float) cg.add(var.set_position(template_)) if CONF_TILT in config: - template_ = yield cg.templatable(config[CONF_TILT], args, float) + template_ = await cg.templatable(config[CONF_TILT], args, float) cg.add(var.set_tilt(template_)) - yield var + return var @coroutine_with_priority(100.0) -def to_code(config): +async def to_code(config): cg.add_define("USE_COVER") cg.add_global(cover_ns.using) diff --git a/esphome/components/display/__init__.py b/esphome/components/display/__init__.py index fe8bc9bd7c..5aed998b30 100644 --- a/esphome/components/display/__init__.py +++ b/esphome/components/display/__init__.py @@ -3,7 +3,7 @@ import esphome.config_validation as cv from esphome import core, automation from esphome.automation import maybe_simple_id from esphome.const import CONF_ID, CONF_LAMBDA, CONF_PAGES, CONF_PAGE_ID, CONF_ROTATION -from esphome.core import coroutine, coroutine_with_priority +from esphome.core import coroutine_with_priority IS_PLATFORM_COMPONENT = True @@ -60,14 +60,13 @@ FULL_DISPLAY_SCHEMA = BASIC_DISPLAY_SCHEMA.extend( ) -@coroutine -def setup_display_core_(var, config): +async def setup_display_core_(var, config): if CONF_ROTATION in config: cg.add(var.set_rotation(DISPLAY_ROTATIONS[config[CONF_ROTATION]])) if CONF_PAGES in config: pages = [] for conf in config[CONF_PAGES]: - lambda_ = yield cg.process_lambda( + lambda_ = await cg.process_lambda( conf[CONF_LAMBDA], [(DisplayBufferRef, "it")], return_type=cg.void ) page = cg.new_Pvariable(conf[CONF_ID], lambda_) @@ -75,9 +74,8 @@ def setup_display_core_(var, config): cg.add(var.set_pages(pages)) -@coroutine -def register_display(var, config): - yield setup_display_core_(var, config) +async def register_display(var, config): + await setup_display_core_(var, config) @automation.register_action( @@ -89,15 +87,15 @@ def register_display(var, config): } ), ) -def display_page_show_to_code(config, action_id, template_arg, args): +async def display_page_show_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) if isinstance(config[CONF_ID], core.Lambda): - template_ = yield cg.templatable(config[CONF_ID], args, DisplayPagePtr) + template_ = await cg.templatable(config[CONF_ID], args, DisplayPagePtr) cg.add(var.set_page(template_)) else: - paren = yield cg.get_variable(config[CONF_ID]) + paren = await cg.get_variable(config[CONF_ID]) cg.add(var.set_page(paren)) - yield var + return var @automation.register_action( @@ -109,9 +107,9 @@ def display_page_show_to_code(config, action_id, template_arg, args): } ), ) -def display_page_show_next_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) - yield cg.new_Pvariable(action_id, template_arg, paren) +async def display_page_show_next_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, paren) @automation.register_action( @@ -123,9 +121,9 @@ def display_page_show_next_to_code(config, action_id, template_arg, args): } ), ) -def display_page_show_previous_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) - yield cg.new_Pvariable(action_id, template_arg, paren) +async def display_page_show_previous_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, paren) @automation.register_condition( @@ -149,5 +147,5 @@ def display_is_displaying_page_to_code(config, condition_id, template_arg, args) @coroutine_with_priority(100.0) -def to_code(config): +async def to_code(config): cg.add_global(display_ns.using) diff --git a/esphome/components/fan/__init__.py b/esphome/components/fan/__init__.py index 43d9297f96..d1f43467ed 100644 --- a/esphome/components/fan/__init__.py +++ b/esphome/components/fan/__init__.py @@ -18,7 +18,7 @@ from esphome.const import ( CONF_ON_TURN_ON, CONF_TRIGGER_ID, ) -from esphome.core import CORE, coroutine, coroutine_with_priority +from esphome.core import CORE, coroutine_with_priority IS_PLATFORM_COMPONENT = True @@ -64,15 +64,14 @@ FAN_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend( ) -@coroutine -def setup_fan_core_(var, config): +async def setup_fan_core_(var, config): cg.add(var.set_name(config[CONF_NAME])) if CONF_INTERNAL in config: cg.add(var.set_internal(config[CONF_INTERNAL])) if CONF_MQTT_ID in config: mqtt_ = cg.new_Pvariable(config[CONF_MQTT_ID], var) - yield mqtt.register_mqtt_component(mqtt_, config) + await mqtt.register_mqtt_component(mqtt_, config) if CONF_OSCILLATION_STATE_TOPIC in config: cg.add( @@ -95,26 +94,24 @@ def setup_fan_core_(var, config): for conf in config.get(CONF_ON_TURN_ON, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) - yield automation.build_automation(trigger, [], conf) + await automation.build_automation(trigger, [], conf) for conf in config.get(CONF_ON_TURN_OFF, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) - yield automation.build_automation(trigger, [], conf) + await automation.build_automation(trigger, [], conf) -@coroutine -def register_fan(var, config): +async def register_fan(var, config): if not CORE.has_id(config[CONF_ID]): var = cg.Pvariable(config[CONF_ID], var) cg.add(cg.App.register_fan(var)) - yield cg.register_component(var, config) - yield setup_fan_core_(var, config) + await cg.register_component(var, config) + await setup_fan_core_(var, config) -@coroutine -def create_fan_state(config): +async def create_fan_state(config): var = cg.new_Pvariable(config[CONF_ID]) - yield register_fan(var, config) - yield var + await register_fan(var, config) + return var FAN_ACTION_SCHEMA = maybe_simple_id( @@ -125,15 +122,15 @@ FAN_ACTION_SCHEMA = maybe_simple_id( @automation.register_action("fan.toggle", ToggleAction, FAN_ACTION_SCHEMA) -def fan_toggle_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) - yield cg.new_Pvariable(action_id, template_arg, paren) +async def fan_toggle_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, paren) @automation.register_action("fan.turn_off", TurnOffAction, FAN_ACTION_SCHEMA) -def fan_turn_off_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) - yield cg.new_Pvariable(action_id, template_arg, paren) +async def fan_turn_off_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, paren) @automation.register_action( @@ -147,19 +144,19 @@ def fan_turn_off_to_code(config, action_id, template_arg, args): } ), ) -def fan_turn_on_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def fan_turn_on_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) if CONF_OSCILLATING in config: - template_ = yield cg.templatable(config[CONF_OSCILLATING], args, bool) + template_ = await cg.templatable(config[CONF_OSCILLATING], args, bool) cg.add(var.set_oscillating(template_)) if CONF_SPEED in config: - template_ = yield cg.templatable(config[CONF_SPEED], args, int) + template_ = await cg.templatable(config[CONF_SPEED], args, int) cg.add(var.set_speed(template_)) - yield var + return var @coroutine_with_priority(100.0) -def to_code(config): +async def to_code(config): cg.add_define("USE_FAN") cg.add_global(fan_ns.using) diff --git a/esphome/components/globals/__init__.py b/esphome/components/globals/__init__.py index 9ec3bc17ce..9039d0d62e 100644 --- a/esphome/components/globals/__init__.py +++ b/esphome/components/globals/__init__.py @@ -29,7 +29,7 @@ CONFIG_SCHEMA = cv.Schema( # Run with low priority so that namespaces are registered first @coroutine_with_priority(-100.0) -def to_code(config): +async def to_code(config): type_ = cg.RawExpression(config[CONF_TYPE]) template_args = cg.TemplateArguments(type_) res_type = GlobalsComponent.template(template_args) @@ -40,7 +40,7 @@ def to_code(config): rhs = GlobalsComponent.new(template_args, initial_value) glob = cg.Pvariable(config[CONF_ID], rhs, res_type) - yield cg.register_component(glob, config) + await cg.register_component(glob, config) if config[CONF_RESTORE_VALUE]: value = config[CONF_ID].id @@ -60,12 +60,12 @@ def to_code(config): } ), ) -def globals_set_to_code(config, action_id, template_arg, args): - full_id, paren = yield cg.get_variable_with_full_id(config[CONF_ID]) +async def globals_set_to_code(config, action_id, template_arg, args): + full_id, paren = await cg.get_variable_with_full_id(config[CONF_ID]) template_arg = cg.TemplateArguments(full_id.type, *template_arg) var = cg.new_Pvariable(action_id, template_arg, paren) - templ = yield cg.templatable( + templ = await cg.templatable( config[CONF_VALUE], args, None, to_exp=cg.RawExpression ) cg.add(var.set_value(templ)) - yield var + return var diff --git a/esphome/components/i2c/__init__.py b/esphome/components/i2c/__init__.py index 59f90842e1..f43729066d 100644 --- a/esphome/components/i2c/__init__.py +++ b/esphome/components/i2c/__init__.py @@ -12,7 +12,7 @@ from esphome.const import ( CONF_I2C_ID, CONF_MULTIPLEXER, ) -from esphome.core import coroutine, coroutine_with_priority +from esphome.core import coroutine_with_priority CODEOWNERS = ["@esphome/core"] i2c_ns = cg.esphome_ns.namespace("i2c") @@ -42,10 +42,10 @@ I2CMULTIPLEXER_SCHEMA = cv.Schema( @coroutine_with_priority(1.0) -def to_code(config): +async def to_code(config): cg.add_global(i2c_ns.using) var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) + await cg.register_component(var, config) cg.add(var.set_sda_pin(config[CONF_SDA])) cg.add(var.set_scl_pin(config[CONF_SCL])) @@ -72,19 +72,18 @@ def i2c_device_schema(default_address): return cv.Schema(schema) -@coroutine -def register_i2c_device(var, config): +async def register_i2c_device(var, config): """Register an i2c device with the given config. Sets the i2c bus to use and the i2c address. This is a coroutine, you need to await it with a 'yield' expression! """ - parent = yield cg.get_variable(config[CONF_I2C_ID]) + parent = await cg.get_variable(config[CONF_I2C_ID]) cg.add(var.set_i2c_parent(parent)) cg.add(var.set_i2c_address(config[CONF_ADDRESS])) if CONF_MULTIPLEXER in config: - multiplexer = yield cg.get_variable(config[CONF_MULTIPLEXER][CONF_ID]) + multiplexer = await cg.get_variable(config[CONF_MULTIPLEXER][CONF_ID]) cg.add( var.set_i2c_multiplexer(multiplexer, config[CONF_MULTIPLEXER][CONF_CHANNEL]) ) diff --git a/esphome/components/json/__init__.py b/esphome/components/json/__init__.py index f73fcb53fb..7bdef6ea0e 100644 --- a/esphome/components/json/__init__.py +++ b/esphome/components/json/__init__.py @@ -6,7 +6,7 @@ json_ns = cg.esphome_ns.namespace("json") @coroutine_with_priority(1.0) -def to_code(config): +async def to_code(config): cg.add_library("ArduinoJson-esphomelib", "5.13.3") cg.add_define("USE_JSON") cg.add_global(json_ns.using) diff --git a/esphome/components/light/__init__.py b/esphome/components/light/__init__.py index 034dbdaf34..a382c5604e 100644 --- a/esphome/components/light/__init__.py +++ b/esphome/components/light/__init__.py @@ -17,7 +17,7 @@ from esphome.const import ( CONF_ON_TURN_ON, CONF_TRIGGER_ID, ) -from esphome.core import coroutine, coroutine_with_priority +from esphome.core import coroutine_with_priority from .automation import light_control_to_code # noqa from .effects import ( validate_effects, @@ -102,8 +102,7 @@ ADDRESSABLE_LIGHT_SCHEMA = RGB_LIGHT_SCHEMA.extend( ) -@coroutine -def setup_light_core_(light_var, output_var, config): +async def setup_light_core_(light_var, output_var, config): cg.add(light_var.set_restore_mode(config[CONF_RESTORE_MODE])) if CONF_INTERNAL in config: cg.add(light_var.set_internal(config[CONF_INTERNAL])) @@ -115,39 +114,38 @@ def setup_light_core_(light_var, output_var, config): ) if CONF_GAMMA_CORRECT in config: cg.add(light_var.set_gamma_correct(config[CONF_GAMMA_CORRECT])) - effects = yield cg.build_registry_list( + effects = await cg.build_registry_list( EFFECTS_REGISTRY, config.get(CONF_EFFECTS, []) ) cg.add(light_var.add_effects(effects)) for conf in config.get(CONF_ON_TURN_ON, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], light_var) - yield auto.build_automation(trigger, [], conf) + await auto.build_automation(trigger, [], conf) for conf in config.get(CONF_ON_TURN_OFF, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], light_var) - yield auto.build_automation(trigger, [], conf) + await auto.build_automation(trigger, [], conf) if CONF_COLOR_CORRECT in config: cg.add(output_var.set_correction(*config[CONF_COLOR_CORRECT])) if CONF_POWER_SUPPLY in config: - var_ = yield cg.get_variable(config[CONF_POWER_SUPPLY]) + var_ = await cg.get_variable(config[CONF_POWER_SUPPLY]) cg.add(output_var.set_power_supply(var_)) if CONF_MQTT_ID in config: mqtt_ = cg.new_Pvariable(config[CONF_MQTT_ID], light_var) - yield mqtt.register_mqtt_component(mqtt_, config) + await mqtt.register_mqtt_component(mqtt_, config) -@coroutine -def register_light(output_var, config): +async def register_light(output_var, config): light_var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME], output_var) cg.add(cg.App.register_light(light_var)) - yield cg.register_component(light_var, config) - yield setup_light_core_(light_var, output_var, config) + await cg.register_component(light_var, config) + await setup_light_core_(light_var, output_var, config) @coroutine_with_priority(100.0) -def to_code(config): +async def to_code(config): cg.add_define("USE_LIGHT") cg.add_global(light_ns.using) diff --git a/esphome/components/logger/__init__.py b/esphome/components/logger/__init__.py index d865be856b..2b571b817b 100644 --- a/esphome/components/logger/__init__.py +++ b/esphome/components/logger/__init__.py @@ -127,7 +127,7 @@ CONFIG_SCHEMA = cv.All( @coroutine_with_priority(90.0) -def to_code(config): +async def to_code(config): baud_rate = config[CONF_BAUD_RATE] rhs = Logger.new( baud_rate, @@ -177,13 +177,13 @@ def to_code(config): cg.add_build_flag("-DUSE_STORE_LOG_STR_IN_FLASH") # Register at end for safe mode - yield cg.register_component(log, config) + await cg.register_component(log, config) for conf in config.get(CONF_ON_MESSAGE, []): trigger = cg.new_Pvariable( conf[CONF_TRIGGER_ID], log, LOG_LEVEL_SEVERITY.index(conf[CONF_LEVEL]) ) - yield automation.build_automation( + await automation.build_automation( trigger, [ (cg.int_, "level"), @@ -242,11 +242,11 @@ LOGGER_LOG_ACTION_SCHEMA = cv.All( @automation.register_action(CONF_LOGGER_LOG, LambdaAction, LOGGER_LOG_ACTION_SCHEMA) -def logger_log_action_to_code(config, action_id, template_arg, args): +async def logger_log_action_to_code(config, action_id, template_arg, args): esp_log = LOG_LEVEL_TO_ESP_LOG[config[CONF_LEVEL]] args_ = [cg.RawExpression(str(x)) for x in config[CONF_ARGS]] text = str(cg.statement(esp_log(config[CONF_TAG], config[CONF_FORMAT], *args_))) - lambda_ = yield cg.process_lambda(Lambda(text), args, return_type=cg.void) - yield cg.new_Pvariable(action_id, template_arg, lambda_) + lambda_ = await cg.process_lambda(Lambda(text), args, return_type=cg.void) + return cg.new_Pvariable(action_id, template_arg, lambda_) diff --git a/esphome/components/mqtt/__init__.py b/esphome/components/mqtt/__init__.py index e90f90cd6a..906c570b17 100644 --- a/esphome/components/mqtt/__init__.py +++ b/esphome/components/mqtt/__init__.py @@ -37,7 +37,7 @@ from esphome.const import ( CONF_USERNAME, CONF_WILL_MESSAGE, ) -from esphome.core import coroutine_with_priority, coroutine, CORE +from esphome.core import coroutine_with_priority, CORE DEPENDENCIES = ["network"] AUTO_LOAD = ["json", "async_tcp"] @@ -207,9 +207,9 @@ def exp_mqtt_message(config): @coroutine_with_priority(40.0) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) + await cg.register_component(var, config) # https://github.com/OttoWinter/async-mqtt-client/blob/master/library.json cg.add_library("AsyncMqttClient-esphome", "0.8.4") @@ -279,12 +279,12 @@ def to_code(config): cg.add(trig.set_qos(conf[CONF_QOS])) if CONF_PAYLOAD in conf: cg.add(trig.set_payload(conf[CONF_PAYLOAD])) - yield cg.register_component(trig, conf) - yield automation.build_automation(trig, [(cg.std_string, "x")], conf) + await cg.register_component(trig, conf) + await automation.build_automation(trig, [(cg.std_string, "x")], conf) for conf in config.get(CONF_ON_JSON_MESSAGE, []): trig = cg.new_Pvariable(conf[CONF_TRIGGER_ID], conf[CONF_TOPIC], conf[CONF_QOS]) - yield automation.build_automation(trig, [(cg.JsonObjectConstRef, "x")], conf) + await automation.build_automation(trig, [(cg.JsonObjectConstRef, "x")], conf) MQTT_PUBLISH_ACTION_SCHEMA = cv.Schema( @@ -301,19 +301,19 @@ MQTT_PUBLISH_ACTION_SCHEMA = cv.Schema( @automation.register_action( "mqtt.publish", MQTTPublishAction, MQTT_PUBLISH_ACTION_SCHEMA ) -def mqtt_publish_action_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def mqtt_publish_action_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) - template_ = yield cg.templatable(config[CONF_TOPIC], args, cg.std_string) + template_ = await cg.templatable(config[CONF_TOPIC], args, cg.std_string) cg.add(var.set_topic(template_)) - template_ = yield cg.templatable(config[CONF_PAYLOAD], args, cg.std_string) + template_ = await cg.templatable(config[CONF_PAYLOAD], args, cg.std_string) cg.add(var.set_payload(template_)) - template_ = yield cg.templatable(config[CONF_QOS], args, cg.uint8) + template_ = await cg.templatable(config[CONF_QOS], args, cg.uint8) cg.add(var.set_qos(template_)) - template_ = yield cg.templatable(config[CONF_RETAIN], args, bool) + template_ = await cg.templatable(config[CONF_RETAIN], args, bool) cg.add(var.set_retain(template_)) - yield var + return var MQTT_PUBLISH_JSON_ACTION_SCHEMA = cv.Schema( @@ -330,20 +330,20 @@ MQTT_PUBLISH_JSON_ACTION_SCHEMA = cv.Schema( @automation.register_action( "mqtt.publish_json", MQTTPublishJsonAction, MQTT_PUBLISH_JSON_ACTION_SCHEMA ) -def mqtt_publish_json_action_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def mqtt_publish_json_action_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) - template_ = yield cg.templatable(config[CONF_TOPIC], args, cg.std_string) + template_ = await cg.templatable(config[CONF_TOPIC], args, cg.std_string) cg.add(var.set_topic(template_)) args_ = args + [(cg.JsonObjectRef, "root")] - lambda_ = yield cg.process_lambda(config[CONF_PAYLOAD], args_, return_type=cg.void) + lambda_ = await cg.process_lambda(config[CONF_PAYLOAD], args_, return_type=cg.void) cg.add(var.set_payload(lambda_)) - template_ = yield cg.templatable(config[CONF_QOS], args, cg.uint8) + template_ = await cg.templatable(config[CONF_QOS], args, cg.uint8) cg.add(var.set_qos(template_)) - template_ = yield cg.templatable(config[CONF_RETAIN], args, bool) + template_ = await cg.templatable(config[CONF_RETAIN], args, bool) cg.add(var.set_retain(template_)) - yield var + return var def get_default_topic_for(data, component_type, name, suffix): @@ -356,9 +356,8 @@ def get_default_topic_for(data, component_type, name, suffix): ) -@coroutine -def register_mqtt_component(var, config): - yield cg.register_component(var, {}) +async def register_mqtt_component(var, config): + await cg.register_component(var, {}) if CONF_RETAIN in config: cg.add(var.set_retain(config[CONF_RETAIN])) @@ -391,6 +390,6 @@ def register_mqtt_component(var, config): } ), ) -def mqtt_connected_to_code(config, condition_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) - yield cg.new_Pvariable(condition_id, template_arg, paren) +async def mqtt_connected_to_code(config, condition_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(condition_id, template_arg, paren) diff --git a/esphome/components/output/__init__.py b/esphome/components/output/__init__.py index 487bd8cba5..975fe8adbe 100644 --- a/esphome/components/output/__init__.py +++ b/esphome/components/output/__init__.py @@ -11,7 +11,7 @@ from esphome.const import ( CONF_MIN_POWER, CONF_POWER_SUPPLY, ) -from esphome.core import CORE, coroutine +from esphome.core import CORE CODEOWNERS = ["@esphome/core"] @@ -43,12 +43,11 @@ TurnOnAction = output_ns.class_("TurnOnAction", automation.Action) SetLevelAction = output_ns.class_("SetLevelAction", automation.Action) -@coroutine -def setup_output_platform_(obj, config): +async def setup_output_platform_(obj, config): if CONF_INVERTED in config: cg.add(obj.set_inverted(config[CONF_INVERTED])) if CONF_POWER_SUPPLY in config: - power_supply_ = yield cg.get_variable(config[CONF_POWER_SUPPLY]) + power_supply_ = await cg.get_variable(config[CONF_POWER_SUPPLY]) cg.add(obj.set_power_supply(power_supply_)) if CONF_MAX_POWER in config: cg.add(obj.set_max_power(config[CONF_MAX_POWER])) @@ -56,11 +55,10 @@ def setup_output_platform_(obj, config): cg.add(obj.set_min_power(config[CONF_MIN_POWER])) -@coroutine -def register_output(var, config): +async def register_output(var, config): if not CORE.has_id(config[CONF_ID]): var = cg.Pvariable(config[CONF_ID], var) - yield setup_output_platform_(var, config) + await setup_output_platform_(var, config) BINARY_OUTPUT_ACTION_SCHEMA = maybe_simple_id( @@ -71,17 +69,17 @@ BINARY_OUTPUT_ACTION_SCHEMA = maybe_simple_id( @automation.register_action("output.turn_on", TurnOnAction, BINARY_OUTPUT_ACTION_SCHEMA) -def output_turn_on_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) - yield cg.new_Pvariable(action_id, template_arg, paren) +async def output_turn_on_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, paren) @automation.register_action( "output.turn_off", TurnOffAction, BINARY_OUTPUT_ACTION_SCHEMA ) -def output_turn_off_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) - yield cg.new_Pvariable(action_id, template_arg, paren) +async def output_turn_off_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, paren) @automation.register_action( @@ -94,12 +92,12 @@ def output_turn_off_to_code(config, action_id, template_arg, args): } ), ) -def output_set_level_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def output_set_level_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) - template_ = yield cg.templatable(config[CONF_LEVEL], args, float) + template_ = await cg.templatable(config[CONF_LEVEL], args, float) cg.add(var.set_level(template_)) - yield var + return var def to_code(config): diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py index c5df0ca97c..2f5ada6930 100644 --- a/esphome/components/sensor/__init__.py +++ b/esphome/components/sensor/__init__.py @@ -45,7 +45,7 @@ from esphome.const import ( DEVICE_CLASS_TIMESTAMP, DEVICE_CLASS_VOLTAGE, ) -from esphome.core import CORE, coroutine, coroutine_with_priority +from esphome.core import CORE, coroutine_with_priority from esphome.util import Registry CODEOWNERS = ["@esphome/core"] @@ -441,13 +441,11 @@ def calibrate_polynomial_filter_to_code(config, filter_id): yield cg.new_Pvariable(filter_id, res) -@coroutine -def build_filters(config): - yield cg.build_registry_list(FILTER_REGISTRY, config) +async def build_filters(config): + return await cg.build_registry_list(FILTER_REGISTRY, config) -@coroutine -def setup_sensor_core_(var, config): +async def setup_sensor_core_(var, config): cg.add(var.set_name(config[CONF_NAME])) if CONF_INTERNAL in config: cg.add(var.set_internal(config[CONF_INTERNAL])) @@ -461,29 +459,29 @@ def setup_sensor_core_(var, config): cg.add(var.set_accuracy_decimals(config[CONF_ACCURACY_DECIMALS])) cg.add(var.set_force_update(config[CONF_FORCE_UPDATE])) if config.get(CONF_FILTERS): # must exist and not be empty - filters = yield build_filters(config[CONF_FILTERS]) + filters = await build_filters(config[CONF_FILTERS]) cg.add(var.set_filters(filters)) for conf in config.get(CONF_ON_VALUE, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) - yield automation.build_automation(trigger, [(float, "x")], conf) + await automation.build_automation(trigger, [(float, "x")], conf) for conf in config.get(CONF_ON_RAW_VALUE, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) - yield automation.build_automation(trigger, [(float, "x")], conf) + await automation.build_automation(trigger, [(float, "x")], conf) for conf in config.get(CONF_ON_VALUE_RANGE, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) - yield cg.register_component(trigger, conf) + await cg.register_component(trigger, conf) if CONF_ABOVE in conf: - template_ = yield cg.templatable(conf[CONF_ABOVE], [(float, "x")], float) + template_ = await cg.templatable(conf[CONF_ABOVE], [(float, "x")], float) cg.add(trigger.set_min(template_)) if CONF_BELOW in conf: - template_ = yield cg.templatable(conf[CONF_BELOW], [(float, "x")], float) + template_ = await cg.templatable(conf[CONF_BELOW], [(float, "x")], float) cg.add(trigger.set_max(template_)) - yield automation.build_automation(trigger, [(float, "x")], conf) + await automation.build_automation(trigger, [(float, "x")], conf) if CONF_MQTT_ID in config: mqtt_ = cg.new_Pvariable(config[CONF_MQTT_ID], var) - yield mqtt.register_mqtt_component(mqtt_, config) + await mqtt.register_mqtt_component(mqtt_, config) if CONF_EXPIRE_AFTER in config: if config[CONF_EXPIRE_AFTER] is None: @@ -492,19 +490,17 @@ def setup_sensor_core_(var, config): cg.add(mqtt_.set_expire_after(config[CONF_EXPIRE_AFTER])) -@coroutine -def register_sensor(var, config): +async def register_sensor(var, config): if not CORE.has_id(config[CONF_ID]): var = cg.Pvariable(config[CONF_ID], var) cg.add(cg.App.register_sensor(var)) - yield setup_sensor_core_(var, config) + await setup_sensor_core_(var, config) -@coroutine -def new_sensor(config): +async def new_sensor(config): var = cg.new_Pvariable(config[CONF_ID]) - yield register_sensor(var, config) - yield var + await register_sensor(var, config) + return var SENSOR_IN_RANGE_CONDITION_SCHEMA = cv.All( @@ -520,8 +516,8 @@ SENSOR_IN_RANGE_CONDITION_SCHEMA = cv.All( @automation.register_condition( "sensor.in_range", SensorInRangeCondition, SENSOR_IN_RANGE_CONDITION_SCHEMA ) -def sensor_in_range_to_code(config, condition_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def sensor_in_range_to_code(config, condition_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(condition_id, template_arg, paren) if CONF_ABOVE in config: @@ -529,7 +525,7 @@ def sensor_in_range_to_code(config, condition_id, template_arg, args): if CONF_BELOW in config: cg.add(var.set_max(config[CONF_BELOW])) - yield var + return var def _mean(xs): @@ -618,6 +614,6 @@ def _lstsq(a, b): @coroutine_with_priority(40.0) -def to_code(config): +async def to_code(config): cg.add_define("USE_SENSOR") cg.add_global(sensor_ns.using) diff --git a/esphome/components/spi/__init__.py b/esphome/components/spi/__init__.py index 5a25ac254b..00d21e619e 100644 --- a/esphome/components/spi/__init__.py +++ b/esphome/components/spi/__init__.py @@ -9,7 +9,7 @@ from esphome.const import ( CONF_SPI_ID, CONF_CS_PIN, ) -from esphome.core import coroutine, coroutine_with_priority +from esphome.core import coroutine_with_priority CODEOWNERS = ["@esphome/core"] spi_ns = cg.esphome_ns.namespace("spi") @@ -31,18 +31,18 @@ CONFIG_SCHEMA = cv.All( @coroutine_with_priority(1.0) -def to_code(config): +async def to_code(config): cg.add_global(spi_ns.using) var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) + await cg.register_component(var, config) - clk = yield cg.gpio_pin_expression(config[CONF_CLK_PIN]) + clk = await cg.gpio_pin_expression(config[CONF_CLK_PIN]) cg.add(var.set_clk(clk)) if CONF_MISO_PIN in config: - miso = yield cg.gpio_pin_expression(config[CONF_MISO_PIN]) + miso = await cg.gpio_pin_expression(config[CONF_MISO_PIN]) cg.add(var.set_miso(miso)) if CONF_MOSI_PIN in config: - mosi = yield cg.gpio_pin_expression(config[CONF_MOSI_PIN]) + mosi = await cg.gpio_pin_expression(config[CONF_MOSI_PIN]) cg.add(var.set_mosi(mosi)) @@ -61,10 +61,9 @@ def spi_device_schema(cs_pin_required=True): return cv.Schema(schema) -@coroutine -def register_spi_device(var, config): - parent = yield cg.get_variable(config[CONF_SPI_ID]) +async def register_spi_device(var, config): + parent = await cg.get_variable(config[CONF_SPI_ID]) cg.add(var.set_spi_parent(parent)) if CONF_CS_PIN in config: - pin = yield cg.gpio_pin_expression(config[CONF_CS_PIN]) + pin = await cg.gpio_pin_expression(config[CONF_CS_PIN]) cg.add(var.set_cs_pin(pin)) diff --git a/esphome/components/status_led/__init__.py b/esphome/components/status_led/__init__.py index 76fbc01f39..92869ee630 100644 --- a/esphome/components/status_led/__init__.py +++ b/esphome/components/status_led/__init__.py @@ -16,10 +16,10 @@ CONFIG_SCHEMA = cv.Schema( @coroutine_with_priority(80.0) -def to_code(config): - pin = yield cg.gpio_pin_expression(config[CONF_PIN]) +async def to_code(config): + pin = await cg.gpio_pin_expression(config[CONF_PIN]) rhs = StatusLED.new(pin) var = cg.Pvariable(config[CONF_ID], rhs) - yield cg.register_component(var, config) + await cg.register_component(var, config) cg.add(var.pre_setup()) cg.add_define("USE_STATUS_LED") diff --git a/esphome/components/switch/__init__.py b/esphome/components/switch/__init__.py index cc47b059cb..647041c19c 100644 --- a/esphome/components/switch/__init__.py +++ b/esphome/components/switch/__init__.py @@ -14,7 +14,7 @@ from esphome.const import ( CONF_MQTT_ID, CONF_NAME, ) -from esphome.core import CORE, coroutine, coroutine_with_priority +from esphome.core import CORE, coroutine_with_priority CODEOWNERS = ["@esphome/core"] IS_PLATFORM_COMPONENT = True @@ -57,8 +57,7 @@ SWITCH_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend( ) -@coroutine -def setup_switch_core_(var, config): +async def setup_switch_core_(var, config): cg.add(var.set_name(config[CONF_NAME])) if CONF_INTERNAL in config: cg.add(var.set_internal(config[CONF_INTERNAL])) @@ -68,22 +67,21 @@ def setup_switch_core_(var, config): cg.add(var.set_inverted(config[CONF_INVERTED])) for conf in config.get(CONF_ON_TURN_ON, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) - yield automation.build_automation(trigger, [], conf) + await automation.build_automation(trigger, [], conf) for conf in config.get(CONF_ON_TURN_OFF, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) - yield automation.build_automation(trigger, [], conf) + await automation.build_automation(trigger, [], conf) if CONF_MQTT_ID in config: mqtt_ = cg.new_Pvariable(config[CONF_MQTT_ID], var) - yield mqtt.register_mqtt_component(mqtt_, config) + await mqtt.register_mqtt_component(mqtt_, config) -@coroutine -def register_switch(var, config): +async def register_switch(var, config): if not CORE.has_id(config[CONF_ID]): var = cg.Pvariable(config[CONF_ID], var) cg.add(cg.App.register_switch(var)) - yield setup_switch_core_(var, config) + await setup_switch_core_(var, config) SWITCH_ACTION_SCHEMA = maybe_simple_id( @@ -96,24 +94,24 @@ SWITCH_ACTION_SCHEMA = maybe_simple_id( @automation.register_action("switch.toggle", ToggleAction, SWITCH_ACTION_SCHEMA) @automation.register_action("switch.turn_off", TurnOffAction, SWITCH_ACTION_SCHEMA) @automation.register_action("switch.turn_on", TurnOnAction, SWITCH_ACTION_SCHEMA) -def switch_toggle_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) - yield cg.new_Pvariable(action_id, template_arg, paren) +async def switch_toggle_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, paren) @automation.register_condition("switch.is_on", SwitchCondition, SWITCH_ACTION_SCHEMA) -def switch_is_on_to_code(config, condition_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) - yield cg.new_Pvariable(condition_id, template_arg, paren, True) +async def switch_is_on_to_code(config, condition_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(condition_id, template_arg, paren, True) @automation.register_condition("switch.is_off", SwitchCondition, SWITCH_ACTION_SCHEMA) -def switch_is_off_to_code(config, condition_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) - yield cg.new_Pvariable(condition_id, template_arg, paren, False) +async def switch_is_off_to_code(config, condition_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(condition_id, template_arg, paren, False) @coroutine_with_priority(100.0) -def to_code(config): +async def to_code(config): cg.add_global(switch_ns.using) cg.add_define("USE_SWITCH") diff --git a/esphome/components/text_sensor/__init__.py b/esphome/components/text_sensor/__init__.py index ff73889d61..84fedc8d94 100644 --- a/esphome/components/text_sensor/__init__.py +++ b/esphome/components/text_sensor/__init__.py @@ -12,7 +12,7 @@ from esphome.const import ( CONF_NAME, CONF_STATE, ) -from esphome.core import CORE, coroutine, coroutine_with_priority +from esphome.core import CORE, coroutine_with_priority IS_PLATFORM_COMPONENT = True @@ -46,8 +46,7 @@ TEXT_SENSOR_SCHEMA = cv.MQTT_COMPONENT_SCHEMA.extend( ) -@coroutine -def setup_text_sensor_core_(var, config): +async def setup_text_sensor_core_(var, config): cg.add(var.set_name(config[CONF_NAME])) if CONF_INTERNAL in config: cg.add(var.set_internal(config[CONF_INTERNAL])) @@ -56,23 +55,22 @@ def setup_text_sensor_core_(var, config): for conf in config.get(CONF_ON_VALUE, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) - yield automation.build_automation(trigger, [(cg.std_string, "x")], conf) + await automation.build_automation(trigger, [(cg.std_string, "x")], conf) if CONF_MQTT_ID in config: mqtt_ = cg.new_Pvariable(config[CONF_MQTT_ID], var) - yield mqtt.register_mqtt_component(mqtt_, config) + await mqtt.register_mqtt_component(mqtt_, config) -@coroutine -def register_text_sensor(var, config): +async def register_text_sensor(var, config): if not CORE.has_id(config[CONF_ID]): var = cg.Pvariable(config[CONF_ID], var) cg.add(cg.App.register_text_sensor(var)) - yield setup_text_sensor_core_(var, config) + await setup_text_sensor_core_(var, config) @coroutine_with_priority(100.0) -def to_code(config): +async def to_code(config): cg.add_define("USE_TEXT_SENSOR") cg.add_global(text_sensor_ns.using) @@ -87,9 +85,9 @@ def to_code(config): } ), ) -def text_sensor_state_to_code(config, condition_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def text_sensor_state_to_code(config, condition_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(condition_id, template_arg, paren) - templ = yield cg.templatable(config[CONF_STATE], args, cg.std_string) + templ = await cg.templatable(config[CONF_STATE], args, cg.std_string) cg.add(var.set_state(templ)) - yield var + return var diff --git a/esphome/components/time/__init__.py b/esphome/components/time/__init__.py index 8fbc2dcaf6..4872c89f88 100644 --- a/esphome/components/time/__init__.py +++ b/esphome/components/time/__init__.py @@ -28,7 +28,7 @@ from esphome.const import ( CONF_HOUR, CONF_MINUTE, ) -from esphome.core import coroutine, coroutine_with_priority +from esphome.core import coroutine_with_priority from esphome.automation import Condition _LOGGER = logging.getLogger(__name__) @@ -380,8 +380,7 @@ TIME_SCHEMA = cv.Schema( ).extend(cv.polling_component_schema("15min")) -@coroutine -def setup_time_core_(time_var, config): +async def setup_time_core_(time_var, config): cg.add(time_var.set_timezone(config[CONF_TIMEZONE])) for conf in config.get(CONF_ON_TIME, []): @@ -400,23 +399,22 @@ def setup_time_core_(time_var, config): days_of_week = conf.get(CONF_DAYS_OF_WEEK, list(range(1, 8))) cg.add(trigger.add_days_of_week(days_of_week)) - yield cg.register_component(trigger, conf) - yield automation.build_automation(trigger, [], conf) + await cg.register_component(trigger, conf) + await automation.build_automation(trigger, [], conf) for conf in config.get(CONF_ON_TIME_SYNC, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], time_var) - yield cg.register_component(trigger, conf) - yield automation.build_automation(trigger, [], conf) + await cg.register_component(trigger, conf) + await automation.build_automation(trigger, [], conf) -@coroutine -def register_time(time_var, config): - yield setup_time_core_(time_var, config) +async def register_time(time_var, config): + await setup_time_core_(time_var, config) @coroutine_with_priority(100.0) -def to_code(config): +async def to_code(config): cg.add_define("USE_TIME") cg.add_global(time_ns.using) @@ -430,6 +428,6 @@ def to_code(config): } ), ) -def time_has_time_to_code(config, condition_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) - yield cg.new_Pvariable(condition_id, template_arg, paren) +async def time_has_time_to_code(config, condition_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(condition_id, template_arg, paren) diff --git a/esphome/components/uart/__init__.py b/esphome/components/uart/__init__.py index a02ea58def..fb82fd9aee 100644 --- a/esphome/components/uart/__init__.py +++ b/esphome/components/uart/__init__.py @@ -11,7 +11,7 @@ from esphome.const import ( CONF_RX_BUFFER_SIZE, CONF_INVERT, ) -from esphome.core import CORE, coroutine +from esphome.core import CORE CODEOWNERS = ["@esphome/core"] uart_ns = cg.esphome_ns.namespace("uart") @@ -73,10 +73,10 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): cg.add_global(uart_ns.using) var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) + await cg.register_component(var, config) cg.add(var.set_baud_rate(config[CONF_BAUD_RATE])) @@ -100,13 +100,12 @@ UART_DEVICE_SCHEMA = cv.Schema( ) -@coroutine -def register_uart_device(var, config): +async def register_uart_device(var, config): """Register a UART device, setting up all the internal values. This is a coroutine, you need to await it with a 'yield' expression! """ - parent = yield cg.get_variable(config[CONF_UART_ID]) + parent = await cg.get_variable(config[CONF_UART_ID]) cg.add(var.set_uart_parent(parent)) @@ -121,16 +120,16 @@ def register_uart_device(var, config): key=CONF_DATA, ), ) -def uart_write_to_code(config, action_id, template_arg, args): +async def uart_write_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) - yield cg.register_parented(var, config[CONF_ID]) + await cg.register_parented(var, config[CONF_ID]) data = config[CONF_DATA] if isinstance(data, bytes): data = list(data) if cg.is_template(data): - templ = yield cg.templatable(data, args, cg.std_vector.template(cg.uint8)) + templ = await cg.templatable(data, args, cg.std_vector.template(cg.uint8)) cg.add(var.set_data_template(templ)) else: cg.add(var.set_data_static(data)) - yield var + return var diff --git a/esphome/components/web_server/__init__.py b/esphome/components/web_server/__init__.py index d04f2077f4..a181f83c64 100644 --- a/esphome/components/web_server/__init__.py +++ b/esphome/components/web_server/__init__.py @@ -46,11 +46,11 @@ CONFIG_SCHEMA = cv.Schema( @coroutine_with_priority(40.0) -def to_code(config): - paren = yield cg.get_variable(config[CONF_WEB_SERVER_BASE_ID]) +async def to_code(config): + paren = await cg.get_variable(config[CONF_WEB_SERVER_BASE_ID]) var = cg.new_Pvariable(config[CONF_ID], paren) - yield cg.register_component(var, config) + await cg.register_component(var, config) cg.add(paren.set_port(config[CONF_PORT])) cg.add_define("WEBSERVER_PORT", config[CONF_PORT]) diff --git a/esphome/components/web_server_base/__init__.py b/esphome/components/web_server_base/__init__.py index 09f5dacd7c..37f3c989e4 100644 --- a/esphome/components/web_server_base/__init__.py +++ b/esphome/components/web_server_base/__init__.py @@ -19,9 +19,9 @@ CONFIG_SCHEMA = cv.Schema( @coroutine_with_priority(65.0) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) + await cg.register_component(var, config) if CORE.is_esp32: cg.add_library("FS", None) diff --git a/esphome/components/wifi/__init__.py b/esphome/components/wifi/__init__.py index 421797eb28..d2676bce36 100644 --- a/esphome/components/wifi/__init__.py +++ b/esphome/components/wifi/__init__.py @@ -277,7 +277,7 @@ def wifi_network(config, static_ip): @coroutine_with_priority(60.0) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) cg.add(var.set_use_address(config[CONF_USE_ADDRESS])) @@ -305,9 +305,9 @@ def to_code(config): add_mdns_library() # Register at end for OTA safe mode - yield cg.register_component(var, config) + await cg.register_component(var, config) @automation.register_condition("wifi.connected", WiFiConnectedCondition, cv.Schema({})) -def wifi_connected_to_code(config, condition_id, template_arg, args): - yield cg.new_Pvariable(condition_id, template_arg) +async def wifi_connected_to_code(config, condition_id, template_arg, args): + return cg.new_Pvariable(condition_id, template_arg) diff --git a/esphome/cpp_generator.py b/esphome/cpp_generator.py index d71e0df4d2..70c3826d27 100644 --- a/esphome/cpp_generator.py +++ b/esphome/cpp_generator.py @@ -575,8 +575,7 @@ async def get_variable_with_full_id(id_: ID) -> Tuple[ID, "MockObj"]: return await CORE.get_variable_with_full_id(id_) -@coroutine -def process_lambda( +async def process_lambda( value: Lambda, parameters: List[Tuple[SafeExpType, str]], capture: str = "=", @@ -596,11 +595,10 @@ def process_lambda( from esphome.components.globals import GlobalsComponent if value is None: - yield return parts = value.parts[:] for i, id in enumerate(value.requires_ids): - full_id, var = yield get_variable_with_full_id(id) + full_id, var = await get_variable_with_full_id(id) if ( full_id is not None and isinstance(full_id.type, MockObjClass) @@ -620,7 +618,7 @@ def process_lambda( location.line += value.content_offset else: location = None - yield LambdaExpression(parts, parameters, capture, return_type, location) + return LambdaExpression(parts, parameters, capture, return_type, location) def is_template(value): @@ -628,8 +626,7 @@ def is_template(value): return isinstance(value, Lambda) -@coroutine -def templatable( +async def templatable( value: Any, args: List[Tuple[SafeExpType, str]], output_type: Optional[SafeExpType], @@ -647,15 +644,12 @@ def templatable( :return: The potentially templated value. """ if is_template(value): - lambda_ = yield process_lambda(value, args, return_type=output_type) - yield lambda_ - else: - if to_exp is None: - yield value - elif isinstance(to_exp, dict): - yield to_exp[value] - else: - yield to_exp(value) + return await process_lambda(value, args, return_type=output_type) + if to_exp is None: + return value + if isinstance(to_exp, dict): + return to_exp[value] + return to_exp(value) class MockObj(Expression): diff --git a/esphome/cpp_helpers.py b/esphome/cpp_helpers.py index e83f989d7a..e1b1a09133 100644 --- a/esphome/cpp_helpers.py +++ b/esphome/cpp_helpers.py @@ -14,8 +14,7 @@ from esphome.cpp_types import App, GPIOPin from esphome.util import Registry, RegistryEntry -@coroutine -def gpio_pin_expression(conf): +async def gpio_pin_expression(conf): """Generate an expression for the given pin option. This is a coroutine, you must await it with a 'yield' expression! @@ -26,17 +25,15 @@ def gpio_pin_expression(conf): for key, (func, _) in pins.PIN_SCHEMA_REGISTRY.items(): if key in conf: - yield coroutine(func)(conf) - return + return await coroutine(func)(conf) number = conf[CONF_NUMBER] mode = conf[CONF_MODE] inverted = conf.get(CONF_INVERTED) - yield GPIOPin.new(number, RawExpression(mode), inverted) + return GPIOPin.new(number, RawExpression(mode), inverted) -@coroutine -def register_component(var, config): +async def register_component(var, config): """Register the given obj as a component. This is a coroutine, you must await it with a 'yield' expression! @@ -57,13 +54,12 @@ def register_component(var, config): if CONF_UPDATE_INTERVAL in config: add(var.set_update_interval(config[CONF_UPDATE_INTERVAL])) add(App.register_component(var)) - yield var + return var -@coroutine -def register_parented(var, value): +async def register_parented(var, value): if isinstance(value, ID): - paren = yield get_variable(value) + paren = await get_variable(value) else: paren = value add(var.set_parent(paren)) @@ -75,18 +71,16 @@ def extract_registry_entry_config(registry, full_config): return registry[key], config -@coroutine -def build_registry_entry(registry, full_config): +async def build_registry_entry(registry, full_config): registry_entry, config = extract_registry_entry_config(registry, full_config) type_id = full_config[CONF_TYPE_ID] builder = registry_entry.coroutine_fun - yield builder(config, type_id) + return await builder(config, type_id) -@coroutine -def build_registry_list(registry, config): +async def build_registry_list(registry, config): actions = [] for conf in config: - action = yield build_registry_entry(registry, conf) + action = await build_registry_entry(registry, conf) actions.append(action) - yield actions + return actions From 0ce57e5a39af1c55b469cea99d520ee28fb7e9ce Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Sun, 23 May 2021 22:20:11 +0200 Subject: [PATCH 051/104] Light & Switch Inverted Restore mode (#1810) --- esphome/components/gpio/switch/__init__.py | 2 ++ esphome/components/gpio/switch/gpio_switch.cpp | 12 ++++++++++++ esphome/components/gpio/switch/gpio_switch.h | 2 ++ esphome/components/light/__init__.py | 2 ++ esphome/components/light/light_state.cpp | 14 ++++++++++++-- esphome/components/light/light_state.h | 2 ++ 6 files changed, 32 insertions(+), 2 deletions(-) diff --git a/esphome/components/gpio/switch/__init__.py b/esphome/components/gpio/switch/__init__.py index ebd12d10ca..44a9699b84 100644 --- a/esphome/components/gpio/switch/__init__.py +++ b/esphome/components/gpio/switch/__init__.py @@ -13,6 +13,8 @@ RESTORE_MODES = { "RESTORE_DEFAULT_ON": GPIOSwitchRestoreMode.GPIO_SWITCH_RESTORE_DEFAULT_ON, "ALWAYS_OFF": GPIOSwitchRestoreMode.GPIO_SWITCH_ALWAYS_OFF, "ALWAYS_ON": GPIOSwitchRestoreMode.GPIO_SWITCH_ALWAYS_ON, + "RESTORE_INVERTED_DEFAULT_OFF": GPIOSwitchRestoreMode.GPIO_SWITCH_RESTORE_INVERTED_DEFAULT_OFF, + "RESTORE_INVERTED_DEFAULT_ON": GPIOSwitchRestoreMode.GPIO_SWITCH_RESTORE_INVERTED_DEFAULT_ON, } CONF_INTERLOCK_WAIT_TIME = "interlock_wait_time" diff --git a/esphome/components/gpio/switch/gpio_switch.cpp b/esphome/components/gpio/switch/gpio_switch.cpp index d87e5a61e6..2475d43e93 100644 --- a/esphome/components/gpio/switch/gpio_switch.cpp +++ b/esphome/components/gpio/switch/gpio_switch.cpp @@ -18,6 +18,12 @@ void GPIOSwitch::setup() { case GPIO_SWITCH_RESTORE_DEFAULT_ON: initial_state = this->get_initial_state().value_or(true); break; + case GPIO_SWITCH_RESTORE_INVERTED_DEFAULT_OFF: + initial_state = !this->get_initial_state().value_or(true); + break; + case GPIO_SWITCH_RESTORE_INVERTED_DEFAULT_ON: + initial_state = !this->get_initial_state().value_or(false); + break; case GPIO_SWITCH_ALWAYS_OFF: initial_state = false; break; @@ -49,6 +55,12 @@ void GPIOSwitch::dump_config() { case GPIO_SWITCH_RESTORE_DEFAULT_ON: restore_mode = "Restore (Defaults to ON)"; break; + case GPIO_SWITCH_RESTORE_INVERTED_DEFAULT_ON: + restore_mode = "Restore inverted (Defaults to ON)"; + break; + case GPIO_SWITCH_RESTORE_INVERTED_DEFAULT_OFF: + restore_mode = "Restore inverted (Defaults to OFF)"; + break; case GPIO_SWITCH_ALWAYS_OFF: restore_mode = "Always OFF"; break; diff --git a/esphome/components/gpio/switch/gpio_switch.h b/esphome/components/gpio/switch/gpio_switch.h index dc0dd9bc95..c0036b20e9 100644 --- a/esphome/components/gpio/switch/gpio_switch.h +++ b/esphome/components/gpio/switch/gpio_switch.h @@ -11,6 +11,8 @@ enum GPIOSwitchRestoreMode { GPIO_SWITCH_RESTORE_DEFAULT_ON, GPIO_SWITCH_ALWAYS_OFF, GPIO_SWITCH_ALWAYS_ON, + GPIO_SWITCH_RESTORE_INVERTED_DEFAULT_OFF, + GPIO_SWITCH_RESTORE_INVERTED_DEFAULT_ON, }; class GPIOSwitch : public switch_::Switch, public Component { diff --git a/esphome/components/light/__init__.py b/esphome/components/light/__init__.py index a382c5604e..276bf8073d 100644 --- a/esphome/components/light/__init__.py +++ b/esphome/components/light/__init__.py @@ -46,6 +46,8 @@ RESTORE_MODES = { "RESTORE_DEFAULT_ON": LightRestoreMode.LIGHT_RESTORE_DEFAULT_ON, "ALWAYS_OFF": LightRestoreMode.LIGHT_ALWAYS_OFF, "ALWAYS_ON": LightRestoreMode.LIGHT_ALWAYS_ON, + "RESTORE_INVERTED_DEFAULT_OFF": LightRestoreMode.LIGHT_RESTORE_INVERTED_DEFAULT_OFF, + "RESTORE_INVERTED_DEFAULT_ON": LightRestoreMode.LIGHT_RESTORE_INVERTED_DEFAULT_ON, } LIGHT_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend( diff --git a/esphome/components/light/light_state.cpp b/esphome/components/light/light_state.cpp index dd78ced650..4e450f6ccb 100644 --- a/esphome/components/light/light_state.cpp +++ b/esphome/components/light/light_state.cpp @@ -106,10 +106,20 @@ void LightState::setup() { switch (this->restore_mode_) { case LIGHT_RESTORE_DEFAULT_OFF: case LIGHT_RESTORE_DEFAULT_ON: + case LIGHT_RESTORE_INVERTED_DEFAULT_OFF: + case LIGHT_RESTORE_INVERTED_DEFAULT_ON: this->rtc_ = global_preferences.make_preference(this->get_object_id_hash()); - // Attempt to load from preferences, else fall back to default values from struct + // Attempt to load from preferences, else fall back to default values if (!this->rtc_.load(&recovered)) { - recovered.state = this->restore_mode_ == LIGHT_RESTORE_DEFAULT_ON; + recovered.state = false; + if (this->restore_mode_ == LIGHT_RESTORE_DEFAULT_ON || + this->restore_mode_ == LIGHT_RESTORE_INVERTED_DEFAULT_ON) { + recovered.state = true; + } + } else if (this->restore_mode_ == LIGHT_RESTORE_INVERTED_DEFAULT_OFF || + this->restore_mode_ == LIGHT_RESTORE_INVERTED_DEFAULT_ON) { + // Inverted restore state + recovered.state = !recovered.state; } break; case LIGHT_ALWAYS_OFF: diff --git a/esphome/components/light/light_state.h b/esphome/components/light/light_state.h index e761e576e3..aff63bf5db 100644 --- a/esphome/components/light/light_state.h +++ b/esphome/components/light/light_state.h @@ -165,6 +165,8 @@ enum LightRestoreMode { LIGHT_RESTORE_DEFAULT_ON, LIGHT_ALWAYS_OFF, LIGHT_ALWAYS_ON, + LIGHT_RESTORE_INVERTED_DEFAULT_OFF, + LIGHT_RESTORE_INVERTED_DEFAULT_ON, }; /** This class represents the communication layer between the front-end MQTT layer and the From 8d8d42128629dc074c633a58540b5808d9cbcb30 Mon Sep 17 00:00:00 2001 From: wifwucite <74489218+wifwucite@users.noreply.github.com> Date: Sun, 23 May 2021 22:24:24 +0200 Subject: [PATCH 052/104] allow default option for typed_schema (#1700) Co-authored-by: Otto Winter --- esphome/config_validation.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/esphome/config_validation.py b/esphome/config_validation.py index dcc0da8b2b..2cdb6b0b76 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -1363,15 +1363,17 @@ def extract_keys(schema): def typed_schema(schemas, **kwargs): """Create a schema that has a key to distinguish between schemas""" key = kwargs.pop("key", CONF_TYPE) + default_schema_option = kwargs.pop("default_type", None) key_validator = one_of(*schemas, **kwargs) def validator(value): if not isinstance(value, dict): raise Invalid("Value must be dict") - if key not in value: - raise Invalid("type not specified!") value = value.copy() - key_v = key_validator(value.pop(key)) + schema_option = value.pop(key, default_schema_option) + if schema_option is None: + raise Invalid(key + " not specified!") + key_v = key_validator(schema_option) value = schemas[key_v](value) value[key] = key_v return value From 063d9c47a402bf78f57e051f88c56acc08eedfdf Mon Sep 17 00:00:00 2001 From: Stanislav Meduna Date: Sun, 23 May 2021 22:24:54 +0200 Subject: [PATCH 053/104] Refactor font creation to save stack (#1707) --- esphome/codegen.py | 1 + esphome/components/display/display_buffer.cpp | 56 +++++++++---------- esphome/components/display/display_buffer.h | 21 ++++--- esphome/components/font/__init__.py | 26 ++++++++- esphome/cpp_generator.py | 19 +++++++ 5 files changed, 80 insertions(+), 43 deletions(-) diff --git a/esphome/codegen.py b/esphome/codegen.py index 90f59f75bc..8361faeb81 100644 --- a/esphome/codegen.py +++ b/esphome/codegen.py @@ -19,6 +19,7 @@ from esphome.cpp_generator import ( # noqa Statement, LineComment, progmem_array, + static_const_array, statement, variable, new_variable, diff --git a/esphome/components/display/display_buffer.cpp b/esphome/components/display/display_buffer.cpp index 994997e6e0..c66f87a7aa 100644 --- a/esphome/components/display/display_buffer.cpp +++ b/esphome/components/display/display_buffer.cpp @@ -170,7 +170,7 @@ void DisplayBuffer::print(int x, int y, Font *font, Color color, TextAlign align // Unknown char, skip ESP_LOGW(TAG, "Encountered character without representation in font: '%c'", text[i]); if (!font->get_glyphs().empty()) { - uint8_t glyph_width = font->get_glyphs()[0].width_; + uint8_t glyph_width = font->get_glyphs()[0].glyph_data_->width; for (int glyph_x = 0; glyph_x < glyph_width; glyph_x++) for (int glyph_y = 0; glyph_y < height; glyph_y++) this->draw_pixel_at(glyph_x + x_at, glyph_y + y_start, color); @@ -193,7 +193,7 @@ void DisplayBuffer::print(int x, int y, Font *font, Color color, TextAlign align } } - x_at += glyph.width_ + glyph.offset_x_; + x_at += glyph.glyph_data_->width + glyph.glyph_data_->offset_x; i += match_length; } @@ -345,35 +345,27 @@ void DisplayBuffer::strftime(int x, int y, Font *font, const char *format, time: } #endif -Glyph::Glyph(const char *a_char, const uint8_t *data_start, uint32_t offset, int offset_x, int offset_y, int width, - int height) - : char_(a_char), - data_(data_start + offset), - offset_x_(offset_x), - offset_y_(offset_y), - width_(width), - height_(height) {} bool Glyph::get_pixel(int x, int y) const { - const int x_data = x - this->offset_x_; - const int y_data = y - this->offset_y_; - if (x_data < 0 || x_data >= this->width_ || y_data < 0 || y_data >= this->height_) + const int x_data = x - this->glyph_data_->offset_x; + const int y_data = y - this->glyph_data_->offset_y; + if (x_data < 0 || x_data >= this->glyph_data_->width || y_data < 0 || y_data >= this->glyph_data_->height) return false; - const uint32_t width_8 = ((this->width_ + 7u) / 8u) * 8u; + const uint32_t width_8 = ((this->glyph_data_->width + 7u) / 8u) * 8u; const uint32_t pos = x_data + y_data * width_8; - return pgm_read_byte(this->data_ + (pos / 8u)) & (0x80 >> (pos % 8u)); + return pgm_read_byte(this->glyph_data_->data + (pos / 8u)) & (0x80 >> (pos % 8u)); } -const char *Glyph::get_char() const { return this->char_; } +const char *Glyph::get_char() const { return this->glyph_data_->a_char; } bool Glyph::compare_to(const char *str) const { // 1 -> this->char_ // 2 -> str for (uint32_t i = 0;; i++) { - if (this->char_[i] == '\0') + if (this->glyph_data_->a_char[i] == '\0') return true; if (str[i] == '\0') return false; - if (this->char_[i] > str[i]) + if (this->glyph_data_->a_char[i] > str[i]) return false; - if (this->char_[i] < str[i]) + if (this->glyph_data_->a_char[i] < str[i]) return true; } // this should not happen @@ -381,19 +373,19 @@ bool Glyph::compare_to(const char *str) const { } int Glyph::match_length(const char *str) const { for (uint32_t i = 0;; i++) { - if (this->char_[i] == '\0') + if (this->glyph_data_->a_char[i] == '\0') return i; - if (str[i] != this->char_[i]) + if (str[i] != this->glyph_data_->a_char[i]) return 0; } // this should not happen return 0; } void Glyph::scan_area(int *x1, int *y1, int *width, int *height) const { - *x1 = this->offset_x_; - *y1 = this->offset_y_; - *width = this->width_; - *height = this->height_; + *x1 = this->glyph_data_->offset_x; + *y1 = this->glyph_data_->offset_y; + *width = this->glyph_data_->width; + *height = this->glyph_data_->height; } int Font::match_next_glyph(const char *str, int *match_length) { int lo = 0; @@ -423,17 +415,17 @@ void Font::measure(const char *str, int *width, int *x_offset, int *baseline, in if (glyph_n < 0) { // Unknown char, skip if (!this->get_glyphs().empty()) - x += this->get_glyphs()[0].width_; + x += this->get_glyphs()[0].glyph_data_->width; i++; continue; } const Glyph &glyph = this->glyphs_[glyph_n]; if (!has_char) - min_x = glyph.offset_x_; + min_x = glyph.glyph_data_->offset_x; else - min_x = std::min(min_x, x + glyph.offset_x_); - x += glyph.width_ + glyph.offset_x_; + min_x = std::min(min_x, x + glyph.glyph_data_->offset_x); + x += glyph.glyph_data_->width + glyph.glyph_data_->offset_x; i += match_length; has_char = true; @@ -442,8 +434,10 @@ void Font::measure(const char *str, int *width, int *x_offset, int *baseline, in *width = x - min_x; } const std::vector &Font::get_glyphs() const { return this->glyphs_; } -Font::Font(std::vector &&glyphs, int baseline, int bottom) - : glyphs_(std::move(glyphs)), baseline_(baseline), bottom_(bottom) {} +Font::Font(const GlyphData *data, int data_nr, int baseline, int bottom) : baseline_(baseline), bottom_(bottom) { + for (int i = 0; i < data_nr; ++i) + glyphs_.emplace_back(data + i); +} bool Image::get_pixel(int x, int y) const { if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) diff --git a/esphome/components/display/display_buffer.h b/esphome/components/display/display_buffer.h index 71a6189990..42e3c5871f 100644 --- a/esphome/components/display/display_buffer.h +++ b/esphome/components/display/display_buffer.h @@ -338,10 +338,18 @@ class DisplayPage { DisplayPage *next_{nullptr}; }; +struct GlyphData { + const char *a_char; + const uint8_t *data; + int offset_x; + int offset_y; + int width; + int height; +}; + class Glyph { public: - Glyph(const char *a_char, const uint8_t *data_start, uint32_t offset, int offset_x, int offset_y, int width, - int height); + Glyph(const GlyphData *data) : glyph_data_(data) {} bool get_pixel(int x, int y) const; @@ -357,12 +365,7 @@ class Glyph { friend Font; friend DisplayBuffer; - const char *char_; - const uint8_t *data_; - int offset_x_; - int offset_y_; - int width_; - int height_; + const GlyphData *glyph_data_; }; class Font { @@ -373,7 +376,7 @@ class Font { * @param baseline The y-offset from the top of the text to the baseline. * @param bottom The y-offset from the top of the text to the bottom (i.e. height). */ - Font(std::vector &&glyphs, int baseline, int bottom); + Font(const GlyphData *data, int data_nr, int baseline, int bottom); int match_next_glyph(const char *str, int *match_length); diff --git a/esphome/components/font/__init__.py b/esphome/components/font/__init__.py index c414d37c40..b54342d586 100644 --- a/esphome/components/font/__init__.py +++ b/esphome/components/font/__init__.py @@ -12,6 +12,7 @@ MULTI_CONF = True Font = display.display_ns.class_("Font") Glyph = display.display_ns.class_("Glyph") +GlyphData = display.display_ns.struct("GlyphData") def validate_glyphs(value): @@ -75,6 +76,7 @@ DEFAULT_GLYPHS = ( ' !"%()+,-.:/0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz°' ) CONF_RAW_DATA_ID = "raw_data_id" +CONF_RAW_GLYPH_ID = "raw_glyph_id" FONT_SCHEMA = cv.Schema( { @@ -83,6 +85,7 @@ FONT_SCHEMA = cv.Schema( cv.Optional(CONF_GLYPHS, default=DEFAULT_GLYPHS): validate_glyphs, cv.Optional(CONF_SIZE, default=20): cv.int_range(min=1), cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_id(cg.uint8), + cv.GenerateID(CONF_RAW_GLYPH_ID): cv.declare_id(GlyphData), } ) @@ -120,8 +123,25 @@ def to_code(config): rhs = [HexInt(x) for x in data] prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs) - glyphs = [] + glyph_initializer = [] for glyph in config[CONF_GLYPHS]: - glyphs.append(Glyph(glyph, prog_arr, *glyph_args[glyph])) + glyph_initializer.append( + cg.StructInitializer( + GlyphData, + ("a_char", glyph), + ( + "data", + cg.RawExpression(str(prog_arr) + " + " + str(glyph_args[glyph][0])), + ), + ("offset_x", glyph_args[glyph][1]), + ("offset_y", glyph_args[glyph][2]), + ("width", glyph_args[glyph][3]), + ("height", glyph_args[glyph][4]), + ) + ) - cg.new_Pvariable(config[CONF_ID], glyphs, ascent, ascent + descent) + glyphs = cg.static_const_array(config[CONF_RAW_GLYPH_ID], glyph_initializer) + + cg.new_Pvariable( + config[CONF_ID], glyphs, len(glyph_initializer), ascent, ascent + descent + ) diff --git a/esphome/cpp_generator.py b/esphome/cpp_generator.py index 70c3826d27..5325526c23 100644 --- a/esphome/cpp_generator.py +++ b/esphome/cpp_generator.py @@ -411,6 +411,16 @@ class ProgmemAssignmentExpression(AssignmentExpression): return f"static const {self.type} {self.name}[] PROGMEM = {self.rhs}" +class StaticConstAssignmentExpression(AssignmentExpression): + __slots__ = () + + def __init__(self, type_, name, rhs, obj): + super().__init__(type_, "", name, rhs, obj) + + def __str__(self): + return f"static const {self.type} {self.name}[] = {self.rhs}" + + def progmem_array(id_, rhs) -> "MockObj": rhs = safe_exp(rhs) obj = MockObj(id_, ".") @@ -420,6 +430,15 @@ def progmem_array(id_, rhs) -> "MockObj": return obj +def static_const_array(id_, rhs) -> "MockObj": + rhs = safe_exp(rhs) + obj = MockObj(id_, ".") + assignment = StaticConstAssignmentExpression(id_.type, id_, rhs, obj) + CORE.add(assignment) + CORE.register_variable(id_, obj) + return obj + + def statement(expression: Union[Expression, Statement]) -> Statement: """Convert expression into a statement unless is already a statement.""" if isinstance(expression, Statement): From cccb1a2c9ef1f05e68f68f0978858af0aa5b977a Mon Sep 17 00:00:00 2001 From: Trevor North Date: Sun, 23 May 2021 21:27:19 +0100 Subject: [PATCH 054/104] BME680 BSEC: Allow sample rate overrides for T/P/H sensors (#1710) --- esphome/components/bme680_bsec/__init__.py | 2 +- .../components/bme680_bsec/bme680_bsec.cpp | 124 +++++++++++------- esphome/components/bme680_bsec/bme680_bsec.h | 52 ++++---- esphome/components/bme680_bsec/sensor.py | 46 ++++--- esphome/components/bme680_bsec/text_sensor.py | 15 +-- 5 files changed, 141 insertions(+), 98 deletions(-) diff --git a/esphome/components/bme680_bsec/__init__.py b/esphome/components/bme680_bsec/__init__.py index 8286029c3b..e9704b5e59 100644 --- a/esphome/components/bme680_bsec/__init__.py +++ b/esphome/components/bme680_bsec/__init__.py @@ -60,5 +60,5 @@ def to_code(config): var.set_state_save_interval(config[CONF_STATE_SAVE_INTERVAL].total_milliseconds) ) - cg.add_define("USING_BSEC") + cg.add_define("USE_BSEC") cg.add_library("BSEC Software Library", "1.6.1480") diff --git a/esphome/components/bme680_bsec/bme680_bsec.cpp b/esphome/components/bme680_bsec/bme680_bsec.cpp index a463ff78c4..756629383c 100644 --- a/esphome/components/bme680_bsec/bme680_bsec.cpp +++ b/esphome/components/bme680_bsec/bme680_bsec.cpp @@ -1,5 +1,3 @@ - - #include "bme680_bsec.h" #include "esphome/core/log.h" #include "esphome/core/helpers.h" @@ -7,7 +5,7 @@ namespace esphome { namespace bme680_bsec { -#ifdef USING_BSEC +#ifdef USE_BSEC static const char *TAG = "bme680_bsec.sensor"; static const std::string IAQ_ACCURACY_STATES[4] = {"Stabilizing", "Uncertain", "Calibrating", "Calibrated"}; @@ -30,7 +28,6 @@ void BME680BSECComponent::setup() { this->bme680_.write = BME680BSECComponent::write_bytes_wrapper; this->bme680_.delay_ms = BME680BSECComponent::delay_ms; this->bme680_.amb_temp = 25; - this->bme680_.power_mode = BME680_FORCED_MODE; this->bme680_status_ = bme680_init(&this->bme680_); if (this->bme680_status_ != BME680_OK) { @@ -43,14 +40,13 @@ void BME680BSECComponent::setup() { #include "config/generic_33v_300s_28d/bsec_iaq.txt" }; this->set_config_(bsec_config); - this->update_subscription_(BSEC_SAMPLE_RATE_ULP); } else { const uint8_t bsec_config[] = { #include "config/generic_33v_3s_28d/bsec_iaq.txt" }; this->set_config_(bsec_config); - this->update_subscription_(BSEC_SAMPLE_RATE_LP); } + this->update_subscription_(); if (this->bsec_status_ != BSEC_OK) { this->mark_failed(); return; @@ -64,50 +60,57 @@ void BME680BSECComponent::set_config_(const uint8_t *config) { this->bsec_status_ = bsec_set_configuration(config, BSEC_MAX_PROPERTY_BLOB_SIZE, work_buffer, sizeof(work_buffer)); } -void BME680BSECComponent::update_subscription_(float sample_rate) { +float BME680BSECComponent::calc_sensor_sample_rate_(SampleRate sample_rate) { + if (sample_rate == SAMPLE_RATE_DEFAULT) { + sample_rate = this->sample_rate_; + } + return sample_rate == SAMPLE_RATE_ULP ? BSEC_SAMPLE_RATE_ULP : BSEC_SAMPLE_RATE_LP; +} + +void BME680BSECComponent::update_subscription_() { bsec_sensor_configuration_t virtual_sensors[BSEC_NUMBER_OUTPUTS]; int num_virtual_sensors = 0; if (this->iaq_sensor_) { virtual_sensors[num_virtual_sensors].sensor_id = this->iaq_mode_ == IAQ_MODE_STATIC ? BSEC_OUTPUT_STATIC_IAQ : BSEC_OUTPUT_IAQ; - virtual_sensors[num_virtual_sensors].sample_rate = sample_rate; + virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(SAMPLE_RATE_DEFAULT); num_virtual_sensors++; } if (this->co2_equivalent_sensor_) { virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_CO2_EQUIVALENT; - virtual_sensors[num_virtual_sensors].sample_rate = sample_rate; + virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(SAMPLE_RATE_DEFAULT); num_virtual_sensors++; } if (this->breath_voc_equivalent_sensor_) { virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_BREATH_VOC_EQUIVALENT; - virtual_sensors[num_virtual_sensors].sample_rate = sample_rate; + virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(SAMPLE_RATE_DEFAULT); num_virtual_sensors++; } if (this->pressure_sensor_) { virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_RAW_PRESSURE; - virtual_sensors[num_virtual_sensors].sample_rate = sample_rate; + virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(this->pressure_sample_rate_); num_virtual_sensors++; } if (this->gas_resistance_sensor_) { virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_RAW_GAS; - virtual_sensors[num_virtual_sensors].sample_rate = sample_rate; + virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(SAMPLE_RATE_DEFAULT); num_virtual_sensors++; } if (this->temperature_sensor_) { virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE; - virtual_sensors[num_virtual_sensors].sample_rate = sample_rate; + virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(this->temperature_sample_rate_); num_virtual_sensors++; } if (this->humidity_sensor_) { virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY; - virtual_sensors[num_virtual_sensors].sample_rate = sample_rate; + virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(this->humidity_sample_rate_); num_virtual_sensors++; } @@ -134,12 +137,15 @@ void BME680BSECComponent::dump_config() { ESP_LOGCONFIG(TAG, " Temperature Offset: %.2f", this->temperature_offset_); ESP_LOGCONFIG(TAG, " IAQ Mode: %s", this->iaq_mode_ == IAQ_MODE_STATIC ? "Static" : "Mobile"); - ESP_LOGCONFIG(TAG, " Sample Rate: %s", this->sample_rate_ == SAMPLE_RATE_ULP ? "ULP" : "LP"); + ESP_LOGCONFIG(TAG, " Sample Rate: %s", BME680_BSEC_SAMPLE_RATE_LOG(this->sample_rate_)); ESP_LOGCONFIG(TAG, " State Save Interval: %ims", this->state_save_interval_ms_); LOG_SENSOR(" ", "Temperature", this->temperature_sensor_); + ESP_LOGCONFIG(TAG, " Sample Rate: %s", BME680_BSEC_SAMPLE_RATE_LOG(this->temperature_sample_rate_)); LOG_SENSOR(" ", "Pressure", this->pressure_sensor_); + ESP_LOGCONFIG(TAG, " Sample Rate: %s", BME680_BSEC_SAMPLE_RATE_LOG(this->pressure_sample_rate_)); LOG_SENSOR(" ", "Humidity", this->humidity_sensor_); + ESP_LOGCONFIG(TAG, " Sample Rate: %s", BME680_BSEC_SAMPLE_RATE_LOG(this->humidity_sample_rate_)); LOG_SENSOR(" ", "Gas Resistance", this->gas_resistance_sensor_); LOG_SENSOR(" ", "IAQ", this->iaq_sensor_); LOG_SENSOR(" ", "Numeric IAQ Accuracy", this->iaq_accuracy_sensor_); @@ -181,34 +187,55 @@ void BME680BSECComponent::run_() { } this->next_call_ns_ = bme680_settings.next_call; - this->bme680_.gas_sett.run_gas = bme680_settings.run_gas; - this->bme680_.tph_sett.os_hum = bme680_settings.humidity_oversampling; - this->bme680_.tph_sett.os_temp = bme680_settings.temperature_oversampling; - this->bme680_.tph_sett.os_pres = bme680_settings.pressure_oversampling; - this->bme680_.gas_sett.heatr_temp = bme680_settings.heater_temperature; - this->bme680_.gas_sett.heatr_dur = bme680_settings.heating_duration; - uint16_t desired_settings = - BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_FILTER_SEL | BME680_GAS_SENSOR_SEL; - this->bme680_status_ = bme680_set_sensor_settings(desired_settings, &this->bme680_); - if (this->bme680_status_ != BME680_OK) { - ESP_LOGW(TAG, "Failed to set sensor settings (BME680 Error Code %d)", this->bme680_status_); - return; - } + if (bme680_settings.trigger_measurement) { + this->bme680_.tph_sett.os_temp = bme680_settings.temperature_oversampling; + this->bme680_.tph_sett.os_pres = bme680_settings.pressure_oversampling; + this->bme680_.tph_sett.os_hum = bme680_settings.humidity_oversampling; + this->bme680_.gas_sett.run_gas = bme680_settings.run_gas; + this->bme680_.gas_sett.heatr_temp = bme680_settings.heater_temperature; + this->bme680_.gas_sett.heatr_dur = bme680_settings.heating_duration; + this->bme680_.power_mode = BME680_FORCED_MODE; + uint16_t desired_settings = BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_GAS_SENSOR_SEL; + this->bme680_status_ = bme680_set_sensor_settings(desired_settings, &this->bme680_); + if (this->bme680_status_ != BME680_OK) { + ESP_LOGW(TAG, "Failed to set sensor settings (BME680 Error Code %d)", this->bme680_status_); + return; + } - this->bme680_status_ = bme680_set_sensor_mode(&this->bme680_); - if (this->bme680_status_ != BME680_OK) { - ESP_LOGW(TAG, "Failed to set sensor mode (BME680 Error Code %d)", this->bme680_status_); - return; - } + this->bme680_status_ = bme680_set_sensor_mode(&this->bme680_); + if (this->bme680_status_ != BME680_OK) { + ESP_LOGW(TAG, "Failed to set sensor mode (BME680 Error Code %d)", this->bme680_status_); + return; + } - uint16_t meas_dur = 0; - bme680_get_profile_dur(&meas_dur, &this->bme680_); - ESP_LOGV(TAG, "Queueing read in %ums", meas_dur); - this->set_timeout("read", meas_dur, [this, bme680_settings]() { this->read_(bme680_settings); }); + uint16_t meas_dur = 0; + bme680_get_profile_dur(&meas_dur, &this->bme680_); + ESP_LOGV(TAG, "Queueing read in %ums", meas_dur); + this->set_timeout("read", meas_dur, + [this, curr_time_ns, bme680_settings]() { this->read_(curr_time_ns, bme680_settings); }); + } else { + ESP_LOGV(TAG, "Measurement not required"); + this->read_(curr_time_ns, bme680_settings); + } } -void BME680BSECComponent::read_(bsec_bme_settings_t bme680_settings) { +void BME680BSECComponent::read_(int64_t trigger_time_ns, bsec_bme_settings_t bme680_settings) { ESP_LOGV(TAG, "Reading data"); + + if (bme680_settings.trigger_measurement) { + while (this->bme680_.power_mode != BME680_SLEEP_MODE) { + this->bme680_status_ = bme680_get_sensor_mode(&this->bme680_); + if (this->bme680_status_ != BME680_OK) { + ESP_LOGW(TAG, "Failed to get sensor mode (BME680 Error Code %d)", this->bme680_status_); + } + } + } + + if (!bme680_settings.process_data) { + ESP_LOGV(TAG, "Data processing not required"); + return; + } + struct bme680_field_data data; this->bme680_status_ = bme680_get_sensor_data(&data, &this->bme680_); @@ -223,37 +250,40 @@ void BME680BSECComponent::read_(bsec_bme_settings_t bme680_settings) { bsec_input_t inputs[BSEC_MAX_PHYSICAL_SENSOR]; // Temperature, Pressure, Humidity & Gas Resistance uint8_t num_inputs = 0; - int64_t curr_time_ns = this->get_time_ns_(); if (bme680_settings.process_data & BSEC_PROCESS_TEMPERATURE) { inputs[num_inputs].sensor_id = BSEC_INPUT_TEMPERATURE; inputs[num_inputs].signal = data.temperature / 100.0f; - inputs[num_inputs].time_stamp = curr_time_ns; + inputs[num_inputs].time_stamp = trigger_time_ns; num_inputs++; // Temperature offset from the real temperature due to external heat sources inputs[num_inputs].sensor_id = BSEC_INPUT_HEATSOURCE; inputs[num_inputs].signal = this->temperature_offset_; - inputs[num_inputs].time_stamp = curr_time_ns; + inputs[num_inputs].time_stamp = trigger_time_ns; num_inputs++; } if (bme680_settings.process_data & BSEC_PROCESS_HUMIDITY) { inputs[num_inputs].sensor_id = BSEC_INPUT_HUMIDITY; inputs[num_inputs].signal = data.humidity / 1000.0f; - inputs[num_inputs].time_stamp = curr_time_ns; + inputs[num_inputs].time_stamp = trigger_time_ns; num_inputs++; } if (bme680_settings.process_data & BSEC_PROCESS_PRESSURE) { inputs[num_inputs].sensor_id = BSEC_INPUT_PRESSURE; inputs[num_inputs].signal = data.pressure; - inputs[num_inputs].time_stamp = curr_time_ns; + inputs[num_inputs].time_stamp = trigger_time_ns; num_inputs++; } if (bme680_settings.process_data & BSEC_PROCESS_GAS) { - inputs[num_inputs].sensor_id = BSEC_INPUT_GASRESISTOR; - inputs[num_inputs].signal = data.gas_resistance; - inputs[num_inputs].time_stamp = curr_time_ns; - num_inputs++; + if (data.status & BME680_GASM_VALID_MSK) { + inputs[num_inputs].sensor_id = BSEC_INPUT_GASRESISTOR; + inputs[num_inputs].signal = data.gas_resistance; + inputs[num_inputs].time_stamp = trigger_time_ns; + num_inputs++; + } else { + ESP_LOGD(TAG, "BME680 did not report gas data"); + } } if (num_inputs < 1) { ESP_LOGD(TAG, "No signal inputs available for BSEC"); diff --git a/esphome/components/bme680_bsec/bme680_bsec.h b/esphome/components/bme680_bsec/bme680_bsec.h index 4a71e1d23b..73994b7541 100644 --- a/esphome/components/bme680_bsec/bme680_bsec.h +++ b/esphome/components/bme680_bsec/bme680_bsec.h @@ -1,5 +1,3 @@ - - #pragma once #include "esphome/core/component.h" @@ -9,13 +7,13 @@ #include "esphome/core/preferences.h" #include -#ifdef USING_BSEC +#ifdef USE_BSEC #include #endif namespace esphome { namespace bme680_bsec { -#ifdef USING_BSEC +#ifdef USE_BSEC enum IAQMode { IAQ_MODE_STATIC = 0, @@ -25,32 +23,31 @@ enum IAQMode { enum SampleRate { SAMPLE_RATE_LP = 0, SAMPLE_RATE_ULP = 1, + SAMPLE_RATE_DEFAULT = 2, }; +#define BME680_BSEC_SAMPLE_RATE_LOG(r) (r == SAMPLE_RATE_DEFAULT ? "Default" : (r == SAMPLE_RATE_ULP ? "ULP" : "LP")) + class BME680BSECComponent : public Component, public i2c::I2CDevice { public: void set_temperature_offset(float offset) { this->temperature_offset_ = offset; } void set_iaq_mode(IAQMode iaq_mode) { this->iaq_mode_ = iaq_mode; } - void set_sample_rate(SampleRate sample_rate) { this->sample_rate_ = sample_rate; } void set_state_save_interval(uint32_t interval) { this->state_save_interval_ms_ = interval; } - void set_temperature_sensor(sensor::Sensor *temperature_sensor) { temperature_sensor_ = temperature_sensor; } - void set_pressure_sensor(sensor::Sensor *pressure_sensor) { pressure_sensor_ = pressure_sensor; } - void set_humidity_sensor(sensor::Sensor *humidity_sensor) { humidity_sensor_ = humidity_sensor; } - void set_gas_resistance_sensor(sensor::Sensor *gas_resistance_sensor) { - gas_resistance_sensor_ = gas_resistance_sensor; - } - void set_iaq_sensor(sensor::Sensor *iaq_sensor) { iaq_sensor_ = iaq_sensor; } - void set_iaq_accuracy_text_sensor(text_sensor::TextSensor *iaq_accuracy_text_sensor) { - iaq_accuracy_text_sensor_ = iaq_accuracy_text_sensor; - } - void set_iaq_accuracy_sensor(sensor::Sensor *iaq_accuracy_sensor) { iaq_accuracy_sensor_ = iaq_accuracy_sensor; } - void set_co2_equivalent_sensor(sensor::Sensor *co2_equivalent_sensor) { - co2_equivalent_sensor_ = co2_equivalent_sensor; - } - void set_breath_voc_equivalent_sensor(sensor::Sensor *breath_voc_equivalent_sensor) { - breath_voc_equivalent_sensor_ = breath_voc_equivalent_sensor; - } + void set_sample_rate(SampleRate sample_rate) { this->sample_rate_ = sample_rate; } + void set_temperature_sample_rate(SampleRate sample_rate) { this->temperature_sample_rate_ = sample_rate; } + void set_pressure_sample_rate(SampleRate sample_rate) { this->pressure_sample_rate_ = sample_rate; } + void set_humidity_sample_rate(SampleRate sample_rate) { this->humidity_sample_rate_ = sample_rate; } + + void set_temperature_sensor(sensor::Sensor *sensor) { this->temperature_sensor_ = sensor; } + void set_pressure_sensor(sensor::Sensor *sensor) { this->pressure_sensor_ = sensor; } + void set_humidity_sensor(sensor::Sensor *sensor) { this->humidity_sensor_ = sensor; } + void set_gas_resistance_sensor(sensor::Sensor *sensor) { this->gas_resistance_sensor_ = sensor; } + void set_iaq_sensor(sensor::Sensor *sensor) { this->iaq_sensor_ = sensor; } + void set_iaq_accuracy_text_sensor(text_sensor::TextSensor *sensor) { this->iaq_accuracy_text_sensor_ = sensor; } + void set_iaq_accuracy_sensor(sensor::Sensor *sensor) { this->iaq_accuracy_sensor_ = sensor; } + void set_co2_equivalent_sensor(sensor::Sensor *sensor) { this->co2_equivalent_sensor_ = sensor; } + void set_breath_voc_equivalent_sensor(sensor::Sensor *sensor) { this->breath_voc_equivalent_sensor_ = sensor; } static BME680BSECComponent *instance; static int8_t read_bytes_wrapper(uint8_t address, uint8_t a_register, uint8_t *data, uint16_t len); @@ -64,10 +61,11 @@ class BME680BSECComponent : public Component, public i2c::I2CDevice { protected: void set_config_(const uint8_t *config); - void update_subscription_(float sample_rate); + float calc_sensor_sample_rate_(SampleRate sample_rate); + void update_subscription_(); void run_(); - void read_(bsec_bme_settings_t bme680_settings); + void read_(int64_t trigger_time_ns, bsec_bme_settings_t bme680_settings); void publish_(const bsec_output_t *outputs, uint8_t num_outputs); int64_t get_time_ns_(); @@ -91,7 +89,11 @@ class BME680BSECComponent : public Component, public i2c::I2CDevice { float temperature_offset_{0}; IAQMode iaq_mode_{IAQ_MODE_STATIC}; - SampleRate sample_rate_{SAMPLE_RATE_LP}; + + SampleRate sample_rate_{SAMPLE_RATE_LP}; // Core/gas sample rate + SampleRate temperature_sample_rate_{SAMPLE_RATE_DEFAULT}; + SampleRate pressure_sample_rate_{SAMPLE_RATE_DEFAULT}; + SampleRate humidity_sample_rate_{SAMPLE_RATE_DEFAULT}; sensor::Sensor *temperature_sensor_; sensor::Sensor *pressure_sensor_; diff --git a/esphome/components/bme680_bsec/sensor.py b/esphome/components/bme680_bsec/sensor.py index b27b267c11..b5f0ce190d 100644 --- a/esphome/components/bme680_bsec/sensor.py +++ b/esphome/components/bme680_bsec/sensor.py @@ -22,7 +22,12 @@ from esphome.const import ( ICON_WATER_PERCENT, ) from esphome.core import coroutine -from . import BME680BSECComponent, CONF_BME680_BSEC_ID +from . import ( + BME680BSECComponent, + CONF_BME680_BSEC_ID, + CONF_SAMPLE_RATE, + SAMPLE_RATE_OPTIONS, +) DEPENDENCIES = ["bme680_bsec"] @@ -34,28 +39,34 @@ UNIT_IAQ = "IAQ" ICON_ACCURACY = "mdi:checkbox-marked-circle-outline" ICON_TEST_TUBE = "mdi:test-tube" -TYPES = { - CONF_TEMPERATURE: "set_temperature_sensor", - CONF_PRESSURE: "set_pressure_sensor", - CONF_HUMIDITY: "set_humidity_sensor", - CONF_GAS_RESISTANCE: "set_gas_resistance_sensor", - CONF_IAQ: "set_iaq_sensor", - CONF_IAQ_ACCURACY: "set_iaq_accuracy_sensor", - CONF_CO2_EQUIVALENT: "set_co2_equivalent_sensor", - CONF_BREATH_VOC_EQUIVALENT: "set_breath_voc_equivalent_sensor", -} +TYPES = [ + CONF_TEMPERATURE, + CONF_PRESSURE, + CONF_HUMIDITY, + CONF_GAS_RESISTANCE, + CONF_IAQ, + CONF_IAQ_ACCURACY, + CONF_CO2_EQUIVALENT, + CONF_BREATH_VOC_EQUIVALENT, +] CONFIG_SCHEMA = cv.Schema( { cv.GenerateID(CONF_BME680_BSEC_ID): cv.use_id(BME680BSECComponent), cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( UNIT_CELSIUS, ICON_THERMOMETER, 1, DEVICE_CLASS_TEMPERATURE + ).extend( + {cv.Optional(CONF_SAMPLE_RATE): cv.enum(SAMPLE_RATE_OPTIONS, upper=True)} ), cv.Optional(CONF_PRESSURE): sensor.sensor_schema( UNIT_HECTOPASCAL, ICON_GAUGE, 1, DEVICE_CLASS_PRESSURE + ).extend( + {cv.Optional(CONF_SAMPLE_RATE): cv.enum(SAMPLE_RATE_OPTIONS, upper=True)} ), cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( UNIT_PERCENT, ICON_WATER_PERCENT, 1, DEVICE_CLASS_HUMIDITY + ).extend( + {cv.Optional(CONF_SAMPLE_RATE): cv.enum(SAMPLE_RATE_OPTIONS, upper=True)} ), cv.Optional(CONF_GAS_RESISTANCE): sensor.sensor_schema( UNIT_OHM, ICON_GAS_CYLINDER, 0, DEVICE_CLASS_EMPTY @@ -77,15 +88,16 @@ CONFIG_SCHEMA = cv.Schema( @coroutine -def setup_conf(config, key, hub, funcName): +def setup_conf(config, key, hub): if key in config: conf = config[key] - var = yield sensor.new_sensor(conf) - func = getattr(hub, funcName) - cg.add(func(var)) + sens = yield sensor.new_sensor(conf) + cg.add(getattr(hub, f"set_{key}_sensor")(sens)) + if CONF_SAMPLE_RATE in conf: + cg.add(getattr(hub, f"set_{key}_sample_rate")(conf[CONF_SAMPLE_RATE])) def to_code(config): hub = yield cg.get_variable(config[CONF_BME680_BSEC_ID]) - for key, funcName in TYPES.items(): - yield setup_conf(config, key, hub, funcName) + for key in TYPES: + yield setup_conf(config, key, hub) diff --git a/esphome/components/bme680_bsec/text_sensor.py b/esphome/components/bme680_bsec/text_sensor.py index 992e2989c9..bd90a419f5 100644 --- a/esphome/components/bme680_bsec/text_sensor.py +++ b/esphome/components/bme680_bsec/text_sensor.py @@ -10,7 +10,7 @@ DEPENDENCIES = ["bme680_bsec"] CONF_IAQ_ACCURACY = "iaq_accuracy" ICON_ACCURACY = "mdi:checkbox-marked-circle-outline" -TYPES = {CONF_IAQ_ACCURACY: "set_iaq_accuracy_text_sensor"} +TYPES = [CONF_IAQ_ACCURACY] CONFIG_SCHEMA = cv.Schema( { @@ -26,16 +26,15 @@ CONFIG_SCHEMA = cv.Schema( @coroutine -def setup_conf(config, key, hub, funcName): +def setup_conf(config, key, hub): if key in config: conf = config[key] - var = cg.new_Pvariable(conf[CONF_ID]) - yield text_sensor.register_text_sensor(var, conf) - func = getattr(hub, funcName) - cg.add(func(var)) + sens = cg.new_Pvariable(conf[CONF_ID]) + yield text_sensor.register_text_sensor(sens, conf) + cg.add(getattr(hub, f"set_{key}_text_sensor")(sens)) def to_code(config): hub = yield cg.get_variable(config[CONF_BME680_BSEC_ID]) - for key, funcName in TYPES.items(): - yield setup_conf(config, key, hub, funcName) + for key in TYPES: + yield setup_conf(config, key, hub) From 072dce340e3c0bb5da92be111e6676aaf8c33052 Mon Sep 17 00:00:00 2001 From: Stanislav Meduna Date: Sun, 23 May 2021 22:56:04 +0200 Subject: [PATCH 055/104] Add the on_page_change display trigger (#1687) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/display/__init__.py | 34 ++++++++++++++++++- esphome/components/display/display_buffer.cpp | 13 ++++++- esphome/components/display/display_buffer.h | 17 ++++++++++ tests/test1.yaml | 6 ++++ 4 files changed, 68 insertions(+), 2 deletions(-) diff --git a/esphome/components/display/__init__.py b/esphome/components/display/__init__.py index 5aed998b30..8f48acf2b7 100644 --- a/esphome/components/display/__init__.py +++ b/esphome/components/display/__init__.py @@ -2,7 +2,16 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import core, automation from esphome.automation import maybe_simple_id -from esphome.const import CONF_ID, CONF_LAMBDA, CONF_PAGES, CONF_PAGE_ID, CONF_ROTATION +from esphome.const import ( + CONF_ID, + CONF_LAMBDA, + CONF_PAGES, + CONF_PAGE_ID, + CONF_ROTATION, + CONF_FROM, + CONF_TO, + CONF_TRIGGER_ID, +) from esphome.core import coroutine_with_priority IS_PLATFORM_COMPONENT = True @@ -22,6 +31,9 @@ DisplayPageShowPrevAction = display_ns.class_( DisplayIsDisplayingPageCondition = display_ns.class_( "DisplayIsDisplayingPageCondition", automation.Condition ) +DisplayOnPageChangeTrigger = display_ns.class_("DisplayOnPageChangeTrigger") + +CONF_ON_PAGE_CHANGE = "on_page_change" DISPLAY_ROTATIONS = { 0: display_ns.DISPLAY_ROTATION_0_DEGREES, @@ -56,6 +68,15 @@ FULL_DISPLAY_SCHEMA = BASIC_DISPLAY_SCHEMA.extend( ), cv.Length(min=1), ), + cv.Optional(CONF_ON_PAGE_CHANGE): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id( + DisplayOnPageChangeTrigger + ), + cv.Optional(CONF_FROM): cv.use_id(DisplayPage), + cv.Optional(CONF_TO): cv.use_id(DisplayPage), + } + ), } ) @@ -72,6 +93,17 @@ async def setup_display_core_(var, config): page = cg.new_Pvariable(conf[CONF_ID], lambda_) pages.append(page) cg.add(var.set_pages(pages)) + for conf in config.get(CONF_ON_PAGE_CHANGE, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + if CONF_FROM in conf: + page = await cg.get_variable(conf[CONF_FROM]) + cg.add(trigger.set_from(page)) + if CONF_TO in conf: + page = await cg.get_variable(conf[CONF_TO]) + cg.add(trigger.set_to(page)) + await automation.build_automation( + trigger, [(DisplayPagePtr, "from"), (DisplayPagePtr, "to")], conf + ) async def register_display(var, config): diff --git a/esphome/components/display/display_buffer.cpp b/esphome/components/display/display_buffer.cpp index c66f87a7aa..23f6faccb1 100644 --- a/esphome/components/display/display_buffer.cpp +++ b/esphome/components/display/display_buffer.cpp @@ -315,7 +315,14 @@ void DisplayBuffer::set_pages(std::vector pages) { pages[pages.size() - 1]->set_next(pages[0]); this->show_page(pages[0]); } -void DisplayBuffer::show_page(DisplayPage *page) { this->page_ = page; } +void DisplayBuffer::show_page(DisplayPage *page) { + this->previous_page_ = this->page_; + this->page_ = page; + if (this->previous_page_ != this->page_) { + for (auto *t : on_page_change_triggers_) + t->process(this->previous_page_, this->page_); + } +} void DisplayBuffer::show_next_page() { this->page_->show_next(); } void DisplayBuffer::show_prev_page() { this->page_->show_prev(); } void DisplayBuffer::do_update_() { @@ -326,6 +333,10 @@ void DisplayBuffer::do_update_() { (*this->writer_)(*this); } } +void DisplayOnPageChangeTrigger::process(DisplayPage *from, DisplayPage *to) { + if ((this->from_ == nullptr || this->from_ == from) && (this->to_ == nullptr || this->to_ == to)) + this->trigger(from, to); +} #ifdef USE_TIME void DisplayBuffer::strftime(int x, int y, Font *font, Color color, TextAlign align, const char *format, time::ESPTime time) { diff --git a/esphome/components/display/display_buffer.h b/esphome/components/display/display_buffer.h index 42e3c5871f..0763262d4c 100644 --- a/esphome/components/display/display_buffer.h +++ b/esphome/components/display/display_buffer.h @@ -81,6 +81,7 @@ class Font; class Image; class DisplayBuffer; class DisplayPage; +class DisplayOnPageChangeTrigger; using display_writer_t = std::function; @@ -298,6 +299,8 @@ class DisplayBuffer { const DisplayPage *get_active_page() const { return this->page_; } + void add_on_page_change_trigger(DisplayOnPageChangeTrigger *t) { this->on_page_change_triggers_.push_back(t); } + /// Internal method to set the display rotation with. void set_rotation(DisplayRotation rotation); @@ -318,6 +321,8 @@ class DisplayBuffer { DisplayRotation rotation_{DISPLAY_ROTATION_0_DEGREES}; optional writer_{}; DisplayPage *page_{nullptr}; + DisplayPage *previous_page_{nullptr}; + std::vector on_page_change_triggers_; }; class DisplayPage { @@ -465,5 +470,17 @@ template class DisplayIsDisplayingPageCondition : public Conditi DisplayPage *page_; }; +class DisplayOnPageChangeTrigger : public Trigger { + public: + explicit DisplayOnPageChangeTrigger(DisplayBuffer *parent) { parent->add_on_page_change_trigger(this); } + void process(DisplayPage *from, DisplayPage *to); + void set_from(DisplayPage *p) { this->from_ = p; } + void set_to(DisplayPage *p) { this->to_ = p; } + + protected: + DisplayPage *from_{nullptr}; + DisplayPage *to_{nullptr}; +}; + } // namespace display } // namespace esphome diff --git a/tests/test1.yaml b/tests/test1.yaml index a8633a7067..6f87166490 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -1874,6 +1874,12 @@ display: - id: page2 lambda: |- // Nothing + on_page_change: + from: page1 + to: page2 + then: + lambda: |- + ESP_LOGD("display", "1 -> 2"); - platform: ssd1306_spi model: 'SSD1306 128x64' cs_pin: GPIO23 From b11d5f6799b04585bfe28f35f8eda8e174a90e00 Mon Sep 17 00:00:00 2001 From: Jim Bauwens Date: Sun, 23 May 2021 22:57:48 +0200 Subject: [PATCH 056/104] Allow segments in a light partition to be reversed (#1484) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/partition/light.py | 15 +++++++++++++-- esphome/components/partition/light_partition.h | 16 +++++++++++++--- esphome/const.py | 1 + 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/esphome/components/partition/light.py b/esphome/components/partition/light.py index 202481b936..c366aea033 100644 --- a/esphome/components/partition/light.py +++ b/esphome/components/partition/light.py @@ -1,7 +1,14 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import light -from esphome.const import CONF_FROM, CONF_ID, CONF_SEGMENTS, CONF_TO, CONF_OUTPUT_ID +from esphome.const import ( + CONF_FROM, + CONF_ID, + CONF_SEGMENTS, + CONF_TO, + CONF_OUTPUT_ID, + CONF_REVERSED, +) partitions_ns = cg.esphome_ns.namespace("partition") AddressableSegment = partitions_ns.class_("AddressableSegment") @@ -28,6 +35,7 @@ CONFIG_SCHEMA = light.ADDRESSABLE_LIGHT_SCHEMA.extend( cv.Required(CONF_ID): cv.use_id(light.AddressableLightState), cv.Required(CONF_FROM): cv.positive_int, cv.Required(CONF_TO): cv.positive_int, + cv.Optional(CONF_REVERSED, default=False): cv.boolean, }, validate_from_to, ), @@ -43,7 +51,10 @@ def to_code(config): var = yield cg.get_variable(conf[CONF_ID]) segments.append( AddressableSegment( - var, conf[CONF_FROM], conf[CONF_TO] - conf[CONF_FROM] + 1 + var, + conf[CONF_FROM], + conf[CONF_TO] - conf[CONF_FROM] + 1, + conf[CONF_REVERSED], ) ) diff --git a/esphome/components/partition/light_partition.h b/esphome/components/partition/light_partition.h index 8085c43720..11589ee539 100644 --- a/esphome/components/partition/light_partition.h +++ b/esphome/components/partition/light_partition.h @@ -8,20 +8,25 @@ namespace partition { class AddressableSegment { public: - AddressableSegment(light::LightState *src, int32_t src_offset, int32_t size) - : src_(static_cast(src->get_output())), src_offset_(src_offset), size_(size) {} + AddressableSegment(light::LightState *src, int32_t src_offset, int32_t size, bool reversed) + : src_(static_cast(src->get_output())), + src_offset_(src_offset), + size_(size), + reversed_(reversed) {} light::AddressableLight *get_src() const { return this->src_; } int32_t get_src_offset() const { return this->src_offset_; } int32_t get_size() const { return this->size_; } int32_t get_dst_offset() const { return this->dst_offset_; } void set_dst_offset(int32_t dst_offset) { this->dst_offset_ = dst_offset; } + bool is_reversed() const { return this->reversed_; } protected: light::AddressableLight *src_; int32_t src_offset_; int32_t size_; int32_t dst_offset_; + bool reversed_; }; class PartitionLightOutput : public light::AddressableLight { @@ -72,7 +77,12 @@ class PartitionLightOutput : public light::AddressableLight { // offset within the segment int32_t seg_off = index - seg.get_dst_offset(); // offset within the src - int32_t src_off = seg.get_src_offset() + seg_off; + int32_t src_off; + if (seg.is_reversed()) + src_off = seg.get_src_offset() + seg.get_size() - seg_off - 1; + else + src_off = seg.get_src_offset() + seg_off; + auto view = (*seg.get_src())[src_off]; view.raw_set_color_correction(&this->correction_); return view; diff --git a/esphome/const.py b/esphome/const.py index a70fefa648..e93d2b7d25 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -471,6 +471,7 @@ CONF_RESTORE_STATE = "restore_state" CONF_RESTORE_VALUE = "restore_value" CONF_RETAIN = "retain" CONF_REVERSE_ACTIVE_ENERGY = "reverse_active_energy" +CONF_REVERSED = "reversed" CONF_RGB_ORDER = "rgb_order" CONF_RGBW = "rgbw" CONF_RISING_EDGE = "rising_edge" From b92702a312e8409d29e5224b5271fc8e82eee3c4 Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Sun, 23 May 2021 23:24:00 +0200 Subject: [PATCH 057/104] Document considerations when changing recommended framework version (#1822) --- esphome/core/config.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/esphome/core/config.py b/esphome/core/config.py index 6bd8c6be0e..c6404fc6de 100644 --- a/esphome/core/config.py +++ b/esphome/core/config.py @@ -69,6 +69,13 @@ validate_platform = cv.one_of(*ESP_PLATFORMS, upper=True) PLATFORMIO_ESP8266_LUT = { **ARDUINO_VERSION_ESP8266, + # Keep this in mind when updating the recommended version: + # * New framework historically have had some regressions, especially for WiFi, BLE and the + # bootloader system. The new version needs to be thoroughly validated before changing the + # recommended version as otherwise a bunch of devices could be bricked + # * The docker images need to be updated to ship the new recommended version, in order not + # to DDoS platformio servers. + # Update this file: https://github.com/esphome/esphome-docker-base/blob/master/platformio.ini "RECOMMENDED": ARDUINO_VERSION_ESP8266["2.7.4"], "LATEST": "espressif8266", "DEV": ARDUINO_VERSION_ESP8266["dev"], @@ -76,6 +83,7 @@ PLATFORMIO_ESP8266_LUT = { PLATFORMIO_ESP32_LUT = { **ARDUINO_VERSION_ESP32, + # See PLATFORMIO_ESP8266_LUT for considerations when changing the recommended version "RECOMMENDED": ARDUINO_VERSION_ESP32["1.0.6"], "LATEST": "espressif32", "DEV": ARDUINO_VERSION_ESP32["dev"], From 2376a2c941002c2d5eef1bc487f7f589348e4932 Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Mon, 24 May 2021 10:58:29 +0200 Subject: [PATCH 058/104] Convert components to async-def syntax (#1821) --- esphome/components/a4988/stepper.py | 12 +- esphome/components/ac_dimmer/output.py | 10 +- esphome/components/adc/sensor.py | 6 +- .../components/addressable_light/display.py | 12 +- esphome/components/ade7953/sensor.py | 8 +- esphome/components/ads1115/__init__.py | 6 +- esphome/components/ads1115/sensor.py | 8 +- esphome/components/aht10/sensor.py | 10 +- esphome/components/am2320/sensor.py | 10 +- esphome/components/animation/__init__.py | 2 +- esphome/components/apds9960/__init__.py | 6 +- esphome/components/apds9960/binary_sensor.py | 6 +- esphome/components/apds9960/sensor.py | 6 +- esphome/components/as3935/binary_sensor.py | 6 +- esphome/components/as3935/sensor.py | 8 +- esphome/components/as3935_i2c/__init__.py | 6 +- esphome/components/as3935_spi/__init__.py | 6 +- .../components/atc_mithermometer/sensor.py | 14 +- esphome/components/atm90e32/sensor.py | 24 +-- esphome/components/b_parasite/sensor.py | 8 +- esphome/components/bang_bang/climate.py | 14 +- esphome/components/bh1750/sensor.py | 8 +- esphome/components/binary/fan/__init__.py | 12 +- esphome/components/binary/light/__init__.py | 6 +- .../components/binary_sensor_map/sensor.py | 8 +- esphome/components/ble_client/__init__.py | 10 +- .../components/ble_client/sensor/__init__.py | 12 +- .../components/ble_client/switch/__init__.py | 8 +- .../components/ble_presence/binary_sensor.py | 8 +- esphome/components/ble_rssi/sensor.py | 8 +- esphome/components/ble_scanner/text_sensor.py | 8 +- esphome/components/bme280/sensor.py | 12 +- esphome/components/bme680/sensor.py | 14 +- esphome/components/bme680_bsec/__init__.py | 6 +- esphome/components/bme680_bsec/sensor.py | 6 +- esphome/components/bme680_bsec/text_sensor.py | 6 +- esphome/components/bmp085/sensor.py | 10 +- esphome/components/bmp280/sensor.py | 10 +- esphome/components/ccs811/sensor.py | 14 +- esphome/components/climate_ir_lg/climate.py | 4 +- esphome/components/color/__init__.py | 2 +- esphome/components/coolix/climate.py | 4 +- esphome/components/cse7766/sensor.py | 12 +- esphome/components/ct_clamp/sensor.py | 8 +- .../custom/binary_sensor/__init__.py | 6 +- esphome/components/custom/climate/__init__.py | 6 +- esphome/components/custom/cover/__init__.py | 6 +- esphome/components/custom/light/__init__.py | 6 +- esphome/components/custom/output/__init__.py | 6 +- esphome/components/custom/sensor/__init__.py | 6 +- esphome/components/custom/switch/__init__.py | 6 +- .../components/custom/text_sensor/__init__.py | 6 +- .../components/custom_component/__init__.py | 6 +- esphome/components/cwww/light.py | 8 +- esphome/components/daikin/climate.py | 4 +- esphome/components/dallas/__init__.py | 6 +- esphome/components/dallas/sensor.py | 6 +- esphome/components/debug/__init__.py | 4 +- esphome/components/deep_sleep/__init__.py | 6 +- esphome/components/dfplayer/__init__.py | 8 +- esphome/components/dht/sensor.py | 10 +- esphome/components/dht12/sensor.py | 10 +- esphome/components/ds1307/time.py | 8 +- esphome/components/duty_cycle/sensor.py | 8 +- esphome/components/e131/__init__.py | 4 +- esphome/components/endstop/cover.py | 16 +- .../components/esp32_ble_beacon/__init__.py | 4 +- .../components/esp32_ble_tracker/__init__.py | 10 +- esphome/components/esp32_camera/__init__.py | 4 +- esphome/components/esp32_dac/output.py | 8 +- esphome/components/esp32_hall/sensor.py | 6 +- esphome/components/esp32_touch/__init__.py | 4 +- .../components/esp32_touch/binary_sensor.py | 6 +- esphome/components/esp8266_pwm/output.py | 8 +- esphome/components/ethernet/__init__.py | 6 +- .../exposure_notifications/__init__.py | 6 +- .../external_components/__init__.py | 2 +- esphome/components/ezo/sensor.py | 8 +- esphome/components/fastled_clockless/light.py | 4 +- esphome/components/fastled_spi/light.py | 4 +- .../components/fingerprint_grow/__init__.py | 18 +- .../fingerprint_grow/binary_sensor.py | 6 +- esphome/components/fingerprint_grow/sensor.py | 6 +- esphome/components/font/__init__.py | 2 +- esphome/components/fujitsu_general/climate.py | 4 +- .../components/gpio/binary_sensor/__init__.py | 8 +- esphome/components/gpio/output/__init__.py | 8 +- esphome/components/gpio/switch/__init__.py | 10 +- esphome/components/gps/__init__.py | 18 +- esphome/components/gps/time/__init__.py | 8 +- esphome/components/hbridge/light.py | 10 +- esphome/components/hdc1080/sensor.py | 10 +- esphome/components/hitachi_ac344/climate.py | 4 +- esphome/components/hlw8012/sensor.py | 18 +- esphome/components/hm3301/sensor.py | 14 +- esphome/components/hmc5883l/sensor.py | 14 +- .../homeassistant/binary_sensor/__init__.py | 6 +- .../homeassistant/sensor/__init__.py | 6 +- .../homeassistant/text_sensor/__init__.py | 6 +- .../components/homeassistant/time/__init__.py | 6 +- esphome/components/http_request/__init__.py | 4 +- esphome/components/htu21d/sensor.py | 10 +- esphome/components/hx711/sensor.py | 10 +- esphome/components/ili9341/display.py | 16 +- esphome/components/image/__init__.py | 2 +- esphome/components/ina219/sensor.py | 14 +- esphome/components/ina226/sensor.py | 14 +- esphome/components/ina3221/sensor.py | 14 +- .../components/inkbird_ibsth1_mini/sensor.py | 12 +- esphome/components/inkplate6/display.py | 48 ++--- esphome/components/integration/sensor.py | 8 +- esphome/components/interval/__init__.py | 6 +- esphome/components/lcd_gpio/display.py | 14 +- esphome/components/lcd_pcf8574/display.py | 8 +- esphome/components/ledc/output.py | 8 +- esphome/components/max31855/sensor.py | 10 +- esphome/components/max31856/sensor.py | 8 +- esphome/components/max31865/sensor.py | 8 +- esphome/components/max6675/sensor.py | 8 +- esphome/components/max7219/display.py | 10 +- esphome/components/max7219digit/display.py | 10 +- esphome/components/mcp23008/__init__.py | 6 +- esphome/components/mcp23016/__init__.py | 6 +- esphome/components/mcp23017/__init__.py | 6 +- esphome/components/mcp23s08/__init__.py | 6 +- esphome/components/mcp23s17/__init__.py | 6 +- esphome/components/mcp2515/canbus.py | 6 +- esphome/components/mcp3008/__init__.py | 6 +- esphome/components/mcp3008/sensor.py | 8 +- esphome/components/mcp4725/output.py | 8 +- esphome/components/mcp9808/sensor.py | 8 +- esphome/components/mhz19/sensor.py | 10 +- esphome/components/midea_ac/climate.py | 14 +- esphome/components/midea_dongle/__init__.py | 6 +- esphome/components/mitsubishi/climate.py | 4 +- esphome/components/modbus/__init__.py | 6 +- esphome/components/monochromatic/light.py | 6 +- esphome/components/mpr121/__init__.py | 6 +- esphome/components/mpr121/binary_sensor.py | 6 +- esphome/components/mpu6050/sensor.py | 12 +- .../mqtt_subscribe/sensor/__init__.py | 8 +- .../mqtt_subscribe/text_sensor/__init__.py | 8 +- esphome/components/ms5611/sensor.py | 10 +- esphome/components/my9231/__init__.py | 8 +- esphome/components/my9231/output.py | 6 +- esphome/components/neopixelbus/light.py | 6 +- esphome/components/nextion/binary_sensor.py | 6 +- esphome/components/nextion/display.py | 10 +- esphome/components/ntc/sensor.py | 8 +- esphome/components/output/__init__.py | 2 +- esphome/components/output/switch/__init__.py | 8 +- esphome/components/partition/light.py | 8 +- esphome/components/pca9685/__init__.py | 6 +- esphome/components/pca9685/output.py | 6 +- esphome/components/pcd8544/display.py | 14 +- esphome/components/pcf8574/__init__.py | 6 +- esphome/components/pid/climate.py | 12 +- esphome/components/pid/sensor/__init__.py | 8 +- esphome/components/pmsx003/sensor.py | 18 +- esphome/components/pn532/binary_sensor.py | 6 +- esphome/components/pn532_i2c/__init__.py | 6 +- esphome/components/pn532_spi/__init__.py | 6 +- esphome/components/power_supply/__init__.py | 6 +- esphome/components/prometheus/__init__.py | 6 +- esphome/components/pulse_counter/sensor.py | 10 +- esphome/components/pulse_meter/sensor.py | 10 +- esphome/components/pulse_width/sensor.py | 8 +- esphome/components/pzem004t/sensor.py | 14 +- esphome/components/pzemac/sensor.py | 18 +- esphome/components/pzemdc/sensor.py | 12 +- esphome/components/qmc5883l/sensor.py | 14 +- esphome/components/rc522/binary_sensor.py | 9 +- esphome/components/rc522_i2c/__init__.py | 6 +- esphome/components/rc522_spi/__init__.py | 6 +- esphome/components/rc522_spi/binary_sensor.py | 4 +- esphome/components/rdm6300/__init__.py | 8 +- esphome/components/rdm6300/binary_sensor.py | 6 +- .../components/remote_receiver/__init__.py | 10 +- .../remote_receiver/binary_sensor.py | 6 +- .../components/remote_transmitter/__init__.py | 6 +- esphome/components/resistance/sensor.py | 8 +- esphome/components/restart/switch.py | 6 +- esphome/components/rf_bridge/__init__.py | 10 +- esphome/components/rgb/light.py | 10 +- esphome/components/rgbw/light.py | 12 +- esphome/components/rgbww/light.py | 14 +- esphome/components/rotary_encoder/sensor.py | 16 +- esphome/components/rtttl/__init__.py | 8 +- esphome/components/ruuvi_ble/__init__.py | 4 +- esphome/components/ruuvitag/sensor.py | 28 +-- esphome/components/scd30/sensor.py | 12 +- esphome/components/script/__init__.py | 6 +- esphome/components/sds011/sensor.py | 10 +- esphome/components/senseair/sensor.py | 8 +- esphome/components/servo/__init__.py | 6 +- esphome/components/sgp30/sensor.py | 14 +- esphome/components/sgp40/sensor.py | 12 +- esphome/components/sht3xd/sensor.py | 10 +- esphome/components/sht4x/sensor.py | 8 +- esphome/components/shtcx/sensor.py | 10 +- esphome/components/shutdown/switch.py | 6 +- esphome/components/sim800l/__init__.py | 8 +- esphome/components/slow_pwm/output.py | 8 +- esphome/components/sm16716/__init__.py | 8 +- esphome/components/sm16716/output.py | 6 +- esphome/components/sm2135/__init__.py | 8 +- esphome/components/sm2135/output.py | 6 +- esphome/components/sm300d2/sensor.py | 20 +- esphome/components/sn74hc595/__init__.py | 12 +- esphome/components/sntp/time.py | 6 +- esphome/components/speed/fan/__init__.py | 12 +- esphome/components/sps30/sensor.py | 26 +-- esphome/components/ssd1306_i2c/display.py | 6 +- esphome/components/ssd1306_spi/display.py | 8 +- esphome/components/ssd1322_spi/display.py | 8 +- esphome/components/ssd1325_spi/display.py | 8 +- esphome/components/ssd1327_i2c/display.py | 6 +- esphome/components/ssd1327_spi/display.py | 8 +- esphome/components/ssd1331_spi/display.py | 8 +- esphome/components/ssd1351_spi/display.py | 8 +- esphome/components/st7735/display.py | 200 +++++++++--------- esphome/components/st7789v/display.py | 16 +- esphome/components/status/binary_sensor.py | 6 +- esphome/components/stepper/__init__.py | 2 +- esphome/components/sts3x/sensor.py | 8 +- esphome/components/substitutions/__init__.py | 2 +- esphome/components/sun/__init__.py | 16 +- esphome/components/sun/sensor/__init__.py | 8 +- .../components/sun/text_sensor/__init__.py | 8 +- esphome/components/sx1509/__init__.py | 6 +- .../sx1509/binary_sensor/__init__.py | 6 +- esphome/components/sx1509/output/__init__.py | 8 +- esphome/components/tca9548a/__init__.py | 6 +- esphome/components/tcl112/climate.py | 4 +- esphome/components/tcs34725/sensor.py | 18 +- esphome/components/teleinfo/sensor.py | 8 +- .../template/binary_sensor/__init__.py | 8 +- esphome/components/template/cover/__init__.py | 20 +- .../components/template/output/__init__.py | 8 +- .../components/template/sensor/__init__.py | 8 +- .../components/template/switch/__init__.py | 12 +- .../template/text_sensor/__init__.py | 8 +- esphome/components/thermostat/climate.py | 56 ++--- esphome/components/time_based/cover.py | 12 +- esphome/components/tlc59208f/__init__.py | 6 +- esphome/components/tlc59208f/output.py | 6 +- esphome/components/tm1637/display.py | 12 +- esphome/components/tm1651/__init__.py | 8 +- esphome/components/tmp102/sensor.py | 8 +- esphome/components/tmp117/sensor.py | 8 +- esphome/components/tof10120/sensor.py | 8 +- esphome/components/toshiba/climate.py | 4 +- .../components/total_daily_energy/sensor.py | 10 +- esphome/components/tsl2561/sensor.py | 8 +- esphome/components/ttp229_bsf/__init__.py | 8 +- .../components/ttp229_bsf/binary_sensor.py | 6 +- esphome/components/ttp229_lsf/__init__.py | 6 +- .../components/ttp229_lsf/binary_sensor.py | 6 +- esphome/components/tuya/__init__.py | 8 +- .../components/tuya/binary_sensor/__init__.py | 8 +- esphome/components/tuya/climate/__init__.py | 8 +- esphome/components/tuya/fan/__init__.py | 8 +- esphome/components/tuya/light/__init__.py | 8 +- esphome/components/tuya/sensor/__init__.py | 8 +- esphome/components/tuya/switch/__init__.py | 8 +- esphome/components/tx20/sensor.py | 10 +- esphome/components/uart/switch/__init__.py | 8 +- esphome/components/uln2003/stepper.py | 14 +- esphome/components/ultrasonic/sensor.py | 10 +- esphome/components/uptime/sensor.py | 6 +- esphome/components/version/text_sensor.py | 6 +- esphome/components/vl53l0x/sensor.py | 10 +- .../components/waveshare_epaper/display.py | 16 +- esphome/components/whirlpool/climate.py | 4 +- esphome/components/wifi_info/text_sensor.py | 10 +- esphome/components/wifi_signal/sensor.py | 6 +- esphome/components/xiaomi_ble/__init__.py | 4 +- esphome/components/xiaomi_cgd1/sensor.py | 12 +- esphome/components/xiaomi_cgg1/sensor.py | 12 +- esphome/components/xiaomi_gcls002/sensor.py | 14 +- esphome/components/xiaomi_hhccjcy01/sensor.py | 16 +- .../components/xiaomi_hhccpot002/sensor.py | 10 +- esphome/components/xiaomi_jqjcy01ym/sensor.py | 14 +- esphome/components/xiaomi_lywsd02/sensor.py | 12 +- .../components/xiaomi_lywsd03mmc/sensor.py | 12 +- esphome/components/xiaomi_lywsdcgq/sensor.py | 12 +- esphome/components/xiaomi_mhoc401/sensor.py | 12 +- esphome/components/xiaomi_miscale/sensor.py | 8 +- esphome/components/xiaomi_miscale2/sensor.py | 10 +- .../xiaomi_mjyd02yla/binary_sensor.py | 16 +- .../xiaomi_mue4094rt/binary_sensor.py | 8 +- .../components/xiaomi_wx08zm/binary_sensor.py | 12 +- esphome/components/xpt2046/__init__.py | 10 +- esphome/components/xpt2046/binary_sensor.py | 6 +- esphome/components/yashima/climate.py | 10 +- esphome/components/zyaura/sensor.py | 14 +- 296 files changed, 1423 insertions(+), 1424 deletions(-) diff --git a/esphome/components/a4988/stepper.py b/esphome/components/a4988/stepper.py index 1de3562ff7..7f53856c7b 100644 --- a/esphome/components/a4988/stepper.py +++ b/esphome/components/a4988/stepper.py @@ -18,16 +18,16 @@ CONFIG_SCHEMA = stepper.STEPPER_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield stepper.register_stepper(var, config) + await cg.register_component(var, config) + await stepper.register_stepper(var, config) - step_pin = yield cg.gpio_pin_expression(config[CONF_STEP_PIN]) + step_pin = await cg.gpio_pin_expression(config[CONF_STEP_PIN]) cg.add(var.set_step_pin(step_pin)) - dir_pin = yield cg.gpio_pin_expression(config[CONF_DIR_PIN]) + dir_pin = await cg.gpio_pin_expression(config[CONF_DIR_PIN]) cg.add(var.set_dir_pin(dir_pin)) if CONF_SLEEP_PIN in config: - sleep_pin = yield cg.gpio_pin_expression(config[CONF_SLEEP_PIN]) + sleep_pin = await cg.gpio_pin_expression(config[CONF_SLEEP_PIN]) cg.add(var.set_sleep_pin(sleep_pin)) diff --git a/esphome/components/ac_dimmer/output.py b/esphome/components/ac_dimmer/output.py index 2f06a0b6fc..2c37d325eb 100644 --- a/esphome/components/ac_dimmer/output.py +++ b/esphome/components/ac_dimmer/output.py @@ -32,18 +32,18 @@ CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) + await cg.register_component(var, config) # override default min power to 10% if CONF_MIN_POWER not in config: config[CONF_MIN_POWER] = 0.1 - yield output.register_output(var, config) + await output.register_output(var, config) - pin = yield cg.gpio_pin_expression(config[CONF_GATE_PIN]) + pin = await cg.gpio_pin_expression(config[CONF_GATE_PIN]) cg.add(var.set_gate_pin(pin)) - pin = yield cg.gpio_pin_expression(config[CONF_ZERO_CROSS_PIN]) + pin = await cg.gpio_pin_expression(config[CONF_ZERO_CROSS_PIN]) cg.add(var.set_zero_cross_pin(pin)) cg.add(var.set_init_with_half_cycle(config[CONF_INIT_WITH_HALF_CYCLE])) cg.add(var.set_method(config[CONF_METHOD])) diff --git a/esphome/components/adc/sensor.py b/esphome/components/adc/sensor.py index 2e36c6179a..f988563227 100644 --- a/esphome/components/adc/sensor.py +++ b/esphome/components/adc/sensor.py @@ -49,10 +49,10 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield sensor.register_sensor(var, config) + await cg.register_component(var, config) + await sensor.register_sensor(var, config) if config[CONF_PIN] == "VCC": cg.add_define("USE_ADC_SENSOR_VCC") diff --git a/esphome/components/addressable_light/display.py b/esphome/components/addressable_light/display.py index e5d3ca3034..0684bf8dfc 100644 --- a/esphome/components/addressable_light/display.py +++ b/esphome/components/addressable_light/display.py @@ -38,18 +38,18 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - wrapped_light = yield cg.get_variable(config[CONF_ADDRESSABLE_LIGHT_ID]) + wrapped_light = await cg.get_variable(config[CONF_ADDRESSABLE_LIGHT_ID]) cg.add(var.set_width(config[CONF_WIDTH])) cg.add(var.set_height(config[CONF_HEIGHT])) cg.add(var.set_light(wrapped_light)) - yield cg.register_component(var, config) - yield display.register_display(var, config) + await cg.register_component(var, config) + await display.register_display(var, config) if CONF_PIXEL_MAPPER in config: - pixel_mapper_template_ = yield cg.process_lambda( + pixel_mapper_template_ = await cg.process_lambda( config[CONF_PIXEL_MAPPER], [(int, "x"), (int, "y")], return_type=cg.int_, @@ -57,7 +57,7 @@ def to_code(config): cg.add(var.set_pixel_mapper(pixel_mapper_template_)) if CONF_LAMBDA in config: - lambda_ = yield cg.process_lambda( + lambda_ = await cg.process_lambda( config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void ) cg.add(var.set_writer(lambda_)) diff --git a/esphome/components/ade7953/sensor.py b/esphome/components/ade7953/sensor.py index 6bc9917806..b91e8d3bea 100644 --- a/esphome/components/ade7953/sensor.py +++ b/esphome/components/ade7953/sensor.py @@ -52,10 +52,10 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) if CONF_IRQ_PIN in config: cg.add(var.set_irq_pin(config[CONF_IRQ_PIN])) @@ -70,5 +70,5 @@ def to_code(config): if key not in config: continue conf = config[key] - sens = yield sensor.new_sensor(conf) + sens = await sensor.new_sensor(conf) cg.add(getattr(var, f"set_{key}_sensor")(sens)) diff --git a/esphome/components/ads1115/__init__.py b/esphome/components/ads1115/__init__.py index 32ab17db31..e8861a2f67 100644 --- a/esphome/components/ads1115/__init__.py +++ b/esphome/components/ads1115/__init__.py @@ -23,9 +23,9 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) cg.add(var.set_continuous_mode(config[CONF_CONTINUOUS_MODE])) diff --git a/esphome/components/ads1115/sensor.py b/esphome/components/ads1115/sensor.py index 6eb39bdd1a..4585a758b5 100644 --- a/esphome/components/ads1115/sensor.py +++ b/esphome/components/ads1115/sensor.py @@ -64,11 +64,11 @@ CONFIG_SCHEMA = ( ) -def to_code(config): - paren = yield cg.get_variable(config[CONF_ADS1115_ID]) +async def to_code(config): + paren = await cg.get_variable(config[CONF_ADS1115_ID]) var = cg.new_Pvariable(config[CONF_ID], paren) - yield sensor.register_sensor(var, config) - yield cg.register_component(var, config) + await sensor.register_sensor(var, config) + await cg.register_component(var, config) cg.add(var.set_multiplexer(config[CONF_MULTIPLEXER])) cg.add(var.set_gain(config[CONF_GAIN])) diff --git a/esphome/components/aht10/sensor.py b/esphome/components/aht10/sensor.py index e335934a8e..2e553638d1 100644 --- a/esphome/components/aht10/sensor.py +++ b/esphome/components/aht10/sensor.py @@ -34,15 +34,15 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) if CONF_TEMPERATURE in config: - sens = yield sensor.new_sensor(config[CONF_TEMPERATURE]) + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) cg.add(var.set_temperature_sensor(sens)) if CONF_HUMIDITY in config: - sens = yield sensor.new_sensor(config[CONF_HUMIDITY]) + sens = await sensor.new_sensor(config[CONF_HUMIDITY]) cg.add(var.set_humidity_sensor(sens)) diff --git a/esphome/components/am2320/sensor.py b/esphome/components/am2320/sensor.py index 6d1cc42581..c0a6a60437 100644 --- a/esphome/components/am2320/sensor.py +++ b/esphome/components/am2320/sensor.py @@ -36,15 +36,15 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) if CONF_TEMPERATURE in config: - sens = yield sensor.new_sensor(config[CONF_TEMPERATURE]) + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) cg.add(var.set_temperature_sensor(sens)) if CONF_HUMIDITY in config: - sens = yield sensor.new_sensor(config[CONF_HUMIDITY]) + sens = await sensor.new_sensor(config[CONF_HUMIDITY]) cg.add(var.set_humidity_sensor(sens)) diff --git a/esphome/components/animation/__init__.py b/esphome/components/animation/__init__.py index fbcb2b4c1f..3ae3aa94f9 100644 --- a/esphome/components/animation/__init__.py +++ b/esphome/components/animation/__init__.py @@ -34,7 +34,7 @@ CONFIG_SCHEMA = cv.All(font.validate_pillow_installed, ANIMATION_SCHEMA) CODEOWNERS = ["@syndlex"] -def to_code(config): +async def to_code(config): from PIL import Image path = CORE.relative_config_path(config[CONF_FILE]) diff --git a/esphome/components/apds9960/__init__.py b/esphome/components/apds9960/__init__.py index 9346b5ece1..8de83251b7 100644 --- a/esphome/components/apds9960/__init__.py +++ b/esphome/components/apds9960/__init__.py @@ -23,7 +23,7 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) diff --git a/esphome/components/apds9960/binary_sensor.py b/esphome/components/apds9960/binary_sensor.py index 0433061385..4a5c69f6a9 100644 --- a/esphome/components/apds9960/binary_sensor.py +++ b/esphome/components/apds9960/binary_sensor.py @@ -24,8 +24,8 @@ CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend( ) -def to_code(config): - hub = yield cg.get_variable(config[CONF_APDS9960_ID]) - var = yield binary_sensor.new_binary_sensor(config) +async def to_code(config): + hub = await cg.get_variable(config[CONF_APDS9960_ID]) + var = await binary_sensor.new_binary_sensor(config) func = getattr(hub, DIRECTIONS[config[CONF_DIRECTION]]) cg.add(func(var)) diff --git a/esphome/components/apds9960/sensor.py b/esphome/components/apds9960/sensor.py index a1ebd9b5c3..53633693a2 100644 --- a/esphome/components/apds9960/sensor.py +++ b/esphome/components/apds9960/sensor.py @@ -24,8 +24,8 @@ CONFIG_SCHEMA = sensor.sensor_schema( ) -def to_code(config): - hub = yield cg.get_variable(config[CONF_APDS9960_ID]) - var = yield sensor.new_sensor(config) +async def to_code(config): + hub = await cg.get_variable(config[CONF_APDS9960_ID]) + var = await sensor.new_sensor(config) func = getattr(hub, TYPES[config[CONF_TYPE]]) cg.add(func(var)) diff --git a/esphome/components/as3935/binary_sensor.py b/esphome/components/as3935/binary_sensor.py index 85ba052869..11b2ac812c 100644 --- a/esphome/components/as3935/binary_sensor.py +++ b/esphome/components/as3935/binary_sensor.py @@ -12,7 +12,7 @@ CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend( ) -def to_code(config): - hub = yield cg.get_variable(config[CONF_AS3935_ID]) - var = yield binary_sensor.new_binary_sensor(config) +async def to_code(config): + hub = await cg.get_variable(config[CONF_AS3935_ID]) + var = await binary_sensor.new_binary_sensor(config) cg.add(hub.set_thunder_alert_binary_sensor(var)) diff --git a/esphome/components/as3935/sensor.py b/esphome/components/as3935/sensor.py index 64eeea7b04..6afe890d65 100644 --- a/esphome/components/as3935/sensor.py +++ b/esphome/components/as3935/sensor.py @@ -27,15 +27,15 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): - hub = yield cg.get_variable(config[CONF_AS3935_ID]) +async def to_code(config): + hub = await cg.get_variable(config[CONF_AS3935_ID]) if CONF_DISTANCE in config: conf = config[CONF_DISTANCE] - distance_sensor = yield sensor.new_sensor(conf) + distance_sensor = await sensor.new_sensor(conf) cg.add(hub.set_distance_sensor(distance_sensor)) if CONF_LIGHTNING_ENERGY in config: conf = config[CONF_LIGHTNING_ENERGY] - lightning_energy_sensor = yield sensor.new_sensor(conf) + lightning_energy_sensor = await sensor.new_sensor(conf) cg.add(hub.set_energy_sensor(lightning_energy_sensor)) diff --git a/esphome/components/as3935_i2c/__init__.py b/esphome/components/as3935_i2c/__init__.py index 277ccd84d3..aa741b2ea6 100644 --- a/esphome/components/as3935_i2c/__init__.py +++ b/esphome/components/as3935_i2c/__init__.py @@ -20,7 +20,7 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield as3935.setup_as3935(var, config) - yield i2c.register_i2c_device(var, config) + await as3935.setup_as3935(var, config) + await i2c.register_i2c_device(var, config) diff --git a/esphome/components/as3935_spi/__init__.py b/esphome/components/as3935_spi/__init__.py index b921444b8b..849539f092 100644 --- a/esphome/components/as3935_spi/__init__.py +++ b/esphome/components/as3935_spi/__init__.py @@ -20,7 +20,7 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield as3935.setup_as3935(var, config) - yield spi.register_spi_device(var, config) + await as3935.setup_as3935(var, config) + await spi.register_spi_device(var, config) diff --git a/esphome/components/atc_mithermometer/sensor.py b/esphome/components/atc_mithermometer/sensor.py index 51891b33cb..161f1f021b 100644 --- a/esphome/components/atc_mithermometer/sensor.py +++ b/esphome/components/atc_mithermometer/sensor.py @@ -51,22 +51,22 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield esp32_ble_tracker.register_ble_device(var, config) + await cg.register_component(var, config) + await esp32_ble_tracker.register_ble_device(var, config) cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) if CONF_TEMPERATURE in config: - sens = yield sensor.new_sensor(config[CONF_TEMPERATURE]) + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) cg.add(var.set_temperature(sens)) if CONF_HUMIDITY in config: - sens = yield sensor.new_sensor(config[CONF_HUMIDITY]) + sens = await sensor.new_sensor(config[CONF_HUMIDITY]) cg.add(var.set_humidity(sens)) if CONF_BATTERY_LEVEL in config: - sens = yield sensor.new_sensor(config[CONF_BATTERY_LEVEL]) + sens = await sensor.new_sensor(config[CONF_BATTERY_LEVEL]) cg.add(var.set_battery_level(sens)) if CONF_BATTERY_VOLTAGE in config: - sens = yield sensor.new_sensor(config[CONF_BATTERY_VOLTAGE]) + sens = await sensor.new_sensor(config[CONF_BATTERY_VOLTAGE]) cg.add(var.set_battery_voltage(sens)) diff --git a/esphome/components/atm90e32/sensor.py b/esphome/components/atm90e32/sensor.py index 4a9100d9d6..b0e43559f9 100644 --- a/esphome/components/atm90e32/sensor.py +++ b/esphome/components/atm90e32/sensor.py @@ -113,10 +113,10 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield spi.register_spi_device(var, config) + await cg.register_component(var, config) + await spi.register_spi_device(var, config) for i, phase in enumerate([CONF_PHASE_A, CONF_PHASE_B, CONF_PHASE_C]): if phase not in config: @@ -125,31 +125,31 @@ def to_code(config): cg.add(var.set_volt_gain(i, conf[CONF_GAIN_VOLTAGE])) cg.add(var.set_ct_gain(i, conf[CONF_GAIN_CT])) if CONF_VOLTAGE in conf: - sens = yield sensor.new_sensor(conf[CONF_VOLTAGE]) + sens = await sensor.new_sensor(conf[CONF_VOLTAGE]) cg.add(var.set_voltage_sensor(i, sens)) if CONF_CURRENT in conf: - sens = yield sensor.new_sensor(conf[CONF_CURRENT]) + sens = await sensor.new_sensor(conf[CONF_CURRENT]) cg.add(var.set_current_sensor(i, sens)) if CONF_POWER in conf: - sens = yield sensor.new_sensor(conf[CONF_POWER]) + sens = await sensor.new_sensor(conf[CONF_POWER]) cg.add(var.set_power_sensor(i, sens)) if CONF_REACTIVE_POWER in conf: - sens = yield sensor.new_sensor(conf[CONF_REACTIVE_POWER]) + sens = await sensor.new_sensor(conf[CONF_REACTIVE_POWER]) cg.add(var.set_reactive_power_sensor(i, sens)) if CONF_POWER_FACTOR in conf: - sens = yield sensor.new_sensor(conf[CONF_POWER_FACTOR]) + sens = await sensor.new_sensor(conf[CONF_POWER_FACTOR]) cg.add(var.set_power_factor_sensor(i, sens)) if CONF_FORWARD_ACTIVE_ENERGY in conf: - sens = yield sensor.new_sensor(conf[CONF_FORWARD_ACTIVE_ENERGY]) + sens = await sensor.new_sensor(conf[CONF_FORWARD_ACTIVE_ENERGY]) cg.add(var.set_forward_active_energy_sensor(i, sens)) if CONF_REVERSE_ACTIVE_ENERGY in conf: - sens = yield sensor.new_sensor(conf[CONF_REVERSE_ACTIVE_ENERGY]) + sens = await sensor.new_sensor(conf[CONF_REVERSE_ACTIVE_ENERGY]) cg.add(var.set_reverse_active_energy_sensor(i, sens)) if CONF_FREQUENCY in config: - sens = yield sensor.new_sensor(config[CONF_FREQUENCY]) + sens = await sensor.new_sensor(config[CONF_FREQUENCY]) cg.add(var.set_freq_sensor(sens)) if CONF_CHIP_TEMPERATURE in config: - sens = yield sensor.new_sensor(config[CONF_CHIP_TEMPERATURE]) + sens = await sensor.new_sensor(config[CONF_CHIP_TEMPERATURE]) cg.add(var.set_chip_temperature_sensor(sens)) cg.add(var.set_line_freq(config[CONF_LINE_FREQUENCY])) cg.add(var.set_current_phases(config[CONF_CURRENT_PHASES])) diff --git a/esphome/components/b_parasite/sensor.py b/esphome/components/b_parasite/sensor.py index d90ea84cd3..415cae454f 100644 --- a/esphome/components/b_parasite/sensor.py +++ b/esphome/components/b_parasite/sensor.py @@ -50,10 +50,10 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield esp32_ble_tracker.register_ble_device(var, config) + await cg.register_component(var, config) + await esp32_ble_tracker.register_ble_device(var, config) cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) @@ -64,5 +64,5 @@ def to_code(config): (CONF_MOISTURE, var.set_soil_moisture), ]: if config_key in config: - sens = yield sensor.new_sensor(config[config_key]) + sens = await sensor.new_sensor(config[config_key]) cg.add(setter(sens)) diff --git a/esphome/components/bang_bang/climate.py b/esphome/components/bang_bang/climate.py index e0d75a6a1e..5c935987de 100644 --- a/esphome/components/bang_bang/climate.py +++ b/esphome/components/bang_bang/climate.py @@ -39,12 +39,12 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield climate.register_climate(var, config) + await cg.register_component(var, config) + await climate.register_climate(var, config) - sens = yield cg.get_variable(config[CONF_SENSOR]) + sens = await cg.get_variable(config[CONF_SENSOR]) cg.add(var.set_sensor(sens)) normal_config = BangBangClimateTargetTempConfig( @@ -53,17 +53,17 @@ def to_code(config): ) cg.add(var.set_normal_config(normal_config)) - yield automation.build_automation( + await automation.build_automation( var.get_idle_trigger(), [], config[CONF_IDLE_ACTION] ) if CONF_COOL_ACTION in config: - yield automation.build_automation( + await automation.build_automation( var.get_cool_trigger(), [], config[CONF_COOL_ACTION] ) cg.add(var.set_supports_cool(True)) if CONF_HEAT_ACTION in config: - yield automation.build_automation( + await automation.build_automation( var.get_heat_trigger(), [], config[CONF_HEAT_ACTION] ) cg.add(var.set_supports_heat(True)) diff --git a/esphome/components/bh1750/sensor.py b/esphome/components/bh1750/sensor.py index 0e37b2b865..6c3c20d9c4 100644 --- a/esphome/components/bh1750/sensor.py +++ b/esphome/components/bh1750/sensor.py @@ -46,11 +46,11 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield sensor.register_sensor(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await sensor.register_sensor(var, config) + await i2c.register_i2c_device(var, config) cg.add(var.set_resolution(config[CONF_RESOLUTION])) cg.add(var.set_measurement_duration(config[CONF_MEASUREMENT_DURATION])) diff --git a/esphome/components/binary/fan/__init__.py b/esphome/components/binary/fan/__init__.py index 88dc506235..e6c8d9bfe9 100644 --- a/esphome/components/binary/fan/__init__.py +++ b/esphome/components/binary/fan/__init__.py @@ -21,19 +21,19 @@ CONFIG_SCHEMA = fan.FAN_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_OUTPUT_ID]) - yield cg.register_component(var, config) + await cg.register_component(var, config) - fan_ = yield fan.create_fan_state(config) + fan_ = await fan.create_fan_state(config) cg.add(var.set_fan(fan_)) - output_ = yield cg.get_variable(config[CONF_OUTPUT]) + output_ = await cg.get_variable(config[CONF_OUTPUT]) cg.add(var.set_output(output_)) if CONF_OSCILLATION_OUTPUT in config: - oscillation_output = yield cg.get_variable(config[CONF_OSCILLATION_OUTPUT]) + oscillation_output = await cg.get_variable(config[CONF_OSCILLATION_OUTPUT]) cg.add(var.set_oscillating(oscillation_output)) if CONF_DIRECTION_OUTPUT in config: - direction_output = yield cg.get_variable(config[CONF_DIRECTION_OUTPUT]) + direction_output = await cg.get_variable(config[CONF_DIRECTION_OUTPUT]) cg.add(var.set_direction(direction_output)) diff --git a/esphome/components/binary/light/__init__.py b/esphome/components/binary/light/__init__.py index 7e62f4705f..49227ccadc 100644 --- a/esphome/components/binary/light/__init__.py +++ b/esphome/components/binary/light/__init__.py @@ -14,9 +14,9 @@ CONFIG_SCHEMA = light.BINARY_LIGHT_SCHEMA.extend( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_OUTPUT_ID]) - yield light.register_light(var, config) + await light.register_light(var, config) - out = yield cg.get_variable(config[CONF_OUTPUT]) + out = await cg.get_variable(config[CONF_OUTPUT]) cg.add(var.set_output(out)) diff --git a/esphome/components/binary_sensor_map/sensor.py b/esphome/components/binary_sensor_map/sensor.py index 81bc85e570..406a1b7bd1 100644 --- a/esphome/components/binary_sensor_map/sensor.py +++ b/esphome/components/binary_sensor_map/sensor.py @@ -48,14 +48,14 @@ CONFIG_SCHEMA = cv.typed_schema( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield sensor.register_sensor(var, config) + await cg.register_component(var, config) + await sensor.register_sensor(var, config) constant = SENSOR_MAP_TYPES[config[CONF_TYPE]] cg.add(var.set_sensor_type(constant)) for ch in config[CONF_CHANNELS]: - input_var = yield cg.get_variable(ch[CONF_BINARY_SENSOR]) + input_var = await cg.get_variable(ch[CONF_BINARY_SENSOR]) cg.add(var.add_channel(input_var, ch[CONF_VALUE])) diff --git a/esphome/components/ble_client/__init__.py b/esphome/components/ble_client/__init__.py index d3b287574b..b3ba8c2a47 100644 --- a/esphome/components/ble_client/__init__.py +++ b/esphome/components/ble_client/__init__.py @@ -74,14 +74,14 @@ def register_ble_node(var, config): cg.add(parent.register_ble_node(var)) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield esp32_ble_tracker.register_client(var, config) + await cg.register_component(var, config) + await esp32_ble_tracker.register_client(var, config) cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) for conf in config.get(CONF_ON_CONNECT, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) - yield automation.build_automation(trigger, [], conf) + await automation.build_automation(trigger, [], conf) for conf in config.get(CONF_ON_DISCONNECT, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) - yield automation.build_automation(trigger, [], conf) + await automation.build_automation(trigger, [], conf) diff --git a/esphome/components/ble_client/sensor/__init__.py b/esphome/components/ble_client/sensor/__init__.py index 27eca87a37..a7ab0acd73 100644 --- a/esphome/components/ble_client/sensor/__init__.py +++ b/esphome/components/ble_client/sensor/__init__.py @@ -50,7 +50,7 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) if len(config[CONF_SERVICE_UUID]) == len(esp32_ble_tracker.bt_uuid16_format): cg.add( @@ -105,11 +105,11 @@ def to_code(config): uuid128 = esp32_ble_tracker.as_hex_array(config[CONF_DESCRIPTOR_UUID]) cg.add(var.set_descr_uuid128(uuid128)) - yield cg.register_component(var, config) - yield ble_client.register_ble_node(var, config) + await cg.register_component(var, config) + await ble_client.register_ble_node(var, config) cg.add(var.set_enable_notify(config[CONF_NOTIFY])) - yield sensor.register_sensor(var, config) + await sensor.register_sensor(var, config) for conf in config.get(CONF_ON_NOTIFY, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) - yield ble_client.register_ble_node(trigger, config) - yield automation.build_automation(trigger, [(float, "x")], conf) + await ble_client.register_ble_node(trigger, config) + await automation.build_automation(trigger, [(float, "x")], conf) diff --git a/esphome/components/ble_client/switch/__init__.py b/esphome/components/ble_client/switch/__init__.py index acc8683407..e5b5ab281b 100644 --- a/esphome/components/ble_client/switch/__init__.py +++ b/esphome/components/ble_client/switch/__init__.py @@ -23,8 +23,8 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield switch.register_switch(var, config) - yield ble_client.register_ble_node(var, config) + await cg.register_component(var, config) + await switch.register_switch(var, config) + await ble_client.register_ble_node(var, config) diff --git a/esphome/components/ble_presence/binary_sensor.py b/esphome/components/ble_presence/binary_sensor.py index 4c6e7ee567..c58d29e6be 100644 --- a/esphome/components/ble_presence/binary_sensor.py +++ b/esphome/components/ble_presence/binary_sensor.py @@ -27,11 +27,11 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield esp32_ble_tracker.register_ble_device(var, config) - yield binary_sensor.register_binary_sensor(var, config) + await cg.register_component(var, config) + await esp32_ble_tracker.register_ble_device(var, config) + await binary_sensor.register_binary_sensor(var, config) if CONF_MAC_ADDRESS in config: cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) diff --git a/esphome/components/ble_rssi/sensor.py b/esphome/components/ble_rssi/sensor.py index f6ee209ae1..279fc4ae19 100644 --- a/esphome/components/ble_rssi/sensor.py +++ b/esphome/components/ble_rssi/sensor.py @@ -32,11 +32,11 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield esp32_ble_tracker.register_ble_device(var, config) - yield sensor.register_sensor(var, config) + await cg.register_component(var, config) + await esp32_ble_tracker.register_ble_device(var, config) + await sensor.register_sensor(var, config) if CONF_MAC_ADDRESS in config: cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) diff --git a/esphome/components/ble_scanner/text_sensor.py b/esphome/components/ble_scanner/text_sensor.py index 96c7b4d887..0e140aa701 100644 --- a/esphome/components/ble_scanner/text_sensor.py +++ b/esphome/components/ble_scanner/text_sensor.py @@ -24,8 +24,8 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield esp32_ble_tracker.register_ble_device(var, config) - yield text_sensor.register_text_sensor(var, config) + await cg.register_component(var, config) + await esp32_ble_tracker.register_ble_device(var, config) + await text_sensor.register_text_sensor(var, config) diff --git a/esphome/components/bme280/sensor.py b/esphome/components/bme280/sensor.py index 5b0e418a66..2b1b8825f8 100644 --- a/esphome/components/bme280/sensor.py +++ b/esphome/components/bme280/sensor.py @@ -84,26 +84,26 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) if CONF_TEMPERATURE in config: conf = config[CONF_TEMPERATURE] - sens = yield sensor.new_sensor(conf) + sens = await sensor.new_sensor(conf) cg.add(var.set_temperature_sensor(sens)) cg.add(var.set_temperature_oversampling(conf[CONF_OVERSAMPLING])) if CONF_PRESSURE in config: conf = config[CONF_PRESSURE] - sens = yield sensor.new_sensor(conf) + sens = await sensor.new_sensor(conf) cg.add(var.set_pressure_sensor(sens)) cg.add(var.set_pressure_oversampling(conf[CONF_OVERSAMPLING])) if CONF_HUMIDITY in config: conf = config[CONF_HUMIDITY] - sens = yield sensor.new_sensor(conf) + sens = await sensor.new_sensor(conf) cg.add(var.set_humidity_sensor(sens)) cg.add(var.set_humidity_oversampling(conf[CONF_OVERSAMPLING])) diff --git a/esphome/components/bme680/sensor.py b/esphome/components/bme680/sensor.py index a82ecefe99..08a5b3b0a2 100644 --- a/esphome/components/bme680/sensor.py +++ b/esphome/components/bme680/sensor.py @@ -114,32 +114,32 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) if CONF_TEMPERATURE in config: conf = config[CONF_TEMPERATURE] - sens = yield sensor.new_sensor(conf) + sens = await sensor.new_sensor(conf) cg.add(var.set_temperature_sensor(sens)) cg.add(var.set_temperature_oversampling(conf[CONF_OVERSAMPLING])) if CONF_PRESSURE in config: conf = config[CONF_PRESSURE] - sens = yield sensor.new_sensor(conf) + sens = await sensor.new_sensor(conf) cg.add(var.set_pressure_sensor(sens)) cg.add(var.set_pressure_oversampling(conf[CONF_OVERSAMPLING])) if CONF_HUMIDITY in config: conf = config[CONF_HUMIDITY] - sens = yield sensor.new_sensor(conf) + sens = await sensor.new_sensor(conf) cg.add(var.set_humidity_sensor(sens)) cg.add(var.set_humidity_oversampling(conf[CONF_OVERSAMPLING])) if CONF_GAS_RESISTANCE in config: conf = config[CONF_GAS_RESISTANCE] - sens = yield sensor.new_sensor(conf) + sens = await sensor.new_sensor(conf) cg.add(var.set_gas_resistance_sensor(sens)) cg.add(var.set_iir_filter(IIR_FILTER_OPTIONS[config[CONF_IIR_FILTER]])) diff --git a/esphome/components/bme680_bsec/__init__.py b/esphome/components/bme680_bsec/__init__.py index e9704b5e59..d258819aa4 100644 --- a/esphome/components/bme680_bsec/__init__.py +++ b/esphome/components/bme680_bsec/__init__.py @@ -48,10 +48,10 @@ CONFIG_SCHEMA = cv.Schema( ).extend(i2c.i2c_device_schema(0x76)) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) cg.add(var.set_temperature_offset(config[CONF_TEMPERATURE_OFFSET])) cg.add(var.set_iaq_mode(config[CONF_IAQ_MODE])) diff --git a/esphome/components/bme680_bsec/sensor.py b/esphome/components/bme680_bsec/sensor.py index b5f0ce190d..0781f50f4e 100644 --- a/esphome/components/bme680_bsec/sensor.py +++ b/esphome/components/bme680_bsec/sensor.py @@ -97,7 +97,7 @@ def setup_conf(config, key, hub): cg.add(getattr(hub, f"set_{key}_sample_rate")(conf[CONF_SAMPLE_RATE])) -def to_code(config): - hub = yield cg.get_variable(config[CONF_BME680_BSEC_ID]) +async def to_code(config): + hub = await cg.get_variable(config[CONF_BME680_BSEC_ID]) for key in TYPES: - yield setup_conf(config, key, hub) + await setup_conf(config, key, hub) diff --git a/esphome/components/bme680_bsec/text_sensor.py b/esphome/components/bme680_bsec/text_sensor.py index bd90a419f5..41a63753a6 100644 --- a/esphome/components/bme680_bsec/text_sensor.py +++ b/esphome/components/bme680_bsec/text_sensor.py @@ -34,7 +34,7 @@ def setup_conf(config, key, hub): cg.add(getattr(hub, f"set_{key}_text_sensor")(sens)) -def to_code(config): - hub = yield cg.get_variable(config[CONF_BME680_BSEC_ID]) +async def to_code(config): + hub = await cg.get_variable(config[CONF_BME680_BSEC_ID]) for key in TYPES: - yield setup_conf(config, key, hub) + await setup_conf(config, key, hub) diff --git a/esphome/components/bmp085/sensor.py b/esphome/components/bmp085/sensor.py index a070e4aa69..eca5283d5d 100644 --- a/esphome/components/bmp085/sensor.py +++ b/esphome/components/bmp085/sensor.py @@ -36,17 +36,17 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) if CONF_TEMPERATURE in config: conf = config[CONF_TEMPERATURE] - sens = yield sensor.new_sensor(conf) + sens = await sensor.new_sensor(conf) cg.add(var.set_temperature(sens)) if CONF_PRESSURE in config: conf = config[CONF_PRESSURE] - sens = yield sensor.new_sensor(conf) + sens = await sensor.new_sensor(conf) cg.add(var.set_pressure(sens)) diff --git a/esphome/components/bmp280/sensor.py b/esphome/components/bmp280/sensor.py index b12d7bff7f..d86767ecd5 100644 --- a/esphome/components/bmp280/sensor.py +++ b/esphome/components/bmp280/sensor.py @@ -72,19 +72,19 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) if CONF_TEMPERATURE in config: conf = config[CONF_TEMPERATURE] - sens = yield sensor.new_sensor(conf) + sens = await sensor.new_sensor(conf) cg.add(var.set_temperature_sensor(sens)) cg.add(var.set_temperature_oversampling(conf[CONF_OVERSAMPLING])) if CONF_PRESSURE in config: conf = config[CONF_PRESSURE] - sens = yield sensor.new_sensor(conf) + sens = await sensor.new_sensor(conf) cg.add(var.set_pressure_sensor(sens)) cg.add(var.set_pressure_oversampling(conf[CONF_OVERSAMPLING])) diff --git a/esphome/components/ccs811/sensor.py b/esphome/components/ccs811/sensor.py index 95b108a225..e86d8f9b83 100644 --- a/esphome/components/ccs811/sensor.py +++ b/esphome/components/ccs811/sensor.py @@ -43,22 +43,22 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) - sens = yield sensor.new_sensor(config[CONF_ECO2]) + sens = await sensor.new_sensor(config[CONF_ECO2]) cg.add(var.set_co2(sens)) - sens = yield sensor.new_sensor(config[CONF_TVOC]) + sens = await sensor.new_sensor(config[CONF_TVOC]) cg.add(var.set_tvoc(sens)) if CONF_BASELINE in config: cg.add(var.set_baseline(config[CONF_BASELINE])) if CONF_TEMPERATURE in config: - sens = yield cg.get_variable(config[CONF_TEMPERATURE]) + sens = await cg.get_variable(config[CONF_TEMPERATURE]) cg.add(var.set_temperature(sens)) if CONF_HUMIDITY in config: - sens = yield cg.get_variable(config[CONF_HUMIDITY]) + sens = await cg.get_variable(config[CONF_HUMIDITY]) cg.add(var.set_humidity(sens)) diff --git a/esphome/components/climate_ir_lg/climate.py b/esphome/components/climate_ir_lg/climate.py index 06e538d9c7..c58e40f7f4 100644 --- a/esphome/components/climate_ir_lg/climate.py +++ b/esphome/components/climate_ir_lg/climate.py @@ -36,9 +36,9 @@ CONFIG_SCHEMA = climate_ir.CLIMATE_IR_WITH_RECEIVER_SCHEMA.extend( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield climate_ir.register_climate_ir(var, config) + await climate_ir.register_climate_ir(var, config) cg.add(var.set_header_high(config[CONF_HEADER_HIGH])) cg.add(var.set_header_low(config[CONF_HEADER_LOW])) diff --git a/esphome/components/color/__init__.py b/esphome/components/color/__init__.py index 6712d078a4..47679fcc68 100644 --- a/esphome/components/color/__init__.py +++ b/esphome/components/color/__init__.py @@ -26,7 +26,7 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): r = 0 if CONF_RED in config: r = int(config[CONF_RED] * 255) diff --git a/esphome/components/coolix/climate.py b/esphome/components/coolix/climate.py index b7a584643b..2cfd1912e5 100644 --- a/esphome/components/coolix/climate.py +++ b/esphome/components/coolix/climate.py @@ -16,6 +16,6 @@ CONFIG_SCHEMA = climate_ir.CLIMATE_IR_WITH_RECEIVER_SCHEMA.extend( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield climate_ir.register_climate_ir(var, config) + await climate_ir.register_climate_ir(var, config) diff --git a/esphome/components/cse7766/sensor.py b/esphome/components/cse7766/sensor.py index 71e9458618..3e136dae49 100644 --- a/esphome/components/cse7766/sensor.py +++ b/esphome/components/cse7766/sensor.py @@ -42,20 +42,20 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield uart.register_uart_device(var, config) + await cg.register_component(var, config) + await uart.register_uart_device(var, config) if CONF_VOLTAGE in config: conf = config[CONF_VOLTAGE] - sens = yield sensor.new_sensor(conf) + sens = await sensor.new_sensor(conf) cg.add(var.set_voltage_sensor(sens)) if CONF_CURRENT in config: conf = config[CONF_CURRENT] - sens = yield sensor.new_sensor(conf) + sens = await sensor.new_sensor(conf) cg.add(var.set_current_sensor(sens)) if CONF_POWER in config: conf = config[CONF_POWER] - sens = yield sensor.new_sensor(conf) + sens = await sensor.new_sensor(conf) cg.add(var.set_power_sensor(sens)) diff --git a/esphome/components/ct_clamp/sensor.py b/esphome/components/ct_clamp/sensor.py index e4dbd92387..8b15c9309d 100644 --- a/esphome/components/ct_clamp/sensor.py +++ b/esphome/components/ct_clamp/sensor.py @@ -32,11 +32,11 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield sensor.register_sensor(var, config) + await cg.register_component(var, config) + await sensor.register_sensor(var, config) - sens = yield cg.get_variable(config[CONF_SENSOR]) + sens = await cg.get_variable(config[CONF_SENSOR]) cg.add(var.set_source(sens)) cg.add(var.set_sample_duration(config[CONF_SAMPLE_DURATION])) diff --git a/esphome/components/custom/binary_sensor/__init__.py b/esphome/components/custom/binary_sensor/__init__.py index 402540c254..18d613d4c1 100644 --- a/esphome/components/custom/binary_sensor/__init__.py +++ b/esphome/components/custom/binary_sensor/__init__.py @@ -17,8 +17,8 @@ CONFIG_SCHEMA = cv.Schema( ) -def to_code(config): - template_ = yield cg.process_lambda( +async def to_code(config): + template_ = await cg.process_lambda( config[CONF_LAMBDA], [], return_type=cg.std_vector.template(binary_sensor.BinarySensorPtr), @@ -28,4 +28,4 @@ def to_code(config): custom = cg.variable(config[CONF_ID], rhs) for i, conf in enumerate(config[CONF_BINARY_SENSORS]): rhs = custom.Pget_binary_sensor(i) - yield binary_sensor.register_binary_sensor(rhs, conf) + await binary_sensor.register_binary_sensor(rhs, conf) diff --git a/esphome/components/custom/climate/__init__.py b/esphome/components/custom/climate/__init__.py index 75f9c3247e..a95456133a 100644 --- a/esphome/components/custom/climate/__init__.py +++ b/esphome/components/custom/climate/__init__.py @@ -16,8 +16,8 @@ CONFIG_SCHEMA = cv.Schema( ) -def to_code(config): - template_ = yield cg.process_lambda( +async def to_code(config): + template_ = await cg.process_lambda( config[CONF_LAMBDA], [], return_type=cg.std_vector.template(climate.Climate.operator("ptr")), @@ -27,4 +27,4 @@ def to_code(config): custom = cg.variable(config[CONF_ID], rhs) for i, conf in enumerate(config[CONF_CLIMATES]): rhs = custom.Pget_climate(i) - yield climate.register_climate(rhs, conf) + await climate.register_climate(rhs, conf) diff --git a/esphome/components/custom/cover/__init__.py b/esphome/components/custom/cover/__init__.py index 35f25b827d..37fd4cdbbc 100644 --- a/esphome/components/custom/cover/__init__.py +++ b/esphome/components/custom/cover/__init__.py @@ -16,8 +16,8 @@ CONFIG_SCHEMA = cv.Schema( ) -def to_code(config): - template_ = yield cg.process_lambda( +async def to_code(config): + template_ = await cg.process_lambda( config[CONF_LAMBDA], [], return_type=cg.std_vector.template(cover.Cover.operator("ptr")), @@ -27,4 +27,4 @@ def to_code(config): custom = cg.variable(config[CONF_ID], rhs) for i, conf in enumerate(config[CONF_COVERS]): rhs = custom.Pget_cover(i) - yield cover.register_cover(rhs, conf) + await cover.register_cover(rhs, conf) diff --git a/esphome/components/custom/light/__init__.py b/esphome/components/custom/light/__init__.py index f4bd8331f1..b6ebe13ab2 100644 --- a/esphome/components/custom/light/__init__.py +++ b/esphome/components/custom/light/__init__.py @@ -16,8 +16,8 @@ CONFIG_SCHEMA = cv.Schema( ) -def to_code(config): - template_ = yield cg.process_lambda( +async def to_code(config): + template_ = await cg.process_lambda( config[CONF_LAMBDA], [], return_type=cg.std_vector.template(light.LightOutput.operator("ptr")), @@ -27,4 +27,4 @@ def to_code(config): custom = cg.variable(config[CONF_ID], rhs) for i, conf in enumerate(config[CONF_LIGHTS]): rhs = custom.Pget_light(i) - yield light.register_light(rhs, conf) + await light.register_light(rhs, conf) diff --git a/esphome/components/custom/output/__init__.py b/esphome/components/custom/output/__init__.py index c803d89c32..97ef070fc3 100644 --- a/esphome/components/custom/output/__init__.py +++ b/esphome/components/custom/output/__init__.py @@ -42,7 +42,7 @@ CONFIG_SCHEMA = cv.typed_schema( ) -def to_code(config): +async def to_code(config): type = config[CONF_TYPE] if type == "binary": ret_type = output.BinaryOutputPtr @@ -50,7 +50,7 @@ def to_code(config): else: ret_type = output.FloatOutputPtr klass = CustomFloatOutputConstructor - template_ = yield cg.process_lambda( + template_ = await cg.process_lambda( config[CONF_LAMBDA], [], return_type=cg.std_vector.template(ret_type) ) @@ -58,4 +58,4 @@ def to_code(config): custom = cg.variable(config[CONF_ID], rhs) for i, conf in enumerate(config[CONF_OUTPUTS]): out = cg.Pvariable(conf[CONF_ID], custom.get_output(i)) - yield output.register_output(out, conf) + await output.register_output(out, conf) diff --git a/esphome/components/custom/sensor/__init__.py b/esphome/components/custom/sensor/__init__.py index 2be14afc0d..bf9421e43e 100644 --- a/esphome/components/custom/sensor/__init__.py +++ b/esphome/components/custom/sensor/__init__.py @@ -15,8 +15,8 @@ CONFIG_SCHEMA = cv.Schema( ) -def to_code(config): - template_ = yield cg.process_lambda( +async def to_code(config): + template_ = await cg.process_lambda( config[CONF_LAMBDA], [], return_type=cg.std_vector.template(sensor.SensorPtr) ) @@ -24,4 +24,4 @@ def to_code(config): var = cg.variable(config[CONF_ID], rhs) for i, conf in enumerate(config[CONF_SENSORS]): sens = cg.Pvariable(conf[CONF_ID], var.get_sensor(i)) - yield sensor.register_sensor(sens, conf) + await sensor.register_sensor(sens, conf) diff --git a/esphome/components/custom/switch/__init__.py b/esphome/components/custom/switch/__init__.py index a470c3e440..e0b9d7751a 100644 --- a/esphome/components/custom/switch/__init__.py +++ b/esphome/components/custom/switch/__init__.py @@ -21,8 +21,8 @@ CONFIG_SCHEMA = cv.Schema( ) -def to_code(config): - template_ = yield cg.process_lambda( +async def to_code(config): + template_ = await cg.process_lambda( config[CONF_LAMBDA], [], return_type=cg.std_vector.template(switch.SwitchPtr) ) @@ -30,4 +30,4 @@ def to_code(config): var = cg.variable(config[CONF_ID], rhs) for i, conf in enumerate(config[CONF_SWITCHES]): switch_ = cg.Pvariable(conf[CONF_ID], var.get_switch(i)) - yield switch.register_switch(switch_, conf) + await switch.register_switch(switch_, conf) diff --git a/esphome/components/custom/text_sensor/__init__.py b/esphome/components/custom/text_sensor/__init__.py index f09d72d228..5b6d416436 100644 --- a/esphome/components/custom/text_sensor/__init__.py +++ b/esphome/components/custom/text_sensor/__init__.py @@ -21,8 +21,8 @@ CONFIG_SCHEMA = cv.Schema( ) -def to_code(config): - template_ = yield cg.process_lambda( +async def to_code(config): + template_ = await cg.process_lambda( config[CONF_LAMBDA], [], return_type=cg.std_vector.template(text_sensor.TextSensorPtr), @@ -33,4 +33,4 @@ def to_code(config): for i, conf in enumerate(config[CONF_TEXT_SENSORS]): text = cg.Pvariable(conf[CONF_ID], var.get_text_sensor(i)) - yield text_sensor.register_text_sensor(text, conf) + await text_sensor.register_text_sensor(text, conf) diff --git a/esphome/components/custom_component/__init__.py b/esphome/components/custom_component/__init__.py index fc154a82c3..d41dd7ea59 100644 --- a/esphome/components/custom_component/__init__.py +++ b/esphome/components/custom_component/__init__.py @@ -19,8 +19,8 @@ CONFIG_SCHEMA = cv.Schema( ) -def to_code(config): - template_ = yield cg.process_lambda( +async def to_code(config): + template_ = await cg.process_lambda( config[CONF_LAMBDA], [], return_type=cg.std_vector.template(cg.ComponentPtr) ) @@ -28,4 +28,4 @@ def to_code(config): var = cg.variable(config[CONF_ID], rhs) for i, conf in enumerate(config.get(CONF_COMPONENTS, [])): comp = cg.Pvariable(conf[CONF_ID], var.get_component(i)) - yield cg.register_component(comp, conf) + await cg.register_component(comp, conf) diff --git a/esphome/components/cwww/light.py b/esphome/components/cwww/light.py index b099de435d..674c48d219 100644 --- a/esphome/components/cwww/light.py +++ b/esphome/components/cwww/light.py @@ -26,14 +26,14 @@ CONFIG_SCHEMA = light.RGB_LIGHT_SCHEMA.extend( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_OUTPUT_ID]) - yield light.register_light(var, config) - cwhite = yield cg.get_variable(config[CONF_COLD_WHITE]) + await light.register_light(var, config) + cwhite = await cg.get_variable(config[CONF_COLD_WHITE]) cg.add(var.set_cold_white(cwhite)) cg.add(var.set_cold_white_temperature(config[CONF_COLD_WHITE_COLOR_TEMPERATURE])) - wwhite = yield cg.get_variable(config[CONF_WARM_WHITE]) + wwhite = await cg.get_variable(config[CONF_WARM_WHITE]) cg.add(var.set_warm_white(wwhite)) cg.add(var.set_warm_white_temperature(config[CONF_WARM_WHITE_COLOR_TEMPERATURE])) cg.add(var.set_constant_brightness(config[CONF_CONSTANT_BRIGHTNESS])) diff --git a/esphome/components/daikin/climate.py b/esphome/components/daikin/climate.py index 07bc079a9a..af60b17448 100644 --- a/esphome/components/daikin/climate.py +++ b/esphome/components/daikin/climate.py @@ -15,6 +15,6 @@ CONFIG_SCHEMA = climate_ir.CLIMATE_IR_WITH_RECEIVER_SCHEMA.extend( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield climate_ir.register_climate_ir(var, config) + await climate_ir.register_climate_ir(var, config) diff --git a/esphome/components/dallas/__init__.py b/esphome/components/dallas/__init__.py index 87049b8c64..e889c41175 100644 --- a/esphome/components/dallas/__init__.py +++ b/esphome/components/dallas/__init__.py @@ -20,8 +20,8 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.polling_component_schema("60s")) -def to_code(config): - pin = yield cg.gpio_pin_expression(config[CONF_PIN]) +async def to_code(config): + pin = await cg.gpio_pin_expression(config[CONF_PIN]) one_wire = cg.new_Pvariable(config[CONF_ONE_WIRE_ID], pin) var = cg.new_Pvariable(config[CONF_ID], one_wire) - yield cg.register_component(var, config) + await cg.register_component(var, config) diff --git a/esphome/components/dallas/sensor.py b/esphome/components/dallas/sensor.py index bb0a463a62..21ba7b9154 100644 --- a/esphome/components/dallas/sensor.py +++ b/esphome/components/dallas/sensor.py @@ -29,12 +29,12 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): - hub = yield cg.get_variable(config[CONF_DALLAS_ID]) +async def to_code(config): + hub = await cg.get_variable(config[CONF_DALLAS_ID]) if CONF_ADDRESS in config: address = config[CONF_ADDRESS] rhs = hub.Pget_sensor_by_address(address, config.get(CONF_RESOLUTION)) else: rhs = hub.Pget_sensor_by_index(config[CONF_INDEX], config.get(CONF_RESOLUTION)) var = cg.Pvariable(config[CONF_ID], rhs) - yield sensor.register_sensor(var, config) + await sensor.register_sensor(var, config) diff --git a/esphome/components/debug/__init__.py b/esphome/components/debug/__init__.py index e43eb8bfc1..32c4339530 100644 --- a/esphome/components/debug/__init__.py +++ b/esphome/components/debug/__init__.py @@ -14,6 +14,6 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) + await cg.register_component(var, config) diff --git a/esphome/components/deep_sleep/__init__.py b/esphome/components/deep_sleep/__init__.py index c0d035987d..bfc8c40cfb 100644 --- a/esphome/components/deep_sleep/__init__.py +++ b/esphome/components/deep_sleep/__init__.py @@ -78,14 +78,14 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) + await cg.register_component(var, config) if CONF_SLEEP_DURATION in config: cg.add(var.set_sleep_duration(config[CONF_SLEEP_DURATION])) if CONF_WAKEUP_PIN in config: - pin = yield cg.gpio_pin_expression(config[CONF_WAKEUP_PIN]) + pin = await cg.gpio_pin_expression(config[CONF_WAKEUP_PIN]) cg.add(var.set_wakeup_pin(pin)) if CONF_WAKEUP_PIN_MODE in config: cg.add(var.set_wakeup_pin_mode(config[CONF_WAKEUP_PIN_MODE])) diff --git a/esphome/components/dfplayer/__init__.py b/esphome/components/dfplayer/__init__.py index 33e74a220b..95fef4d234 100644 --- a/esphome/components/dfplayer/__init__.py +++ b/esphome/components/dfplayer/__init__.py @@ -68,14 +68,14 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield uart.register_uart_device(var, config) + await cg.register_component(var, config) + await uart.register_uart_device(var, config) for conf in config.get(CONF_ON_FINISHED_PLAYBACK, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) - yield automation.build_automation(trigger, [], conf) + await automation.build_automation(trigger, [], conf) @automation.register_action( diff --git a/esphome/components/dht/sensor.py b/esphome/components/dht/sensor.py index 4b2f6ee8d2..57971e8202 100644 --- a/esphome/components/dht/sensor.py +++ b/esphome/components/dht/sensor.py @@ -47,18 +47,18 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.polling_component_schema("60s")) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) + await cg.register_component(var, config) - pin = yield gpio_pin_expression(config[CONF_PIN]) + pin = await gpio_pin_expression(config[CONF_PIN]) cg.add(var.set_pin(pin)) if CONF_TEMPERATURE in config: - sens = yield sensor.new_sensor(config[CONF_TEMPERATURE]) + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) cg.add(var.set_temperature_sensor(sens)) if CONF_HUMIDITY in config: - sens = yield sensor.new_sensor(config[CONF_HUMIDITY]) + sens = await sensor.new_sensor(config[CONF_HUMIDITY]) cg.add(var.set_humidity_sensor(sens)) cg.add(var.set_dht_model(config[CONF_MODEL])) diff --git a/esphome/components/dht12/sensor.py b/esphome/components/dht12/sensor.py index f63768142c..68ff6ae1bb 100644 --- a/esphome/components/dht12/sensor.py +++ b/esphome/components/dht12/sensor.py @@ -34,15 +34,15 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) if CONF_TEMPERATURE in config: - sens = yield sensor.new_sensor(config[CONF_TEMPERATURE]) + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) cg.add(var.set_temperature_sensor(sens)) if CONF_HUMIDITY in config: - sens = yield sensor.new_sensor(config[CONF_HUMIDITY]) + sens = await sensor.new_sensor(config[CONF_HUMIDITY]) cg.add(var.set_humidity_sensor(sens)) diff --git a/esphome/components/ds1307/time.py b/esphome/components/ds1307/time.py index 9c1d75c029..cd80a87170 100644 --- a/esphome/components/ds1307/time.py +++ b/esphome/components/ds1307/time.py @@ -50,9 +50,9 @@ def ds1307_read_time_to_code(config, action_id, template_arg, args): yield var -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) - yield time.register_time(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + await time.register_time(var, config) diff --git a/esphome/components/duty_cycle/sensor.py b/esphome/components/duty_cycle/sensor.py index 0dd91bade3..e3d2318b51 100644 --- a/esphome/components/duty_cycle/sensor.py +++ b/esphome/components/duty_cycle/sensor.py @@ -29,10 +29,10 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield sensor.register_sensor(var, config) + await cg.register_component(var, config) + await sensor.register_sensor(var, config) - pin = yield cg.gpio_pin_expression(config[CONF_PIN]) + pin = await cg.gpio_pin_expression(config[CONF_PIN]) cg.add(var.set_pin(pin)) diff --git a/esphome/components/e131/__init__.py b/esphome/components/e131/__init__.py index b33aef8cf3..e02042d4c9 100644 --- a/esphome/components/e131/__init__.py +++ b/esphome/components/e131/__init__.py @@ -29,9 +29,9 @@ CONFIG_SCHEMA = cv.Schema( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) + await cg.register_component(var, config) cg.add(var.set_method(METHODS[config[CONF_METHOD]])) diff --git a/esphome/components/endstop/cover.py b/esphome/components/endstop/cover.py index b463d5d960..9f3cd395a5 100644 --- a/esphome/components/endstop/cover.py +++ b/esphome/components/endstop/cover.py @@ -32,26 +32,26 @@ CONFIG_SCHEMA = cover.COVER_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield cover.register_cover(var, config) + await cg.register_component(var, config) + await cover.register_cover(var, config) - yield automation.build_automation( + await automation.build_automation( var.get_stop_trigger(), [], config[CONF_STOP_ACTION] ) - bin = yield cg.get_variable(config[CONF_OPEN_ENDSTOP]) + bin = await cg.get_variable(config[CONF_OPEN_ENDSTOP]) cg.add(var.set_open_endstop(bin)) cg.add(var.set_open_duration(config[CONF_OPEN_DURATION])) - yield automation.build_automation( + await automation.build_automation( var.get_open_trigger(), [], config[CONF_OPEN_ACTION] ) - bin = yield cg.get_variable(config[CONF_CLOSE_ENDSTOP]) + bin = await cg.get_variable(config[CONF_CLOSE_ENDSTOP]) cg.add(var.set_close_endstop(bin)) cg.add(var.set_close_duration(config[CONF_CLOSE_DURATION])) - yield automation.build_automation( + await automation.build_automation( var.get_close_trigger(), [], config[CONF_CLOSE_ACTION] ) diff --git a/esphome/components/esp32_ble_beacon/__init__.py b/esphome/components/esp32_ble_beacon/__init__.py index 46f5678856..3e00692d3a 100644 --- a/esphome/components/esp32_ble_beacon/__init__.py +++ b/esphome/components/esp32_ble_beacon/__init__.py @@ -22,12 +22,12 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): uuid = config[CONF_UUID].hex uuid_arr = [ cg.RawExpression("0x{}".format(uuid[i : i + 2])) for i in range(0, len(uuid), 2) ] var = cg.new_Pvariable(config[CONF_ID], uuid_arr) - yield cg.register_component(var, config) + await cg.register_component(var, config) cg.add(var.set_major(config[CONF_MAJOR])) cg.add(var.set_minor(config[CONF_MINOR])) diff --git a/esphome/components/esp32_ble_tracker/__init__.py b/esphome/components/esp32_ble_tracker/__init__.py index 8726ab3e8d..916fecffc9 100644 --- a/esphome/components/esp32_ble_tracker/__init__.py +++ b/esphome/components/esp32_ble_tracker/__init__.py @@ -177,9 +177,9 @@ ESP_BLE_DEVICE_SCHEMA = cv.Schema( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) + await cg.register_component(var, config) params = config[CONF_SCAN_PARAMETERS] cg.add(var.set_scan_duration(params[CONF_DURATION])) cg.add(var.set_scan_interval(int(params[CONF_INTERVAL].total_milliseconds / 0.625))) @@ -189,7 +189,7 @@ def to_code(config): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) if CONF_MAC_ADDRESS in conf: cg.add(trigger.set_address(conf[CONF_MAC_ADDRESS].as_hex)) - yield automation.build_automation(trigger, [(ESPBTDeviceConstRef, "x")], conf) + await automation.build_automation(trigger, [(ESPBTDeviceConstRef, "x")], conf) for conf in config.get(CONF_ON_BLE_SERVICE_DATA_ADVERTISE, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) if len(conf[CONF_SERVICE_UUID]) == len(bt_uuid16_format): @@ -201,7 +201,7 @@ def to_code(config): cg.add(trigger.set_service_uuid128(uuid128)) if CONF_MAC_ADDRESS in conf: cg.add(trigger.set_address(conf[CONF_MAC_ADDRESS].as_hex)) - yield automation.build_automation(trigger, [(adv_data_t_const_ref, "x")], conf) + await automation.build_automation(trigger, [(adv_data_t_const_ref, "x")], conf) for conf in config.get(CONF_ON_BLE_MANUFACTURER_DATA_ADVERTISE, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) if len(conf[CONF_MANUFACTURER_ID]) == len(bt_uuid16_format): @@ -213,7 +213,7 @@ def to_code(config): cg.add(trigger.set_manufacturer_uuid128(uuid128)) if CONF_MAC_ADDRESS in conf: cg.add(trigger.set_address(conf[CONF_MAC_ADDRESS].as_hex)) - yield automation.build_automation(trigger, [(adv_data_t_const_ref, "x")], conf) + await automation.build_automation(trigger, [(adv_data_t_const_ref, "x")], conf) @coroutine diff --git a/esphome/components/esp32_camera/__init__.py b/esphome/components/esp32_camera/__init__.py index f7169257a4..f3c0e0f165 100644 --- a/esphome/components/esp32_camera/__init__.py +++ b/esphome/components/esp32_camera/__init__.py @@ -124,9 +124,9 @@ SETTERS = { } -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME]) - yield cg.register_component(var, config) + await cg.register_component(var, config) for key, setter in SETTERS.items(): if key in config: diff --git a/esphome/components/esp32_dac/output.py b/esphome/components/esp32_dac/output.py index 8cfc7570e9..8534a1bae1 100644 --- a/esphome/components/esp32_dac/output.py +++ b/esphome/components/esp32_dac/output.py @@ -26,10 +26,10 @@ CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield output.register_output(var, config) + await cg.register_component(var, config) + await output.register_output(var, config) - pin = yield cg.gpio_pin_expression(config[CONF_PIN]) + pin = await cg.gpio_pin_expression(config[CONF_PIN]) cg.add(var.set_pin(pin)) diff --git a/esphome/components/esp32_hall/sensor.py b/esphome/components/esp32_hall/sensor.py index 363b3f7548..0f1cbb373c 100644 --- a/esphome/components/esp32_hall/sensor.py +++ b/esphome/components/esp32_hall/sensor.py @@ -27,7 +27,7 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield sensor.register_sensor(var, config) + await cg.register_component(var, config) + await sensor.register_sensor(var, config) diff --git a/esphome/components/esp32_touch/__init__.py b/esphome/components/esp32_touch/__init__.py index 5c3b47af77..1564476ecf 100644 --- a/esphome/components/esp32_touch/__init__.py +++ b/esphome/components/esp32_touch/__init__.py @@ -77,9 +77,9 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): touch = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(touch, config) + await cg.register_component(touch, config) cg.add(touch.set_setup_mode(config[CONF_SETUP_MODE])) cg.add(touch.set_iir_filter(config[CONF_IIR_FILTER])) diff --git a/esphome/components/esp32_touch/binary_sensor.py b/esphome/components/esp32_touch/binary_sensor.py index f8bc348132..300de23f08 100644 --- a/esphome/components/esp32_touch/binary_sensor.py +++ b/esphome/components/esp32_touch/binary_sensor.py @@ -51,13 +51,13 @@ CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend( ) -def to_code(config): - hub = yield cg.get_variable(config[CONF_ESP32_TOUCH_ID]) +async def to_code(config): + hub = await cg.get_variable(config[CONF_ESP32_TOUCH_ID]) var = cg.new_Pvariable( config[CONF_ID], config[CONF_NAME], TOUCH_PADS[config[CONF_PIN]], config[CONF_THRESHOLD], ) - yield binary_sensor.register_binary_sensor(var, config) + await binary_sensor.register_binary_sensor(var, config) cg.add(hub.register_touch_pad(var)) diff --git a/esphome/components/esp8266_pwm/output.py b/esphome/components/esp8266_pwm/output.py index ad7da4e001..38361da017 100644 --- a/esphome/components/esp8266_pwm/output.py +++ b/esphome/components/esp8266_pwm/output.py @@ -35,12 +35,12 @@ CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield output.register_output(var, config) + await cg.register_component(var, config) + await output.register_output(var, config) - pin = yield cg.gpio_pin_expression(config[CONF_PIN]) + pin = await cg.gpio_pin_expression(config[CONF_PIN]) cg.add(var.set_pin(pin)) cg.add(var.set_frequency(config[CONF_FREQUENCY])) diff --git a/esphome/components/ethernet/__init__.py b/esphome/components/ethernet/__init__.py index 82366eeac2..c6f81e5046 100644 --- a/esphome/components/ethernet/__init__.py +++ b/esphome/components/ethernet/__init__.py @@ -106,9 +106,9 @@ def manual_ip(config): @coroutine_with_priority(60.0) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) + await cg.register_component(var, config) cg.add(var.set_phy_addr(config[CONF_PHY_ADDR])) cg.add(var.set_mdc_pin(config[CONF_MDC_PIN])) @@ -118,7 +118,7 @@ def to_code(config): cg.add(var.set_use_address(config[CONF_USE_ADDRESS])) if CONF_POWER_PIN in config: - pin = yield cg.gpio_pin_expression(config[CONF_POWER_PIN]) + pin = await cg.gpio_pin_expression(config[CONF_POWER_PIN]) cg.add(var.set_power_pin(pin)) if CONF_MANUAL_IP in config: diff --git a/esphome/components/exposure_notifications/__init__.py b/esphome/components/exposure_notifications/__init__.py index 1bd8007785..9c28552267 100644 --- a/esphome/components/exposure_notifications/__init__.py +++ b/esphome/components/exposure_notifications/__init__.py @@ -32,8 +32,8 @@ CONFIG_SCHEMA = cv.Schema( ) -def to_code(config): +async def to_code(config): for conf in config.get(CONF_ON_EXPOSURE_NOTIFICATION, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID]) - yield automation.build_automation(trigger, [(ExposureNotification, "x")], conf) - yield esp32_ble_tracker.register_ble_device(trigger, conf) + await automation.build_automation(trigger, [(ExposureNotification, "x")], conf) + await esp32_ble_tracker.register_ble_device(trigger, conf) diff --git a/esphome/components/external_components/__init__.py b/esphome/components/external_components/__init__.py index 272812adcf..1602ac3b07 100644 --- a/esphome/components/external_components/__init__.py +++ b/esphome/components/external_components/__init__.py @@ -98,7 +98,7 @@ CONFIG_SCHEMA = cv.ensure_list( ) -def to_code(config): +async def to_code(config): pass diff --git a/esphome/components/ezo/sensor.py b/esphome/components/ezo/sensor.py index 12640f4038..09b36b7135 100644 --- a/esphome/components/ezo/sensor.py +++ b/esphome/components/ezo/sensor.py @@ -24,8 +24,8 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield sensor.register_sensor(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await sensor.register_sensor(var, config) + await i2c.register_i2c_device(var, config) diff --git a/esphome/components/fastled_clockless/light.py b/esphome/components/fastled_clockless/light.py index b8a36ff390..17f72427e4 100644 --- a/esphome/components/fastled_clockless/light.py +++ b/esphome/components/fastled_clockless/light.py @@ -51,8 +51,8 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): - var = yield fastled_base.new_fastled_light(config) +async def to_code(config): + var = await fastled_base.new_fastled_light(config) rgb_order = None if CONF_RGB_ORDER in config: diff --git a/esphome/components/fastled_spi/light.py b/esphome/components/fastled_spi/light.py index 11e0a8159c..d6ba0e8358 100644 --- a/esphome/components/fastled_spi/light.py +++ b/esphome/components/fastled_spi/light.py @@ -34,8 +34,8 @@ CONFIG_SCHEMA = fastled_base.BASE_SCHEMA.extend( ) -def to_code(config): - var = yield fastled_base.new_fastled_light(config) +async def to_code(config): + var = await fastled_base.new_fastled_light(config) rgb_order = cg.RawExpression( config[CONF_RGB_ORDER] if CONF_RGB_ORDER in config else "RGB" diff --git a/esphome/components/fingerprint_grow/__init__.py b/esphome/components/fingerprint_grow/__init__.py index 6fbaa4e6c9..52426a3f2d 100644 --- a/esphome/components/fingerprint_grow/__init__.py +++ b/esphome/components/fingerprint_grow/__init__.py @@ -132,45 +132,45 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) + await cg.register_component(var, config) if CONF_PASSWORD in config: password = config[CONF_PASSWORD] cg.add(var.set_password(password)) - yield uart.register_uart_device(var, config) + await uart.register_uart_device(var, config) if CONF_NEW_PASSWORD in config: new_password = config[CONF_NEW_PASSWORD] cg.add(var.set_new_password(new_password)) if CONF_SENSING_PIN in config: - sensing_pin = yield cg.gpio_pin_expression(config[CONF_SENSING_PIN]) + sensing_pin = await cg.gpio_pin_expression(config[CONF_SENSING_PIN]) cg.add(var.set_sensing_pin(sensing_pin)) for conf in config.get(CONF_ON_FINGER_SCAN_MATCHED, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) - yield automation.build_automation( + await automation.build_automation( trigger, [(cg.uint16, "finger_id"), (cg.uint16, "confidence")], conf ) for conf in config.get(CONF_ON_FINGER_SCAN_UNMATCHED, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) - yield automation.build_automation(trigger, [], conf) + await automation.build_automation(trigger, [], conf) for conf in config.get(CONF_ON_ENROLLMENT_SCAN, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) - yield automation.build_automation( + await automation.build_automation( trigger, [(cg.uint8, "scan_num"), (cg.uint16, "finger_id")], conf ) for conf in config.get(CONF_ON_ENROLLMENT_DONE, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) - yield automation.build_automation(trigger, [(cg.uint16, "finger_id")], conf) + await automation.build_automation(trigger, [(cg.uint16, "finger_id")], conf) for conf in config.get(CONF_ON_ENROLLMENT_FAILED, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) - yield automation.build_automation(trigger, [(cg.uint16, "finger_id")], conf) + await automation.build_automation(trigger, [(cg.uint16, "finger_id")], conf) @automation.register_action( diff --git a/esphome/components/fingerprint_grow/binary_sensor.py b/esphome/components/fingerprint_grow/binary_sensor.py index 4f49841f15..f432ef92cc 100644 --- a/esphome/components/fingerprint_grow/binary_sensor.py +++ b/esphome/components/fingerprint_grow/binary_sensor.py @@ -14,7 +14,7 @@ CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend( ) -def to_code(config): - hub = yield cg.get_variable(config[CONF_FINGERPRINT_GROW_ID]) - var = yield binary_sensor.new_binary_sensor(config) +async def to_code(config): + hub = await cg.get_variable(config[CONF_FINGERPRINT_GROW_ID]) + var = await binary_sensor.new_binary_sensor(config) cg.add(hub.set_enrolling_binary_sensor(var)) diff --git a/esphome/components/fingerprint_grow/sensor.py b/esphome/components/fingerprint_grow/sensor.py index c76c898727..11f61a6a71 100644 --- a/esphome/components/fingerprint_grow/sensor.py +++ b/esphome/components/fingerprint_grow/sensor.py @@ -46,8 +46,8 @@ CONFIG_SCHEMA = cv.Schema( ) -def to_code(config): - hub = yield cg.get_variable(config[CONF_FINGERPRINT_GROW_ID]) +async def to_code(config): + hub = await cg.get_variable(config[CONF_FINGERPRINT_GROW_ID]) for key in [ CONF_FINGERPRINT_COUNT, @@ -60,5 +60,5 @@ def to_code(config): if key not in config: continue conf = config[key] - sens = yield sensor.new_sensor(conf) + sens = await sensor.new_sensor(conf) cg.add(getattr(hub, f"set_{key}_sensor")(sens)) diff --git a/esphome/components/font/__init__.py b/esphome/components/font/__init__.py index b54342d586..11bbedd80b 100644 --- a/esphome/components/font/__init__.py +++ b/esphome/components/font/__init__.py @@ -92,7 +92,7 @@ FONT_SCHEMA = cv.Schema( CONFIG_SCHEMA = cv.All(validate_pillow_installed, FONT_SCHEMA) -def to_code(config): +async def to_code(config): from PIL import ImageFont path = CORE.relative_config_path(config[CONF_FILE]) diff --git a/esphome/components/fujitsu_general/climate.py b/esphome/components/fujitsu_general/climate.py index d58049e3f2..427721f2db 100644 --- a/esphome/components/fujitsu_general/climate.py +++ b/esphome/components/fujitsu_general/climate.py @@ -17,6 +17,6 @@ CONFIG_SCHEMA = climate_ir.CLIMATE_IR_WITH_RECEIVER_SCHEMA.extend( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield climate_ir.register_climate_ir(var, config) + await climate_ir.register_climate_ir(var, config) diff --git a/esphome/components/gpio/binary_sensor/__init__.py b/esphome/components/gpio/binary_sensor/__init__.py index 4a24efcdb0..4d91b81a44 100644 --- a/esphome/components/gpio/binary_sensor/__init__.py +++ b/esphome/components/gpio/binary_sensor/__init__.py @@ -17,10 +17,10 @@ CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield binary_sensor.register_binary_sensor(var, config) + await cg.register_component(var, config) + await binary_sensor.register_binary_sensor(var, config) - pin = yield cg.gpio_pin_expression(config[CONF_PIN]) + pin = await cg.gpio_pin_expression(config[CONF_PIN]) cg.add(var.set_pin(pin)) diff --git a/esphome/components/gpio/output/__init__.py b/esphome/components/gpio/output/__init__.py index d98a490566..2fa9f4dc78 100644 --- a/esphome/components/gpio/output/__init__.py +++ b/esphome/components/gpio/output/__init__.py @@ -15,10 +15,10 @@ CONFIG_SCHEMA = output.BINARY_OUTPUT_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield output.register_output(var, config) - yield cg.register_component(var, config) + await output.register_output(var, config) + await cg.register_component(var, config) - pin = yield cg.gpio_pin_expression(config[CONF_PIN]) + pin = await cg.gpio_pin_expression(config[CONF_PIN]) cg.add(var.set_pin(pin)) diff --git a/esphome/components/gpio/switch/__init__.py b/esphome/components/gpio/switch/__init__.py index 44a9699b84..a03e16a2c1 100644 --- a/esphome/components/gpio/switch/__init__.py +++ b/esphome/components/gpio/switch/__init__.py @@ -33,12 +33,12 @@ CONFIG_SCHEMA = switch.SWITCH_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield switch.register_switch(var, config) + await cg.register_component(var, config) + await switch.register_switch(var, config) - pin = yield cg.gpio_pin_expression(config[CONF_PIN]) + pin = await cg.gpio_pin_expression(config[CONF_PIN]) cg.add(var.set_pin(pin)) cg.add(var.set_restore_mode(config[CONF_RESTORE_MODE])) @@ -46,7 +46,7 @@ def to_code(config): if CONF_INTERLOCK in config: interlock = [] for it in config[CONF_INTERLOCK]: - lock = yield cg.get_variable(it) + lock = await cg.get_variable(it) interlock.append(lock) cg.add(var.set_interlock(interlock)) cg.add(var.set_interlock_wait_time(config[CONF_INTERLOCK_WAIT_TIME])) diff --git a/esphome/components/gps/__init__.py b/esphome/components/gps/__init__.py index c09a49315c..e982bd4dfd 100644 --- a/esphome/components/gps/__init__.py +++ b/esphome/components/gps/__init__.py @@ -58,33 +58,33 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield uart.register_uart_device(var, config) + await cg.register_component(var, config) + await uart.register_uart_device(var, config) if CONF_LATITUDE in config: - sens = yield sensor.new_sensor(config[CONF_LATITUDE]) + sens = await sensor.new_sensor(config[CONF_LATITUDE]) cg.add(var.set_latitude_sensor(sens)) if CONF_LONGITUDE in config: - sens = yield sensor.new_sensor(config[CONF_LONGITUDE]) + sens = await sensor.new_sensor(config[CONF_LONGITUDE]) cg.add(var.set_longitude_sensor(sens)) if CONF_SPEED in config: - sens = yield sensor.new_sensor(config[CONF_SPEED]) + sens = await sensor.new_sensor(config[CONF_SPEED]) cg.add(var.set_speed_sensor(sens)) if CONF_COURSE in config: - sens = yield sensor.new_sensor(config[CONF_COURSE]) + sens = await sensor.new_sensor(config[CONF_COURSE]) cg.add(var.set_course_sensor(sens)) if CONF_ALTITUDE in config: - sens = yield sensor.new_sensor(config[CONF_ALTITUDE]) + sens = await sensor.new_sensor(config[CONF_ALTITUDE]) cg.add(var.set_altitude_sensor(sens)) if CONF_SATELLITES in config: - sens = yield sensor.new_sensor(config[CONF_SATELLITES]) + sens = await sensor.new_sensor(config[CONF_SATELLITES]) cg.add(var.set_satellites_sensor(sens)) # https://platformio.org/lib/show/1655/TinyGPSPlus diff --git a/esphome/components/gps/time/__init__.py b/esphome/components/gps/time/__init__.py index 24ea263f6c..1dae22a2b2 100644 --- a/esphome/components/gps/time/__init__.py +++ b/esphome/components/gps/time/__init__.py @@ -18,10 +18,10 @@ CONFIG_SCHEMA = time_.TIME_SCHEMA.extend( ).extend(cv.polling_component_schema("5min")) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield time_.register_time(var, config) - yield cg.register_component(var, config) + await time_.register_time(var, config) + await cg.register_component(var, config) - paren = yield cg.get_variable(config[CONF_GPS_ID]) + paren = await cg.get_variable(config[CONF_GPS_ID]) cg.add(paren.register_listener(var)) diff --git a/esphome/components/hbridge/light.py b/esphome/components/hbridge/light.py index 6c695fbd4a..b4ae45977a 100644 --- a/esphome/components/hbridge/light.py +++ b/esphome/components/hbridge/light.py @@ -17,12 +17,12 @@ CONFIG_SCHEMA = light.RGB_LIGHT_SCHEMA.extend( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_OUTPUT_ID]) - yield cg.register_component(var, config) - yield light.register_light(var, config) + await cg.register_component(var, config) + await light.register_light(var, config) - hside = yield cg.get_variable(config[CONF_PIN_A]) + hside = await cg.get_variable(config[CONF_PIN_A]) cg.add(var.set_pina_pin(hside)) - lside = yield cg.get_variable(config[CONF_PIN_B]) + lside = await cg.get_variable(config[CONF_PIN_B]) cg.add(var.set_pinb_pin(lside)) diff --git a/esphome/components/hdc1080/sensor.py b/esphome/components/hdc1080/sensor.py index 15a92cccf2..0995f98589 100644 --- a/esphome/components/hdc1080/sensor.py +++ b/esphome/components/hdc1080/sensor.py @@ -36,15 +36,15 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) if CONF_TEMPERATURE in config: - sens = yield sensor.new_sensor(config[CONF_TEMPERATURE]) + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) cg.add(var.set_temperature(sens)) if CONF_HUMIDITY in config: - sens = yield sensor.new_sensor(config[CONF_HUMIDITY]) + sens = await sensor.new_sensor(config[CONF_HUMIDITY]) cg.add(var.set_humidity(sens)) diff --git a/esphome/components/hitachi_ac344/climate.py b/esphome/components/hitachi_ac344/climate.py index 9ae0cd39de..94b34eb955 100644 --- a/esphome/components/hitachi_ac344/climate.py +++ b/esphome/components/hitachi_ac344/climate.py @@ -15,6 +15,6 @@ CONFIG_SCHEMA = climate_ir.CLIMATE_IR_WITH_RECEIVER_SCHEMA.extend( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield climate_ir.register_climate_ir(var, config) + await climate_ir.register_climate_ir(var, config) diff --git a/esphome/components/hlw8012/sensor.py b/esphome/components/hlw8012/sensor.py index 28aa24d7cd..aeab94a05c 100644 --- a/esphome/components/hlw8012/sensor.py +++ b/esphome/components/hlw8012/sensor.py @@ -70,28 +70,28 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.polling_component_schema("60s")) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) + await cg.register_component(var, config) - sel = yield cg.gpio_pin_expression(config[CONF_SEL_PIN]) + sel = await cg.gpio_pin_expression(config[CONF_SEL_PIN]) cg.add(var.set_sel_pin(sel)) - cf = yield cg.gpio_pin_expression(config[CONF_CF_PIN]) + cf = await cg.gpio_pin_expression(config[CONF_CF_PIN]) cg.add(var.set_cf_pin(cf)) - cf1 = yield cg.gpio_pin_expression(config[CONF_CF1_PIN]) + cf1 = await cg.gpio_pin_expression(config[CONF_CF1_PIN]) cg.add(var.set_cf1_pin(cf1)) if CONF_VOLTAGE in config: - sens = yield sensor.new_sensor(config[CONF_VOLTAGE]) + sens = await sensor.new_sensor(config[CONF_VOLTAGE]) cg.add(var.set_voltage_sensor(sens)) if CONF_CURRENT in config: - sens = yield sensor.new_sensor(config[CONF_CURRENT]) + sens = await sensor.new_sensor(config[CONF_CURRENT]) cg.add(var.set_current_sensor(sens)) if CONF_POWER in config: - sens = yield sensor.new_sensor(config[CONF_POWER]) + sens = await sensor.new_sensor(config[CONF_POWER]) cg.add(var.set_power_sensor(sens)) if CONF_ENERGY in config: - sens = yield sensor.new_sensor(config[CONF_ENERGY]) + sens = await sensor.new_sensor(config[CONF_ENERGY]) cg.add(var.set_energy_sensor(sens)) cg.add(var.set_current_resistor(config[CONF_CURRENT_RESISTOR])) cg.add(var.set_voltage_divider(config[CONF_VOLTAGE_DIVIDER])) diff --git a/esphome/components/hm3301/sensor.py b/esphome/components/hm3301/sensor.py index 14ca2e77ba..6d77841d20 100644 --- a/esphome/components/hm3301/sensor.py +++ b/esphome/components/hm3301/sensor.py @@ -76,25 +76,25 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) if CONF_PM_1_0 in config: - sens = yield sensor.new_sensor(config[CONF_PM_1_0]) + sens = await sensor.new_sensor(config[CONF_PM_1_0]) cg.add(var.set_pm_1_0_sensor(sens)) if CONF_PM_2_5 in config: - sens = yield sensor.new_sensor(config[CONF_PM_2_5]) + sens = await sensor.new_sensor(config[CONF_PM_2_5]) cg.add(var.set_pm_2_5_sensor(sens)) if CONF_PM_10_0 in config: - sens = yield sensor.new_sensor(config[CONF_PM_10_0]) + sens = await sensor.new_sensor(config[CONF_PM_10_0]) cg.add(var.set_pm_10_0_sensor(sens)) if CONF_AQI in config: - sens = yield sensor.new_sensor(config[CONF_AQI]) + sens = await sensor.new_sensor(config[CONF_AQI]) cg.add(var.set_aqi_sensor(sens)) cg.add(var.set_aqi_calculation_type(config[CONF_AQI][CONF_CALCULATION_TYPE])) diff --git a/esphome/components/hmc5883l/sensor.py b/esphome/components/hmc5883l/sensor.py index d057caf030..c615f929ee 100644 --- a/esphome/components/hmc5883l/sensor.py +++ b/esphome/components/hmc5883l/sensor.py @@ -115,23 +115,23 @@ def auto_data_rate(config): return HMC5883LDatarates[75] -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) cg.add(var.set_oversampling(config[CONF_OVERSAMPLING])) cg.add(var.set_datarate(auto_data_rate(config))) cg.add(var.set_range(config[CONF_RANGE])) if CONF_FIELD_STRENGTH_X in config: - sens = yield sensor.new_sensor(config[CONF_FIELD_STRENGTH_X]) + sens = await sensor.new_sensor(config[CONF_FIELD_STRENGTH_X]) cg.add(var.set_x_sensor(sens)) if CONF_FIELD_STRENGTH_Y in config: - sens = yield sensor.new_sensor(config[CONF_FIELD_STRENGTH_Y]) + sens = await sensor.new_sensor(config[CONF_FIELD_STRENGTH_Y]) cg.add(var.set_y_sensor(sens)) if CONF_FIELD_STRENGTH_Z in config: - sens = yield sensor.new_sensor(config[CONF_FIELD_STRENGTH_Z]) + sens = await sensor.new_sensor(config[CONF_FIELD_STRENGTH_Z]) cg.add(var.set_z_sensor(sens)) if CONF_HEADING in config: - sens = yield sensor.new_sensor(config[CONF_HEADING]) + sens = await sensor.new_sensor(config[CONF_HEADING]) cg.add(var.set_heading_sensor(sens)) diff --git a/esphome/components/homeassistant/binary_sensor/__init__.py b/esphome/components/homeassistant/binary_sensor/__init__.py index cf2f3092af..4972466aac 100644 --- a/esphome/components/homeassistant/binary_sensor/__init__.py +++ b/esphome/components/homeassistant/binary_sensor/__init__.py @@ -18,10 +18,10 @@ CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield binary_sensor.register_binary_sensor(var, config) + await cg.register_component(var, config) + await binary_sensor.register_binary_sensor(var, config) cg.add(var.set_entity_id(config[CONF_ENTITY_ID])) if CONF_ATTRIBUTE in config: diff --git a/esphome/components/homeassistant/sensor/__init__.py b/esphome/components/homeassistant/sensor/__init__.py index c754ae295b..771db25b85 100644 --- a/esphome/components/homeassistant/sensor/__init__.py +++ b/esphome/components/homeassistant/sensor/__init__.py @@ -28,10 +28,10 @@ CONFIG_SCHEMA = sensor.sensor_schema( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield sensor.register_sensor(var, config) + await cg.register_component(var, config) + await sensor.register_sensor(var, config) cg.add(var.set_entity_id(config[CONF_ENTITY_ID])) if CONF_ATTRIBUTE in config: diff --git a/esphome/components/homeassistant/text_sensor/__init__.py b/esphome/components/homeassistant/text_sensor/__init__.py index ed14615b80..b63d45b9ce 100644 --- a/esphome/components/homeassistant/text_sensor/__init__.py +++ b/esphome/components/homeassistant/text_sensor/__init__.py @@ -19,10 +19,10 @@ CONFIG_SCHEMA = text_sensor.TEXT_SENSOR_SCHEMA.extend( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield text_sensor.register_text_sensor(var, config) + await cg.register_component(var, config) + await text_sensor.register_text_sensor(var, config) cg.add(var.set_entity_id(config[CONF_ENTITY_ID])) if CONF_ATTRIBUTE in config: diff --git a/esphome/components/homeassistant/time/__init__.py b/esphome/components/homeassistant/time/__init__.py index e995421302..0040988794 100644 --- a/esphome/components/homeassistant/time/__init__.py +++ b/esphome/components/homeassistant/time/__init__.py @@ -15,8 +15,8 @@ CONFIG_SCHEMA = time_.TIME_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield time_.register_time(var, config) - yield cg.register_component(var, config) + await time_.register_time(var, config) + await cg.register_component(var, config) cg.add_define("USE_HOMEASSISTANT_TIME") diff --git a/esphome/components/http_request/__init__.py b/esphome/components/http_request/__init__.py index ef664a9d35..6512b59d52 100644 --- a/esphome/components/http_request/__init__.py +++ b/esphome/components/http_request/__init__.py @@ -107,11 +107,11 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) cg.add(var.set_timeout(config[CONF_TIMEOUT])) cg.add(var.set_useragent(config[CONF_USERAGENT])) - yield cg.register_component(var, config) + await cg.register_component(var, config) HTTP_REQUEST_ACTION_SCHEMA = cv.Schema( diff --git a/esphome/components/htu21d/sensor.py b/esphome/components/htu21d/sensor.py index 258681a5aa..596a7d4531 100644 --- a/esphome/components/htu21d/sensor.py +++ b/esphome/components/htu21d/sensor.py @@ -36,15 +36,15 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) if CONF_TEMPERATURE in config: - sens = yield sensor.new_sensor(config[CONF_TEMPERATURE]) + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) cg.add(var.set_temperature(sens)) if CONF_HUMIDITY in config: - sens = yield sensor.new_sensor(config[CONF_HUMIDITY]) + sens = await sensor.new_sensor(config[CONF_HUMIDITY]) cg.add(var.set_humidity(sens)) diff --git a/esphome/components/hx711/sensor.py b/esphome/components/hx711/sensor.py index 191a7386e6..b249ca8f77 100644 --- a/esphome/components/hx711/sensor.py +++ b/esphome/components/hx711/sensor.py @@ -37,13 +37,13 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield sensor.register_sensor(var, config) + await cg.register_component(var, config) + await sensor.register_sensor(var, config) - dout_pin = yield cg.gpio_pin_expression(config[CONF_DOUT_PIN]) + dout_pin = await cg.gpio_pin_expression(config[CONF_DOUT_PIN]) cg.add(var.set_dout_pin(dout_pin)) - sck_pin = yield cg.gpio_pin_expression(config[CONF_CLK_PIN]) + sck_pin = await cg.gpio_pin_expression(config[CONF_CLK_PIN]) cg.add(var.set_sck_pin(sck_pin)) cg.add(var.set_gain(config[CONF_GAIN])) diff --git a/esphome/components/ili9341/display.py b/esphome/components/ili9341/display.py index 8c1a28ea5d..450a958c56 100644 --- a/esphome/components/ili9341/display.py +++ b/esphome/components/ili9341/display.py @@ -47,7 +47,7 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): if config[CONF_MODEL] == "M5STACK": lcd_type = ILI9341M5Stack if config[CONF_MODEL] == "TFT_2.4": @@ -55,21 +55,21 @@ def to_code(config): rhs = lcd_type.new() var = cg.Pvariable(config[CONF_ID], rhs) - yield cg.register_component(var, config) - yield display.register_display(var, config) - yield spi.register_spi_device(var, config) + await cg.register_component(var, config) + await display.register_display(var, config) + await spi.register_spi_device(var, config) cg.add(var.set_model(config[CONF_MODEL])) - dc = yield cg.gpio_pin_expression(config[CONF_DC_PIN]) + dc = await cg.gpio_pin_expression(config[CONF_DC_PIN]) cg.add(var.set_dc_pin(dc)) if CONF_LAMBDA in config: - lambda_ = yield cg.process_lambda( + lambda_ = await cg.process_lambda( config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void ) cg.add(var.set_writer(lambda_)) if CONF_RESET_PIN in config: - reset = yield cg.gpio_pin_expression(config[CONF_RESET_PIN]) + reset = await cg.gpio_pin_expression(config[CONF_RESET_PIN]) cg.add(var.set_reset_pin(reset)) if CONF_LED_PIN in config: - led_pin = yield cg.gpio_pin_expression(config[CONF_LED_PIN]) + led_pin = await cg.gpio_pin_expression(config[CONF_LED_PIN]) cg.add(var.set_led_pin(led_pin)) diff --git a/esphome/components/image/__init__.py b/esphome/components/image/__init__.py index b629779690..b946a86bc4 100644 --- a/esphome/components/image/__init__.py +++ b/esphome/components/image/__init__.py @@ -39,7 +39,7 @@ IMAGE_SCHEMA = cv.Schema( CONFIG_SCHEMA = cv.All(font.validate_pillow_installed, IMAGE_SCHEMA) -def to_code(config): +async def to_code(config): from PIL import Image path = CORE.relative_config_path(config[CONF_FILE]) diff --git a/esphome/components/ina219/sensor.py b/esphome/components/ina219/sensor.py index d122754b88..29241c062e 100644 --- a/esphome/components/ina219/sensor.py +++ b/esphome/components/ina219/sensor.py @@ -58,27 +58,27 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) cg.add(var.set_shunt_resistance_ohm(config[CONF_SHUNT_RESISTANCE])) cg.add(var.set_max_current_a(config[CONF_MAX_CURRENT])) cg.add(var.set_max_voltage_v(config[CONF_MAX_VOLTAGE])) if CONF_BUS_VOLTAGE in config: - sens = yield sensor.new_sensor(config[CONF_BUS_VOLTAGE]) + sens = await sensor.new_sensor(config[CONF_BUS_VOLTAGE]) cg.add(var.set_bus_voltage_sensor(sens)) if CONF_SHUNT_VOLTAGE in config: - sens = yield sensor.new_sensor(config[CONF_SHUNT_VOLTAGE]) + sens = await sensor.new_sensor(config[CONF_SHUNT_VOLTAGE]) cg.add(var.set_shunt_voltage_sensor(sens)) if CONF_CURRENT in config: - sens = yield sensor.new_sensor(config[CONF_CURRENT]) + sens = await sensor.new_sensor(config[CONF_CURRENT]) cg.add(var.set_current_sensor(sens)) if CONF_POWER in config: - sens = yield sensor.new_sensor(config[CONF_POWER]) + sens = await sensor.new_sensor(config[CONF_POWER]) cg.add(var.set_power_sensor(sens)) diff --git a/esphome/components/ina226/sensor.py b/esphome/components/ina226/sensor.py index 2b7346fbe2..d6d385f5cb 100644 --- a/esphome/components/ina226/sensor.py +++ b/esphome/components/ina226/sensor.py @@ -54,27 +54,27 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) cg.add(var.set_shunt_resistance_ohm(config[CONF_SHUNT_RESISTANCE])) cg.add(var.set_max_current_a(config[CONF_MAX_CURRENT])) if CONF_BUS_VOLTAGE in config: - sens = yield sensor.new_sensor(config[CONF_BUS_VOLTAGE]) + sens = await sensor.new_sensor(config[CONF_BUS_VOLTAGE]) cg.add(var.set_bus_voltage_sensor(sens)) if CONF_SHUNT_VOLTAGE in config: - sens = yield sensor.new_sensor(config[CONF_SHUNT_VOLTAGE]) + sens = await sensor.new_sensor(config[CONF_SHUNT_VOLTAGE]) cg.add(var.set_shunt_voltage_sensor(sens)) if CONF_CURRENT in config: - sens = yield sensor.new_sensor(config[CONF_CURRENT]) + sens = await sensor.new_sensor(config[CONF_CURRENT]) cg.add(var.set_current_sensor(sens)) if CONF_POWER in config: - sens = yield sensor.new_sensor(config[CONF_POWER]) + sens = await sensor.new_sensor(config[CONF_POWER]) cg.add(var.set_power_sensor(sens)) diff --git a/esphome/components/ina3221/sensor.py b/esphome/components/ina3221/sensor.py index c055e149b7..b97022ca27 100644 --- a/esphome/components/ina3221/sensor.py +++ b/esphome/components/ina3221/sensor.py @@ -62,10 +62,10 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) for i, channel in enumerate([CONF_CHANNEL_1, CONF_CHANNEL_2, CONF_CHANNEL_3]): if channel not in config: @@ -74,14 +74,14 @@ def to_code(config): if CONF_SHUNT_RESISTANCE in conf: cg.add(var.set_shunt_resistance(i, conf[CONF_SHUNT_RESISTANCE])) if CONF_BUS_VOLTAGE in conf: - sens = yield sensor.new_sensor(conf[CONF_BUS_VOLTAGE]) + sens = await sensor.new_sensor(conf[CONF_BUS_VOLTAGE]) cg.add(var.set_bus_voltage_sensor(i, sens)) if CONF_SHUNT_VOLTAGE in conf: - sens = yield sensor.new_sensor(conf[CONF_SHUNT_VOLTAGE]) + sens = await sensor.new_sensor(conf[CONF_SHUNT_VOLTAGE]) cg.add(var.set_shunt_voltage_sensor(i, sens)) if CONF_CURRENT in conf: - sens = yield sensor.new_sensor(conf[CONF_CURRENT]) + sens = await sensor.new_sensor(conf[CONF_CURRENT]) cg.add(var.set_current_sensor(i, sens)) if CONF_POWER in conf: - sens = yield sensor.new_sensor(conf[CONF_POWER]) + sens = await sensor.new_sensor(conf[CONF_POWER]) cg.add(var.set_power_sensor(i, sens)) diff --git a/esphome/components/inkbird_ibsth1_mini/sensor.py b/esphome/components/inkbird_ibsth1_mini/sensor.py index c67acb8595..cc12be3bf4 100644 --- a/esphome/components/inkbird_ibsth1_mini/sensor.py +++ b/esphome/components/inkbird_ibsth1_mini/sensor.py @@ -44,19 +44,19 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield esp32_ble_tracker.register_ble_device(var, config) + await cg.register_component(var, config) + await esp32_ble_tracker.register_ble_device(var, config) cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) if CONF_TEMPERATURE in config: - sens = yield sensor.new_sensor(config[CONF_TEMPERATURE]) + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) cg.add(var.set_temperature(sens)) if CONF_HUMIDITY in config: - sens = yield sensor.new_sensor(config[CONF_HUMIDITY]) + sens = await sensor.new_sensor(config[CONF_HUMIDITY]) cg.add(var.set_humidity(sens)) if CONF_BATTERY_LEVEL in config: - sens = yield sensor.new_sensor(config[CONF_BATTERY_LEVEL]) + sens = await sensor.new_sensor(config[CONF_BATTERY_LEVEL]) cg.add(var.set_battery_level(sens)) diff --git a/esphome/components/inkplate6/display.py b/esphome/components/inkplate6/display.py index 323936d2c4..8e00a69751 100644 --- a/esphome/components/inkplate6/display.py +++ b/esphome/components/inkplate6/display.py @@ -94,15 +94,15 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield display.register_display(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await display.register_display(var, config) + await i2c.register_i2c_device(var, config) if CONF_LAMBDA in config: - lambda_ = yield cg.process_lambda( + lambda_ = await cg.process_lambda( config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void ) cg.add(var.set_writer(lambda_)) @@ -111,61 +111,61 @@ def to_code(config): cg.add(var.set_partial_updating(config[CONF_PARTIAL_UPDATING])) cg.add(var.set_full_update_every(config[CONF_FULL_UPDATE_EVERY])) - ckv = yield cg.gpio_pin_expression(config[CONF_CKV_PIN]) + ckv = await cg.gpio_pin_expression(config[CONF_CKV_PIN]) cg.add(var.set_ckv_pin(ckv)) - gmod = yield cg.gpio_pin_expression(config[CONF_GMOD_PIN]) + gmod = await cg.gpio_pin_expression(config[CONF_GMOD_PIN]) cg.add(var.set_gmod_pin(gmod)) - gpio0_enable = yield cg.gpio_pin_expression(config[CONF_GPIO0_ENABLE_PIN]) + gpio0_enable = await cg.gpio_pin_expression(config[CONF_GPIO0_ENABLE_PIN]) cg.add(var.set_gpio0_enable_pin(gpio0_enable)) - oe = yield cg.gpio_pin_expression(config[CONF_OE_PIN]) + oe = await cg.gpio_pin_expression(config[CONF_OE_PIN]) cg.add(var.set_oe_pin(oe)) - powerup = yield cg.gpio_pin_expression(config[CONF_POWERUP_PIN]) + powerup = await cg.gpio_pin_expression(config[CONF_POWERUP_PIN]) cg.add(var.set_powerup_pin(powerup)) - sph = yield cg.gpio_pin_expression(config[CONF_SPH_PIN]) + sph = await cg.gpio_pin_expression(config[CONF_SPH_PIN]) cg.add(var.set_sph_pin(sph)) - spv = yield cg.gpio_pin_expression(config[CONF_SPV_PIN]) + spv = await cg.gpio_pin_expression(config[CONF_SPV_PIN]) cg.add(var.set_spv_pin(spv)) - vcom = yield cg.gpio_pin_expression(config[CONF_VCOM_PIN]) + vcom = await cg.gpio_pin_expression(config[CONF_VCOM_PIN]) cg.add(var.set_vcom_pin(vcom)) - wakeup = yield cg.gpio_pin_expression(config[CONF_WAKEUP_PIN]) + wakeup = await cg.gpio_pin_expression(config[CONF_WAKEUP_PIN]) cg.add(var.set_wakeup_pin(wakeup)) - cl = yield cg.gpio_pin_expression(config[CONF_CL_PIN]) + cl = await cg.gpio_pin_expression(config[CONF_CL_PIN]) cg.add(var.set_cl_pin(cl)) - le = yield cg.gpio_pin_expression(config[CONF_LE_PIN]) + le = await cg.gpio_pin_expression(config[CONF_LE_PIN]) cg.add(var.set_le_pin(le)) - display_data_0 = yield cg.gpio_pin_expression(config[CONF_DISPLAY_DATA_0_PIN]) + display_data_0 = await cg.gpio_pin_expression(config[CONF_DISPLAY_DATA_0_PIN]) cg.add(var.set_display_data_0_pin(display_data_0)) - display_data_1 = yield cg.gpio_pin_expression(config[CONF_DISPLAY_DATA_1_PIN]) + display_data_1 = await cg.gpio_pin_expression(config[CONF_DISPLAY_DATA_1_PIN]) cg.add(var.set_display_data_1_pin(display_data_1)) - display_data_2 = yield cg.gpio_pin_expression(config[CONF_DISPLAY_DATA_2_PIN]) + display_data_2 = await cg.gpio_pin_expression(config[CONF_DISPLAY_DATA_2_PIN]) cg.add(var.set_display_data_2_pin(display_data_2)) - display_data_3 = yield cg.gpio_pin_expression(config[CONF_DISPLAY_DATA_3_PIN]) + display_data_3 = await cg.gpio_pin_expression(config[CONF_DISPLAY_DATA_3_PIN]) cg.add(var.set_display_data_3_pin(display_data_3)) - display_data_4 = yield cg.gpio_pin_expression(config[CONF_DISPLAY_DATA_4_PIN]) + display_data_4 = await cg.gpio_pin_expression(config[CONF_DISPLAY_DATA_4_PIN]) cg.add(var.set_display_data_4_pin(display_data_4)) - display_data_5 = yield cg.gpio_pin_expression(config[CONF_DISPLAY_DATA_5_PIN]) + display_data_5 = await cg.gpio_pin_expression(config[CONF_DISPLAY_DATA_5_PIN]) cg.add(var.set_display_data_5_pin(display_data_5)) - display_data_6 = yield cg.gpio_pin_expression(config[CONF_DISPLAY_DATA_6_PIN]) + display_data_6 = await cg.gpio_pin_expression(config[CONF_DISPLAY_DATA_6_PIN]) cg.add(var.set_display_data_6_pin(display_data_6)) - display_data_7 = yield cg.gpio_pin_expression(config[CONF_DISPLAY_DATA_7_PIN]) + display_data_7 = await cg.gpio_pin_expression(config[CONF_DISPLAY_DATA_7_PIN]) cg.add(var.set_display_data_7_pin(display_data_7)) cg.add_build_flag("-DBOARD_HAS_PSRAM") diff --git a/esphome/components/integration/sensor.py b/esphome/components/integration/sensor.py index 81b588610e..5ce5352fd0 100644 --- a/esphome/components/integration/sensor.py +++ b/esphome/components/integration/sensor.py @@ -41,13 +41,13 @@ CONFIG_SCHEMA = sensor.SENSOR_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield sensor.register_sensor(var, config) + await cg.register_component(var, config) + await sensor.register_sensor(var, config) - sens = yield cg.get_variable(config[CONF_SENSOR]) + sens = await cg.get_variable(config[CONF_SENSOR]) cg.add(var.set_sensor(sens)) cg.add(var.set_time(config[CONF_TIME_UNIT])) cg.add(var.set_method(config[CONF_INTEGRATION_METHOD])) diff --git a/esphome/components/interval/__init__.py b/esphome/components/interval/__init__.py index 7d04a9e9ab..4514f80ba3 100644 --- a/esphome/components/interval/__init__.py +++ b/esphome/components/interval/__init__.py @@ -19,10 +19,10 @@ CONFIG_SCHEMA = automation.validate_automation( ) -def to_code(config): +async def to_code(config): for conf in config: var = cg.new_Pvariable(conf[CONF_ID]) - yield cg.register_component(var, conf) - yield automation.build_automation(var, [], conf) + await cg.register_component(var, conf) + await automation.build_automation(var, [], conf) cg.add(var.set_update_interval(conf[CONF_INTERVAL])) diff --git a/esphome/components/lcd_gpio/display.py b/esphome/components/lcd_gpio/display.py index 28c6df2efd..6b0a2f69de 100644 --- a/esphome/components/lcd_gpio/display.py +++ b/esphome/components/lcd_gpio/display.py @@ -39,25 +39,25 @@ CONFIG_SCHEMA = lcd_base.LCD_SCHEMA.extend( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield lcd_base.setup_lcd_display(var, config) + await lcd_base.setup_lcd_display(var, config) pins_ = [] for conf in config[CONF_DATA_PINS]: - pins_.append((yield cg.gpio_pin_expression(conf))) + pins_.append((await cg.gpio_pin_expression(conf))) cg.add(var.set_data_pins(*pins_)) - enable = yield cg.gpio_pin_expression(config[CONF_ENABLE_PIN]) + enable = await cg.gpio_pin_expression(config[CONF_ENABLE_PIN]) cg.add(var.set_enable_pin(enable)) - rs = yield cg.gpio_pin_expression(config[CONF_RS_PIN]) + rs = await cg.gpio_pin_expression(config[CONF_RS_PIN]) cg.add(var.set_rs_pin(rs)) if CONF_RW_PIN in config: - rw = yield cg.gpio_pin_expression(config[CONF_RW_PIN]) + rw = await cg.gpio_pin_expression(config[CONF_RW_PIN]) cg.add(var.set_rw_pin(rw)) if CONF_LAMBDA in config: - lambda_ = yield cg.process_lambda( + lambda_ = await cg.process_lambda( config[CONF_LAMBDA], [(GPIOLCDDisplay.operator("ref"), "it")], return_type=cg.void, diff --git a/esphome/components/lcd_pcf8574/display.py b/esphome/components/lcd_pcf8574/display.py index 6499a8369e..5d9dd7adba 100644 --- a/esphome/components/lcd_pcf8574/display.py +++ b/esphome/components/lcd_pcf8574/display.py @@ -18,13 +18,13 @@ CONFIG_SCHEMA = lcd_base.LCD_SCHEMA.extend( ).extend(i2c.i2c_device_schema(0x3F)) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield lcd_base.setup_lcd_display(var, config) - yield i2c.register_i2c_device(var, config) + await lcd_base.setup_lcd_display(var, config) + await i2c.register_i2c_device(var, config) if CONF_LAMBDA in config: - lambda_ = yield cg.process_lambda( + lambda_ = await cg.process_lambda( config[CONF_LAMBDA], [(PCF8574LCDDisplay.operator("ref"), "it")], return_type=cg.void, diff --git a/esphome/components/ledc/output.py b/esphome/components/ledc/output.py index df746fff4f..4431be2ed5 100644 --- a/esphome/components/ledc/output.py +++ b/esphome/components/ledc/output.py @@ -58,11 +58,11 @@ CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): - gpio = yield cg.gpio_pin_expression(config[CONF_PIN]) +async def to_code(config): + gpio = await cg.gpio_pin_expression(config[CONF_PIN]) var = cg.new_Pvariable(config[CONF_ID], gpio) - yield cg.register_component(var, config) - yield output.register_output(var, config) + await cg.register_component(var, config) + await output.register_output(var, config) if CONF_CHANNEL in config: cg.add(var.set_channel(config[CONF_CHANNEL])) cg.add(var.set_frequency(config[CONF_FREQUENCY])) diff --git a/esphome/components/max31855/sensor.py b/esphome/components/max31855/sensor.py index 5d3fa461b1..55de8d681e 100644 --- a/esphome/components/max31855/sensor.py +++ b/esphome/components/max31855/sensor.py @@ -29,11 +29,11 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield spi.register_spi_device(var, config) - yield sensor.register_sensor(var, config) + await cg.register_component(var, config) + await spi.register_spi_device(var, config) + await sensor.register_sensor(var, config) if CONF_REFERENCE_TEMPERATURE in config: - tc_ref = yield sensor.new_sensor(config[CONF_REFERENCE_TEMPERATURE]) + tc_ref = await sensor.new_sensor(config[CONF_REFERENCE_TEMPERATURE]) cg.add(var.set_reference_sensor(tc_ref)) diff --git a/esphome/components/max31856/sensor.py b/esphome/components/max31856/sensor.py index afbb637609..5c7b7f1f0e 100644 --- a/esphome/components/max31856/sensor.py +++ b/esphome/components/max31856/sensor.py @@ -35,9 +35,9 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield spi.register_spi_device(var, config) - yield sensor.register_sensor(var, config) + await cg.register_component(var, config) + await spi.register_spi_device(var, config) + await sensor.register_sensor(var, config) cg.add(var.set_filter(config[CONF_MAINS_FILTER])) diff --git a/esphome/components/max31865/sensor.py b/esphome/components/max31865/sensor.py index bebc42c95e..addedc8296 100644 --- a/esphome/components/max31865/sensor.py +++ b/esphome/components/max31865/sensor.py @@ -45,11 +45,11 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield spi.register_spi_device(var, config) - yield sensor.register_sensor(var, config) + await cg.register_component(var, config) + await spi.register_spi_device(var, config) + await sensor.register_sensor(var, config) cg.add(var.set_reference_resistance(config[CONF_REFERENCE_RESISTANCE])) cg.add(var.set_nominal_resistance(config[CONF_RTD_NOMINAL_RESISTANCE])) cg.add(var.set_filter(config[CONF_MAINS_FILTER])) diff --git a/esphome/components/max6675/sensor.py b/esphome/components/max6675/sensor.py index 0713654f84..6697f2ae90 100644 --- a/esphome/components/max6675/sensor.py +++ b/esphome/components/max6675/sensor.py @@ -20,8 +20,8 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield spi.register_spi_device(var, config) - yield sensor.register_sensor(var, config) + await cg.register_component(var, config) + await spi.register_spi_device(var, config) + await sensor.register_sensor(var, config) diff --git a/esphome/components/max7219/display.py b/esphome/components/max7219/display.py index fba4d7ca76..391d033f24 100644 --- a/esphome/components/max7219/display.py +++ b/esphome/components/max7219/display.py @@ -27,18 +27,18 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield spi.register_spi_device(var, config) - yield display.register_display(var, config) + await cg.register_component(var, config) + await spi.register_spi_device(var, config) + await display.register_display(var, config) cg.add(var.set_num_chips(config[CONF_NUM_CHIPS])) cg.add(var.set_intensity(config[CONF_INTENSITY])) cg.add(var.set_reverse(config[CONF_REVERSE_ENABLE])) if CONF_LAMBDA in config: - lambda_ = yield cg.process_lambda( + lambda_ = await cg.process_lambda( config[CONF_LAMBDA], [(MAX7219ComponentRef, "it")], return_type=cg.void ) cg.add(var.set_writer(lambda_)) diff --git a/esphome/components/max7219digit/display.py b/esphome/components/max7219digit/display.py index 4863312b5a..e1ca128699 100644 --- a/esphome/components/max7219digit/display.py +++ b/esphome/components/max7219digit/display.py @@ -60,11 +60,11 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield spi.register_spi_device(var, config) - yield display.register_display(var, config) + await cg.register_component(var, config) + await spi.register_spi_device(var, config) + await display.register_display(var, config) cg.add(var.set_num_chips(config[CONF_NUM_CHIPS])) cg.add(var.set_intensity(config[CONF_INTENSITY])) @@ -77,7 +77,7 @@ def to_code(config): cg.add(var.set_reverse(config[CONF_REVERSE_ENABLE])) if CONF_LAMBDA in config: - lambda_ = yield cg.process_lambda( + lambda_ = await cg.process_lambda( config[CONF_LAMBDA], [(MAX7219ComponentRef, "it")], return_type=cg.void ) cg.add(var.set_writer(lambda_)) diff --git a/esphome/components/mcp23008/__init__.py b/esphome/components/mcp23008/__init__.py index ae43e9ff0a..a534c9f87f 100644 --- a/esphome/components/mcp23008/__init__.py +++ b/esphome/components/mcp23008/__init__.py @@ -23,6 +23,6 @@ CONFIG_SCHEMA = ( ) -def to_code(config): - var = yield mcp23xxx_base.register_mcp23xxx(config) - yield i2c.register_i2c_device(var, config) +async def to_code(config): + var = await mcp23xxx_base.register_mcp23xxx(config) + await i2c.register_i2c_device(var, config) diff --git a/esphome/components/mcp23016/__init__.py b/esphome/components/mcp23016/__init__.py index 2aa29c9cde..d1f0dad2b7 100644 --- a/esphome/components/mcp23016/__init__.py +++ b/esphome/components/mcp23016/__init__.py @@ -28,10 +28,10 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) CONF_MCP23016 = "mcp23016" diff --git a/esphome/components/mcp23017/__init__.py b/esphome/components/mcp23017/__init__.py index a86133e232..42fc37dd1d 100644 --- a/esphome/components/mcp23017/__init__.py +++ b/esphome/components/mcp23017/__init__.py @@ -23,6 +23,6 @@ CONFIG_SCHEMA = ( ) -def to_code(config): - var = yield mcp23xxx_base.register_mcp23xxx(config) - yield i2c.register_i2c_device(var, config) +async def to_code(config): + var = await mcp23xxx_base.register_mcp23xxx(config) + await i2c.register_i2c_device(var, config) diff --git a/esphome/components/mcp23s08/__init__.py b/esphome/components/mcp23s08/__init__.py index cfeb65de9b..4d3998def8 100644 --- a/esphome/components/mcp23s08/__init__.py +++ b/esphome/components/mcp23s08/__init__.py @@ -26,7 +26,7 @@ CONFIG_SCHEMA = ( ) -def to_code(config): - var = yield mcp23xxx_base.register_mcp23xxx(config) +async def to_code(config): + var = await mcp23xxx_base.register_mcp23xxx(config) cg.add(var.set_device_address(config[CONF_DEVICEADDRESS])) - yield spi.register_spi_device(var, config) + await spi.register_spi_device(var, config) diff --git a/esphome/components/mcp23s17/__init__.py b/esphome/components/mcp23s17/__init__.py index c38bd2617a..9e199f79c4 100644 --- a/esphome/components/mcp23s17/__init__.py +++ b/esphome/components/mcp23s17/__init__.py @@ -26,7 +26,7 @@ CONFIG_SCHEMA = ( ) -def to_code(config): - var = yield mcp23xxx_base.register_mcp23xxx(config) +async def to_code(config): + var = await mcp23xxx_base.register_mcp23xxx(config) cg.add(var.set_device_address(config[CONF_DEVICEADDRESS])) - yield spi.register_spi_device(var, config) + await spi.register_spi_device(var, config) diff --git a/esphome/components/mcp2515/canbus.py b/esphome/components/mcp2515/canbus.py index 0fc679d17a..c410c1af69 100644 --- a/esphome/components/mcp2515/canbus.py +++ b/esphome/components/mcp2515/canbus.py @@ -35,10 +35,10 @@ CONFIG_SCHEMA = canbus.CANBUS_SCHEMA.extend( ).extend(spi.spi_device_schema(True)) -def to_code(config): +async def to_code(config): rhs = mcp2515.new() var = cg.Pvariable(config[CONF_ID], rhs) - yield canbus.register_canbus(var, config) + await canbus.register_canbus(var, config) if CONF_CLOCK in config: canclock = CAN_CLOCK[config[CONF_CLOCK]] cg.add(var.set_mcp_clock(canclock)) @@ -46,4 +46,4 @@ def to_code(config): mode = MCP_MODE[config[CONF_MODE]] cg.add(var.set_mcp_mode(mode)) - yield spi.register_spi_device(var, config) + await spi.register_spi_device(var, config) diff --git a/esphome/components/mcp3008/__init__.py b/esphome/components/mcp3008/__init__.py index 6a0410a75b..24a48664c1 100644 --- a/esphome/components/mcp3008/__init__.py +++ b/esphome/components/mcp3008/__init__.py @@ -19,7 +19,7 @@ CONFIG_SCHEMA = cv.Schema( ).extend(spi.spi_device_schema(cs_pin_required=True)) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield spi.register_spi_device(var, config) + await cg.register_component(var, config) + await spi.register_spi_device(var, config) diff --git a/esphome/components/mcp3008/sensor.py b/esphome/components/mcp3008/sensor.py index b146158552..4fc9b83afb 100644 --- a/esphome/components/mcp3008/sensor.py +++ b/esphome/components/mcp3008/sensor.py @@ -24,8 +24,8 @@ CONFIG_SCHEMA = sensor.SENSOR_SCHEMA.extend( ).extend(cv.polling_component_schema("1s")) -def to_code(config): - parent = yield cg.get_variable(config[CONF_MCP3008_ID]) +async def to_code(config): + parent = await cg.get_variable(config[CONF_MCP3008_ID]) var = cg.new_Pvariable( config[CONF_ID], parent, @@ -33,5 +33,5 @@ def to_code(config): config[CONF_NUMBER], config[CONF_REFERENCE_VOLTAGE], ) - yield cg.register_component(var, config) - yield sensor.register_sensor(var, config) + await cg.register_component(var, config) + await sensor.register_sensor(var, config) diff --git a/esphome/components/mcp4725/output.py b/esphome/components/mcp4725/output.py index a010ca9970..8f8b80d927 100644 --- a/esphome/components/mcp4725/output.py +++ b/esphome/components/mcp4725/output.py @@ -19,8 +19,8 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) - yield output.register_output(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + await output.register_output(var, config) diff --git a/esphome/components/mcp9808/sensor.py b/esphome/components/mcp9808/sensor.py index 4973d41ff5..f11d5cd755 100644 --- a/esphome/components/mcp9808/sensor.py +++ b/esphome/components/mcp9808/sensor.py @@ -23,8 +23,8 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) - yield sensor.register_sensor(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + await sensor.register_sensor(var, config) diff --git a/esphome/components/mhz19/sensor.py b/esphome/components/mhz19/sensor.py index 6989814ada..abe33cae7e 100644 --- a/esphome/components/mhz19/sensor.py +++ b/esphome/components/mhz19/sensor.py @@ -45,17 +45,17 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield uart.register_uart_device(var, config) + await cg.register_component(var, config) + await uart.register_uart_device(var, config) if CONF_CO2 in config: - sens = yield sensor.new_sensor(config[CONF_CO2]) + sens = await sensor.new_sensor(config[CONF_CO2]) cg.add(var.set_co2_sensor(sens)) if CONF_TEMPERATURE in config: - sens = yield sensor.new_sensor(config[CONF_TEMPERATURE]) + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) cg.add(var.set_temperature_sensor(sens)) if CONF_AUTOMATIC_BASELINE_CALIBRATION in config: diff --git a/esphome/components/midea_ac/climate.py b/esphome/components/midea_ac/climate.py index 94aed91d4c..e0128febfb 100644 --- a/esphome/components/midea_ac/climate.py +++ b/esphome/components/midea_ac/climate.py @@ -49,21 +49,21 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield climate.register_climate(var, config) - paren = yield cg.get_variable(config[CONF_MIDEA_DONGLE_ID]) + await cg.register_component(var, config) + await climate.register_climate(var, config) + paren = await cg.get_variable(config[CONF_MIDEA_DONGLE_ID]) cg.add(var.set_midea_dongle_parent(paren)) cg.add(var.set_beeper_feedback(config[CONF_BEEPER])) cg.add(var.set_swing_horizontal(config[CONF_SWING_HORIZONTAL])) cg.add(var.set_swing_both(config[CONF_SWING_BOTH])) if CONF_OUTDOOR_TEMPERATURE in config: - sens = yield sensor.new_sensor(config[CONF_OUTDOOR_TEMPERATURE]) + sens = await sensor.new_sensor(config[CONF_OUTDOOR_TEMPERATURE]) cg.add(var.set_outdoor_temperature_sensor(sens)) if CONF_POWER_USAGE in config: - sens = yield sensor.new_sensor(config[CONF_POWER_USAGE]) + sens = await sensor.new_sensor(config[CONF_POWER_USAGE]) cg.add(var.set_power_sensor(sens)) if CONF_HUMIDITY_SETPOINT in config: - sens = yield sensor.new_sensor(config[CONF_HUMIDITY_SETPOINT]) + sens = await sensor.new_sensor(config[CONF_HUMIDITY_SETPOINT]) cg.add(var.set_humidity_setpoint_sensor(sens)) diff --git a/esphome/components/midea_dongle/__init__.py b/esphome/components/midea_dongle/__init__.py index 3efeb2661d..daa8ea6657 100644 --- a/esphome/components/midea_dongle/__init__.py +++ b/esphome/components/midea_dongle/__init__.py @@ -23,8 +23,8 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield uart.register_uart_device(var, config) + await cg.register_component(var, config) + await uart.register_uart_device(var, config) cg.add(var.use_strength_icon(config[CONF_STRENGTH_ICON])) diff --git a/esphome/components/mitsubishi/climate.py b/esphome/components/mitsubishi/climate.py index f150985d28..0df17a5d16 100644 --- a/esphome/components/mitsubishi/climate.py +++ b/esphome/components/mitsubishi/climate.py @@ -16,6 +16,6 @@ CONFIG_SCHEMA = climate_ir.CLIMATE_IR_SCHEMA.extend( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield climate_ir.register_climate_ir(var, config) + await climate_ir.register_climate_ir(var, config) diff --git a/esphome/components/modbus/__init__.py b/esphome/components/modbus/__init__.py index e71f196fca..c8e58431da 100644 --- a/esphome/components/modbus/__init__.py +++ b/esphome/components/modbus/__init__.py @@ -23,12 +23,12 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): cg.add_global(modbus_ns.using) var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) + await cg.register_component(var, config) - yield uart.register_uart_device(var, config) + await uart.register_uart_device(var, config) def modbus_device_schema(default_address): diff --git a/esphome/components/monochromatic/light.py b/esphome/components/monochromatic/light.py index 32d9981a57..8f13f58f89 100644 --- a/esphome/components/monochromatic/light.py +++ b/esphome/components/monochromatic/light.py @@ -16,9 +16,9 @@ CONFIG_SCHEMA = light.BRIGHTNESS_ONLY_LIGHT_SCHEMA.extend( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_OUTPUT_ID]) - yield light.register_light(var, config) + await light.register_light(var, config) - out = yield cg.get_variable(config[CONF_OUTPUT]) + out = await cg.get_variable(config[CONF_OUTPUT]) cg.add(var.set_output(out)) diff --git a/esphome/components/mpr121/__init__.py b/esphome/components/mpr121/__init__.py index eb3043c2b1..dabfb47ad6 100644 --- a/esphome/components/mpr121/__init__.py +++ b/esphome/components/mpr121/__init__.py @@ -35,11 +35,11 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) cg.add(var.set_touch_debounce(config[CONF_TOUCH_DEBOUNCE])) cg.add(var.set_release_debounce(config[CONF_RELEASE_DEBOUNCE])) cg.add(var.set_touch_threshold(config[CONF_TOUCH_THRESHOLD])) cg.add(var.set_release_threshold(config[CONF_RELEASE_THRESHOLD])) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) diff --git a/esphome/components/mpr121/binary_sensor.py b/esphome/components/mpr121/binary_sensor.py index 68e56075f5..20b80e063e 100644 --- a/esphome/components/mpr121/binary_sensor.py +++ b/esphome/components/mpr121/binary_sensor.py @@ -24,10 +24,10 @@ CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield binary_sensor.register_binary_sensor(var, config) - hub = yield cg.get_variable(config[CONF_MPR121_ID]) + await binary_sensor.register_binary_sensor(var, config) + hub = await cg.get_variable(config[CONF_MPR121_ID]) cg.add(var.set_channel(config[CONF_CHANNEL])) if CONF_TOUCH_THRESHOLD in config: diff --git a/esphome/components/mpu6050/sensor.py b/esphome/components/mpu6050/sensor.py index 11d491006e..2054897dfb 100644 --- a/esphome/components/mpu6050/sensor.py +++ b/esphome/components/mpu6050/sensor.py @@ -56,21 +56,21 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) for d in ["x", "y", "z"]: accel_key = f"accel_{d}" if accel_key in config: - sens = yield sensor.new_sensor(config[accel_key]) + sens = await sensor.new_sensor(config[accel_key]) cg.add(getattr(var, f"set_accel_{d}_sensor")(sens)) accel_key = f"gyro_{d}" if accel_key in config: - sens = yield sensor.new_sensor(config[accel_key]) + sens = await sensor.new_sensor(config[accel_key]) cg.add(getattr(var, f"set_gyro_{d}_sensor")(sens)) if CONF_TEMPERATURE in config: - sens = yield sensor.new_sensor(config[CONF_TEMPERATURE]) + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) cg.add(var.set_temperature_sensor(sens)) diff --git a/esphome/components/mqtt_subscribe/sensor/__init__.py b/esphome/components/mqtt_subscribe/sensor/__init__.py index 00c2d324d3..25a2079f81 100644 --- a/esphome/components/mqtt_subscribe/sensor/__init__.py +++ b/esphome/components/mqtt_subscribe/sensor/__init__.py @@ -32,12 +32,12 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield sensor.register_sensor(var, config) + await cg.register_component(var, config) + await sensor.register_sensor(var, config) - parent = yield cg.get_variable(config[CONF_MQTT_PARENT_ID]) + parent = await cg.get_variable(config[CONF_MQTT_PARENT_ID]) cg.add(var.set_parent(parent)) cg.add(var.set_topic(config[CONF_TOPIC])) cg.add(var.set_qos(config[CONF_QOS])) diff --git a/esphome/components/mqtt_subscribe/text_sensor/__init__.py b/esphome/components/mqtt_subscribe/text_sensor/__init__.py index b5f2c4307b..477e4dec45 100644 --- a/esphome/components/mqtt_subscribe/text_sensor/__init__.py +++ b/esphome/components/mqtt_subscribe/text_sensor/__init__.py @@ -21,12 +21,12 @@ CONFIG_SCHEMA = text_sensor.TEXT_SENSOR_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield text_sensor.register_text_sensor(var, config) + await cg.register_component(var, config) + await text_sensor.register_text_sensor(var, config) - parent = yield cg.get_variable(config[CONF_MQTT_PARENT_ID]) + parent = await cg.get_variable(config[CONF_MQTT_PARENT_ID]) cg.add(var.set_parent(parent)) cg.add(var.set_topic(config[CONF_TOPIC])) cg.add(var.set_qos(config[CONF_QOS])) diff --git a/esphome/components/ms5611/sensor.py b/esphome/components/ms5611/sensor.py index d180008140..ebf1a949e7 100644 --- a/esphome/components/ms5611/sensor.py +++ b/esphome/components/ms5611/sensor.py @@ -37,15 +37,15 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) if CONF_TEMPERATURE in config: - sens = yield sensor.new_sensor(config[CONF_TEMPERATURE]) + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) cg.add(var.set_temperature_sensor(sens)) if CONF_PRESSURE in config: - sens = yield sensor.new_sensor(config[CONF_PRESSURE]) + sens = await sensor.new_sensor(config[CONF_PRESSURE]) cg.add(var.set_pressure_sensor(sens)) diff --git a/esphome/components/my9231/__init__.py b/esphome/components/my9231/__init__.py index ed1edd7b2d..58419450cd 100644 --- a/esphome/components/my9231/__init__.py +++ b/esphome/components/my9231/__init__.py @@ -27,13 +27,13 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) + await cg.register_component(var, config) - di = yield cg.gpio_pin_expression(config[CONF_DATA_PIN]) + di = await cg.gpio_pin_expression(config[CONF_DATA_PIN]) cg.add(var.set_pin_di(di)) - dcki = yield cg.gpio_pin_expression(config[CONF_CLOCK_PIN]) + dcki = await cg.gpio_pin_expression(config[CONF_CLOCK_PIN]) cg.add(var.set_pin_dcki(dcki)) cg.add(var.set_num_channels(config[CONF_NUM_CHANNELS])) diff --git a/esphome/components/my9231/output.py b/esphome/components/my9231/output.py index 30db84064d..a3c16fd49a 100644 --- a/esphome/components/my9231/output.py +++ b/esphome/components/my9231/output.py @@ -18,10 +18,10 @@ CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield output.register_output(var, config) + await output.register_output(var, config) - parent = yield cg.get_variable(config[CONF_MY9231_ID]) + parent = await cg.get_variable(config[CONF_MY9231_ID]) cg.add(var.set_parent(parent)) cg.add(var.set_channel(config[CONF_CHANNEL])) diff --git a/esphome/components/neopixelbus/light.py b/esphome/components/neopixelbus/light.py index ae3a941bf9..f643b476e8 100644 --- a/esphome/components/neopixelbus/light.py +++ b/esphome/components/neopixelbus/light.py @@ -181,7 +181,7 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): has_white = "W" in config[CONF_TYPE] template = cg.TemplateArguments(getattr(cg.global_ns, format_method(config))) if has_white: @@ -190,8 +190,8 @@ def to_code(config): out_type = NeoPixelRGBLightOutput.template(template) rhs = out_type.new() var = cg.Pvariable(config[CONF_OUTPUT_ID], rhs, out_type) - yield light.register_light(var, config) - yield cg.register_component(var, config) + await light.register_light(var, config) + await cg.register_component(var, config) if CONF_PIN in config: cg.add(var.add_leds(config[CONF_NUM_LEDS], config[CONF_PIN])) diff --git a/esphome/components/nextion/binary_sensor.py b/esphome/components/nextion/binary_sensor.py index e822b65eb5..ed4e8d832a 100644 --- a/esphome/components/nextion/binary_sensor.py +++ b/esphome/components/nextion/binary_sensor.py @@ -23,11 +23,11 @@ CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield binary_sensor.register_binary_sensor(var, config) + await binary_sensor.register_binary_sensor(var, config) - hub = yield cg.get_variable(config[CONF_NEXTION_ID]) + hub = await cg.get_variable(config[CONF_NEXTION_ID]) cg.add(hub.register_touch_component(var)) cg.add(var.set_component_id(config[CONF_COMPONENT_ID])) diff --git a/esphome/components/nextion/display.py b/esphome/components/nextion/display.py index 483395fe2f..7d7018a4c4 100644 --- a/esphome/components/nextion/display.py +++ b/esphome/components/nextion/display.py @@ -22,17 +22,17 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield uart.register_uart_device(var, config) + await cg.register_component(var, config) + await uart.register_uart_device(var, config) if CONF_BRIGHTNESS in config: cg.add(var.set_brightness(config[CONF_BRIGHTNESS])) if CONF_LAMBDA in config: - lambda_ = yield cg.process_lambda( + lambda_ = await cg.process_lambda( config[CONF_LAMBDA], [(NextionRef, "it")], return_type=cg.void ) cg.add(var.set_writer(lambda_)) - yield display.register_display(var, config) + await display.register_display(var, config) diff --git a/esphome/components/ntc/sensor.py b/esphome/components/ntc/sensor.py index f3505eec53..d83afae350 100644 --- a/esphome/components/ntc/sensor.py +++ b/esphome/components/ntc/sensor.py @@ -130,12 +130,12 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield sensor.register_sensor(var, config) + await cg.register_component(var, config) + await sensor.register_sensor(var, config) - sens = yield cg.get_variable(config[CONF_SENSOR]) + sens = await cg.get_variable(config[CONF_SENSOR]) cg.add(var.set_sensor(sens)) calib = config[CONF_CALIBRATION] cg.add(var.set_a(calib[CONF_A])) diff --git a/esphome/components/output/__init__.py b/esphome/components/output/__init__.py index 975fe8adbe..4471794033 100644 --- a/esphome/components/output/__init__.py +++ b/esphome/components/output/__init__.py @@ -100,5 +100,5 @@ async def output_set_level_to_code(config, action_id, template_arg, args): return var -def to_code(config): +async def to_code(config): cg.add_global(output_ns.using) diff --git a/esphome/components/output/switch/__init__.py b/esphome/components/output/switch/__init__.py index 14027de74c..11d073d28c 100644 --- a/esphome/components/output/switch/__init__.py +++ b/esphome/components/output/switch/__init__.py @@ -14,10 +14,10 @@ CONFIG_SCHEMA = switch.SWITCH_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield switch.register_switch(var, config) + await cg.register_component(var, config) + await switch.register_switch(var, config) - output_ = yield cg.get_variable(config[CONF_OUTPUT]) + output_ = await cg.get_variable(config[CONF_OUTPUT]) cg.add(var.set_output(output_)) diff --git a/esphome/components/partition/light.py b/esphome/components/partition/light.py index c366aea033..5ded6b906c 100644 --- a/esphome/components/partition/light.py +++ b/esphome/components/partition/light.py @@ -45,10 +45,10 @@ CONFIG_SCHEMA = light.ADDRESSABLE_LIGHT_SCHEMA.extend( ) -def to_code(config): +async def to_code(config): segments = [] for conf in config[CONF_SEGMENTS]: - var = yield cg.get_variable(conf[CONF_ID]) + var = await cg.get_variable(conf[CONF_ID]) segments.append( AddressableSegment( var, @@ -59,5 +59,5 @@ def to_code(config): ) var = cg.new_Pvariable(config[CONF_OUTPUT_ID], segments) - yield cg.register_component(var, config) - yield light.register_light(var, config) + await cg.register_component(var, config) + await light.register_light(var, config) diff --git a/esphome/components/pca9685/__init__.py b/esphome/components/pca9685/__init__.py index d88012a1cd..1a5ccc3247 100644 --- a/esphome/components/pca9685/__init__.py +++ b/esphome/components/pca9685/__init__.py @@ -23,7 +23,7 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID], config[CONF_FREQUENCY]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) diff --git a/esphome/components/pca9685/output.py b/esphome/components/pca9685/output.py index c3cb88eeaf..40f7b3cd74 100644 --- a/esphome/components/pca9685/output.py +++ b/esphome/components/pca9685/output.py @@ -18,8 +18,8 @@ CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( ) -def to_code(config): - paren = yield cg.get_variable(config[CONF_PCA9685_ID]) +async def to_code(config): + paren = await cg.get_variable(config[CONF_PCA9685_ID]) rhs = paren.create_channel(config[CONF_CHANNEL]) var = cg.Pvariable(config[CONF_ID], rhs) - yield output.register_output(var, config) + await output.register_output(var, config) diff --git a/esphome/components/pcd8544/display.py b/esphome/components/pcd8544/display.py index 50cc1b02a8..d0184a58d3 100644 --- a/esphome/components/pcd8544/display.py +++ b/esphome/components/pcd8544/display.py @@ -36,22 +36,22 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield display.register_display(var, config) - yield spi.register_spi_device(var, config) + await cg.register_component(var, config) + await display.register_display(var, config) + await spi.register_spi_device(var, config) - dc = yield cg.gpio_pin_expression(config[CONF_DC_PIN]) + dc = await cg.gpio_pin_expression(config[CONF_DC_PIN]) cg.add(var.set_dc_pin(dc)) - reset = yield cg.gpio_pin_expression(config[CONF_RESET_PIN]) + reset = await cg.gpio_pin_expression(config[CONF_RESET_PIN]) cg.add(var.set_reset_pin(reset)) cg.add(var.set_contrast(config[CONF_CONTRAST])) if CONF_LAMBDA in config: - lambda_ = yield cg.process_lambda( + lambda_ = await cg.process_lambda( config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void ) cg.add(var.set_writer(lambda_)) diff --git a/esphome/components/pcf8574/__init__.py b/esphome/components/pcf8574/__init__.py index 8c028fabc1..9c0aeb2e12 100644 --- a/esphome/components/pcf8574/__init__.py +++ b/esphome/components/pcf8574/__init__.py @@ -31,10 +31,10 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) cg.add(var.set_pcf8575(config[CONF_PCF8575])) diff --git a/esphome/components/pid/climate.py b/esphome/components/pid/climate.py index c16f1726ae..8b9b090893 100644 --- a/esphome/components/pid/climate.py +++ b/esphome/components/pid/climate.py @@ -51,19 +51,19 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield climate.register_climate(var, config) + await cg.register_component(var, config) + await climate.register_climate(var, config) - sens = yield cg.get_variable(config[CONF_SENSOR]) + sens = await cg.get_variable(config[CONF_SENSOR]) cg.add(var.set_sensor(sens)) if CONF_COOL_OUTPUT in config: - out = yield cg.get_variable(config[CONF_COOL_OUTPUT]) + out = await cg.get_variable(config[CONF_COOL_OUTPUT]) cg.add(var.set_cool_output(out)) if CONF_HEAT_OUTPUT in config: - out = yield cg.get_variable(config[CONF_HEAT_OUTPUT]) + out = await cg.get_variable(config[CONF_HEAT_OUTPUT]) cg.add(var.set_heat_output(out)) params = config[CONF_CONTROL_PARAMETERS] cg.add(var.set_kp(params[CONF_KP])) diff --git a/esphome/components/pid/sensor/__init__.py b/esphome/components/pid/sensor/__init__.py index d29fb6b662..d958f239de 100644 --- a/esphome/components/pid/sensor/__init__.py +++ b/esphome/components/pid/sensor/__init__.py @@ -40,11 +40,11 @@ CONFIG_SCHEMA = ( ) -def to_code(config): - parent = yield cg.get_variable(config[CONF_CLIMATE_ID]) +async def to_code(config): + parent = await cg.get_variable(config[CONF_CLIMATE_ID]) var = cg.new_Pvariable(config[CONF_ID]) - yield sensor.register_sensor(var, config) - yield cg.register_component(var, config) + await sensor.register_sensor(var, config) + await cg.register_component(var, config) cg.add(var.set_parent(parent)) cg.add(var.set_type(config[CONF_TYPE])) diff --git a/esphome/components/pmsx003/sensor.py b/esphome/components/pmsx003/sensor.py index 05becfb71f..bdbe2b1811 100644 --- a/esphome/components/pmsx003/sensor.py +++ b/esphome/components/pmsx003/sensor.py @@ -98,33 +98,33 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield uart.register_uart_device(var, config) + await cg.register_component(var, config) + await uart.register_uart_device(var, config) cg.add(var.set_type(config[CONF_TYPE])) if CONF_PM_1_0 in config: - sens = yield sensor.new_sensor(config[CONF_PM_1_0]) + sens = await sensor.new_sensor(config[CONF_PM_1_0]) cg.add(var.set_pm_1_0_sensor(sens)) if CONF_PM_2_5 in config: - sens = yield sensor.new_sensor(config[CONF_PM_2_5]) + sens = await sensor.new_sensor(config[CONF_PM_2_5]) cg.add(var.set_pm_2_5_sensor(sens)) if CONF_PM_10_0 in config: - sens = yield sensor.new_sensor(config[CONF_PM_10_0]) + sens = await sensor.new_sensor(config[CONF_PM_10_0]) cg.add(var.set_pm_10_0_sensor(sens)) if CONF_TEMPERATURE in config: - sens = yield sensor.new_sensor(config[CONF_TEMPERATURE]) + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) cg.add(var.set_temperature_sensor(sens)) if CONF_HUMIDITY in config: - sens = yield sensor.new_sensor(config[CONF_HUMIDITY]) + sens = await sensor.new_sensor(config[CONF_HUMIDITY]) cg.add(var.set_humidity_sensor(sens)) if CONF_FORMALDEHYDE in config: - sens = yield sensor.new_sensor(config[CONF_FORMALDEHYDE]) + sens = await sensor.new_sensor(config[CONF_FORMALDEHYDE]) cg.add(var.set_formaldehyde_sensor(sens)) diff --git a/esphome/components/pn532/binary_sensor.py b/esphome/components/pn532/binary_sensor.py index 5e6bf6c2b9..9a5816b322 100644 --- a/esphome/components/pn532/binary_sensor.py +++ b/esphome/components/pn532/binary_sensor.py @@ -40,11 +40,11 @@ CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield binary_sensor.register_binary_sensor(var, config) + await binary_sensor.register_binary_sensor(var, config) - hub = yield cg.get_variable(config[CONF_PN532_ID]) + hub = await cg.get_variable(config[CONF_PN532_ID]) cg.add(hub.register_tag(var)) addr = [HexInt(int(x, 16)) for x in config[CONF_UID].split("-")] cg.add(var.set_uid(addr)) diff --git a/esphome/components/pn532_i2c/__init__.py b/esphome/components/pn532_i2c/__init__.py index 80995bd018..36af2f8aa0 100644 --- a/esphome/components/pn532_i2c/__init__.py +++ b/esphome/components/pn532_i2c/__init__.py @@ -19,7 +19,7 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield pn532.setup_pn532(var, config) - yield i2c.register_i2c_device(var, config) + await pn532.setup_pn532(var, config) + await i2c.register_i2c_device(var, config) diff --git a/esphome/components/pn532_spi/__init__.py b/esphome/components/pn532_spi/__init__.py index 2abe436291..2683f34ad5 100644 --- a/esphome/components/pn532_spi/__init__.py +++ b/esphome/components/pn532_spi/__init__.py @@ -19,7 +19,7 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield pn532.setup_pn532(var, config) - yield spi.register_spi_device(var, config) + await pn532.setup_pn532(var, config) + await spi.register_spi_device(var, config) diff --git a/esphome/components/power_supply/__init__.py b/esphome/components/power_supply/__init__.py index efed5e0d81..f7dd8bca84 100644 --- a/esphome/components/power_supply/__init__.py +++ b/esphome/components/power_supply/__init__.py @@ -22,11 +22,11 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) + await cg.register_component(var, config) - pin = yield cg.gpio_pin_expression(config[CONF_PIN]) + pin = await cg.gpio_pin_expression(config[CONF_PIN]) cg.add(var.set_pin(pin)) cg.add(var.set_enable_time(config[CONF_ENABLE_TIME])) cg.add(var.set_keep_on_time(config[CONF_KEEP_ON_TIME])) diff --git a/esphome/components/prometheus/__init__.py b/esphome/components/prometheus/__init__.py index a1b376c763..f5f166d085 100644 --- a/esphome/components/prometheus/__init__.py +++ b/esphome/components/prometheus/__init__.py @@ -19,10 +19,10 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): - paren = yield cg.get_variable(config[CONF_WEB_SERVER_BASE_ID]) +async def to_code(config): + paren = await cg.get_variable(config[CONF_WEB_SERVER_BASE_ID]) cg.add_define("USE_PROMETHEUS") var = cg.new_Pvariable(config[CONF_ID], paren) - yield cg.register_component(var, config) + await cg.register_component(var, config) diff --git a/esphome/components/pulse_counter/sensor.py b/esphome/components/pulse_counter/sensor.py index 0dff2959e8..d6e4dfc1a3 100644 --- a/esphome/components/pulse_counter/sensor.py +++ b/esphome/components/pulse_counter/sensor.py @@ -94,12 +94,12 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield sensor.register_sensor(var, config) + await cg.register_component(var, config) + await sensor.register_sensor(var, config) - pin = yield cg.gpio_pin_expression(config[CONF_PIN]) + pin = await cg.gpio_pin_expression(config[CONF_PIN]) cg.add(var.set_pin(pin)) count = config[CONF_COUNT_MODE] cg.add(var.set_rising_edge_mode(count[CONF_RISING_EDGE])) @@ -107,5 +107,5 @@ def to_code(config): cg.add(var.set_filter_us(config[CONF_INTERNAL_FILTER])) if CONF_TOTAL in config: - sens = yield sensor.new_sensor(config[CONF_TOTAL]) + sens = await sensor.new_sensor(config[CONF_TOTAL]) cg.add(var.set_total_sensor(sens)) diff --git a/esphome/components/pulse_meter/sensor.py b/esphome/components/pulse_meter/sensor.py index c7256b2987..9bf4bfddd6 100644 --- a/esphome/components/pulse_meter/sensor.py +++ b/esphome/components/pulse_meter/sensor.py @@ -63,18 +63,18 @@ CONFIG_SCHEMA = sensor.sensor_schema( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield sensor.register_sensor(var, config) + await cg.register_component(var, config) + await sensor.register_sensor(var, config) - pin = yield cg.gpio_pin_expression(config[CONF_PIN]) + pin = await cg.gpio_pin_expression(config[CONF_PIN]) cg.add(var.set_pin(pin)) cg.add(var.set_filter_us(config[CONF_INTERNAL_FILTER])) cg.add(var.set_timeout_us(config[CONF_TIMEOUT])) if CONF_TOTAL in config: - sens = yield sensor.new_sensor(config[CONF_TOTAL]) + sens = await sensor.new_sensor(config[CONF_TOTAL]) cg.add(var.set_total_sensor(sens)) diff --git a/esphome/components/pulse_width/sensor.py b/esphome/components/pulse_width/sensor.py index 228c5f8dfe..358ffd2962 100644 --- a/esphome/components/pulse_width/sensor.py +++ b/esphome/components/pulse_width/sensor.py @@ -24,10 +24,10 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield sensor.register_sensor(var, config) + await cg.register_component(var, config) + await sensor.register_sensor(var, config) - pin = yield cg.gpio_pin_expression(config[CONF_PIN]) + pin = await cg.gpio_pin_expression(config[CONF_PIN]) cg.add(var.set_pin(pin)) diff --git a/esphome/components/pzem004t/sensor.py b/esphome/components/pzem004t/sensor.py index 1228fc4ab6..b463e58f94 100644 --- a/esphome/components/pzem004t/sensor.py +++ b/esphome/components/pzem004t/sensor.py @@ -46,24 +46,24 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield uart.register_uart_device(var, config) + await cg.register_component(var, config) + await uart.register_uart_device(var, config) if CONF_VOLTAGE in config: conf = config[CONF_VOLTAGE] - sens = yield sensor.new_sensor(conf) + sens = await sensor.new_sensor(conf) cg.add(var.set_voltage_sensor(sens)) if CONF_CURRENT in config: conf = config[CONF_CURRENT] - sens = yield sensor.new_sensor(conf) + sens = await sensor.new_sensor(conf) cg.add(var.set_current_sensor(sens)) if CONF_POWER in config: conf = config[CONF_POWER] - sens = yield sensor.new_sensor(conf) + sens = await sensor.new_sensor(conf) cg.add(var.set_power_sensor(sens)) if CONF_ENERGY in config: conf = config[CONF_ENERGY] - sens = yield sensor.new_sensor(conf) + sens = await sensor.new_sensor(conf) cg.add(var.set_energy_sensor(sens)) diff --git a/esphome/components/pzemac/sensor.py b/esphome/components/pzemac/sensor.py index aa30549c25..bac2f1b60e 100644 --- a/esphome/components/pzemac/sensor.py +++ b/esphome/components/pzemac/sensor.py @@ -59,32 +59,32 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield modbus.register_modbus_device(var, config) + await cg.register_component(var, config) + await modbus.register_modbus_device(var, config) if CONF_VOLTAGE in config: conf = config[CONF_VOLTAGE] - sens = yield sensor.new_sensor(conf) + sens = await sensor.new_sensor(conf) cg.add(var.set_voltage_sensor(sens)) if CONF_CURRENT in config: conf = config[CONF_CURRENT] - sens = yield sensor.new_sensor(conf) + sens = await sensor.new_sensor(conf) cg.add(var.set_current_sensor(sens)) if CONF_POWER in config: conf = config[CONF_POWER] - sens = yield sensor.new_sensor(conf) + sens = await sensor.new_sensor(conf) cg.add(var.set_power_sensor(sens)) if CONF_ENERGY in config: conf = config[CONF_ENERGY] - sens = yield sensor.new_sensor(conf) + sens = await sensor.new_sensor(conf) cg.add(var.set_energy_sensor(sens)) if CONF_FREQUENCY in config: conf = config[CONF_FREQUENCY] - sens = yield sensor.new_sensor(conf) + sens = await sensor.new_sensor(conf) cg.add(var.set_frequency_sensor(sens)) if CONF_POWER_FACTOR in config: conf = config[CONF_POWER_FACTOR] - sens = yield sensor.new_sensor(conf) + sens = await sensor.new_sensor(conf) cg.add(var.set_power_factor_sensor(sens)) diff --git a/esphome/components/pzemdc/sensor.py b/esphome/components/pzemdc/sensor.py index 962c970359..0bf4c9ba2a 100644 --- a/esphome/components/pzemdc/sensor.py +++ b/esphome/components/pzemdc/sensor.py @@ -40,20 +40,20 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield modbus.register_modbus_device(var, config) + await cg.register_component(var, config) + await modbus.register_modbus_device(var, config) if CONF_VOLTAGE in config: conf = config[CONF_VOLTAGE] - sens = yield sensor.new_sensor(conf) + sens = await sensor.new_sensor(conf) cg.add(var.set_voltage_sensor(sens)) if CONF_CURRENT in config: conf = config[CONF_CURRENT] - sens = yield sensor.new_sensor(conf) + sens = await sensor.new_sensor(conf) cg.add(var.set_current_sensor(sens)) if CONF_POWER in config: conf = config[CONF_POWER] - sens = yield sensor.new_sensor(conf) + sens = await sensor.new_sensor(conf) cg.add(var.set_power_sensor(sens)) diff --git a/esphome/components/qmc5883l/sensor.py b/esphome/components/qmc5883l/sensor.py index 4359427628..395cb681a3 100644 --- a/esphome/components/qmc5883l/sensor.py +++ b/esphome/components/qmc5883l/sensor.py @@ -106,23 +106,23 @@ def auto_data_rate(config): return QMC5883LDatarates[200] -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) cg.add(var.set_oversampling(config[CONF_OVERSAMPLING])) cg.add(var.set_datarate(auto_data_rate(config))) cg.add(var.set_range(config[CONF_RANGE])) if CONF_FIELD_STRENGTH_X in config: - sens = yield sensor.new_sensor(config[CONF_FIELD_STRENGTH_X]) + sens = await sensor.new_sensor(config[CONF_FIELD_STRENGTH_X]) cg.add(var.set_x_sensor(sens)) if CONF_FIELD_STRENGTH_Y in config: - sens = yield sensor.new_sensor(config[CONF_FIELD_STRENGTH_Y]) + sens = await sensor.new_sensor(config[CONF_FIELD_STRENGTH_Y]) cg.add(var.set_y_sensor(sens)) if CONF_FIELD_STRENGTH_Z in config: - sens = yield sensor.new_sensor(config[CONF_FIELD_STRENGTH_Z]) + sens = await sensor.new_sensor(config[CONF_FIELD_STRENGTH_Z]) cg.add(var.set_z_sensor(sens)) if CONF_HEADING in config: - sens = yield sensor.new_sensor(config[CONF_HEADING]) + sens = await sensor.new_sensor(config[CONF_HEADING]) cg.add(var.set_heading_sensor(sens)) diff --git a/esphome/components/rc522/binary_sensor.py b/esphome/components/rc522/binary_sensor.py index 89eef2f976..67d3068599 100644 --- a/esphome/components/rc522/binary_sensor.py +++ b/esphome/components/rc522/binary_sensor.py @@ -2,7 +2,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import binary_sensor from esphome.const import CONF_UID, CONF_ID -from esphome.core import HexInt, coroutine +from esphome.core import HexInt from . import rc522_ns, RC522, CONF_RC522_ID DEPENDENCIES = ["rc522"] @@ -40,12 +40,11 @@ CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend( ) -@coroutine -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield binary_sensor.register_binary_sensor(var, config) + await binary_sensor.register_binary_sensor(var, config) - hub = yield cg.get_variable(config[CONF_RC522_ID]) + hub = await cg.get_variable(config[CONF_RC522_ID]) cg.add(hub.register_tag(var)) addr = [HexInt(int(x, 16)) for x in config[CONF_UID].split("-")] cg.add(var.set_uid(addr)) diff --git a/esphome/components/rc522_i2c/__init__.py b/esphome/components/rc522_i2c/__init__.py index 081536b6b1..e42817352c 100644 --- a/esphome/components/rc522_i2c/__init__.py +++ b/esphome/components/rc522_i2c/__init__.py @@ -20,7 +20,7 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield rc522.setup_rc522(var, config) - yield i2c.register_i2c_device(var, config) + await rc522.setup_rc522(var, config) + await i2c.register_i2c_device(var, config) diff --git a/esphome/components/rc522_spi/__init__.py b/esphome/components/rc522_spi/__init__.py index 2e5630f46d..b21af1d07f 100644 --- a/esphome/components/rc522_spi/__init__.py +++ b/esphome/components/rc522_spi/__init__.py @@ -20,7 +20,7 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield rc522.setup_rc522(var, config) - yield spi.register_spi_device(var, config) + await rc522.setup_rc522(var, config) + await spi.register_spi_device(var, config) diff --git a/esphome/components/rc522_spi/binary_sensor.py b/esphome/components/rc522_spi/binary_sensor.py index f5400a2331..8139f6d2ac 100644 --- a/esphome/components/rc522_spi/binary_sensor.py +++ b/esphome/components/rc522_spi/binary_sensor.py @@ -5,5 +5,5 @@ DEPENDENCIES = ["rc522"] CONFIG_SCHEMA = rc522_binary_sensor.CONFIG_SCHEMA -def to_code(config): - yield rc522_binary_sensor.to_code(config) +async def to_code(config): + await rc522_binary_sensor.to_code(config) diff --git a/esphome/components/rdm6300/__init__.py b/esphome/components/rdm6300/__init__.py index a416d95a12..37ebcb49a9 100644 --- a/esphome/components/rdm6300/__init__.py +++ b/esphome/components/rdm6300/__init__.py @@ -29,12 +29,12 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield uart.register_uart_device(var, config) + await cg.register_component(var, config) + await uart.register_uart_device(var, config) for conf in config.get(CONF_ON_TAG, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID]) cg.add(var.register_trigger(trigger)) - yield automation.build_automation(trigger, [(cg.uint32, "x")], conf) + await automation.build_automation(trigger, [(cg.uint32, "x")], conf) diff --git a/esphome/components/rdm6300/binary_sensor.py b/esphome/components/rdm6300/binary_sensor.py index 02e0b6ceb6..c99a2bfc06 100644 --- a/esphome/components/rdm6300/binary_sensor.py +++ b/esphome/components/rdm6300/binary_sensor.py @@ -20,10 +20,10 @@ CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield binary_sensor.register_binary_sensor(var, config) + await binary_sensor.register_binary_sensor(var, config) - hub = yield cg.get_variable(config[CONF_RDM6300_ID]) + hub = await cg.get_variable(config[CONF_RDM6300_ID]) cg.add(hub.register_card(var)) cg.add(var.set_id(config[CONF_UID])) diff --git a/esphome/components/remote_receiver/__init__.py b/esphome/components/remote_receiver/__init__.py index f29c59b3f8..fed52803cb 100644 --- a/esphome/components/remote_receiver/__init__.py +++ b/esphome/components/remote_receiver/__init__.py @@ -47,16 +47,16 @@ CONFIG_SCHEMA = remote_base.validate_triggers( ) -def to_code(config): - pin = yield cg.gpio_pin_expression(config[CONF_PIN]) +async def to_code(config): + pin = await cg.gpio_pin_expression(config[CONF_PIN]) if CORE.is_esp32: var = cg.new_Pvariable(config[CONF_ID], pin, config[CONF_MEMORY_BLOCKS]) else: var = cg.new_Pvariable(config[CONF_ID], pin) - yield remote_base.build_dumpers(config[CONF_DUMP]) - yield remote_base.build_triggers(config) - yield cg.register_component(var, config) + await remote_base.build_dumpers(config[CONF_DUMP]) + await remote_base.build_triggers(config) + await cg.register_component(var, config) cg.add(var.set_tolerance(config[CONF_TOLERANCE])) cg.add(var.set_buffer_size(config[CONF_BUFFER_SIZE])) diff --git a/esphome/components/remote_receiver/binary_sensor.py b/esphome/components/remote_receiver/binary_sensor.py index 522333584c..62c1d9cb27 100644 --- a/esphome/components/remote_receiver/binary_sensor.py +++ b/esphome/components/remote_receiver/binary_sensor.py @@ -7,7 +7,7 @@ DEPENDENCIES = ["remote_receiver"] CONFIG_SCHEMA = remote_base.validate_binary_sensor -def to_code(config): - var = yield remote_base.build_binary_sensor(config) +async def to_code(config): + var = await remote_base.build_binary_sensor(config) cg.add(var.set_name(config[CONF_NAME])) - yield binary_sensor.register_binary_sensor(var, config) + await binary_sensor.register_binary_sensor(var, config) diff --git a/esphome/components/remote_transmitter/__init__.py b/esphome/components/remote_transmitter/__init__.py index 123af7db97..e09e4c7f55 100644 --- a/esphome/components/remote_transmitter/__init__.py +++ b/esphome/components/remote_transmitter/__init__.py @@ -22,9 +22,9 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): - pin = yield cg.gpio_pin_expression(config[CONF_PIN]) +async def to_code(config): + pin = await cg.gpio_pin_expression(config[CONF_PIN]) var = cg.new_Pvariable(config[CONF_ID], pin) - yield cg.register_component(var, config) + await cg.register_component(var, config) cg.add(var.set_carrier_duty_percent(config[CONF_CARRIER_DUTY_PERCENT])) diff --git a/esphome/components/resistance/sensor.py b/esphome/components/resistance/sensor.py index 92a564f68e..8ee00b25be 100644 --- a/esphome/components/resistance/sensor.py +++ b/esphome/components/resistance/sensor.py @@ -31,12 +31,12 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield sensor.register_sensor(var, config) + await cg.register_component(var, config) + await sensor.register_sensor(var, config) - sens = yield cg.get_variable(config[CONF_SENSOR]) + sens = await cg.get_variable(config[CONF_SENSOR]) cg.add(var.set_sensor(sens)) cg.add(var.set_configuration(config[CONF_CONFIGURATION])) cg.add(var.set_resistor(config[CONF_RESISTOR])) diff --git a/esphome/components/restart/switch.py b/esphome/components/restart/switch.py index fe170aee61..4f1904e273 100644 --- a/esphome/components/restart/switch.py +++ b/esphome/components/restart/switch.py @@ -17,7 +17,7 @@ CONFIG_SCHEMA = switch.SWITCH_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield switch.register_switch(var, config) + await cg.register_component(var, config) + await switch.register_switch(var, config) diff --git a/esphome/components/rf_bridge/__init__.py b/esphome/components/rf_bridge/__init__.py index b24e19b4bf..1eda99e7af 100644 --- a/esphome/components/rf_bridge/__init__.py +++ b/esphome/components/rf_bridge/__init__.py @@ -79,18 +79,18 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield uart.register_uart_device(var, config) + await cg.register_component(var, config) + await uart.register_uart_device(var, config) for conf in config.get(CONF_ON_CODE_RECEIVED, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) - yield automation.build_automation(trigger, [(RFBridgeData, "data")], conf) + await automation.build_automation(trigger, [(RFBridgeData, "data")], conf) for conf in config.get(CONF_ON_ADVANCED_CODE_RECEIVED, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) - yield automation.build_automation( + await automation.build_automation( trigger, [(RFBridgeAdvancedData, "data")], conf ) diff --git a/esphome/components/rgb/light.py b/esphome/components/rgb/light.py index 33e381d59e..3d07855b8e 100644 --- a/esphome/components/rgb/light.py +++ b/esphome/components/rgb/light.py @@ -16,13 +16,13 @@ CONFIG_SCHEMA = light.RGB_LIGHT_SCHEMA.extend( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_OUTPUT_ID]) - yield light.register_light(var, config) + await light.register_light(var, config) - red = yield cg.get_variable(config[CONF_RED]) + red = await cg.get_variable(config[CONF_RED]) cg.add(var.set_red(red)) - green = yield cg.get_variable(config[CONF_GREEN]) + green = await cg.get_variable(config[CONF_GREEN]) cg.add(var.set_green(green)) - blue = yield cg.get_variable(config[CONF_BLUE]) + blue = await cg.get_variable(config[CONF_BLUE]) cg.add(var.set_blue(blue)) diff --git a/esphome/components/rgbw/light.py b/esphome/components/rgbw/light.py index a922a7de37..de26edf7d5 100644 --- a/esphome/components/rgbw/light.py +++ b/esphome/components/rgbw/light.py @@ -19,16 +19,16 @@ CONFIG_SCHEMA = light.RGB_LIGHT_SCHEMA.extend( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_OUTPUT_ID]) - yield light.register_light(var, config) + await light.register_light(var, config) - red = yield cg.get_variable(config[CONF_RED]) + red = await cg.get_variable(config[CONF_RED]) cg.add(var.set_red(red)) - green = yield cg.get_variable(config[CONF_GREEN]) + green = await cg.get_variable(config[CONF_GREEN]) cg.add(var.set_green(green)) - blue = yield cg.get_variable(config[CONF_BLUE]) + blue = await cg.get_variable(config[CONF_BLUE]) cg.add(var.set_blue(blue)) - white = yield cg.get_variable(config[CONF_WHITE]) + white = await cg.get_variable(config[CONF_WHITE]) cg.add(var.set_white(white)) cg.add(var.set_color_interlock(config[CONF_COLOR_INTERLOCK])) diff --git a/esphome/components/rgbww/light.py b/esphome/components/rgbww/light.py index d7d0d7fb15..d152fbc6db 100644 --- a/esphome/components/rgbww/light.py +++ b/esphome/components/rgbww/light.py @@ -34,22 +34,22 @@ CONFIG_SCHEMA = light.RGB_LIGHT_SCHEMA.extend( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_OUTPUT_ID]) - yield light.register_light(var, config) + await light.register_light(var, config) - red = yield cg.get_variable(config[CONF_RED]) + red = await cg.get_variable(config[CONF_RED]) cg.add(var.set_red(red)) - green = yield cg.get_variable(config[CONF_GREEN]) + green = await cg.get_variable(config[CONF_GREEN]) cg.add(var.set_green(green)) - blue = yield cg.get_variable(config[CONF_BLUE]) + blue = await cg.get_variable(config[CONF_BLUE]) cg.add(var.set_blue(blue)) - cwhite = yield cg.get_variable(config[CONF_COLD_WHITE]) + cwhite = await cg.get_variable(config[CONF_COLD_WHITE]) cg.add(var.set_cold_white(cwhite)) cg.add(var.set_cold_white_temperature(config[CONF_COLD_WHITE_COLOR_TEMPERATURE])) - wwhite = yield cg.get_variable(config[CONF_WARM_WHITE]) + wwhite = await cg.get_variable(config[CONF_WARM_WHITE]) cg.add(var.set_warm_white(wwhite)) cg.add(var.set_warm_white_temperature(config[CONF_WARM_WHITE_COLOR_TEMPERATURE])) cg.add(var.set_constant_brightness(config[CONF_CONSTANT_BRIGHTNESS])) diff --git a/esphome/components/rotary_encoder/sensor.py b/esphome/components/rotary_encoder/sensor.py index bcc4a5c930..4af1d75139 100644 --- a/esphome/components/rotary_encoder/sensor.py +++ b/esphome/components/rotary_encoder/sensor.py @@ -91,17 +91,17 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield sensor.register_sensor(var, config) - pin_a = yield cg.gpio_pin_expression(config[CONF_PIN_A]) + await cg.register_component(var, config) + await sensor.register_sensor(var, config) + pin_a = await cg.gpio_pin_expression(config[CONF_PIN_A]) cg.add(var.set_pin_a(pin_a)) - pin_b = yield cg.gpio_pin_expression(config[CONF_PIN_B]) + pin_b = await cg.gpio_pin_expression(config[CONF_PIN_B]) cg.add(var.set_pin_b(pin_b)) if CONF_PIN_RESET in config: - pin_i = yield cg.gpio_pin_expression(config[CONF_PIN_RESET]) + pin_i = await cg.gpio_pin_expression(config[CONF_PIN_RESET]) cg.add(var.set_reset_pin(pin_i)) cg.add(var.set_resolution(config[CONF_RESOLUTION])) if CONF_MIN_VALUE in config: @@ -111,10 +111,10 @@ def to_code(config): for conf in config.get(CONF_ON_CLOCKWISE, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) - yield automation.build_automation(trigger, [], conf) + await automation.build_automation(trigger, [], conf) for conf in config.get(CONF_ON_ANTICLOCKWISE, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) - yield automation.build_automation(trigger, [], conf) + await automation.build_automation(trigger, [], conf) @automation.register_action( diff --git a/esphome/components/rtttl/__init__.py b/esphome/components/rtttl/__init__.py index 97b7405c63..fb193c5b92 100644 --- a/esphome/components/rtttl/__init__.py +++ b/esphome/components/rtttl/__init__.py @@ -33,16 +33,16 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) + await cg.register_component(var, config) - out = yield cg.get_variable(config[CONF_OUTPUT]) + out = await cg.get_variable(config[CONF_OUTPUT]) cg.add(var.set_output(out)) for conf in config.get(CONF_ON_FINISHED_PLAYBACK, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) - yield automation.build_automation(trigger, [], conf) + await automation.build_automation(trigger, [], conf) @automation.register_action( diff --git a/esphome/components/ruuvi_ble/__init__.py b/esphome/components/ruuvi_ble/__init__.py index 74aec457bb..1e3fb4b003 100644 --- a/esphome/components/ruuvi_ble/__init__.py +++ b/esphome/components/ruuvi_ble/__init__.py @@ -17,6 +17,6 @@ CONFIG_SCHEMA = cv.Schema( ).extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield esp32_ble_tracker.register_ble_device(var, config) + await esp32_ble_tracker.register_ble_device(var, config) diff --git a/esphome/components/ruuvitag/sensor.py b/esphome/components/ruuvitag/sensor.py index 2bde7b485c..d59dc094fb 100644 --- a/esphome/components/ruuvitag/sensor.py +++ b/esphome/components/ruuvitag/sensor.py @@ -89,43 +89,43 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield esp32_ble_tracker.register_ble_device(var, config) + await cg.register_component(var, config) + await esp32_ble_tracker.register_ble_device(var, config) cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) if CONF_TEMPERATURE in config: - sens = yield sensor.new_sensor(config[CONF_TEMPERATURE]) + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) cg.add(var.set_temperature(sens)) if CONF_HUMIDITY in config: - sens = yield sensor.new_sensor(config[CONF_HUMIDITY]) + sens = await sensor.new_sensor(config[CONF_HUMIDITY]) cg.add(var.set_humidity(sens)) if CONF_PRESSURE in config: - sens = yield sensor.new_sensor(config[CONF_PRESSURE]) + sens = await sensor.new_sensor(config[CONF_PRESSURE]) cg.add(var.set_pressure(sens)) if CONF_ACCELERATION in config: - sens = yield sensor.new_sensor(config[CONF_ACCELERATION]) + sens = await sensor.new_sensor(config[CONF_ACCELERATION]) cg.add(var.set_acceleration(sens)) if CONF_ACCELERATION_X in config: - sens = yield sensor.new_sensor(config[CONF_ACCELERATION_X]) + sens = await sensor.new_sensor(config[CONF_ACCELERATION_X]) cg.add(var.set_acceleration_x(sens)) if CONF_ACCELERATION_Y in config: - sens = yield sensor.new_sensor(config[CONF_ACCELERATION_Y]) + sens = await sensor.new_sensor(config[CONF_ACCELERATION_Y]) cg.add(var.set_acceleration_y(sens)) if CONF_ACCELERATION_Z in config: - sens = yield sensor.new_sensor(config[CONF_ACCELERATION_Z]) + sens = await sensor.new_sensor(config[CONF_ACCELERATION_Z]) cg.add(var.set_acceleration_z(sens)) if CONF_BATTERY_VOLTAGE in config: - sens = yield sensor.new_sensor(config[CONF_BATTERY_VOLTAGE]) + sens = await sensor.new_sensor(config[CONF_BATTERY_VOLTAGE]) cg.add(var.set_battery_voltage(sens)) if CONF_TX_POWER in config: - sens = yield sensor.new_sensor(config[CONF_TX_POWER]) + sens = await sensor.new_sensor(config[CONF_TX_POWER]) cg.add(var.set_tx_power(sens)) if CONF_MOVEMENT_COUNTER in config: - sens = yield sensor.new_sensor(config[CONF_MOVEMENT_COUNTER]) + sens = await sensor.new_sensor(config[CONF_MOVEMENT_COUNTER]) cg.add(var.set_movement_counter(sens)) if CONF_MEASUREMENT_SEQUENCE_NUMBER in config: - sens = yield sensor.new_sensor(config[CONF_MEASUREMENT_SEQUENCE_NUMBER]) + sens = await sensor.new_sensor(config[CONF_MEASUREMENT_SEQUENCE_NUMBER]) cg.add(var.set_measurement_sequence_number(sens)) diff --git a/esphome/components/scd30/sensor.py b/esphome/components/scd30/sensor.py index aa3e5b65ba..a5eb5d8ca4 100644 --- a/esphome/components/scd30/sensor.py +++ b/esphome/components/scd30/sensor.py @@ -59,10 +59,10 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) cg.add(var.set_automatic_self_calibration(config[CONF_AUTOMATIC_SELF_CALIBRATION])) if CONF_ALTITUDE_COMPENSATION in config: @@ -79,13 +79,13 @@ def to_code(config): cg.add(var.set_temperature_offset(config[CONF_TEMPERATURE_OFFSET])) if CONF_CO2 in config: - sens = yield sensor.new_sensor(config[CONF_CO2]) + sens = await sensor.new_sensor(config[CONF_CO2]) cg.add(var.set_co2_sensor(sens)) if CONF_HUMIDITY in config: - sens = yield sensor.new_sensor(config[CONF_HUMIDITY]) + sens = await sensor.new_sensor(config[CONF_HUMIDITY]) cg.add(var.set_humidity_sensor(sens)) if CONF_TEMPERATURE in config: - sens = yield sensor.new_sensor(config[CONF_TEMPERATURE]) + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) cg.add(var.set_temperature_sensor(sens)) diff --git a/esphome/components/script/__init__.py b/esphome/components/script/__init__.py index 45b01778da..a14f48a547 100644 --- a/esphome/components/script/__init__.py +++ b/esphome/components/script/__init__.py @@ -61,7 +61,7 @@ CONFIG_SCHEMA = automation.validate_automation( ) -def to_code(config): +async def to_code(config): # Register all variables first, so that scripts can use other scripts triggers = [] for conf in config: @@ -73,12 +73,12 @@ def to_code(config): cg.add(trigger.set_max_runs(conf[CONF_MAX_RUNS])) if conf[CONF_MODE] == CONF_QUEUED: - yield cg.register_component(trigger, conf) + await cg.register_component(trigger, conf) triggers.append((trigger, conf)) for trigger, conf in triggers: - yield automation.build_automation(trigger, [], conf) + await automation.build_automation(trigger, [], conf) @automation.register_action( diff --git a/esphome/components/sds011/sensor.py b/esphome/components/sds011/sensor.py index fcee6fe7d2..5655533b21 100644 --- a/esphome/components/sds011/sensor.py +++ b/esphome/components/sds011/sensor.py @@ -59,19 +59,19 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield uart.register_uart_device(var, config) + await cg.register_component(var, config) + await uart.register_uart_device(var, config) if CONF_UPDATE_INTERVAL in config: cg.add(var.set_update_interval_min(config[CONF_UPDATE_INTERVAL])) cg.add(var.set_rx_mode_only(config[CONF_RX_ONLY])) if CONF_PM_2_5 in config: - sens = yield sensor.new_sensor(config[CONF_PM_2_5]) + sens = await sensor.new_sensor(config[CONF_PM_2_5]) cg.add(var.set_pm_2_5_sensor(sens)) if CONF_PM_10_0 in config: - sens = yield sensor.new_sensor(config[CONF_PM_10_0]) + sens = await sensor.new_sensor(config[CONF_PM_10_0]) cg.add(var.set_pm_10_0_sensor(sens)) diff --git a/esphome/components/senseair/sensor.py b/esphome/components/senseair/sensor.py index 6f48651563..a2690f37ed 100644 --- a/esphome/components/senseair/sensor.py +++ b/esphome/components/senseair/sensor.py @@ -47,13 +47,13 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield uart.register_uart_device(var, config) + await cg.register_component(var, config) + await uart.register_uart_device(var, config) if CONF_CO2 in config: - sens = yield sensor.new_sensor(config[CONF_CO2]) + sens = await sensor.new_sensor(config[CONF_CO2]) cg.add(var.set_co2_sensor(sens)) diff --git a/esphome/components/servo/__init__.py b/esphome/components/servo/__init__.py index 489c295255..e54dd27dea 100644 --- a/esphome/components/servo/__init__.py +++ b/esphome/components/servo/__init__.py @@ -39,11 +39,11 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) + await cg.register_component(var, config) - out = yield cg.get_variable(config[CONF_OUTPUT]) + out = await cg.get_variable(config[CONF_OUTPUT]) cg.add(var.set_output(out)) cg.add(var.set_min_level(config[CONF_MIN_LEVEL])) cg.add(var.set_idle_level(config[CONF_IDLE_LEVEL])) diff --git a/esphome/components/sgp30/sensor.py b/esphome/components/sgp30/sensor.py index 31b40840e3..7046605f3b 100644 --- a/esphome/components/sgp30/sensor.py +++ b/esphome/components/sgp30/sensor.py @@ -54,17 +54,17 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) if CONF_ECO2 in config: - sens = yield sensor.new_sensor(config[CONF_ECO2]) + sens = await sensor.new_sensor(config[CONF_ECO2]) cg.add(var.set_eco2_sensor(sens)) if CONF_TVOC in config: - sens = yield sensor.new_sensor(config[CONF_TVOC]) + sens = await sensor.new_sensor(config[CONF_TVOC]) cg.add(var.set_tvoc_sensor(sens)) if CONF_BASELINE in config: @@ -74,7 +74,7 @@ def to_code(config): if CONF_COMPENSATION in config: compensation_config = config[CONF_COMPENSATION] - sens = yield cg.get_variable(compensation_config[CONF_HUMIDITY_SOURCE]) + sens = await cg.get_variable(compensation_config[CONF_HUMIDITY_SOURCE]) cg.add(var.set_humidity_sensor(sens)) - sens = yield cg.get_variable(compensation_config[CONF_TEMPERATURE_SOURCE]) + sens = await cg.get_variable(compensation_config[CONF_TEMPERATURE_SOURCE]) cg.add(var.set_temperature_sensor(sens)) diff --git a/esphome/components/sgp40/sensor.py b/esphome/components/sgp40/sensor.py index 40bc07389b..a308d7bb79 100644 --- a/esphome/components/sgp40/sensor.py +++ b/esphome/components/sgp40/sensor.py @@ -38,17 +38,17 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) - yield sensor.register_sensor(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + await sensor.register_sensor(var, config) if CONF_COMPENSATION in config: compensation_config = config[CONF_COMPENSATION] - sens = yield cg.get_variable(compensation_config[CONF_HUMIDITY_SOURCE]) + sens = await cg.get_variable(compensation_config[CONF_HUMIDITY_SOURCE]) cg.add(var.set_humidity_sensor(sens)) - sens = yield cg.get_variable(compensation_config[CONF_TEMPERATURE_SOURCE]) + sens = await cg.get_variable(compensation_config[CONF_TEMPERATURE_SOURCE]) cg.add(var.set_temperature_sensor(sens)) cg.add(var.set_store_baseline(config[CONF_STORE_BASELINE])) diff --git a/esphome/components/sht3xd/sensor.py b/esphome/components/sht3xd/sensor.py index 0b30d6780b..cac53e47e3 100644 --- a/esphome/components/sht3xd/sensor.py +++ b/esphome/components/sht3xd/sensor.py @@ -36,15 +36,15 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) if CONF_TEMPERATURE in config: - sens = yield sensor.new_sensor(config[CONF_TEMPERATURE]) + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) cg.add(var.set_temperature_sensor(sens)) if CONF_HUMIDITY in config: - sens = yield sensor.new_sensor(config[CONF_HUMIDITY]) + sens = await sensor.new_sensor(config[CONF_HUMIDITY]) cg.add(var.set_humidity_sensor(sens)) diff --git a/esphome/components/sht4x/sensor.py b/esphome/components/sht4x/sensor.py index bd3e5c108c..fdc4029e41 100644 --- a/esphome/components/sht4x/sensor.py +++ b/esphome/components/sht4x/sensor.py @@ -75,10 +75,10 @@ TYPES = { } -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) cg.add(var.set_precision_value(config[CONF_PRECISION])) cg.add(var.set_heater_power_value(config[CONF_HEATER_POWER])) @@ -88,5 +88,5 @@ def to_code(config): for key, funcName in TYPES.items(): if key in config: - sens = yield sensor.new_sensor(config[key]) + sens = await sensor.new_sensor(config[key]) cg.add(getattr(var, funcName)(sens)) diff --git a/esphome/components/shtcx/sensor.py b/esphome/components/shtcx/sensor.py index 4b1c6c7afe..7156029488 100644 --- a/esphome/components/shtcx/sensor.py +++ b/esphome/components/shtcx/sensor.py @@ -36,15 +36,15 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) if CONF_TEMPERATURE in config: - sens = yield sensor.new_sensor(config[CONF_TEMPERATURE]) + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) cg.add(var.set_temperature_sensor(sens)) if CONF_HUMIDITY in config: - sens = yield sensor.new_sensor(config[CONF_HUMIDITY]) + sens = await sensor.new_sensor(config[CONF_HUMIDITY]) cg.add(var.set_humidity_sensor(sens)) diff --git a/esphome/components/shutdown/switch.py b/esphome/components/shutdown/switch.py index e35029afd7..30c2bc2b74 100644 --- a/esphome/components/shutdown/switch.py +++ b/esphome/components/shutdown/switch.py @@ -17,7 +17,7 @@ CONFIG_SCHEMA = switch.SWITCH_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield switch.register_switch(var, config) + await cg.register_component(var, config) + await switch.register_switch(var, config) diff --git a/esphome/components/sim800l/__init__.py b/esphome/components/sim800l/__init__.py index 3b06ca6d89..4fa1661d21 100644 --- a/esphome/components/sim800l/__init__.py +++ b/esphome/components/sim800l/__init__.py @@ -42,14 +42,14 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield uart.register_uart_device(var, config) + await cg.register_component(var, config) + await uart.register_uart_device(var, config) for conf in config.get(CONF_ON_SMS_RECEIVED, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) - yield automation.build_automation( + await automation.build_automation( trigger, [(cg.std_string, "message"), (cg.std_string, "sender")], conf ) diff --git a/esphome/components/slow_pwm/output.py b/esphome/components/slow_pwm/output.py index f7b26a953a..4f44582eba 100644 --- a/esphome/components/slow_pwm/output.py +++ b/esphome/components/slow_pwm/output.py @@ -19,11 +19,11 @@ CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield output.register_output(var, config) + await cg.register_component(var, config) + await output.register_output(var, config) - pin = yield cg.gpio_pin_expression(config[CONF_PIN]) + pin = await cg.gpio_pin_expression(config[CONF_PIN]) cg.add(var.set_pin(pin)) cg.add(var.set_period(config[CONF_PERIOD])) diff --git a/esphome/components/sm16716/__init__.py b/esphome/components/sm16716/__init__.py index 8030f78f41..ec8ed722f3 100644 --- a/esphome/components/sm16716/__init__.py +++ b/esphome/components/sm16716/__init__.py @@ -25,13 +25,13 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) + await cg.register_component(var, config) - data = yield cg.gpio_pin_expression(config[CONF_DATA_PIN]) + data = await cg.gpio_pin_expression(config[CONF_DATA_PIN]) cg.add(var.set_data_pin(data)) - clock = yield cg.gpio_pin_expression(config[CONF_CLOCK_PIN]) + clock = await cg.gpio_pin_expression(config[CONF_CLOCK_PIN]) cg.add(var.set_clock_pin(clock)) cg.add(var.set_num_channels(config[CONF_NUM_CHANNELS])) diff --git a/esphome/components/sm16716/output.py b/esphome/components/sm16716/output.py index 033bd86e9c..e9b92f68f8 100644 --- a/esphome/components/sm16716/output.py +++ b/esphome/components/sm16716/output.py @@ -18,10 +18,10 @@ CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield output.register_output(var, config) + await output.register_output(var, config) - parent = yield cg.get_variable(config[CONF_SM16716_ID]) + parent = await cg.get_variable(config[CONF_SM16716_ID]) cg.add(var.set_parent(parent)) cg.add(var.set_channel(config[CONF_CHANNEL])) diff --git a/esphome/components/sm2135/__init__.py b/esphome/components/sm2135/__init__.py index 019a1c68c1..68a9094518 100644 --- a/esphome/components/sm2135/__init__.py +++ b/esphome/components/sm2135/__init__.py @@ -23,11 +23,11 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) + await cg.register_component(var, config) - data = yield cg.gpio_pin_expression(config[CONF_DATA_PIN]) + data = await cg.gpio_pin_expression(config[CONF_DATA_PIN]) cg.add(var.set_data_pin(data)) - clock = yield cg.gpio_pin_expression(config[CONF_CLOCK_PIN]) + clock = await cg.gpio_pin_expression(config[CONF_CLOCK_PIN]) cg.add(var.set_clock_pin(clock)) diff --git a/esphome/components/sm2135/output.py b/esphome/components/sm2135/output.py index 86f6db1bb4..5cd969c6a5 100644 --- a/esphome/components/sm2135/output.py +++ b/esphome/components/sm2135/output.py @@ -19,10 +19,10 @@ CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield output.register_output(var, config) + await output.register_output(var, config) - parent = yield cg.get_variable(config[CONF_SM2135_ID]) + parent = await cg.get_variable(config[CONF_SM2135_ID]) cg.add(var.set_parent(parent)) cg.add(var.set_channel(config[CONF_CHANNEL])) diff --git a/esphome/components/sm300d2/sensor.py b/esphome/components/sm300d2/sensor.py index b1df1fb1b8..7618136bd9 100644 --- a/esphome/components/sm300d2/sensor.py +++ b/esphome/components/sm300d2/sensor.py @@ -64,29 +64,29 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield uart.register_uart_device(var, config) + await cg.register_component(var, config) + await uart.register_uart_device(var, config) if CONF_CO2 in config: - sens = yield sensor.new_sensor(config[CONF_CO2]) + sens = await sensor.new_sensor(config[CONF_CO2]) cg.add(var.set_co2_sensor(sens)) if CONF_FORMALDEHYDE in config: - sens = yield sensor.new_sensor(config[CONF_FORMALDEHYDE]) + sens = await sensor.new_sensor(config[CONF_FORMALDEHYDE]) cg.add(var.set_formaldehyde_sensor(sens)) if CONF_TVOC in config: - sens = yield sensor.new_sensor(config[CONF_TVOC]) + sens = await sensor.new_sensor(config[CONF_TVOC]) cg.add(var.set_tvoc_sensor(sens)) if CONF_PM_2_5 in config: - sens = yield sensor.new_sensor(config[CONF_PM_2_5]) + sens = await sensor.new_sensor(config[CONF_PM_2_5]) cg.add(var.set_pm_2_5_sensor(sens)) if CONF_PM_10_0 in config: - sens = yield sensor.new_sensor(config[CONF_PM_10_0]) + sens = await sensor.new_sensor(config[CONF_PM_10_0]) cg.add(var.set_pm_10_0_sensor(sens)) if CONF_TEMPERATURE in config: - sens = yield sensor.new_sensor(config[CONF_TEMPERATURE]) + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) cg.add(var.set_temperature_sensor(sens)) if CONF_HUMIDITY in config: - sens = yield sensor.new_sensor(config[CONF_HUMIDITY]) + sens = await sensor.new_sensor(config[CONF_HUMIDITY]) cg.add(var.set_humidity_sensor(sens)) diff --git a/esphome/components/sn74hc595/__init__.py b/esphome/components/sn74hc595/__init__.py index 152ac02106..67d759cadd 100644 --- a/esphome/components/sn74hc595/__init__.py +++ b/esphome/components/sn74hc595/__init__.py @@ -33,17 +33,17 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - data_pin = yield cg.gpio_pin_expression(config[CONF_DATA_PIN]) + await cg.register_component(var, config) + data_pin = await cg.gpio_pin_expression(config[CONF_DATA_PIN]) cg.add(var.set_data_pin(data_pin)) - clock_pin = yield cg.gpio_pin_expression(config[CONF_CLOCK_PIN]) + clock_pin = await cg.gpio_pin_expression(config[CONF_CLOCK_PIN]) cg.add(var.set_clock_pin(clock_pin)) - latch_pin = yield cg.gpio_pin_expression(config[CONF_LATCH_PIN]) + latch_pin = await cg.gpio_pin_expression(config[CONF_LATCH_PIN]) cg.add(var.set_latch_pin(latch_pin)) if CONF_OE_PIN in config: - oe_pin = yield cg.gpio_pin_expression(config[CONF_OE_PIN]) + oe_pin = await cg.gpio_pin_expression(config[CONF_OE_PIN]) cg.add(var.set_oe_pin(oe_pin)) cg.add(var.set_sr_count(config[CONF_SR_COUNT])) diff --git a/esphome/components/sntp/time.py b/esphome/components/sntp/time.py index a142ad72d7..5475dc0a1f 100644 --- a/esphome/components/sntp/time.py +++ b/esphome/components/sntp/time.py @@ -22,15 +22,15 @@ CONFIG_SCHEMA = time_.TIME_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) servers = config[CONF_SERVERS] servers += [""] * (3 - len(servers)) cg.add(var.set_servers(*servers)) - yield cg.register_component(var, config) - yield time_.register_time(var, config) + await cg.register_component(var, config) + await time_.register_time(var, config) if CORE.is_esp8266 and len(servers) > 1: # We need LwIP features enabled to get 3 SNTP servers (not just one) diff --git a/esphome/components/speed/fan/__init__.py b/esphome/components/speed/fan/__init__.py index fdb0a9af09..0ee31c76a0 100644 --- a/esphome/components/speed/fan/__init__.py +++ b/esphome/components/speed/fan/__init__.py @@ -27,18 +27,18 @@ CONFIG_SCHEMA = fan.FAN_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): - output_ = yield cg.get_variable(config[CONF_OUTPUT]) - state = yield fan.create_fan_state(config) +async def to_code(config): + output_ = await cg.get_variable(config[CONF_OUTPUT]) + state = await fan.create_fan_state(config) var = cg.new_Pvariable( config[CONF_OUTPUT_ID], state, output_, config[CONF_SPEED_COUNT] ) - yield cg.register_component(var, config) + await cg.register_component(var, config) if CONF_OSCILLATION_OUTPUT in config: - oscillation_output = yield cg.get_variable(config[CONF_OSCILLATION_OUTPUT]) + oscillation_output = await cg.get_variable(config[CONF_OSCILLATION_OUTPUT]) cg.add(var.set_oscillating(oscillation_output)) if CONF_DIRECTION_OUTPUT in config: - direction_output = yield cg.get_variable(config[CONF_DIRECTION_OUTPUT]) + direction_output = await cg.get_variable(config[CONF_DIRECTION_OUTPUT]) cg.add(var.set_direction(direction_output)) diff --git a/esphome/components/sps30/sensor.py b/esphome/components/sps30/sensor.py index 5bc586ea8b..32c55b969c 100644 --- a/esphome/components/sps30/sensor.py +++ b/esphome/components/sps30/sensor.py @@ -80,47 +80,47 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) if CONF_PM_1_0 in config: - sens = yield sensor.new_sensor(config[CONF_PM_1_0]) + sens = await sensor.new_sensor(config[CONF_PM_1_0]) cg.add(var.set_pm_1_0_sensor(sens)) if CONF_PM_2_5 in config: - sens = yield sensor.new_sensor(config[CONF_PM_2_5]) + sens = await sensor.new_sensor(config[CONF_PM_2_5]) cg.add(var.set_pm_2_5_sensor(sens)) if CONF_PM_4_0 in config: - sens = yield sensor.new_sensor(config[CONF_PM_4_0]) + sens = await sensor.new_sensor(config[CONF_PM_4_0]) cg.add(var.set_pm_4_0_sensor(sens)) if CONF_PM_10_0 in config: - sens = yield sensor.new_sensor(config[CONF_PM_10_0]) + sens = await sensor.new_sensor(config[CONF_PM_10_0]) cg.add(var.set_pm_10_0_sensor(sens)) if CONF_PMC_0_5 in config: - sens = yield sensor.new_sensor(config[CONF_PMC_0_5]) + sens = await sensor.new_sensor(config[CONF_PMC_0_5]) cg.add(var.set_pmc_0_5_sensor(sens)) if CONF_PMC_1_0 in config: - sens = yield sensor.new_sensor(config[CONF_PMC_1_0]) + sens = await sensor.new_sensor(config[CONF_PMC_1_0]) cg.add(var.set_pmc_1_0_sensor(sens)) if CONF_PMC_2_5 in config: - sens = yield sensor.new_sensor(config[CONF_PMC_2_5]) + sens = await sensor.new_sensor(config[CONF_PMC_2_5]) cg.add(var.set_pmc_2_5_sensor(sens)) if CONF_PMC_4_0 in config: - sens = yield sensor.new_sensor(config[CONF_PMC_4_0]) + sens = await sensor.new_sensor(config[CONF_PMC_4_0]) cg.add(var.set_pmc_4_0_sensor(sens)) if CONF_PMC_10_0 in config: - sens = yield sensor.new_sensor(config[CONF_PMC_10_0]) + sens = await sensor.new_sensor(config[CONF_PMC_10_0]) cg.add(var.set_pmc_10_0_sensor(sens)) if CONF_PM_SIZE in config: - sens = yield sensor.new_sensor(config[CONF_PM_SIZE]) + sens = await sensor.new_sensor(config[CONF_PM_SIZE]) cg.add(var.set_pm_size_sensor(sens)) diff --git a/esphome/components/ssd1306_i2c/display.py b/esphome/components/ssd1306_i2c/display.py index c51ef1cfba..4b51a90431 100644 --- a/esphome/components/ssd1306_i2c/display.py +++ b/esphome/components/ssd1306_i2c/display.py @@ -21,7 +21,7 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield ssd1306_base.setup_ssd1036(var, config) - yield i2c.register_i2c_device(var, config) + await ssd1306_base.setup_ssd1036(var, config) + await i2c.register_i2c_device(var, config) diff --git a/esphome/components/ssd1306_spi/display.py b/esphome/components/ssd1306_spi/display.py index b1558ac413..f7dd1553ba 100644 --- a/esphome/components/ssd1306_spi/display.py +++ b/esphome/components/ssd1306_spi/display.py @@ -23,10 +23,10 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield ssd1306_base.setup_ssd1036(var, config) - yield spi.register_spi_device(var, config) + await ssd1306_base.setup_ssd1036(var, config) + await spi.register_spi_device(var, config) - dc = yield cg.gpio_pin_expression(config[CONF_DC_PIN]) + dc = await cg.gpio_pin_expression(config[CONF_DC_PIN]) cg.add(var.set_dc_pin(dc)) diff --git a/esphome/components/ssd1322_spi/display.py b/esphome/components/ssd1322_spi/display.py index fa094acc5f..88b3a53355 100644 --- a/esphome/components/ssd1322_spi/display.py +++ b/esphome/components/ssd1322_spi/display.py @@ -25,10 +25,10 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield ssd1322_base.setup_ssd1322(var, config) - yield spi.register_spi_device(var, config) + await ssd1322_base.setup_ssd1322(var, config) + await spi.register_spi_device(var, config) - dc = yield cg.gpio_pin_expression(config[CONF_DC_PIN]) + dc = await cg.gpio_pin_expression(config[CONF_DC_PIN]) cg.add(var.set_dc_pin(dc)) diff --git a/esphome/components/ssd1325_spi/display.py b/esphome/components/ssd1325_spi/display.py index 6ce133bec1..a86dc751d5 100644 --- a/esphome/components/ssd1325_spi/display.py +++ b/esphome/components/ssd1325_spi/display.py @@ -25,10 +25,10 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield ssd1325_base.setup_ssd1325(var, config) - yield spi.register_spi_device(var, config) + await ssd1325_base.setup_ssd1325(var, config) + await spi.register_spi_device(var, config) - dc = yield cg.gpio_pin_expression(config[CONF_DC_PIN]) + dc = await cg.gpio_pin_expression(config[CONF_DC_PIN]) cg.add(var.set_dc_pin(dc)) diff --git a/esphome/components/ssd1327_i2c/display.py b/esphome/components/ssd1327_i2c/display.py index f13ed003ad..7b581cc92c 100644 --- a/esphome/components/ssd1327_i2c/display.py +++ b/esphome/components/ssd1327_i2c/display.py @@ -23,7 +23,7 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield ssd1327_base.setup_ssd1327(var, config) - yield i2c.register_i2c_device(var, config) + await ssd1327_base.setup_ssd1327(var, config) + await i2c.register_i2c_device(var, config) diff --git a/esphome/components/ssd1327_spi/display.py b/esphome/components/ssd1327_spi/display.py index fe119836a3..138e85eecd 100644 --- a/esphome/components/ssd1327_spi/display.py +++ b/esphome/components/ssd1327_spi/display.py @@ -25,10 +25,10 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield ssd1327_base.setup_ssd1327(var, config) - yield spi.register_spi_device(var, config) + await ssd1327_base.setup_ssd1327(var, config) + await spi.register_spi_device(var, config) - dc = yield cg.gpio_pin_expression(config[CONF_DC_PIN]) + dc = await cg.gpio_pin_expression(config[CONF_DC_PIN]) cg.add(var.set_dc_pin(dc)) diff --git a/esphome/components/ssd1331_spi/display.py b/esphome/components/ssd1331_spi/display.py index c4e9dad8bc..c32ac60578 100644 --- a/esphome/components/ssd1331_spi/display.py +++ b/esphome/components/ssd1331_spi/display.py @@ -25,10 +25,10 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield ssd1331_base.setup_ssd1331(var, config) - yield spi.register_spi_device(var, config) + await ssd1331_base.setup_ssd1331(var, config) + await spi.register_spi_device(var, config) - dc = yield cg.gpio_pin_expression(config[CONF_DC_PIN]) + dc = await cg.gpio_pin_expression(config[CONF_DC_PIN]) cg.add(var.set_dc_pin(dc)) diff --git a/esphome/components/ssd1351_spi/display.py b/esphome/components/ssd1351_spi/display.py index 66e4fad02c..3f3409226c 100644 --- a/esphome/components/ssd1351_spi/display.py +++ b/esphome/components/ssd1351_spi/display.py @@ -25,10 +25,10 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield ssd1351_base.setup_ssd1351(var, config) - yield spi.register_spi_device(var, config) + await ssd1351_base.setup_ssd1351(var, config) + await spi.register_spi_device(var, config) - dc = yield cg.gpio_pin_expression(config[CONF_DC_PIN]) + dc = await cg.gpio_pin_expression(config[CONF_DC_PIN]) cg.add(var.set_dc_pin(dc)) diff --git a/esphome/components/st7735/display.py b/esphome/components/st7735/display.py index f1e7d37d51..bbacc5f55e 100644 --- a/esphome/components/st7735/display.py +++ b/esphome/components/st7735/display.py @@ -1,100 +1,100 @@ -import esphome.codegen as cg -import esphome.config_validation as cv -from esphome import pins -from esphome.components import spi -from esphome.components import display -from esphome.core import coroutine -from esphome.const import ( - CONF_DC_PIN, - CONF_ID, - CONF_LAMBDA, - CONF_MODEL, - CONF_RESET_PIN, - CONF_PAGES, -) -from . import st7735_ns - -CODEOWNERS = ["@SenexCrenshaw"] - -DEPENDENCIES = ["spi"] - -CONF_DEVICE_WIDTH = "device_width" -CONF_DEVICE_HEIGHT = "device_height" -CONF_ROW_START = "row_start" -CONF_COL_START = "col_start" -CONF_EIGHT_BIT_COLOR = "eight_bit_color" -CONF_USE_BGR = "use_bgr" - -SPIST7735 = st7735_ns.class_( - "ST7735", cg.PollingComponent, display.DisplayBuffer, spi.SPIDevice -) -ST7735Model = st7735_ns.enum("ST7735Model") - -MODELS = { - "INITR_GREENTAB": ST7735Model.ST7735_INITR_GREENTAB, - "INITR_REDTAB": ST7735Model.ST7735_INITR_REDTAB, - "INITR_BLACKTAB": ST7735Model.ST7735_INITR_BLACKTAB, - "INITR_MINI160X80": ST7735Model.ST7735_INITR_MINI_160X80, - "INITR_18BLACKTAB": ST7735Model.ST7735_INITR_18BLACKTAB, - "INITR_18REDTAB": ST7735Model.ST7735_INITR_18REDTAB, -} -ST7735_MODEL = cv.enum(MODELS, upper=True, space="_") - - -ST7735_SCHEMA = display.FULL_DISPLAY_SCHEMA.extend( - { - cv.Required(CONF_MODEL): ST7735_MODEL, - cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema, - } -).extend(cv.polling_component_schema("1s")) - -CONFIG_SCHEMA = cv.All( - ST7735_SCHEMA.extend( - { - cv.GenerateID(): cv.declare_id(SPIST7735), - cv.Required(CONF_DC_PIN): pins.gpio_output_pin_schema, - cv.Required(CONF_DEVICE_WIDTH): cv.int_, - cv.Required(CONF_DEVICE_HEIGHT): cv.int_, - cv.Required(CONF_COL_START): cv.int_, - cv.Required(CONF_ROW_START): cv.int_, - cv.Optional(CONF_EIGHT_BIT_COLOR, default=False): cv.boolean, - cv.Optional(CONF_USE_BGR, default=False): cv.boolean, - } - ) - .extend(cv.COMPONENT_SCHEMA) - .extend(spi.spi_device_schema()), - cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA), -) - - -@coroutine -def setup_st7735(var, config): - yield cg.register_component(var, config) - yield display.register_display(var, config) - - if CONF_RESET_PIN in config: - reset = yield cg.gpio_pin_expression(config[CONF_RESET_PIN]) - cg.add(var.set_reset_pin(reset)) - if CONF_LAMBDA in config: - lambda_ = yield cg.process_lambda( - config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void - ) - cg.add(var.set_writer(lambda_)) - - -def to_code(config): - var = cg.new_Pvariable( - config[CONF_ID], - config[CONF_MODEL], - config[CONF_DEVICE_WIDTH], - config[CONF_DEVICE_HEIGHT], - config[CONF_COL_START], - config[CONF_ROW_START], - config[CONF_EIGHT_BIT_COLOR], - config[CONF_USE_BGR], - ) - yield setup_st7735(var, config) - yield spi.register_spi_device(var, config) - - dc = yield cg.gpio_pin_expression(config[CONF_DC_PIN]) - cg.add(var.set_dc_pin(dc)) +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome import pins +from esphome.components import spi +from esphome.components import display +from esphome.core import coroutine +from esphome.const import ( + CONF_DC_PIN, + CONF_ID, + CONF_LAMBDA, + CONF_MODEL, + CONF_RESET_PIN, + CONF_PAGES, +) +from . import st7735_ns + +CODEOWNERS = ["@SenexCrenshaw"] + +DEPENDENCIES = ["spi"] + +CONF_DEVICE_WIDTH = "device_width" +CONF_DEVICE_HEIGHT = "device_height" +CONF_ROW_START = "row_start" +CONF_COL_START = "col_start" +CONF_EIGHT_BIT_COLOR = "eight_bit_color" +CONF_USE_BGR = "use_bgr" + +SPIST7735 = st7735_ns.class_( + "ST7735", cg.PollingComponent, display.DisplayBuffer, spi.SPIDevice +) +ST7735Model = st7735_ns.enum("ST7735Model") + +MODELS = { + "INITR_GREENTAB": ST7735Model.ST7735_INITR_GREENTAB, + "INITR_REDTAB": ST7735Model.ST7735_INITR_REDTAB, + "INITR_BLACKTAB": ST7735Model.ST7735_INITR_BLACKTAB, + "INITR_MINI160X80": ST7735Model.ST7735_INITR_MINI_160X80, + "INITR_18BLACKTAB": ST7735Model.ST7735_INITR_18BLACKTAB, + "INITR_18REDTAB": ST7735Model.ST7735_INITR_18REDTAB, +} +ST7735_MODEL = cv.enum(MODELS, upper=True, space="_") + + +ST7735_SCHEMA = display.FULL_DISPLAY_SCHEMA.extend( + { + cv.Required(CONF_MODEL): ST7735_MODEL, + cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema, + } +).extend(cv.polling_component_schema("1s")) + +CONFIG_SCHEMA = cv.All( + ST7735_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(SPIST7735), + cv.Required(CONF_DC_PIN): pins.gpio_output_pin_schema, + cv.Required(CONF_DEVICE_WIDTH): cv.int_, + cv.Required(CONF_DEVICE_HEIGHT): cv.int_, + cv.Required(CONF_COL_START): cv.int_, + cv.Required(CONF_ROW_START): cv.int_, + cv.Optional(CONF_EIGHT_BIT_COLOR, default=False): cv.boolean, + cv.Optional(CONF_USE_BGR, default=False): cv.boolean, + } + ) + .extend(cv.COMPONENT_SCHEMA) + .extend(spi.spi_device_schema()), + cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA), +) + + +@coroutine +def setup_st7735(var, config): + yield cg.register_component(var, config) + yield display.register_display(var, config) + + if CONF_RESET_PIN in config: + reset = yield cg.gpio_pin_expression(config[CONF_RESET_PIN]) + cg.add(var.set_reset_pin(reset)) + if CONF_LAMBDA in config: + lambda_ = yield cg.process_lambda( + config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void + ) + cg.add(var.set_writer(lambda_)) + + +async def to_code(config): + var = cg.new_Pvariable( + config[CONF_ID], + config[CONF_MODEL], + config[CONF_DEVICE_WIDTH], + config[CONF_DEVICE_HEIGHT], + config[CONF_COL_START], + config[CONF_ROW_START], + config[CONF_EIGHT_BIT_COLOR], + config[CONF_USE_BGR], + ) + await setup_st7735(var, config) + await spi.register_spi_device(var, config) + + dc = await cg.gpio_pin_expression(config[CONF_DC_PIN]) + cg.add(var.set_dc_pin(dc)) diff --git a/esphome/components/st7789v/display.py b/esphome/components/st7789v/display.py index 9b3d550374..a053d00ea2 100644 --- a/esphome/components/st7789v/display.py +++ b/esphome/components/st7789v/display.py @@ -38,24 +38,24 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield spi.register_spi_device(var, config) + await cg.register_component(var, config) + await spi.register_spi_device(var, config) - dc = yield cg.gpio_pin_expression(config[CONF_DC_PIN]) + dc = await cg.gpio_pin_expression(config[CONF_DC_PIN]) cg.add(var.set_dc_pin(dc)) - reset = yield cg.gpio_pin_expression(config[CONF_RESET_PIN]) + reset = await cg.gpio_pin_expression(config[CONF_RESET_PIN]) cg.add(var.set_reset_pin(reset)) - bl = yield cg.gpio_pin_expression(config[CONF_BACKLIGHT_PIN]) + bl = await cg.gpio_pin_expression(config[CONF_BACKLIGHT_PIN]) cg.add(var.set_backlight_pin(bl)) if CONF_LAMBDA in config: - lambda_ = yield cg.process_lambda( + lambda_ = await cg.process_lambda( config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void ) cg.add(var.set_writer(lambda_)) - yield display.register_display(var, config) + await display.register_display(var, config) diff --git a/esphome/components/status/binary_sensor.py b/esphome/components/status/binary_sensor.py index 3a52b0b617..e462bc5385 100644 --- a/esphome/components/status/binary_sensor.py +++ b/esphome/components/status/binary_sensor.py @@ -18,7 +18,7 @@ CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield binary_sensor.register_binary_sensor(var, config) + await cg.register_component(var, config) + await binary_sensor.register_binary_sensor(var, config) diff --git a/esphome/components/stepper/__init__.py b/esphome/components/stepper/__init__.py index 53ddc82e09..ce7b7ae6f9 100644 --- a/esphome/components/stepper/__init__.py +++ b/esphome/components/stepper/__init__.py @@ -146,5 +146,5 @@ def stepper_set_speed_to_code(config, action_id, template_arg, args): @coroutine_with_priority(100.0) -def to_code(config): +async def to_code(config): cg.add_global(stepper_ns.using) diff --git a/esphome/components/sts3x/sensor.py b/esphome/components/sts3x/sensor.py index 5e44c3ca3c..9fb798e7f1 100644 --- a/esphome/components/sts3x/sensor.py +++ b/esphome/components/sts3x/sensor.py @@ -23,8 +23,8 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield sensor.register_sensor(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await sensor.register_sensor(var, config) + await i2c.register_i2c_device(var, config) diff --git a/esphome/components/substitutions/__init__.py b/esphome/components/substitutions/__init__.py index 61ad4a698a..e7a5e24ee6 100644 --- a/esphome/components/substitutions/__init__.py +++ b/esphome/components/substitutions/__init__.py @@ -38,7 +38,7 @@ CONFIG_SCHEMA = cv.Schema( ) -def to_code(config): +async def to_code(config): pass diff --git a/esphome/components/sun/__init__.py b/esphome/components/sun/__init__.py index 8cc911529b..296f2027dc 100644 --- a/esphome/components/sun/__init__.py +++ b/esphome/components/sun/__init__.py @@ -115,28 +115,28 @@ CONFIG_SCHEMA = cv.Schema( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - time_ = yield cg.get_variable(config[CONF_TIME_ID]) + time_ = await cg.get_variable(config[CONF_TIME_ID]) cg.add(var.set_time(time_)) cg.add(var.set_latitude(config[CONF_LATITUDE])) cg.add(var.set_longitude(config[CONF_LONGITUDE])) for conf in config.get(CONF_ON_SUNRISE, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID]) - yield cg.register_component(trigger, conf) - yield cg.register_parented(trigger, var) + await cg.register_component(trigger, conf) + await cg.register_parented(trigger, var) cg.add(trigger.set_sunrise(True)) cg.add(trigger.set_elevation(conf[CONF_ELEVATION])) - yield automation.build_automation(trigger, [], conf) + await automation.build_automation(trigger, [], conf) for conf in config.get(CONF_ON_SUNSET, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID]) - yield cg.register_component(trigger, conf) - yield cg.register_parented(trigger, var) + await cg.register_component(trigger, conf) + await cg.register_parented(trigger, var) cg.add(trigger.set_sunrise(False)) cg.add(trigger.set_elevation(conf[CONF_ELEVATION])) - yield automation.build_automation(trigger, [], conf) + await automation.build_automation(trigger, [], conf) @automation.register_condition( diff --git a/esphome/components/sun/sensor/__init__.py b/esphome/components/sun/sensor/__init__.py index 02e1ef28eb..3e72a2a04e 100644 --- a/esphome/components/sun/sensor/__init__.py +++ b/esphome/components/sun/sensor/__init__.py @@ -32,11 +32,11 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield sensor.register_sensor(var, config) + await cg.register_component(var, config) + await sensor.register_sensor(var, config) cg.add(var.set_type(config[CONF_TYPE])) - paren = yield cg.get_variable(config[CONF_SUN_ID]) + paren = await cg.get_variable(config[CONF_SUN_ID]) cg.add(var.set_parent(paren)) diff --git a/esphome/components/sun/text_sensor/__init__.py b/esphome/components/sun/text_sensor/__init__.py index b527da699b..ac1ce223d1 100644 --- a/esphome/components/sun/text_sensor/__init__.py +++ b/esphome/components/sun/text_sensor/__init__.py @@ -46,12 +46,12 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield text_sensor.register_text_sensor(var, config) + await cg.register_component(var, config) + await text_sensor.register_text_sensor(var, config) - paren = yield cg.get_variable(config[CONF_SUN_ID]) + paren = await cg.get_variable(config[CONF_SUN_ID]) cg.add(var.set_parent(paren)) cg.add(var.set_sunrise(SUN_TYPES[config[CONF_TYPE]])) cg.add(var.set_elevation(config[CONF_ELEVATION])) diff --git a/esphome/components/sx1509/__init__.py b/esphome/components/sx1509/__init__.py index 06ee364e1b..fd0b5befb6 100644 --- a/esphome/components/sx1509/__init__.py +++ b/esphome/components/sx1509/__init__.py @@ -47,10 +47,10 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) if CONF_KEYPAD in config: keypad = config[CONF_KEYPAD] cg.add(var.set_rows_cols(keypad[CONF_KEY_ROWS], keypad[CONF_KEY_COLUMNS])) diff --git a/esphome/components/sx1509/binary_sensor/__init__.py b/esphome/components/sx1509/binary_sensor/__init__.py index e2344cd4af..1560af8e99 100644 --- a/esphome/components/sx1509/binary_sensor/__init__.py +++ b/esphome/components/sx1509/binary_sensor/__init__.py @@ -21,10 +21,10 @@ CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield binary_sensor.register_binary_sensor(var, config) - hub = yield cg.get_variable(config[CONF_SX1509_ID]) + await binary_sensor.register_binary_sensor(var, config) + hub = await cg.get_variable(config[CONF_SX1509_ID]) cg.add(var.set_row_col(config[CONF_ROW], config[CONF_COL])) cg.add(hub.register_keypad_binary_sensor(var)) diff --git a/esphome/components/sx1509/output/__init__.py b/esphome/components/sx1509/output/__init__.py index 878534e829..7afea0fbf8 100644 --- a/esphome/components/sx1509/output/__init__.py +++ b/esphome/components/sx1509/output/__init__.py @@ -19,10 +19,10 @@ CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): - parent = yield cg.get_variable(config[CONF_SX1509_ID]) +async def to_code(config): + parent = await cg.get_variable(config[CONF_SX1509_ID]) var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield output.register_output(var, config) + await cg.register_component(var, config) + await output.register_output(var, config) cg.add(var.set_pin(config[CONF_PIN])) cg.add(var.set_parent(parent)) diff --git a/esphome/components/tca9548a/__init__.py b/esphome/components/tca9548a/__init__.py index aedd751086..62cbace56a 100644 --- a/esphome/components/tca9548a/__init__.py +++ b/esphome/components/tca9548a/__init__.py @@ -22,9 +22,9 @@ CONFIG_SCHEMA = cv.Schema( ).extend(i2c.i2c_device_schema(0x70)) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) cg.add_define("USE_I2C_MULTIPLEXER") - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) cg.add(var.set_scan(config[CONF_SCAN])) diff --git a/esphome/components/tcl112/climate.py b/esphome/components/tcl112/climate.py index 587bdcfbe9..9facd6b8db 100644 --- a/esphome/components/tcl112/climate.py +++ b/esphome/components/tcl112/climate.py @@ -16,6 +16,6 @@ CONFIG_SCHEMA = climate_ir.CLIMATE_IR_WITH_RECEIVER_SCHEMA.extend( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield climate_ir.register_climate_ir(var, config) + await climate_ir.register_climate_ir(var, config) diff --git a/esphome/components/tcs34725/sensor.py b/esphome/components/tcs34725/sensor.py index 84e3c290bf..2b02f7b296 100644 --- a/esphome/components/tcs34725/sensor.py +++ b/esphome/components/tcs34725/sensor.py @@ -78,29 +78,29 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) cg.add(var.set_integration_time(config[CONF_INTEGRATION_TIME])) cg.add(var.set_gain(config[CONF_GAIN])) if CONF_RED_CHANNEL in config: - sens = yield sensor.new_sensor(config[CONF_RED_CHANNEL]) + sens = await sensor.new_sensor(config[CONF_RED_CHANNEL]) cg.add(var.set_red_sensor(sens)) if CONF_GREEN_CHANNEL in config: - sens = yield sensor.new_sensor(config[CONF_GREEN_CHANNEL]) + sens = await sensor.new_sensor(config[CONF_GREEN_CHANNEL]) cg.add(var.set_green_sensor(sens)) if CONF_BLUE_CHANNEL in config: - sens = yield sensor.new_sensor(config[CONF_BLUE_CHANNEL]) + sens = await sensor.new_sensor(config[CONF_BLUE_CHANNEL]) cg.add(var.set_blue_sensor(sens)) if CONF_CLEAR_CHANNEL in config: - sens = yield sensor.new_sensor(config[CONF_CLEAR_CHANNEL]) + sens = await sensor.new_sensor(config[CONF_CLEAR_CHANNEL]) cg.add(var.set_clear_sensor(sens)) if CONF_ILLUMINANCE in config: - sens = yield sensor.new_sensor(config[CONF_ILLUMINANCE]) + sens = await sensor.new_sensor(config[CONF_ILLUMINANCE]) cg.add(var.set_illuminance_sensor(sens)) if CONF_COLOR_TEMPERATURE in config: - sens = yield sensor.new_sensor(config[CONF_COLOR_TEMPERATURE]) + sens = await sensor.new_sensor(config[CONF_COLOR_TEMPERATURE]) cg.add(var.set_color_temperature_sensor(sens)) diff --git a/esphome/components/teleinfo/sensor.py b/esphome/components/teleinfo/sensor.py index 9f6c2c8e89..d8b4dbade7 100644 --- a/esphome/components/teleinfo/sensor.py +++ b/esphome/components/teleinfo/sensor.py @@ -39,12 +39,12 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID], config[CONF_HISTORICAL_MODE]) - yield cg.register_component(var, config) - yield uart.register_uart_device(var, config) + await cg.register_component(var, config) + await uart.register_uart_device(var, config) if CONF_TAGS in config: for tag in config[CONF_TAGS]: - sens = yield sensor.new_sensor(tag[CONF_SENSOR]) + sens = await sensor.new_sensor(tag[CONF_SENSOR]) cg.add(var.register_teleinfo_sensor(tag[CONF_TAG_NAME], sens)) diff --git a/esphome/components/template/binary_sensor/__init__.py b/esphome/components/template/binary_sensor/__init__.py index d23e6423a1..754b7a4a43 100644 --- a/esphome/components/template/binary_sensor/__init__.py +++ b/esphome/components/template/binary_sensor/__init__.py @@ -17,13 +17,13 @@ CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield binary_sensor.register_binary_sensor(var, config) + await cg.register_component(var, config) + await binary_sensor.register_binary_sensor(var, config) if CONF_LAMBDA in config: - template_ = yield cg.process_lambda( + template_ = await cg.process_lambda( config[CONF_LAMBDA], [], return_type=cg.optional.template(bool) ) cg.add(var.set_template(template_)) diff --git a/esphome/components/template/cover/__init__.py b/esphome/components/template/cover/__init__.py index 14050cb7c6..3d28e839ad 100644 --- a/esphome/components/template/cover/__init__.py +++ b/esphome/components/template/cover/__init__.py @@ -52,39 +52,39 @@ CONFIG_SCHEMA = cover.COVER_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield cover.register_cover(var, config) + await cg.register_component(var, config) + await cover.register_cover(var, config) if CONF_LAMBDA in config: - template_ = yield cg.process_lambda( + template_ = await cg.process_lambda( config[CONF_LAMBDA], [], return_type=cg.optional.template(float) ) cg.add(var.set_state_lambda(template_)) if CONF_OPEN_ACTION in config: - yield automation.build_automation( + await automation.build_automation( var.get_open_trigger(), [], config[CONF_OPEN_ACTION] ) if CONF_CLOSE_ACTION in config: - yield automation.build_automation( + await automation.build_automation( var.get_close_trigger(), [], config[CONF_CLOSE_ACTION] ) if CONF_STOP_ACTION in config: - yield automation.build_automation( + await automation.build_automation( var.get_stop_trigger(), [], config[CONF_STOP_ACTION] ) if CONF_TILT_ACTION in config: - yield automation.build_automation( + await automation.build_automation( var.get_tilt_trigger(), [(float, "tilt")], config[CONF_TILT_ACTION] ) cg.add(var.set_has_tilt(True)) if CONF_TILT_LAMBDA in config: - tilt_template_ = yield cg.process_lambda( + tilt_template_ = await cg.process_lambda( config[CONF_TILT_LAMBDA], [], return_type=cg.optional.template(float) ) cg.add(var.set_tilt_lambda(tilt_template_)) if CONF_POSITION_ACTION in config: - yield automation.build_automation( + await automation.build_automation( var.get_position_trigger(), [(float, "pos")], config[CONF_POSITION_ACTION] ) cg.add(var.set_has_position(True)) diff --git a/esphome/components/template/output/__init__.py b/esphome/components/template/output/__init__.py index 61286772d2..b42a4be166 100644 --- a/esphome/components/template/output/__init__.py +++ b/esphome/components/template/output/__init__.py @@ -34,14 +34,14 @@ CONFIG_SCHEMA = cv.typed_schema( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) if config[CONF_TYPE] == CONF_BINARY: - yield automation.build_automation( + await automation.build_automation( var.get_trigger(), [(bool, "state")], config[CONF_WRITE_ACTION] ) else: - yield automation.build_automation( + await automation.build_automation( var.get_trigger(), [(float, "state")], config[CONF_WRITE_ACTION] ) - yield output.register_output(var, config) + await output.register_output(var, config) diff --git a/esphome/components/template/sensor/__init__.py b/esphome/components/template/sensor/__init__.py index 21ef5db32d..ea776f6705 100644 --- a/esphome/components/template/sensor/__init__.py +++ b/esphome/components/template/sensor/__init__.py @@ -28,13 +28,13 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield sensor.register_sensor(var, config) + await cg.register_component(var, config) + await sensor.register_sensor(var, config) if CONF_LAMBDA in config: - template_ = yield cg.process_lambda( + template_ = await cg.process_lambda( config[CONF_LAMBDA], [], return_type=cg.optional.template(float) ) cg.add(var.set_template(template_)) diff --git a/esphome/components/template/switch/__init__.py b/esphome/components/template/switch/__init__.py index 7698e4f2a9..9fd4baeb3a 100644 --- a/esphome/components/template/switch/__init__.py +++ b/esphome/components/template/switch/__init__.py @@ -29,22 +29,22 @@ CONFIG_SCHEMA = switch.SWITCH_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield switch.register_switch(var, config) + await cg.register_component(var, config) + await switch.register_switch(var, config) if CONF_LAMBDA in config: - template_ = yield cg.process_lambda( + template_ = await cg.process_lambda( config[CONF_LAMBDA], [], return_type=cg.optional.template(bool) ) cg.add(var.set_state_lambda(template_)) if CONF_TURN_OFF_ACTION in config: - yield automation.build_automation( + await automation.build_automation( var.get_turn_off_trigger(), [], config[CONF_TURN_OFF_ACTION] ) if CONF_TURN_ON_ACTION in config: - yield automation.build_automation( + await automation.build_automation( var.get_turn_on_trigger(), [], config[CONF_TURN_ON_ACTION] ) cg.add(var.set_optimistic(config[CONF_OPTIMISTIC])) diff --git a/esphome/components/template/text_sensor/__init__.py b/esphome/components/template/text_sensor/__init__.py index cae00e3932..e97632025d 100644 --- a/esphome/components/template/text_sensor/__init__.py +++ b/esphome/components/template/text_sensor/__init__.py @@ -18,13 +18,13 @@ CONFIG_SCHEMA = text_sensor.TEXT_SENSOR_SCHEMA.extend( ).extend(cv.polling_component_schema("60s")) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield text_sensor.register_text_sensor(var, config) + await cg.register_component(var, config) + await text_sensor.register_text_sensor(var, config) if CONF_LAMBDA in config: - template_ = yield cg.process_lambda( + template_ = await cg.process_lambda( config[CONF_LAMBDA], [], return_type=cg.optional.template(cg.std_string) ) cg.add(var.set_template(template_)) diff --git a/esphome/components/thermostat/climate.py b/esphome/components/thermostat/climate.py index 04584583af..4a371ec165 100644 --- a/esphome/components/thermostat/climate.py +++ b/esphome/components/thermostat/climate.py @@ -222,17 +222,17 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield climate.register_climate(var, config) + await cg.register_component(var, config) + await climate.register_climate(var, config) auto_mode_available = CONF_HEAT_ACTION in config and CONF_COOL_ACTION in config two_points_available = CONF_HEAT_ACTION in config and ( CONF_COOL_ACTION in config or CONF_FAN_ONLY_ACTION in config ) - sens = yield cg.get_variable(config[CONF_SENSOR]) + sens = await cg.get_variable(config[CONF_SENSOR]) cg.add(var.set_sensor(sens)) cg.add(var.set_hysteresis(config[CONF_HYSTERESIS])) @@ -254,7 +254,7 @@ def to_code(config): ) cg.add(var.set_normal_config(normal_config)) - yield automation.build_automation( + await automation.build_automation( var.get_idle_action_trigger(), [], config[CONF_IDLE_ACTION] ) @@ -264,117 +264,117 @@ def to_code(config): cg.add(var.set_supports_auto(False)) if CONF_COOL_ACTION in config: - yield automation.build_automation( + await automation.build_automation( var.get_cool_action_trigger(), [], config[CONF_COOL_ACTION] ) cg.add(var.set_supports_cool(True)) if CONF_DRY_ACTION in config: - yield automation.build_automation( + await automation.build_automation( var.get_dry_action_trigger(), [], config[CONF_DRY_ACTION] ) cg.add(var.set_supports_dry(True)) if CONF_FAN_ONLY_ACTION in config: - yield automation.build_automation( + await automation.build_automation( var.get_fan_only_action_trigger(), [], config[CONF_FAN_ONLY_ACTION] ) cg.add(var.set_supports_fan_only(True)) if CONF_HEAT_ACTION in config: - yield automation.build_automation( + await automation.build_automation( var.get_heat_action_trigger(), [], config[CONF_HEAT_ACTION] ) cg.add(var.set_supports_heat(True)) if CONF_AUTO_MODE in config: - yield automation.build_automation( + await automation.build_automation( var.get_auto_mode_trigger(), [], config[CONF_AUTO_MODE] ) if CONF_COOL_MODE in config: - yield automation.build_automation( + await automation.build_automation( var.get_cool_mode_trigger(), [], config[CONF_COOL_MODE] ) cg.add(var.set_supports_cool(True)) if CONF_DRY_MODE in config: - yield automation.build_automation( + await automation.build_automation( var.get_dry_mode_trigger(), [], config[CONF_DRY_MODE] ) cg.add(var.set_supports_dry(True)) if CONF_FAN_ONLY_MODE in config: - yield automation.build_automation( + await automation.build_automation( var.get_fan_only_mode_trigger(), [], config[CONF_FAN_ONLY_MODE] ) cg.add(var.set_supports_fan_only(True)) if CONF_HEAT_MODE in config: - yield automation.build_automation( + await automation.build_automation( var.get_heat_mode_trigger(), [], config[CONF_HEAT_MODE] ) cg.add(var.set_supports_heat(True)) if CONF_OFF_MODE in config: - yield automation.build_automation( + await automation.build_automation( var.get_off_mode_trigger(), [], config[CONF_OFF_MODE] ) if CONF_FAN_MODE_ON_ACTION in config: - yield automation.build_automation( + await automation.build_automation( var.get_fan_mode_on_trigger(), [], config[CONF_FAN_MODE_ON_ACTION] ) cg.add(var.set_supports_fan_mode_on(True)) if CONF_FAN_MODE_OFF_ACTION in config: - yield automation.build_automation( + await automation.build_automation( var.get_fan_mode_off_trigger(), [], config[CONF_FAN_MODE_OFF_ACTION] ) cg.add(var.set_supports_fan_mode_off(True)) if CONF_FAN_MODE_AUTO_ACTION in config: - yield automation.build_automation( + await automation.build_automation( var.get_fan_mode_auto_trigger(), [], config[CONF_FAN_MODE_AUTO_ACTION] ) cg.add(var.set_supports_fan_mode_auto(True)) if CONF_FAN_MODE_LOW_ACTION in config: - yield automation.build_automation( + await automation.build_automation( var.get_fan_mode_low_trigger(), [], config[CONF_FAN_MODE_LOW_ACTION] ) cg.add(var.set_supports_fan_mode_low(True)) if CONF_FAN_MODE_MEDIUM_ACTION in config: - yield automation.build_automation( + await automation.build_automation( var.get_fan_mode_medium_trigger(), [], config[CONF_FAN_MODE_MEDIUM_ACTION] ) cg.add(var.set_supports_fan_mode_medium(True)) if CONF_FAN_MODE_HIGH_ACTION in config: - yield automation.build_automation( + await automation.build_automation( var.get_fan_mode_high_trigger(), [], config[CONF_FAN_MODE_HIGH_ACTION] ) cg.add(var.set_supports_fan_mode_high(True)) if CONF_FAN_MODE_MIDDLE_ACTION in config: - yield automation.build_automation( + await automation.build_automation( var.get_fan_mode_middle_trigger(), [], config[CONF_FAN_MODE_MIDDLE_ACTION] ) cg.add(var.set_supports_fan_mode_middle(True)) if CONF_FAN_MODE_FOCUS_ACTION in config: - yield automation.build_automation( + await automation.build_automation( var.get_fan_mode_focus_trigger(), [], config[CONF_FAN_MODE_FOCUS_ACTION] ) cg.add(var.set_supports_fan_mode_focus(True)) if CONF_FAN_MODE_DIFFUSE_ACTION in config: - yield automation.build_automation( + await automation.build_automation( var.get_fan_mode_diffuse_trigger(), [], config[CONF_FAN_MODE_DIFFUSE_ACTION] ) cg.add(var.set_supports_fan_mode_diffuse(True)) if CONF_SWING_BOTH_ACTION in config: - yield automation.build_automation( + await automation.build_automation( var.get_swing_mode_both_trigger(), [], config[CONF_SWING_BOTH_ACTION] ) cg.add(var.set_supports_swing_mode_both(True)) if CONF_SWING_HORIZONTAL_ACTION in config: - yield automation.build_automation( + await automation.build_automation( var.get_swing_mode_horizontal_trigger(), [], config[CONF_SWING_HORIZONTAL_ACTION], ) cg.add(var.set_supports_swing_mode_horizontal(True)) if CONF_SWING_OFF_ACTION in config: - yield automation.build_automation( + await automation.build_automation( var.get_swing_mode_off_trigger(), [], config[CONF_SWING_OFF_ACTION] ) cg.add(var.set_supports_swing_mode_off(True)) if CONF_SWING_VERTICAL_ACTION in config: - yield automation.build_automation( + await automation.build_automation( var.get_swing_mode_vertical_trigger(), [], config[CONF_SWING_VERTICAL_ACTION], diff --git a/esphome/components/time_based/cover.py b/esphome/components/time_based/cover.py index 9246f78884..9625781c96 100644 --- a/esphome/components/time_based/cover.py +++ b/esphome/components/time_based/cover.py @@ -31,22 +31,22 @@ CONFIG_SCHEMA = cover.COVER_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield cover.register_cover(var, config) + await cg.register_component(var, config) + await cover.register_cover(var, config) - yield automation.build_automation( + await automation.build_automation( var.get_stop_trigger(), [], config[CONF_STOP_ACTION] ) cg.add(var.set_open_duration(config[CONF_OPEN_DURATION])) - yield automation.build_automation( + await automation.build_automation( var.get_open_trigger(), [], config[CONF_OPEN_ACTION] ) cg.add(var.set_close_duration(config[CONF_CLOSE_DURATION])) - yield automation.build_automation( + await automation.build_automation( var.get_close_trigger(), [], config[CONF_CLOSE_ACTION] ) diff --git a/esphome/components/tlc59208f/__init__.py b/esphome/components/tlc59208f/__init__.py index ff5b75954b..419fa397b7 100644 --- a/esphome/components/tlc59208f/__init__.py +++ b/esphome/components/tlc59208f/__init__.py @@ -20,7 +20,7 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) diff --git a/esphome/components/tlc59208f/output.py b/esphome/components/tlc59208f/output.py index 94cf529a75..f7cc89b252 100644 --- a/esphome/components/tlc59208f/output.py +++ b/esphome/components/tlc59208f/output.py @@ -18,8 +18,8 @@ CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( ) -def to_code(config): - paren = yield cg.get_variable(config[CONF_TLC59208F_ID]) +async def to_code(config): + paren = await cg.get_variable(config[CONF_TLC59208F_ID]) rhs = paren.create_channel(config[CONF_CHANNEL]) var = cg.Pvariable(config[CONF_ID], rhs) - yield output.register_output(var, config) + await output.register_output(var, config) diff --git a/esphome/components/tm1637/display.py b/esphome/components/tm1637/display.py index 06a9716e59..7999029f5a 100644 --- a/esphome/components/tm1637/display.py +++ b/esphome/components/tm1637/display.py @@ -28,20 +28,20 @@ CONFIG_SCHEMA = display.BASIC_DISPLAY_SCHEMA.extend( ).extend(cv.polling_component_schema("1s")) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield display.register_display(var, config) + await cg.register_component(var, config) + await display.register_display(var, config) - clk = yield cg.gpio_pin_expression(config[CONF_CLK_PIN]) + clk = await cg.gpio_pin_expression(config[CONF_CLK_PIN]) cg.add(var.set_clk_pin(clk)) - dio = yield cg.gpio_pin_expression(config[CONF_DIO_PIN]) + dio = await cg.gpio_pin_expression(config[CONF_DIO_PIN]) cg.add(var.set_dio_pin(dio)) cg.add(var.set_intensity(config[CONF_INTENSITY])) if CONF_LAMBDA in config: - lambda_ = yield cg.process_lambda( + lambda_ = await cg.process_lambda( config[CONF_LAMBDA], [(TM1637DisplayRef, "it")], return_type=cg.void ) cg.add(var.set_writer(lambda_)) diff --git a/esphome/components/tm1651/__init__.py b/esphome/components/tm1651/__init__.py index 97c1e472e9..e8c1425d83 100644 --- a/esphome/components/tm1651/__init__.py +++ b/esphome/components/tm1651/__init__.py @@ -40,13 +40,13 @@ validate_level = cv.All(cv.int_range(min=0, max=7)) validate_brightness = cv.enum(TM1651_BRIGHTNESS_OPTIONS, int=True) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) + await cg.register_component(var, config) - clk_pin = yield cg.gpio_pin_expression(config[CONF_CLK_PIN]) + clk_pin = await cg.gpio_pin_expression(config[CONF_CLK_PIN]) cg.add(var.set_clk_pin(clk_pin)) - dio_pin = yield cg.gpio_pin_expression(config[CONF_DIO_PIN]) + dio_pin = await cg.gpio_pin_expression(config[CONF_DIO_PIN]) cg.add(var.set_dio_pin(dio_pin)) # https://platformio.org/lib/show/6865/TM1651 diff --git a/esphome/components/tmp102/sensor.py b/esphome/components/tmp102/sensor.py index 4c04271d96..6a0d3cd73e 100644 --- a/esphome/components/tmp102/sensor.py +++ b/esphome/components/tmp102/sensor.py @@ -32,8 +32,8 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) - yield sensor.register_sensor(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + await sensor.register_sensor(var, config) diff --git a/esphome/components/tmp117/sensor.py b/esphome/components/tmp117/sensor.py index 33c13e3f3b..81a9569ca5 100644 --- a/esphome/components/tmp117/sensor.py +++ b/esphome/components/tmp117/sensor.py @@ -70,11 +70,11 @@ def determine_config_register(polling_period): return 0x0000 -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) - yield sensor.register_sensor(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + await sensor.register_sensor(var, config) update_period = config[CONF_UPDATE_INTERVAL].total_seconds cg.add(var.set_config(determine_config_register(update_period))) diff --git a/esphome/components/tof10120/sensor.py b/esphome/components/tof10120/sensor.py index 91a15960b4..5ff8c23cc6 100644 --- a/esphome/components/tof10120/sensor.py +++ b/esphome/components/tof10120/sensor.py @@ -19,8 +19,8 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield sensor.register_sensor(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await sensor.register_sensor(var, config) + await i2c.register_i2c_device(var, config) diff --git a/esphome/components/toshiba/climate.py b/esphome/components/toshiba/climate.py index 3021697f21..95c9f1f127 100644 --- a/esphome/components/toshiba/climate.py +++ b/esphome/components/toshiba/climate.py @@ -15,6 +15,6 @@ CONFIG_SCHEMA = climate_ir.CLIMATE_IR_WITH_RECEIVER_SCHEMA.extend( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield climate_ir.register_climate_ir(var, config) + await climate_ir.register_climate_ir(var, config) diff --git a/esphome/components/total_daily_energy/sensor.py b/esphome/components/total_daily_energy/sensor.py index 150cab77b4..b70a0cece9 100644 --- a/esphome/components/total_daily_energy/sensor.py +++ b/esphome/components/total_daily_energy/sensor.py @@ -20,13 +20,13 @@ CONFIG_SCHEMA = sensor.SENSOR_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield sensor.register_sensor(var, config) + await cg.register_component(var, config) + await sensor.register_sensor(var, config) - sens = yield cg.get_variable(config[CONF_POWER_ID]) + sens = await cg.get_variable(config[CONF_POWER_ID]) cg.add(var.set_parent(sens)) - time_ = yield cg.get_variable(config[CONF_TIME_ID]) + time_ = await cg.get_variable(config[CONF_TIME_ID]) cg.add(var.set_time(time_)) diff --git a/esphome/components/tsl2561/sensor.py b/esphome/components/tsl2561/sensor.py index d0219fc078..a49c776447 100644 --- a/esphome/components/tsl2561/sensor.py +++ b/esphome/components/tsl2561/sensor.py @@ -55,11 +55,11 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) - yield sensor.register_sensor(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + await sensor.register_sensor(var, config) cg.add(var.set_integration_time(config[CONF_INTEGRATION_TIME])) cg.add(var.set_gain(config[CONF_GAIN])) diff --git a/esphome/components/ttp229_bsf/__init__.py b/esphome/components/ttp229_bsf/__init__.py index 8707c9efe3..f1f86c929e 100644 --- a/esphome/components/ttp229_bsf/__init__.py +++ b/esphome/components/ttp229_bsf/__init__.py @@ -21,11 +21,11 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) + await cg.register_component(var, config) - sdo = yield cg.gpio_pin_expression(config[CONF_SDO_PIN]) + sdo = await cg.gpio_pin_expression(config[CONF_SDO_PIN]) cg.add(var.set_sdo_pin(sdo)) - scl = yield cg.gpio_pin_expression(config[CONF_SCL_PIN]) + scl = await cg.gpio_pin_expression(config[CONF_SCL_PIN]) cg.add(var.set_scl_pin(scl)) diff --git a/esphome/components/ttp229_bsf/binary_sensor.py b/esphome/components/ttp229_bsf/binary_sensor.py index 7351e73d80..75540fe0e8 100644 --- a/esphome/components/ttp229_bsf/binary_sensor.py +++ b/esphome/components/ttp229_bsf/binary_sensor.py @@ -16,10 +16,10 @@ CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield binary_sensor.register_binary_sensor(var, config) + await binary_sensor.register_binary_sensor(var, config) cg.add(var.set_channel(config[CONF_CHANNEL])) - hub = yield cg.get_variable(config[CONF_TTP229_ID]) + hub = await cg.get_variable(config[CONF_TTP229_ID]) cg.add(hub.register_channel(var)) diff --git a/esphome/components/ttp229_lsf/__init__.py b/esphome/components/ttp229_lsf/__init__.py index 1d7efea205..cba41a7938 100644 --- a/esphome/components/ttp229_lsf/__init__.py +++ b/esphome/components/ttp229_lsf/__init__.py @@ -25,7 +25,7 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield i2c.register_i2c_device(var, config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) diff --git a/esphome/components/ttp229_lsf/binary_sensor.py b/esphome/components/ttp229_lsf/binary_sensor.py index 09a8a1e207..b52a9e8575 100644 --- a/esphome/components/ttp229_lsf/binary_sensor.py +++ b/esphome/components/ttp229_lsf/binary_sensor.py @@ -16,10 +16,10 @@ CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield binary_sensor.register_binary_sensor(var, config) + await binary_sensor.register_binary_sensor(var, config) cg.add(var.set_channel(config[CONF_CHANNEL])) - hub = yield cg.get_variable(config[CONF_TTP229_ID]) + hub = await cg.get_variable(config[CONF_TTP229_ID]) cg.add(hub.register_channel(var)) diff --git a/esphome/components/tuya/__init__.py b/esphome/components/tuya/__init__.py index 58dad13257..436759979a 100644 --- a/esphome/components/tuya/__init__.py +++ b/esphome/components/tuya/__init__.py @@ -27,12 +27,12 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield uart.register_uart_device(var, config) + await cg.register_component(var, config) + await uart.register_uart_device(var, config) if CONF_TIME_ID in config: - time_ = yield cg.get_variable(config[CONF_TIME_ID]) + time_ = await cg.get_variable(config[CONF_TIME_ID]) cg.add(var.set_time_id(time_)) if CONF_IGNORE_MCU_UPDATE_ON_DATAPOINTS in config: for dp in config[CONF_IGNORE_MCU_UPDATE_ON_DATAPOINTS]: diff --git a/esphome/components/tuya/binary_sensor/__init__.py b/esphome/components/tuya/binary_sensor/__init__.py index 45f918ff24..65f13ea422 100644 --- a/esphome/components/tuya/binary_sensor/__init__.py +++ b/esphome/components/tuya/binary_sensor/__init__.py @@ -22,12 +22,12 @@ CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield binary_sensor.register_binary_sensor(var, config) + await cg.register_component(var, config) + await binary_sensor.register_binary_sensor(var, config) - paren = yield cg.get_variable(config[CONF_TUYA_ID]) + paren = await cg.get_variable(config[CONF_TUYA_ID]) cg.add(var.set_tuya_parent(paren)) cg.add(var.set_sensor_id(config[CONF_SENSOR_DATAPOINT])) diff --git a/esphome/components/tuya/climate/__init__.py b/esphome/components/tuya/climate/__init__.py index 8ac42f7c8f..a24ae23edc 100644 --- a/esphome/components/tuya/climate/__init__.py +++ b/esphome/components/tuya/climate/__init__.py @@ -77,12 +77,12 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield climate.register_climate(var, config) + await cg.register_component(var, config) + await climate.register_climate(var, config) - paren = yield cg.get_variable(config[CONF_TUYA_ID]) + paren = await cg.get_variable(config[CONF_TUYA_ID]) cg.add(var.set_tuya_parent(paren)) if CONF_SWITCH_DATAPOINT in config: diff --git a/esphome/components/tuya/fan/__init__.py b/esphome/components/tuya/fan/__init__.py index 5d3345a5c4..6d660e6d29 100644 --- a/esphome/components/tuya/fan/__init__.py +++ b/esphome/components/tuya/fan/__init__.py @@ -28,14 +28,14 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): - parent = yield cg.get_variable(config[CONF_TUYA_ID]) - state = yield fan.create_fan_state(config) +async def to_code(config): + parent = await cg.get_variable(config[CONF_TUYA_ID]) + state = await fan.create_fan_state(config) var = cg.new_Pvariable( config[CONF_OUTPUT_ID], parent, state, config[CONF_SPEED_COUNT] ) - yield cg.register_component(var, config) + await cg.register_component(var, config) if CONF_SPEED_DATAPOINT in config: cg.add(var.set_speed_id(config[CONF_SPEED_DATAPOINT])) diff --git a/esphome/components/tuya/light/__init__.py b/esphome/components/tuya/light/__init__.py index f8026e47e8..6dd8b6b775 100644 --- a/esphome/components/tuya/light/__init__.py +++ b/esphome/components/tuya/light/__init__.py @@ -40,10 +40,10 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_OUTPUT_ID]) - yield cg.register_component(var, config) - yield light.register_light(var, config) + await cg.register_component(var, config) + await light.register_light(var, config) if CONF_DIMMER_DATAPOINT in config: cg.add(var.set_dimmer_id(config[CONF_DIMMER_DATAPOINT])) @@ -55,5 +55,5 @@ def to_code(config): cg.add(var.set_min_value(config[CONF_MIN_VALUE])) if CONF_MAX_VALUE in config: cg.add(var.set_max_value(config[CONF_MAX_VALUE])) - paren = yield cg.get_variable(config[CONF_TUYA_ID]) + paren = await cg.get_variable(config[CONF_TUYA_ID]) cg.add(var.set_tuya_parent(paren)) diff --git a/esphome/components/tuya/sensor/__init__.py b/esphome/components/tuya/sensor/__init__.py index 0a02fb77a1..d87a2e7ce4 100644 --- a/esphome/components/tuya/sensor/__init__.py +++ b/esphome/components/tuya/sensor/__init__.py @@ -20,12 +20,12 @@ CONFIG_SCHEMA = sensor.SENSOR_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield sensor.register_sensor(var, config) + await cg.register_component(var, config) + await sensor.register_sensor(var, config) - paren = yield cg.get_variable(config[CONF_TUYA_ID]) + paren = await cg.get_variable(config[CONF_TUYA_ID]) cg.add(var.set_tuya_parent(paren)) cg.add(var.set_sensor_id(config[CONF_SENSOR_DATAPOINT])) diff --git a/esphome/components/tuya/switch/__init__.py b/esphome/components/tuya/switch/__init__.py index 4c4ccbf814..4df6bba713 100644 --- a/esphome/components/tuya/switch/__init__.py +++ b/esphome/components/tuya/switch/__init__.py @@ -18,12 +18,12 @@ CONFIG_SCHEMA = switch.SWITCH_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield switch.register_switch(var, config) + await cg.register_component(var, config) + await switch.register_switch(var, config) - paren = yield cg.get_variable(config[CONF_TUYA_ID]) + paren = await cg.get_variable(config[CONF_TUYA_ID]) cg.add(var.set_tuya_parent(paren)) cg.add(var.set_switch_id(config[CONF_SWITCH_DATAPOINT])) diff --git a/esphome/components/tx20/sensor.py b/esphome/components/tx20/sensor.py index 434257470b..5b275505fd 100644 --- a/esphome/components/tx20/sensor.py +++ b/esphome/components/tx20/sensor.py @@ -33,19 +33,19 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) + await cg.register_component(var, config) if CONF_WIND_SPEED in config: conf = config[CONF_WIND_SPEED] - sens = yield sensor.new_sensor(conf) + sens = await sensor.new_sensor(conf) cg.add(var.set_wind_speed_sensor(sens)) if CONF_WIND_DIRECTION_DEGREES in config: conf = config[CONF_WIND_DIRECTION_DEGREES] - sens = yield sensor.new_sensor(conf) + sens = await sensor.new_sensor(conf) cg.add(var.set_wind_direction_degrees_sensor(sens)) - pin = yield cg.gpio_pin_expression(config[CONF_PIN]) + pin = await cg.gpio_pin_expression(config[CONF_PIN]) cg.add(var.set_pin(pin)) diff --git a/esphome/components/uart/switch/__init__.py b/esphome/components/uart/switch/__init__.py index e84035aa3e..9e7f95bd2a 100644 --- a/esphome/components/uart/switch/__init__.py +++ b/esphome/components/uart/switch/__init__.py @@ -26,11 +26,11 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield switch.register_switch(var, config) - yield uart.register_uart_device(var, config) + await cg.register_component(var, config) + await switch.register_switch(var, config) + await uart.register_uart_device(var, config) data = config[CONF_DATA] if isinstance(data, bytes): diff --git a/esphome/components/uln2003/stepper.py b/esphome/components/uln2003/stepper.py index 4d2e5ab518..88252ead73 100644 --- a/esphome/components/uln2003/stepper.py +++ b/esphome/components/uln2003/stepper.py @@ -38,18 +38,18 @@ CONFIG_SCHEMA = stepper.STEPPER_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield stepper.register_stepper(var, config) + await cg.register_component(var, config) + await stepper.register_stepper(var, config) - pin_a = yield cg.gpio_pin_expression(config[CONF_PIN_A]) + pin_a = await cg.gpio_pin_expression(config[CONF_PIN_A]) cg.add(var.set_pin_a(pin_a)) - pin_b = yield cg.gpio_pin_expression(config[CONF_PIN_B]) + pin_b = await cg.gpio_pin_expression(config[CONF_PIN_B]) cg.add(var.set_pin_b(pin_b)) - pin_c = yield cg.gpio_pin_expression(config[CONF_PIN_C]) + pin_c = await cg.gpio_pin_expression(config[CONF_PIN_C]) cg.add(var.set_pin_c(pin_c)) - pin_d = yield cg.gpio_pin_expression(config[CONF_PIN_D]) + pin_d = await cg.gpio_pin_expression(config[CONF_PIN_D]) cg.add(var.set_pin_d(pin_d)) cg.add(var.set_sleep_when_done(config[CONF_SLEEP_WHEN_DONE])) diff --git a/esphome/components/ultrasonic/sensor.py b/esphome/components/ultrasonic/sensor.py index d5d8dec6f4..43492a7a2e 100644 --- a/esphome/components/ultrasonic/sensor.py +++ b/esphome/components/ultrasonic/sensor.py @@ -43,14 +43,14 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield sensor.register_sensor(var, config) + await cg.register_component(var, config) + await sensor.register_sensor(var, config) - trigger = yield cg.gpio_pin_expression(config[CONF_TRIGGER_PIN]) + trigger = await cg.gpio_pin_expression(config[CONF_TRIGGER_PIN]) cg.add(var.set_trigger_pin(trigger)) - echo = yield cg.gpio_pin_expression(config[CONF_ECHO_PIN]) + echo = await cg.gpio_pin_expression(config[CONF_ECHO_PIN]) cg.add(var.set_echo_pin(echo)) cg.add(var.set_timeout_us(config[CONF_TIMEOUT] / (0.000343 / 2))) diff --git a/esphome/components/uptime/sensor.py b/esphome/components/uptime/sensor.py index c2e35ddfef..86bd58e739 100644 --- a/esphome/components/uptime/sensor.py +++ b/esphome/components/uptime/sensor.py @@ -17,7 +17,7 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield sensor.register_sensor(var, config) + await cg.register_component(var, config) + await sensor.register_sensor(var, config) diff --git a/esphome/components/version/text_sensor.py b/esphome/components/version/text_sensor.py index 711800136c..e67f881d32 100644 --- a/esphome/components/version/text_sensor.py +++ b/esphome/components/version/text_sensor.py @@ -17,8 +17,8 @@ CONFIG_SCHEMA = text_sensor.TEXT_SENSOR_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield text_sensor.register_text_sensor(var, config) - yield cg.register_component(var, config) + await text_sensor.register_text_sensor(var, config) + await cg.register_component(var, config) cg.add(var.set_hide_timestamp(config[CONF_HIDE_TIMESTAMP])) diff --git a/esphome/components/vl53l0x/sensor.py b/esphome/components/vl53l0x/sensor.py index 309d4cf8b3..775532dc9e 100644 --- a/esphome/components/vl53l0x/sensor.py +++ b/esphome/components/vl53l0x/sensor.py @@ -58,16 +58,16 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) + await cg.register_component(var, config) cg.add(var.set_signal_rate_limit(config[CONF_SIGNAL_RATE_LIMIT])) cg.add(var.set_long_range(config[CONF_LONG_RANGE])) cg.add(var.set_timeout_us(config[CONF_TIMEOUT])) if CONF_ENABLE_PIN in config: - enable = yield cg.gpio_pin_expression(config[CONF_ENABLE_PIN]) + enable = await cg.gpio_pin_expression(config[CONF_ENABLE_PIN]) cg.add(var.set_enable_pin(enable)) - yield sensor.register_sensor(var, config) - yield i2c.register_i2c_device(var, config) + await sensor.register_sensor(var, config) + await i2c.register_i2c_device(var, config) diff --git a/esphome/components/waveshare_epaper/display.py b/esphome/components/waveshare_epaper/display.py index 16f234563c..42509f39f1 100644 --- a/esphome/components/waveshare_epaper/display.py +++ b/esphome/components/waveshare_epaper/display.py @@ -90,7 +90,7 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): model_type, model = MODELS[config[CONF_MODEL]] if model_type == "a": rhs = WaveshareEPaperTypeA.new(model) @@ -101,23 +101,23 @@ def to_code(config): else: raise NotImplementedError() - yield cg.register_component(var, config) - yield display.register_display(var, config) - yield spi.register_spi_device(var, config) + await cg.register_component(var, config) + await display.register_display(var, config) + await spi.register_spi_device(var, config) - dc = yield cg.gpio_pin_expression(config[CONF_DC_PIN]) + dc = await cg.gpio_pin_expression(config[CONF_DC_PIN]) cg.add(var.set_dc_pin(dc)) if CONF_LAMBDA in config: - lambda_ = yield cg.process_lambda( + lambda_ = await cg.process_lambda( config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void ) cg.add(var.set_writer(lambda_)) if CONF_RESET_PIN in config: - reset = yield cg.gpio_pin_expression(config[CONF_RESET_PIN]) + reset = await cg.gpio_pin_expression(config[CONF_RESET_PIN]) cg.add(var.set_reset_pin(reset)) if CONF_BUSY_PIN in config: - reset = yield cg.gpio_pin_expression(config[CONF_BUSY_PIN]) + reset = await cg.gpio_pin_expression(config[CONF_BUSY_PIN]) cg.add(var.set_busy_pin(reset)) if CONF_FULL_UPDATE_EVERY in config: cg.add(var.set_full_update_every(config[CONF_FULL_UPDATE_EVERY])) diff --git a/esphome/components/whirlpool/climate.py b/esphome/components/whirlpool/climate.py index d6d9f3e111..c5b953c46f 100644 --- a/esphome/components/whirlpool/climate.py +++ b/esphome/components/whirlpool/climate.py @@ -23,7 +23,7 @@ CONFIG_SCHEMA = climate_ir.CLIMATE_IR_WITH_RECEIVER_SCHEMA.extend( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield climate_ir.register_climate_ir(var, config) + await climate_ir.register_climate_ir(var, config) cg.add(var.set_model(config[CONF_MODEL])) diff --git a/esphome/components/wifi_info/text_sensor.py b/esphome/components/wifi_info/text_sensor.py index 07af63524c..11978f7bfe 100644 --- a/esphome/components/wifi_info/text_sensor.py +++ b/esphome/components/wifi_info/text_sensor.py @@ -59,8 +59,8 @@ def setup_conf(config, key): yield text_sensor.register_text_sensor(var, conf) -def to_code(config): - yield setup_conf(config, CONF_IP_ADDRESS) - yield setup_conf(config, CONF_SSID) - yield setup_conf(config, CONF_BSSID) - yield setup_conf(config, CONF_MAC_ADDRESS) +async def to_code(config): + await setup_conf(config, CONF_IP_ADDRESS) + await setup_conf(config, CONF_SSID) + await setup_conf(config, CONF_BSSID) + await setup_conf(config, CONF_MAC_ADDRESS) diff --git a/esphome/components/wifi_signal/sensor.py b/esphome/components/wifi_signal/sensor.py index 891d95d33e..be7f32b0d4 100644 --- a/esphome/components/wifi_signal/sensor.py +++ b/esphome/components/wifi_signal/sensor.py @@ -27,7 +27,7 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield sensor.register_sensor(var, config) + await cg.register_component(var, config) + await sensor.register_sensor(var, config) diff --git a/esphome/components/xiaomi_ble/__init__.py b/esphome/components/xiaomi_ble/__init__.py index 3d11ea8125..046adc6248 100644 --- a/esphome/components/xiaomi_ble/__init__.py +++ b/esphome/components/xiaomi_ble/__init__.py @@ -17,6 +17,6 @@ CONFIG_SCHEMA = cv.Schema( ).extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield esp32_ble_tracker.register_ble_device(var, config) + await esp32_ble_tracker.register_ble_device(var, config) diff --git a/esphome/components/xiaomi_cgd1/sensor.py b/esphome/components/xiaomi_cgd1/sensor.py index 25d1f93674..e8a27660fd 100644 --- a/esphome/components/xiaomi_cgd1/sensor.py +++ b/esphome/components/xiaomi_cgd1/sensor.py @@ -46,20 +46,20 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield esp32_ble_tracker.register_ble_device(var, config) + await cg.register_component(var, config) + await esp32_ble_tracker.register_ble_device(var, config) cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) cg.add(var.set_bindkey(config[CONF_BINDKEY])) if CONF_TEMPERATURE in config: - sens = yield sensor.new_sensor(config[CONF_TEMPERATURE]) + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) cg.add(var.set_temperature(sens)) if CONF_HUMIDITY in config: - sens = yield sensor.new_sensor(config[CONF_HUMIDITY]) + sens = await sensor.new_sensor(config[CONF_HUMIDITY]) cg.add(var.set_humidity(sens)) if CONF_BATTERY_LEVEL in config: - sens = yield sensor.new_sensor(config[CONF_BATTERY_LEVEL]) + sens = await sensor.new_sensor(config[CONF_BATTERY_LEVEL]) cg.add(var.set_battery_level(sens)) diff --git a/esphome/components/xiaomi_cgg1/sensor.py b/esphome/components/xiaomi_cgg1/sensor.py index cedf04d8a6..978393d2d4 100644 --- a/esphome/components/xiaomi_cgg1/sensor.py +++ b/esphome/components/xiaomi_cgg1/sensor.py @@ -46,21 +46,21 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield esp32_ble_tracker.register_ble_device(var, config) + await cg.register_component(var, config) + await esp32_ble_tracker.register_ble_device(var, config) cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) if CONF_BINDKEY in config: cg.add(var.set_bindkey(config[CONF_BINDKEY])) if CONF_TEMPERATURE in config: - sens = yield sensor.new_sensor(config[CONF_TEMPERATURE]) + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) cg.add(var.set_temperature(sens)) if CONF_HUMIDITY in config: - sens = yield sensor.new_sensor(config[CONF_HUMIDITY]) + sens = await sensor.new_sensor(config[CONF_HUMIDITY]) cg.add(var.set_humidity(sens)) if CONF_BATTERY_LEVEL in config: - sens = yield sensor.new_sensor(config[CONF_BATTERY_LEVEL]) + sens = await sensor.new_sensor(config[CONF_BATTERY_LEVEL]) cg.add(var.set_battery_level(sens)) diff --git a/esphome/components/xiaomi_gcls002/sensor.py b/esphome/components/xiaomi_gcls002/sensor.py index b838371155..8789378824 100644 --- a/esphome/components/xiaomi_gcls002/sensor.py +++ b/esphome/components/xiaomi_gcls002/sensor.py @@ -52,22 +52,22 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield esp32_ble_tracker.register_ble_device(var, config) + await cg.register_component(var, config) + await esp32_ble_tracker.register_ble_device(var, config) cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) if CONF_TEMPERATURE in config: - sens = yield sensor.new_sensor(config[CONF_TEMPERATURE]) + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) cg.add(var.set_temperature(sens)) if CONF_MOISTURE in config: - sens = yield sensor.new_sensor(config[CONF_MOISTURE]) + sens = await sensor.new_sensor(config[CONF_MOISTURE]) cg.add(var.set_moisture(sens)) if CONF_ILLUMINANCE in config: - sens = yield sensor.new_sensor(config[CONF_ILLUMINANCE]) + sens = await sensor.new_sensor(config[CONF_ILLUMINANCE]) cg.add(var.set_illuminance(sens)) if CONF_CONDUCTIVITY in config: - sens = yield sensor.new_sensor(config[CONF_CONDUCTIVITY]) + sens = await sensor.new_sensor(config[CONF_CONDUCTIVITY]) cg.add(var.set_conductivity(sens)) diff --git a/esphome/components/xiaomi_hhccjcy01/sensor.py b/esphome/components/xiaomi_hhccjcy01/sensor.py index f657ec9373..13f6e5685c 100644 --- a/esphome/components/xiaomi_hhccjcy01/sensor.py +++ b/esphome/components/xiaomi_hhccjcy01/sensor.py @@ -57,25 +57,25 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield esp32_ble_tracker.register_ble_device(var, config) + await cg.register_component(var, config) + await esp32_ble_tracker.register_ble_device(var, config) cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) if CONF_TEMPERATURE in config: - sens = yield sensor.new_sensor(config[CONF_TEMPERATURE]) + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) cg.add(var.set_temperature(sens)) if CONF_MOISTURE in config: - sens = yield sensor.new_sensor(config[CONF_MOISTURE]) + sens = await sensor.new_sensor(config[CONF_MOISTURE]) cg.add(var.set_moisture(sens)) if CONF_ILLUMINANCE in config: - sens = yield sensor.new_sensor(config[CONF_ILLUMINANCE]) + sens = await sensor.new_sensor(config[CONF_ILLUMINANCE]) cg.add(var.set_illuminance(sens)) if CONF_CONDUCTIVITY in config: - sens = yield sensor.new_sensor(config[CONF_CONDUCTIVITY]) + sens = await sensor.new_sensor(config[CONF_CONDUCTIVITY]) cg.add(var.set_conductivity(sens)) if CONF_BATTERY_LEVEL in config: - sens = yield sensor.new_sensor(config[CONF_BATTERY_LEVEL]) + sens = await sensor.new_sensor(config[CONF_BATTERY_LEVEL]) cg.add(var.set_battery_level(sens)) diff --git a/esphome/components/xiaomi_hhccpot002/sensor.py b/esphome/components/xiaomi_hhccpot002/sensor.py index 820cda173d..d2493f77c6 100644 --- a/esphome/components/xiaomi_hhccpot002/sensor.py +++ b/esphome/components/xiaomi_hhccpot002/sensor.py @@ -39,16 +39,16 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield esp32_ble_tracker.register_ble_device(var, config) + await cg.register_component(var, config) + await esp32_ble_tracker.register_ble_device(var, config) cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) if CONF_MOISTURE in config: - sens = yield sensor.new_sensor(config[CONF_MOISTURE]) + sens = await sensor.new_sensor(config[CONF_MOISTURE]) cg.add(var.set_moisture(sens)) if CONF_CONDUCTIVITY in config: - sens = yield sensor.new_sensor(config[CONF_CONDUCTIVITY]) + sens = await sensor.new_sensor(config[CONF_CONDUCTIVITY]) cg.add(var.set_conductivity(sens)) diff --git a/esphome/components/xiaomi_jqjcy01ym/sensor.py b/esphome/components/xiaomi_jqjcy01ym/sensor.py index ce5e8e2b37..e2c2bce40e 100644 --- a/esphome/components/xiaomi_jqjcy01ym/sensor.py +++ b/esphome/components/xiaomi_jqjcy01ym/sensor.py @@ -54,22 +54,22 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield esp32_ble_tracker.register_ble_device(var, config) + await cg.register_component(var, config) + await esp32_ble_tracker.register_ble_device(var, config) cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) if CONF_TEMPERATURE in config: - sens = yield sensor.new_sensor(config[CONF_TEMPERATURE]) + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) cg.add(var.set_temperature(sens)) if CONF_HUMIDITY in config: - sens = yield sensor.new_sensor(config[CONF_HUMIDITY]) + sens = await sensor.new_sensor(config[CONF_HUMIDITY]) cg.add(var.set_humidity(sens)) if CONF_FORMALDEHYDE in config: - sens = yield sensor.new_sensor(config[CONF_FORMALDEHYDE]) + sens = await sensor.new_sensor(config[CONF_FORMALDEHYDE]) cg.add(var.set_formaldehyde(sens)) if CONF_BATTERY_LEVEL in config: - sens = yield sensor.new_sensor(config[CONF_BATTERY_LEVEL]) + sens = await sensor.new_sensor(config[CONF_BATTERY_LEVEL]) cg.add(var.set_battery_level(sens)) diff --git a/esphome/components/xiaomi_lywsd02/sensor.py b/esphome/components/xiaomi_lywsd02/sensor.py index c17eb17a5f..5ea633dfa3 100644 --- a/esphome/components/xiaomi_lywsd02/sensor.py +++ b/esphome/components/xiaomi_lywsd02/sensor.py @@ -44,19 +44,19 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield esp32_ble_tracker.register_ble_device(var, config) + await cg.register_component(var, config) + await esp32_ble_tracker.register_ble_device(var, config) cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) if CONF_TEMPERATURE in config: - sens = yield sensor.new_sensor(config[CONF_TEMPERATURE]) + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) cg.add(var.set_temperature(sens)) if CONF_HUMIDITY in config: - sens = yield sensor.new_sensor(config[CONF_HUMIDITY]) + sens = await sensor.new_sensor(config[CONF_HUMIDITY]) cg.add(var.set_humidity(sens)) if CONF_BATTERY_LEVEL in config: - sens = yield sensor.new_sensor(config[CONF_BATTERY_LEVEL]) + sens = await sensor.new_sensor(config[CONF_BATTERY_LEVEL]) cg.add(var.set_battery_level(sens)) diff --git a/esphome/components/xiaomi_lywsd03mmc/sensor.py b/esphome/components/xiaomi_lywsd03mmc/sensor.py index b9de3f0bcc..24bd8d78c6 100644 --- a/esphome/components/xiaomi_lywsd03mmc/sensor.py +++ b/esphome/components/xiaomi_lywsd03mmc/sensor.py @@ -48,20 +48,20 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield esp32_ble_tracker.register_ble_device(var, config) + await cg.register_component(var, config) + await esp32_ble_tracker.register_ble_device(var, config) cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) cg.add(var.set_bindkey(config[CONF_BINDKEY])) if CONF_TEMPERATURE in config: - sens = yield sensor.new_sensor(config[CONF_TEMPERATURE]) + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) cg.add(var.set_temperature(sens)) if CONF_HUMIDITY in config: - sens = yield sensor.new_sensor(config[CONF_HUMIDITY]) + sens = await sensor.new_sensor(config[CONF_HUMIDITY]) cg.add(var.set_humidity(sens)) if CONF_BATTERY_LEVEL in config: - sens = yield sensor.new_sensor(config[CONF_BATTERY_LEVEL]) + sens = await sensor.new_sensor(config[CONF_BATTERY_LEVEL]) cg.add(var.set_battery_level(sens)) diff --git a/esphome/components/xiaomi_lywsdcgq/sensor.py b/esphome/components/xiaomi_lywsdcgq/sensor.py index a4a03a3fb0..b36a03e455 100644 --- a/esphome/components/xiaomi_lywsdcgq/sensor.py +++ b/esphome/components/xiaomi_lywsdcgq/sensor.py @@ -44,19 +44,19 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield esp32_ble_tracker.register_ble_device(var, config) + await cg.register_component(var, config) + await esp32_ble_tracker.register_ble_device(var, config) cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) if CONF_TEMPERATURE in config: - sens = yield sensor.new_sensor(config[CONF_TEMPERATURE]) + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) cg.add(var.set_temperature(sens)) if CONF_HUMIDITY in config: - sens = yield sensor.new_sensor(config[CONF_HUMIDITY]) + sens = await sensor.new_sensor(config[CONF_HUMIDITY]) cg.add(var.set_humidity(sens)) if CONF_BATTERY_LEVEL in config: - sens = yield sensor.new_sensor(config[CONF_BATTERY_LEVEL]) + sens = await sensor.new_sensor(config[CONF_BATTERY_LEVEL]) cg.add(var.set_battery_level(sens)) diff --git a/esphome/components/xiaomi_mhoc401/sensor.py b/esphome/components/xiaomi_mhoc401/sensor.py index ee0e06b3a8..94c594621e 100644 --- a/esphome/components/xiaomi_mhoc401/sensor.py +++ b/esphome/components/xiaomi_mhoc401/sensor.py @@ -47,20 +47,20 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield esp32_ble_tracker.register_ble_device(var, config) + await cg.register_component(var, config) + await esp32_ble_tracker.register_ble_device(var, config) cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) cg.add(var.set_bindkey(config[CONF_BINDKEY])) if CONF_TEMPERATURE in config: - sens = yield sensor.new_sensor(config[CONF_TEMPERATURE]) + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) cg.add(var.set_temperature(sens)) if CONF_HUMIDITY in config: - sens = yield sensor.new_sensor(config[CONF_HUMIDITY]) + sens = await sensor.new_sensor(config[CONF_HUMIDITY]) cg.add(var.set_humidity(sens)) if CONF_BATTERY_LEVEL in config: - sens = yield sensor.new_sensor(config[CONF_BATTERY_LEVEL]) + sens = await sensor.new_sensor(config[CONF_BATTERY_LEVEL]) cg.add(var.set_battery_level(sens)) diff --git a/esphome/components/xiaomi_miscale/sensor.py b/esphome/components/xiaomi_miscale/sensor.py index cd225e4853..4423dc13cd 100644 --- a/esphome/components/xiaomi_miscale/sensor.py +++ b/esphome/components/xiaomi_miscale/sensor.py @@ -32,13 +32,13 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield esp32_ble_tracker.register_ble_device(var, config) + await cg.register_component(var, config) + await esp32_ble_tracker.register_ble_device(var, config) cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) if CONF_WEIGHT in config: - sens = yield sensor.new_sensor(config[CONF_WEIGHT]) + sens = await sensor.new_sensor(config[CONF_WEIGHT]) cg.add(var.set_weight(sens)) diff --git a/esphome/components/xiaomi_miscale2/sensor.py b/esphome/components/xiaomi_miscale2/sensor.py index fa124e8860..f20ef38c87 100644 --- a/esphome/components/xiaomi_miscale2/sensor.py +++ b/esphome/components/xiaomi_miscale2/sensor.py @@ -38,16 +38,16 @@ CONFIG_SCHEMA = ( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield esp32_ble_tracker.register_ble_device(var, config) + await cg.register_component(var, config) + await esp32_ble_tracker.register_ble_device(var, config) cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) if CONF_WEIGHT in config: - sens = yield sensor.new_sensor(config[CONF_WEIGHT]) + sens = await sensor.new_sensor(config[CONF_WEIGHT]) cg.add(var.set_weight(sens)) if CONF_IMPEDANCE in config: - sens = yield sensor.new_sensor(config[CONF_IMPEDANCE]) + sens = await sensor.new_sensor(config[CONF_IMPEDANCE]) cg.add(var.set_impedance(sens)) diff --git a/esphome/components/xiaomi_mjyd02yla/binary_sensor.py b/esphome/components/xiaomi_mjyd02yla/binary_sensor.py index 1b0ad03f1a..a1c26b62a8 100644 --- a/esphome/components/xiaomi_mjyd02yla/binary_sensor.py +++ b/esphome/components/xiaomi_mjyd02yla/binary_sensor.py @@ -63,24 +63,24 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield esp32_ble_tracker.register_ble_device(var, config) - yield binary_sensor.register_binary_sensor(var, config) + await cg.register_component(var, config) + await esp32_ble_tracker.register_ble_device(var, config) + await binary_sensor.register_binary_sensor(var, config) cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) cg.add(var.set_bindkey(config[CONF_BINDKEY])) if CONF_IDLE_TIME in config: - sens = yield sensor.new_sensor(config[CONF_IDLE_TIME]) + sens = await sensor.new_sensor(config[CONF_IDLE_TIME]) cg.add(var.set_idle_time(sens)) if CONF_BATTERY_LEVEL in config: - sens = yield sensor.new_sensor(config[CONF_BATTERY_LEVEL]) + sens = await sensor.new_sensor(config[CONF_BATTERY_LEVEL]) cg.add(var.set_battery_level(sens)) if CONF_ILLUMINANCE in config: - sens = yield sensor.new_sensor(config[CONF_ILLUMINANCE]) + sens = await sensor.new_sensor(config[CONF_ILLUMINANCE]) cg.add(var.set_illuminance(sens)) if CONF_LIGHT in config: - sens = yield binary_sensor.new_binary_sensor(config[CONF_LIGHT]) + sens = await binary_sensor.new_binary_sensor(config[CONF_LIGHT]) cg.add(var.set_light(sens)) diff --git a/esphome/components/xiaomi_mue4094rt/binary_sensor.py b/esphome/components/xiaomi_mue4094rt/binary_sensor.py index 353e9aa3a6..5d19263c9c 100644 --- a/esphome/components/xiaomi_mue4094rt/binary_sensor.py +++ b/esphome/components/xiaomi_mue4094rt/binary_sensor.py @@ -33,11 +33,11 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield esp32_ble_tracker.register_ble_device(var, config) - yield binary_sensor.register_binary_sensor(var, config) + await cg.register_component(var, config) + await esp32_ble_tracker.register_ble_device(var, config) + await binary_sensor.register_binary_sensor(var, config) cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) cg.add(var.set_time(config[CONF_TIMEOUT])) diff --git a/esphome/components/xiaomi_wx08zm/binary_sensor.py b/esphome/components/xiaomi_wx08zm/binary_sensor.py index c13085b5eb..d538d4fbd7 100644 --- a/esphome/components/xiaomi_wx08zm/binary_sensor.py +++ b/esphome/components/xiaomi_wx08zm/binary_sensor.py @@ -43,17 +43,17 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield esp32_ble_tracker.register_ble_device(var, config) - yield binary_sensor.register_binary_sensor(var, config) + await cg.register_component(var, config) + await esp32_ble_tracker.register_ble_device(var, config) + await binary_sensor.register_binary_sensor(var, config) cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) if CONF_TABLET in config: - sens = yield sensor.new_sensor(config[CONF_TABLET]) + sens = await sensor.new_sensor(config[CONF_TABLET]) cg.add(var.set_tablet(sens)) if CONF_BATTERY_LEVEL in config: - sens = yield sensor.new_sensor(config[CONF_BATTERY_LEVEL]) + sens = await sensor.new_sensor(config[CONF_BATTERY_LEVEL]) cg.add(var.set_battery_level(sens)) diff --git a/esphome/components/xpt2046/__init__.py b/esphome/components/xpt2046/__init__.py index fc440bcbba..3de89a6425 100644 --- a/esphome/components/xpt2046/__init__.py +++ b/esphome/components/xpt2046/__init__.py @@ -97,10 +97,10 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield spi.register_spi_device(var, config) + await cg.register_component(var, config) + await spi.register_spi_device(var, config) cg.add(var.set_threshold(config[CONF_THRESHOLD])) cg.add(var.set_report_interval(config[CONF_REPORT_INTERVAL])) @@ -118,11 +118,11 @@ def to_code(config): cg.add(var.set_swap_x_y(config[CONF_SWAP_X_Y])) if CONF_IRQ_PIN in config: - pin = yield cg.gpio_pin_expression(config[CONF_IRQ_PIN]) + pin = await cg.gpio_pin_expression(config[CONF_IRQ_PIN]) cg.add(var.set_irq_pin(pin)) for conf in config.get(CONF_ON_STATE, []): - yield automation.build_automation( + await automation.build_automation( var.get_on_state_trigger(), [(cg.int_, "x"), (cg.int_, "y"), (cg.bool_, "touched")], conf, diff --git a/esphome/components/xpt2046/binary_sensor.py b/esphome/components/xpt2046/binary_sensor.py index 457b706caf..6959d6c342 100644 --- a/esphome/components/xpt2046/binary_sensor.py +++ b/esphome/components/xpt2046/binary_sensor.py @@ -41,10 +41,10 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield binary_sensor.register_binary_sensor(var, config) - hub = yield cg.get_variable(config[CONF_XPT2046_ID]) + await binary_sensor.register_binary_sensor(var, config) + hub = await cg.get_variable(config[CONF_XPT2046_ID]) cg.add( var.set_area( config[CONF_X_MIN], diff --git a/esphome/components/yashima/climate.py b/esphome/components/yashima/climate.py index 2965d4cdb8..8cafd468ac 100644 --- a/esphome/components/yashima/climate.py +++ b/esphome/components/yashima/climate.py @@ -24,16 +24,16 @@ CONFIG_SCHEMA = cv.All( ) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) - yield climate.register_climate(var, config) + await cg.register_component(var, config) + await climate.register_climate(var, config) cg.add(var.set_supports_cool(config[CONF_SUPPORTS_COOL])) cg.add(var.set_supports_heat(config[CONF_SUPPORTS_HEAT])) if CONF_SENSOR in config: - sens = yield cg.get_variable(config[CONF_SENSOR]) + sens = await cg.get_variable(config[CONF_SENSOR]) cg.add(var.set_sensor(sens)) - transmitter = yield cg.get_variable(config[CONF_TRANSMITTER_ID]) + transmitter = await cg.get_variable(config[CONF_TRANSMITTER_ID]) cg.add(var.set_transmitter(transmitter)) diff --git a/esphome/components/zyaura/sensor.py b/esphome/components/zyaura/sensor.py index e9035ce106..ebd43af630 100644 --- a/esphome/components/zyaura/sensor.py +++ b/esphome/components/zyaura/sensor.py @@ -45,21 +45,21 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.polling_component_schema("60s")) -def to_code(config): +async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) + await cg.register_component(var, config) - pin_clock = yield gpio_pin_expression(config[CONF_CLOCK_PIN]) + pin_clock = await gpio_pin_expression(config[CONF_CLOCK_PIN]) cg.add(var.set_pin_clock(pin_clock)) - pin_data = yield gpio_pin_expression(config[CONF_DATA_PIN]) + pin_data = await gpio_pin_expression(config[CONF_DATA_PIN]) cg.add(var.set_pin_data(pin_data)) if CONF_CO2 in config: - sens = yield sensor.new_sensor(config[CONF_CO2]) + sens = await sensor.new_sensor(config[CONF_CO2]) cg.add(var.set_co2_sensor(sens)) if CONF_TEMPERATURE in config: - sens = yield sensor.new_sensor(config[CONF_TEMPERATURE]) + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) cg.add(var.set_temperature_sensor(sens)) if CONF_HUMIDITY in config: - sens = yield sensor.new_sensor(config[CONF_HUMIDITY]) + sens = await sensor.new_sensor(config[CONF_HUMIDITY]) cg.add(var.set_humidity_sensor(sens)) From 93d9d4b50ad12886b8ef5249c31a16d1f05e626e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 May 2021 11:23:29 +0200 Subject: [PATCH 059/104] Bump protobuf from 3.15.8 to 3.17.0 (#1776) Bumps [protobuf](https://github.com/protocolbuffers/protobuf) from 3.15.8 to 3.17.0. - [Release notes](https://github.com/protocolbuffers/protobuf/releases) - [Changelog](https://github.com/protocolbuffers/protobuf/blob/master/generate_changelog.py) - [Commits](https://github.com/protocolbuffers/protobuf/compare/v3.15.8...v3.17.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index f749358001..5915c2963f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,7 @@ PyYAML==5.4.1 paho-mqtt==1.5.1 colorama==0.4.4 tornado==6.1 -protobuf==3.15.8 +protobuf==3.17.0 tzlocal==2.1 pytz==2021.1 pyserial==3.5 From a33bb328744bd46800ade33bf37a28cf24ae17d3 Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Mon, 24 May 2021 21:45:31 +0200 Subject: [PATCH 060/104] Convert components to async-def syntax (#1823) * Convert components to async-def syntax * Remove stray @coroutine * Manual part * Convert complexer components code to async-def * Manual cleanup * More manual cleanup --- esphome/components/adalight/__init__.py | 7 +- esphome/components/binary_sensor/__init__.py | 46 ++--- esphome/components/ble_client/__init__.py | 6 +- esphome/components/bme680_bsec/sensor.py | 6 +- esphome/components/bme680_bsec/text_sensor.py | 6 +- esphome/components/canbus/__init__.py | 28 ++- esphome/components/deep_sleep/__init__.py | 14 +- esphome/components/dfplayer/__init__.py | 100 +++++------ esphome/components/display/__init__.py | 8 +- esphome/components/ds1307/time.py | 12 +- esphome/components/e131/__init__.py | 6 +- .../components/esp32_ble_tracker/__init__.py | 15 +- esphome/components/esp8266_pwm/output.py | 8 +- esphome/components/fastled_base/__init__.py | 10 +- .../components/fingerprint_grow/__init__.py | 48 ++--- esphome/components/http_request/__init__.py | 18 +- esphome/components/integration/sensor.py | 6 +- esphome/components/lcd_base/__init__.py | 8 +- esphome/components/ledc/output.py | 8 +- esphome/components/light/automation.py | 68 ++++---- esphome/components/light/effects.py | 64 +++---- esphome/components/mcp23016/__init__.py | 6 +- esphome/components/mcp23xxx_base/__init__.py | 10 +- esphome/components/mhz19/sensor.py | 6 +- esphome/components/modbus/__init__.py | 6 +- esphome/components/pcf8574/__init__.py | 6 +- esphome/components/pid/climate.py | 24 +-- esphome/components/pn532/__init__.py | 18 +- esphome/components/pulse_meter/sensor.py | 8 +- esphome/components/rc522/__init__.py | 10 +- esphome/components/remote_base/__init__.py | 165 +++++++++--------- esphome/components/rf_bridge/__init__.py | 56 +++--- esphome/components/rotary_encoder/sensor.py | 8 +- esphome/components/rtttl/__init__.py | 20 +-- esphome/components/script/__init__.py | 28 +-- esphome/components/senseair/sensor.py | 6 +- esphome/components/sensor/__init__.py | 72 ++++---- esphome/components/servo/__init__.py | 14 +- esphome/components/sim800l/__init__.py | 18 +- esphome/components/sn74hc595/__init__.py | 6 +- esphome/components/ssd1306_base/__init__.py | 12 +- esphome/components/ssd1322_base/__init__.py | 12 +- esphome/components/ssd1325_base/__init__.py | 12 +- esphome/components/ssd1327_base/__init__.py | 12 +- esphome/components/ssd1331_base/__init__.py | 12 +- esphome/components/ssd1351_base/__init__.py | 12 +- esphome/components/st7735/display.py | 12 +- esphome/components/stepper/__init__.py | 34 ++-- esphome/components/sun/__init__.py | 16 +- esphome/components/sx1509/__init__.py | 6 +- .../template/binary_sensor/__init__.py | 8 +- esphome/components/template/cover/__init__.py | 14 +- .../components/template/sensor/__init__.py | 8 +- .../components/template/switch/__init__.py | 8 +- .../template/text_sensor/__init__.py | 8 +- esphome/components/tm1651/__init__.py | 36 ++-- esphome/components/wifi_info/text_sensor.py | 8 +- esphome/components/wled/__init__.py | 4 +- esphome/cpp_generator.py | 8 +- esphome/cpp_helpers.py | 4 +- 60 files changed, 592 insertions(+), 633 deletions(-) diff --git a/esphome/components/adalight/__init__.py b/esphome/components/adalight/__init__.py index 169a137165..919ffecbea 100644 --- a/esphome/components/adalight/__init__.py +++ b/esphome/components/adalight/__init__.py @@ -21,8 +21,7 @@ CONFIG_SCHEMA = cv.Schema({}) "Adalight", {cv.GenerateID(CONF_UART_ID): cv.use_id(uart.UARTComponent)}, ) -def adalight_light_effect_to_code(config, effect_id): +async def adalight_light_effect_to_code(config, effect_id): effect = cg.new_Pvariable(effect_id, config[CONF_NAME]) - yield uart.register_uart_device(effect, config) - - yield effect + await uart.register_uart_device(effect, config) + return effect diff --git a/esphome/components/binary_sensor/__init__.py b/esphome/components/binary_sensor/__init__.py index c31a14996f..68d4d3e324 100644 --- a/esphome/components/binary_sensor/__init__.py +++ b/esphome/components/binary_sensor/__init__.py @@ -129,35 +129,35 @@ validate_filters = cv.validate_registry("filter", FILTER_REGISTRY) @FILTER_REGISTRY.register("invert", InvertFilter, {}) -def invert_filter_to_code(config, filter_id): - yield cg.new_Pvariable(filter_id) +async def invert_filter_to_code(config, filter_id): + return cg.new_Pvariable(filter_id) @FILTER_REGISTRY.register( "delayed_on_off", DelayedOnOffFilter, cv.positive_time_period_milliseconds ) -def delayed_on_off_filter_to_code(config, filter_id): +async def delayed_on_off_filter_to_code(config, filter_id): var = cg.new_Pvariable(filter_id, config) - yield cg.register_component(var, {}) - yield var + await cg.register_component(var, {}) + return var @FILTER_REGISTRY.register( "delayed_on", DelayedOnFilter, cv.positive_time_period_milliseconds ) -def delayed_on_filter_to_code(config, filter_id): +async def delayed_on_filter_to_code(config, filter_id): var = cg.new_Pvariable(filter_id, config) - yield cg.register_component(var, {}) - yield var + await cg.register_component(var, {}) + return var @FILTER_REGISTRY.register( "delayed_off", DelayedOffFilter, cv.positive_time_period_milliseconds ) -def delayed_off_filter_to_code(config, filter_id): +async def delayed_off_filter_to_code(config, filter_id): var = cg.new_Pvariable(filter_id, config) - yield cg.register_component(var, {}) - yield var + await cg.register_component(var, {}) + return var CONF_TIME_OFF = "time_off" @@ -187,7 +187,7 @@ DEFAULT_TIME_ON = "900ms" ), ), ) -def autorepeat_filter_to_code(config, filter_id): +async def autorepeat_filter_to_code(config, filter_id): timings = [] if len(config) > 0: for conf in config: @@ -201,16 +201,16 @@ def autorepeat_filter_to_code(config, filter_id): ) ) var = cg.new_Pvariable(filter_id, timings) - yield cg.register_component(var, {}) - yield var + await cg.register_component(var, {}) + return var @FILTER_REGISTRY.register("lambda", LambdaFilter, cv.returning_lambda) -def lambda_filter_to_code(config, filter_id): - lambda_ = yield cg.process_lambda( +async def lambda_filter_to_code(config, filter_id): + lambda_ = await cg.process_lambda( config, [(bool, "x")], return_type=cg.optional.template(bool) ) - yield cg.new_Pvariable(filter_id, lambda_) + return cg.new_Pvariable(filter_id, lambda_) MULTI_CLICK_TIMING_SCHEMA = cv.Schema( @@ -466,17 +466,17 @@ BINARY_SENSOR_CONDITION_SCHEMA = maybe_simple_id( @automation.register_condition( "binary_sensor.is_on", BinarySensorCondition, BINARY_SENSOR_CONDITION_SCHEMA ) -def binary_sensor_is_on_to_code(config, condition_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) - yield cg.new_Pvariable(condition_id, template_arg, paren, True) +async def binary_sensor_is_on_to_code(config, condition_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(condition_id, template_arg, paren, True) @automation.register_condition( "binary_sensor.is_off", BinarySensorCondition, BINARY_SENSOR_CONDITION_SCHEMA ) -def binary_sensor_is_off_to_code(config, condition_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) - yield cg.new_Pvariable(condition_id, template_arg, paren, False) +async def binary_sensor_is_off_to_code(config, condition_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(condition_id, template_arg, paren, False) @coroutine_with_priority(100.0) diff --git a/esphome/components/ble_client/__init__.py b/esphome/components/ble_client/__init__.py index b3ba8c2a47..4bd5c25246 100644 --- a/esphome/components/ble_client/__init__.py +++ b/esphome/components/ble_client/__init__.py @@ -9,7 +9,6 @@ from esphome.const import ( CONF_ON_DISCONNECT, CONF_TRIGGER_ID, ) -from esphome.core import coroutine from esphome import automation CODEOWNERS = ["@buxtronix"] @@ -68,9 +67,8 @@ BLE_CLIENT_SCHEMA = cv.Schema( ) -@coroutine -def register_ble_node(var, config): - parent = yield cg.get_variable(config[CONF_BLE_CLIENT_ID]) +async def register_ble_node(var, config): + parent = await cg.get_variable(config[CONF_BLE_CLIENT_ID]) cg.add(parent.register_ble_node(var)) diff --git a/esphome/components/bme680_bsec/sensor.py b/esphome/components/bme680_bsec/sensor.py index 0781f50f4e..5634b21e75 100644 --- a/esphome/components/bme680_bsec/sensor.py +++ b/esphome/components/bme680_bsec/sensor.py @@ -21,7 +21,6 @@ from esphome.const import ( ICON_THERMOMETER, ICON_WATER_PERCENT, ) -from esphome.core import coroutine from . import ( BME680BSECComponent, CONF_BME680_BSEC_ID, @@ -87,11 +86,10 @@ CONFIG_SCHEMA = cv.Schema( ) -@coroutine -def setup_conf(config, key, hub): +async def setup_conf(config, key, hub): if key in config: conf = config[key] - sens = yield sensor.new_sensor(conf) + sens = await sensor.new_sensor(conf) cg.add(getattr(hub, f"set_{key}_sensor")(sens)) if CONF_SAMPLE_RATE in conf: cg.add(getattr(hub, f"set_{key}_sample_rate")(conf[CONF_SAMPLE_RATE])) diff --git a/esphome/components/bme680_bsec/text_sensor.py b/esphome/components/bme680_bsec/text_sensor.py index 41a63753a6..96020544e7 100644 --- a/esphome/components/bme680_bsec/text_sensor.py +++ b/esphome/components/bme680_bsec/text_sensor.py @@ -2,7 +2,6 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import text_sensor from esphome.const import CONF_ID, CONF_ICON -from esphome.core import coroutine from . import BME680BSECComponent, CONF_BME680_BSEC_ID DEPENDENCIES = ["bme680_bsec"] @@ -25,12 +24,11 @@ CONFIG_SCHEMA = cv.Schema( ) -@coroutine -def setup_conf(config, key, hub): +async def setup_conf(config, key, hub): if key in config: conf = config[key] sens = cg.new_Pvariable(conf[CONF_ID]) - yield text_sensor.register_text_sensor(sens, conf) + await text_sensor.register_text_sensor(sens, conf) cg.add(getattr(hub, f"set_{key}_text_sensor")(sens)) diff --git a/esphome/components/canbus/__init__.py b/esphome/components/canbus/__init__.py index 1cbebb07da..3a3cece579 100644 --- a/esphome/components/canbus/__init__.py +++ b/esphome/components/canbus/__init__.py @@ -1,7 +1,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import automation -from esphome.core import CORE, coroutine +from esphome.core import CORE from esphome.const import CONF_ID, CONF_TRIGGER_ID, CONF_DATA CODEOWNERS = ["@mvturnho", "@danielschramm"] @@ -82,10 +82,9 @@ CANBUS_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) -@coroutine -def setup_canbus_core_(var, config): +async def setup_canbus_core_(var, config): validate_id(config[CONF_CAN_ID], config[CONF_USE_EXTENDED_ID]) - yield cg.register_component(var, config) + await cg.register_component(var, config) cg.add(var.set_can_id([config[CONF_CAN_ID]])) cg.add(var.set_use_extended_id([config[CONF_USE_EXTENDED_ID]])) cg.add(var.set_bitrate(CAN_SPEEDS[config[CONF_BIT_RATE]])) @@ -95,17 +94,16 @@ def setup_canbus_core_(var, config): ext_id = conf[CONF_USE_EXTENDED_ID] validate_id(can_id, ext_id) trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var, can_id, ext_id) - yield cg.register_component(trigger, conf) - yield automation.build_automation( + await cg.register_component(trigger, conf) + await automation.build_automation( trigger, [(cg.std_vector.template(cg.uint8), "x")], conf ) -@coroutine -def register_canbus(var, config): +async def register_canbus(var, config): if not CORE.has_id(config[CONF_ID]): var = cg.new_Pvariable(config[CONF_ID], var) - yield setup_canbus_core_(var, config) + await setup_canbus_core_(var, config) # Actions @@ -122,16 +120,16 @@ def register_canbus(var, config): key=CONF_DATA, ), ) -def canbus_action_to_code(config, action_id, template_arg, args): +async def canbus_action_to_code(config, action_id, template_arg, args): validate_id(config[CONF_CAN_ID], config[CONF_USE_EXTENDED_ID]) var = cg.new_Pvariable(action_id, template_arg) - yield cg.register_parented(var, config[CONF_CANBUS_ID]) + await cg.register_parented(var, config[CONF_CANBUS_ID]) if CONF_CAN_ID in config: - can_id = yield cg.templatable(config[CONF_CAN_ID], args, cg.uint32) + can_id = await cg.templatable(config[CONF_CAN_ID], args, cg.uint32) cg.add(var.set_can_id(can_id)) - use_extended_id = yield cg.templatable( + use_extended_id = await cg.templatable( config[CONF_USE_EXTENDED_ID], args, cg.uint32 ) cg.add(var.set_use_extended_id(use_extended_id)) @@ -140,8 +138,8 @@ def canbus_action_to_code(config, action_id, template_arg, args): if isinstance(data, bytes): data = [int(x) for x in data] if cg.is_template(data): - templ = yield cg.templatable(data, args, cg.std_vector.template(cg.uint8)) + templ = await cg.templatable(data, args, cg.std_vector.template(cg.uint8)) cg.add(var.set_data_template(templ)) else: cg.add(var.set_data_static(data)) - yield var + return var diff --git a/esphome/components/deep_sleep/__init__.py b/esphome/components/deep_sleep/__init__.py index bfc8c40cfb..7011081774 100644 --- a/esphome/components/deep_sleep/__init__.py +++ b/esphome/components/deep_sleep/__init__.py @@ -125,18 +125,18 @@ DEEP_SLEEP_PREVENT_SCHEMA = automation.maybe_simple_id( @automation.register_action( "deep_sleep.enter", EnterDeepSleepAction, DEEP_SLEEP_ENTER_SCHEMA ) -def deep_sleep_enter_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def deep_sleep_enter_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) if CONF_SLEEP_DURATION in config: - template_ = yield cg.templatable(config[CONF_SLEEP_DURATION], args, cg.int32) + template_ = await cg.templatable(config[CONF_SLEEP_DURATION], args, cg.int32) cg.add(var.set_sleep_duration(template_)) - yield var + return var @automation.register_action( "deep_sleep.prevent", PreventDeepSleepAction, DEEP_SLEEP_PREVENT_SCHEMA ) -def deep_sleep_prevent_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) - yield cg.new_Pvariable(action_id, template_arg, paren) +async def deep_sleep_prevent_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, paren) diff --git a/esphome/components/dfplayer/__init__.py b/esphome/components/dfplayer/__init__.py index 95fef4d234..d23e40000e 100644 --- a/esphome/components/dfplayer/__init__.py +++ b/esphome/components/dfplayer/__init__.py @@ -87,10 +87,10 @@ async def to_code(config): } ), ) -def dfplayer_next_to_code(config, action_id, template_arg, args): +async def dfplayer_next_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) - yield cg.register_parented(var, config[CONF_ID]) - yield var + await cg.register_parented(var, config[CONF_ID]) + return var @automation.register_action( @@ -102,10 +102,10 @@ def dfplayer_next_to_code(config, action_id, template_arg, args): } ), ) -def dfplayer_previous_to_code(config, action_id, template_arg, args): +async def dfplayer_previous_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) - yield cg.register_parented(var, config[CONF_ID]) - yield var + await cg.register_parented(var, config[CONF_ID]) + return var @automation.register_action( @@ -120,15 +120,15 @@ def dfplayer_previous_to_code(config, action_id, template_arg, args): key=CONF_FILE, ), ) -def dfplayer_play_to_code(config, action_id, template_arg, args): +async def dfplayer_play_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) - yield cg.register_parented(var, config[CONF_ID]) - template_ = yield cg.templatable(config[CONF_FILE], args, float) + await cg.register_parented(var, config[CONF_ID]) + template_ = await cg.templatable(config[CONF_FILE], args, float) cg.add(var.set_file(template_)) if CONF_LOOP in config: - template_ = yield cg.templatable(config[CONF_LOOP], args, float) + template_ = await cg.templatable(config[CONF_LOOP], args, float) cg.add(var.set_loop(template_)) - yield var + return var @automation.register_action( @@ -143,18 +143,18 @@ def dfplayer_play_to_code(config, action_id, template_arg, args): } ), ) -def dfplayer_play_folder_to_code(config, action_id, template_arg, args): +async def dfplayer_play_folder_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) - yield cg.register_parented(var, config[CONF_ID]) - template_ = yield cg.templatable(config[CONF_FOLDER], args, float) + await cg.register_parented(var, config[CONF_ID]) + template_ = await cg.templatable(config[CONF_FOLDER], args, float) cg.add(var.set_folder(template_)) if CONF_FILE in config: - template_ = yield cg.templatable(config[CONF_FILE], args, float) + template_ = await cg.templatable(config[CONF_FILE], args, float) cg.add(var.set_file(template_)) if CONF_LOOP in config: - template_ = yield cg.templatable(config[CONF_LOOP], args, float) + template_ = await cg.templatable(config[CONF_LOOP], args, float) cg.add(var.set_loop(template_)) - yield var + return var @automation.register_action( @@ -168,12 +168,12 @@ def dfplayer_play_folder_to_code(config, action_id, template_arg, args): key=CONF_DEVICE, ), ) -def dfplayer_set_device_to_code(config, action_id, template_arg, args): +async def dfplayer_set_device_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) - yield cg.register_parented(var, config[CONF_ID]) - template_ = yield cg.templatable(config[CONF_DEVICE], args, Device) + await cg.register_parented(var, config[CONF_ID]) + template_ = await cg.templatable(config[CONF_DEVICE], args, Device) cg.add(var.set_device(template_)) - yield var + return var @automation.register_action( @@ -187,12 +187,12 @@ def dfplayer_set_device_to_code(config, action_id, template_arg, args): key=CONF_VOLUME, ), ) -def dfplayer_set_volume_to_code(config, action_id, template_arg, args): +async def dfplayer_set_volume_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) - yield cg.register_parented(var, config[CONF_ID]) - template_ = yield cg.templatable(config[CONF_VOLUME], args, float) + await cg.register_parented(var, config[CONF_ID]) + template_ = await cg.templatable(config[CONF_VOLUME], args, float) cg.add(var.set_volume(template_)) - yield var + return var @automation.register_action( @@ -206,12 +206,12 @@ def dfplayer_set_volume_to_code(config, action_id, template_arg, args): key=CONF_EQ_PRESET, ), ) -def dfplayer_set_eq_to_code(config, action_id, template_arg, args): +async def dfplayer_set_eq_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) - yield cg.register_parented(var, config[CONF_ID]) - template_ = yield cg.templatable(config[CONF_EQ_PRESET], args, EqPreset) + await cg.register_parented(var, config[CONF_ID]) + template_ = await cg.templatable(config[CONF_EQ_PRESET], args, EqPreset) cg.add(var.set_eq(template_)) - yield var + return var @automation.register_action( @@ -223,10 +223,10 @@ def dfplayer_set_eq_to_code(config, action_id, template_arg, args): } ), ) -def dfplayer_sleep_to_code(config, action_id, template_arg, args): +async def dfplayer_sleep_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) - yield cg.register_parented(var, config[CONF_ID]) - yield var + await cg.register_parented(var, config[CONF_ID]) + return var @automation.register_action( @@ -238,10 +238,10 @@ def dfplayer_sleep_to_code(config, action_id, template_arg, args): } ), ) -def dfplayer_reset_to_code(config, action_id, template_arg, args): +async def dfplayer_reset_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) - yield cg.register_parented(var, config[CONF_ID]) - yield var + await cg.register_parented(var, config[CONF_ID]) + return var @automation.register_action( @@ -253,10 +253,10 @@ def dfplayer_reset_to_code(config, action_id, template_arg, args): } ), ) -def dfplayer_start_to_code(config, action_id, template_arg, args): +async def dfplayer_start_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) - yield cg.register_parented(var, config[CONF_ID]) - yield var + await cg.register_parented(var, config[CONF_ID]) + return var @automation.register_action( @@ -268,10 +268,10 @@ def dfplayer_start_to_code(config, action_id, template_arg, args): } ), ) -def dfplayer_pause_to_code(config, action_id, template_arg, args): +async def dfplayer_pause_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) - yield cg.register_parented(var, config[CONF_ID]) - yield var + await cg.register_parented(var, config[CONF_ID]) + return var @automation.register_action( @@ -283,10 +283,10 @@ def dfplayer_pause_to_code(config, action_id, template_arg, args): } ), ) -def dfplayer_stop_to_code(config, action_id, template_arg, args): +async def dfplayer_stop_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) - yield cg.register_parented(var, config[CONF_ID]) - yield var + await cg.register_parented(var, config[CONF_ID]) + return var @automation.register_action( @@ -298,10 +298,10 @@ def dfplayer_stop_to_code(config, action_id, template_arg, args): } ), ) -def dfplayer_random_to_code(config, action_id, template_arg, args): +async def dfplayer_random_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) - yield cg.register_parented(var, config[CONF_ID]) - yield var + await cg.register_parented(var, config[CONF_ID]) + return var @automation.register_condition( @@ -313,7 +313,7 @@ def dfplayer_random_to_code(config, action_id, template_arg, args): } ), ) -def dfplyaer_is_playing_to_code(config, condition_id, template_arg, args): +async def dfplyaer_is_playing_to_code(config, condition_id, template_arg, args): var = cg.new_Pvariable(condition_id, template_arg) - yield cg.register_parented(var, config[CONF_ID]) - yield var + await cg.register_parented(var, config[CONF_ID]) + return var diff --git a/esphome/components/display/__init__.py b/esphome/components/display/__init__.py index 8f48acf2b7..2dff00da03 100644 --- a/esphome/components/display/__init__.py +++ b/esphome/components/display/__init__.py @@ -169,13 +169,13 @@ async def display_page_show_previous_to_code(config, action_id, template_arg, ar key=CONF_PAGE_ID, ), ) -def display_is_displaying_page_to_code(config, condition_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) - page = yield cg.get_variable(config[CONF_PAGE_ID]) +async def display_is_displaying_page_to_code(config, condition_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + page = await cg.get_variable(config[CONF_PAGE_ID]) var = cg.new_Pvariable(condition_id, template_arg, paren) cg.add(var.set_page(page)) - yield var + return var @coroutine_with_priority(100.0) diff --git a/esphome/components/ds1307/time.py b/esphome/components/ds1307/time.py index cd80a87170..ddc2939038 100644 --- a/esphome/components/ds1307/time.py +++ b/esphome/components/ds1307/time.py @@ -29,10 +29,10 @@ CONFIG_SCHEMA = time.TIME_SCHEMA.extend( } ), ) -def ds1307_write_time_to_code(config, action_id, template_arg, args): +async def ds1307_write_time_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) - yield cg.register_parented(var, config[CONF_ID]) - yield var + await cg.register_parented(var, config[CONF_ID]) + return var @automation.register_action( @@ -44,10 +44,10 @@ def ds1307_write_time_to_code(config, action_id, template_arg, args): } ), ) -def ds1307_read_time_to_code(config, action_id, template_arg, args): +async def ds1307_read_time_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) - yield cg.register_parented(var, config[CONF_ID]) - yield var + await cg.register_parented(var, config[CONF_ID]) + return var async def to_code(config): diff --git a/esphome/components/e131/__init__.py b/esphome/components/e131/__init__.py index e02042d4c9..5eb823064d 100644 --- a/esphome/components/e131/__init__.py +++ b/esphome/components/e131/__init__.py @@ -45,11 +45,11 @@ async def to_code(config): cv.Optional(CONF_CHANNELS, default="RGB"): cv.one_of(*CHANNELS, upper=True), }, ) -def e131_light_effect_to_code(config, effect_id): - parent = yield cg.get_variable(config[CONF_E131_ID]) +async def e131_light_effect_to_code(config, effect_id): + parent = await cg.get_variable(config[CONF_E131_ID]) effect = cg.new_Pvariable(effect_id, config[CONF_NAME]) cg.add(effect.set_first_universe(config[CONF_UNIVERSE])) cg.add(effect.set_channels(CHANNELS[config[CONF_CHANNELS]])) cg.add(effect.set_e131(parent)) - yield effect + return effect diff --git a/esphome/components/esp32_ble_tracker/__init__.py b/esphome/components/esp32_ble_tracker/__init__.py index 916fecffc9..5c70ddb27f 100644 --- a/esphome/components/esp32_ble_tracker/__init__.py +++ b/esphome/components/esp32_ble_tracker/__init__.py @@ -15,7 +15,6 @@ from esphome.const import ( CONF_ON_BLE_SERVICE_DATA_ADVERTISE, CONF_ON_BLE_MANUFACTURER_DATA_ADVERTISE, ) -from esphome.core import coroutine ESP_PLATFORMS = [ESP_PLATFORM_ESP32] AUTO_LOAD = ["xiaomi_ble", "ruuvi_ble"] @@ -216,15 +215,13 @@ async def to_code(config): await automation.build_automation(trigger, [(adv_data_t_const_ref, "x")], conf) -@coroutine -def register_ble_device(var, config): - paren = yield cg.get_variable(config[CONF_ESP32_BLE_ID]) +async def register_ble_device(var, config): + paren = await cg.get_variable(config[CONF_ESP32_BLE_ID]) cg.add(paren.register_listener(var)) - yield var + return var -@coroutine -def register_client(var, config): - paren = yield cg.get_variable(config[CONF_ESP32_BLE_ID]) +async def register_client(var, config): + paren = await cg.get_variable(config[CONF_ESP32_BLE_ID]) cg.add(paren.register_client(var)) - yield var + return var diff --git a/esphome/components/esp8266_pwm/output.py b/esphome/components/esp8266_pwm/output.py index 38361da017..770d400013 100644 --- a/esphome/components/esp8266_pwm/output.py +++ b/esphome/components/esp8266_pwm/output.py @@ -56,9 +56,9 @@ async def to_code(config): } ), ) -def esp8266_set_frequency_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def esp8266_set_frequency_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) - template_ = yield cg.templatable(config[CONF_FREQUENCY], args, float) + template_ = await cg.templatable(config[CONF_FREQUENCY], args, float) cg.add(var.set_frequency(template_)) - yield var + return var diff --git a/esphome/components/fastled_base/__init__.py b/esphome/components/fastled_base/__init__.py index 4c720191b9..f2d0bb1f38 100644 --- a/esphome/components/fastled_base/__init__.py +++ b/esphome/components/fastled_base/__init__.py @@ -7,7 +7,6 @@ from esphome.const import ( CONF_RGB_ORDER, CONF_MAX_REFRESH_RATE, ) -from esphome.core import coroutine CODEOWNERS = ["@OttoWinter"] fastled_base_ns = cg.esphome_ns.namespace("fastled_base") @@ -34,17 +33,16 @@ BASE_SCHEMA = light.ADDRESSABLE_LIGHT_SCHEMA.extend( ).extend(cv.COMPONENT_SCHEMA) -@coroutine -def new_fastled_light(config): +async def new_fastled_light(config): var = cg.new_Pvariable(config[CONF_OUTPUT_ID]) - yield cg.register_component(var, config) + await cg.register_component(var, config) if CONF_MAX_REFRESH_RATE in config: cg.add(var.set_max_refresh_rate(config[CONF_MAX_REFRESH_RATE])) - yield light.register_light(var, config) + await light.register_light(var, config) # https://github.com/FastLED/FastLED/blob/master/library.json # 3.3.3 has an issue on ESP32 with RMT and fastled_clockless: # https://github.com/esphome/issues/issues/1375 cg.add_library("FastLED", "3.3.2") - yield var + return var diff --git a/esphome/components/fingerprint_grow/__init__.py b/esphome/components/fingerprint_grow/__init__.py index 52426a3f2d..757a633e09 100644 --- a/esphome/components/fingerprint_grow/__init__.py +++ b/esphome/components/fingerprint_grow/__init__.py @@ -185,16 +185,16 @@ async def to_code(config): key=CONF_FINGER_ID, ), ) -def fingerprint_grow_enroll_to_code(config, action_id, template_arg, args): +async def fingerprint_grow_enroll_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) - yield cg.register_parented(var, config[CONF_ID]) + await cg.register_parented(var, config[CONF_ID]) - template_ = yield cg.templatable(config[CONF_FINGER_ID], args, cg.uint16) + template_ = await cg.templatable(config[CONF_FINGER_ID], args, cg.uint16) cg.add(var.set_finger_id(template_)) if CONF_NUM_SCANS in config: - template_ = yield cg.templatable(config[CONF_NUM_SCANS], args, cg.uint8) + template_ = await cg.templatable(config[CONF_NUM_SCANS], args, cg.uint8) cg.add(var.set_num_scans(template_)) - yield var + return var @automation.register_action( @@ -206,10 +206,10 @@ def fingerprint_grow_enroll_to_code(config, action_id, template_arg, args): } ), ) -def fingerprint_grow_cancel_enroll_to_code(config, action_id, template_arg, args): +async def fingerprint_grow_cancel_enroll_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) - yield cg.register_parented(var, config[CONF_ID]) - yield var + await cg.register_parented(var, config[CONF_ID]) + return var @automation.register_action( @@ -223,13 +223,13 @@ def fingerprint_grow_cancel_enroll_to_code(config, action_id, template_arg, args key=CONF_FINGER_ID, ), ) -def fingerprint_grow_delete_to_code(config, action_id, template_arg, args): +async def fingerprint_grow_delete_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) - yield cg.register_parented(var, config[CONF_ID]) + await cg.register_parented(var, config[CONF_ID]) - template_ = yield cg.templatable(config[CONF_FINGER_ID], args, cg.uint16) + template_ = await cg.templatable(config[CONF_FINGER_ID], args, cg.uint16) cg.add(var.set_finger_id(template_)) - yield var + return var @automation.register_action( @@ -241,10 +241,10 @@ def fingerprint_grow_delete_to_code(config, action_id, template_arg, args): } ), ) -def fingerprint_grow_delete_all_to_code(config, action_id, template_arg, args): +async def fingerprint_grow_delete_all_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) - yield cg.register_parented(var, config[CONF_ID]) - yield var + await cg.register_parented(var, config[CONF_ID]) + return var FINGERPRINT_GROW_LED_CONTROL_ACTION_SCHEMA = cv.maybe_simple_value( @@ -261,13 +261,13 @@ FINGERPRINT_GROW_LED_CONTROL_ACTION_SCHEMA = cv.maybe_simple_value( LEDControlAction, FINGERPRINT_GROW_LED_CONTROL_ACTION_SCHEMA, ) -def fingerprint_grow_led_control_to_code(config, action_id, template_arg, args): +async def fingerprint_grow_led_control_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) - yield cg.register_parented(var, config[CONF_ID]) + await cg.register_parented(var, config[CONF_ID]) - template_ = yield cg.templatable(config[CONF_STATE], args, cg.bool_) + template_ = await cg.templatable(config[CONF_STATE], args, cg.bool_) cg.add(var.set_state(template_)) - yield var + return var @automation.register_action( @@ -283,11 +283,13 @@ def fingerprint_grow_led_control_to_code(config, action_id, template_arg, args): } ), ) -def fingerprint_grow_aura_led_control_to_code(config, action_id, template_arg, args): +async def fingerprint_grow_aura_led_control_to_code( + config, action_id, template_arg, args +): var = cg.new_Pvariable(action_id, template_arg) - yield cg.register_parented(var, config[CONF_ID]) + await cg.register_parented(var, config[CONF_ID]) for key in [CONF_STATE, CONF_SPEED, CONF_COLOR, CONF_COUNT]: - template_ = yield cg.templatable(config[key], args, cg.uint8) + template_ = await cg.templatable(config[key], args, cg.uint8) cg.add(getattr(var, f"set_{key}")(template_)) - yield var + return var diff --git a/esphome/components/http_request/__init__.py b/esphome/components/http_request/__init__.py index 6512b59d52..650602150a 100644 --- a/esphome/components/http_request/__init__.py +++ b/esphome/components/http_request/__init__.py @@ -171,28 +171,28 @@ HTTP_REQUEST_SEND_ACTION_SCHEMA = HTTP_REQUEST_ACTION_SCHEMA.extend( @automation.register_action( "http_request.send", HttpRequestSendAction, HTTP_REQUEST_SEND_ACTION_SCHEMA ) -def http_request_action_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def http_request_action_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) - template_ = yield cg.templatable(config[CONF_URL], args, cg.std_string) + template_ = await cg.templatable(config[CONF_URL], args, cg.std_string) cg.add(var.set_url(template_)) cg.add(var.set_method(config[CONF_METHOD])) if CONF_BODY in config: - template_ = yield cg.templatable(config[CONF_BODY], args, cg.std_string) + template_ = await cg.templatable(config[CONF_BODY], args, cg.std_string) cg.add(var.set_body(template_)) if CONF_JSON in config: json_ = config[CONF_JSON] if isinstance(json_, Lambda): args_ = args + [(cg.JsonObjectRef, "root")] - lambda_ = yield cg.process_lambda(json_, args_, return_type=cg.void) + lambda_ = await cg.process_lambda(json_, args_, return_type=cg.void) cg.add(var.set_json(lambda_)) else: for key in json_: - template_ = yield cg.templatable(json_[key], args, cg.std_string) + template_ = await cg.templatable(json_[key], args, cg.std_string) cg.add(var.add_json(key, template_)) for key in config.get(CONF_HEADERS, []): - template_ = yield cg.templatable( + template_ = await cg.templatable( config[CONF_HEADERS][key], args, cg.const_char_ptr ) cg.add(var.add_header(key, template_)) @@ -200,6 +200,6 @@ def http_request_action_to_code(config, action_id, template_arg, args): for conf in config.get(CONF_ON_RESPONSE, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID]) cg.add(var.register_response_trigger(trigger)) - yield automation.build_automation(trigger, [(int, "status_code")], conf) + await automation.build_automation(trigger, [(int, "status_code")], conf) - yield var + return var diff --git a/esphome/components/integration/sensor.py b/esphome/components/integration/sensor.py index 5ce5352fd0..3f32394ff6 100644 --- a/esphome/components/integration/sensor.py +++ b/esphome/components/integration/sensor.py @@ -63,6 +63,6 @@ async def to_code(config): } ), ) -def sensor_integration_reset_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) - yield cg.new_Pvariable(action_id, template_arg, paren) +async def sensor_integration_reset_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, paren) diff --git a/esphome/components/lcd_base/__init__.py b/esphome/components/lcd_base/__init__.py index c577d7f8be..0ed2036c55 100644 --- a/esphome/components/lcd_base/__init__.py +++ b/esphome/components/lcd_base/__init__.py @@ -2,7 +2,6 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import display from esphome.const import CONF_DIMENSIONS -from esphome.core import coroutine lcd_base_ns = cg.esphome_ns.namespace("lcd_base") LCDDisplay = lcd_base_ns.class_("LCDDisplay", cg.PollingComponent) @@ -24,8 +23,7 @@ LCD_SCHEMA = display.BASIC_DISPLAY_SCHEMA.extend( ).extend(cv.polling_component_schema("1s")) -@coroutine -def setup_lcd_display(var, config): - yield cg.register_component(var, config) - yield display.register_display(var, config) +async def setup_lcd_display(var, config): + await cg.register_component(var, config) + await display.register_display(var, config) cg.add(var.set_dimensions(config[CONF_DIMENSIONS][0], config[CONF_DIMENSIONS][1])) diff --git a/esphome/components/ledc/output.py b/esphome/components/ledc/output.py index 4431be2ed5..150c5fa410 100644 --- a/esphome/components/ledc/output.py +++ b/esphome/components/ledc/output.py @@ -78,9 +78,9 @@ async def to_code(config): } ), ) -def ledc_set_frequency_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def ledc_set_frequency_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) - template_ = yield cg.templatable(config[CONF_FREQUENCY], args, float) + template_ = await cg.templatable(config[CONF_FREQUENCY], args, float) cg.add(var.set_frequency(template_)) - yield var + return var diff --git a/esphome/components/light/automation.py b/esphome/components/light/automation.py index 7f1c6d9cb9..3fb3126f14 100644 --- a/esphome/components/light/automation.py +++ b/esphome/components/light/automation.py @@ -40,15 +40,15 @@ from .types import ( } ), ) -def light_toggle_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def light_toggle_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) if CONF_TRANSITION_LENGTH in config: - template_ = yield cg.templatable( + template_ = await cg.templatable( config[CONF_TRANSITION_LENGTH], args, cg.uint32 ) cg.add(var.set_transition_length(template_)) - yield var + return var LIGHT_CONTROL_ACTION_SCHEMA = cv.Schema( @@ -97,42 +97,42 @@ LIGHT_TURN_ON_ACTION_SCHEMA = automation.maybe_simple_id( @automation.register_action( "light.control", LightControlAction, LIGHT_CONTROL_ACTION_SCHEMA ) -def light_control_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def light_control_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) if CONF_STATE in config: - template_ = yield cg.templatable(config[CONF_STATE], args, bool) + template_ = await cg.templatable(config[CONF_STATE], args, bool) cg.add(var.set_state(template_)) if CONF_TRANSITION_LENGTH in config: - template_ = yield cg.templatable( + template_ = await cg.templatable( config[CONF_TRANSITION_LENGTH], args, cg.uint32 ) cg.add(var.set_transition_length(template_)) if CONF_FLASH_LENGTH in config: - template_ = yield cg.templatable(config[CONF_FLASH_LENGTH], args, cg.uint32) + template_ = await cg.templatable(config[CONF_FLASH_LENGTH], args, cg.uint32) cg.add(var.set_flash_length(template_)) if CONF_BRIGHTNESS in config: - template_ = yield cg.templatable(config[CONF_BRIGHTNESS], args, float) + template_ = await cg.templatable(config[CONF_BRIGHTNESS], args, float) cg.add(var.set_brightness(template_)) if CONF_RED in config: - template_ = yield cg.templatable(config[CONF_RED], args, float) + template_ = await cg.templatable(config[CONF_RED], args, float) cg.add(var.set_red(template_)) if CONF_GREEN in config: - template_ = yield cg.templatable(config[CONF_GREEN], args, float) + template_ = await cg.templatable(config[CONF_GREEN], args, float) cg.add(var.set_green(template_)) if CONF_BLUE in config: - template_ = yield cg.templatable(config[CONF_BLUE], args, float) + template_ = await cg.templatable(config[CONF_BLUE], args, float) cg.add(var.set_blue(template_)) if CONF_WHITE in config: - template_ = yield cg.templatable(config[CONF_WHITE], args, float) + template_ = await cg.templatable(config[CONF_WHITE], args, float) cg.add(var.set_white(template_)) if CONF_COLOR_TEMPERATURE in config: - template_ = yield cg.templatable(config[CONF_COLOR_TEMPERATURE], args, float) + template_ = await cg.templatable(config[CONF_COLOR_TEMPERATURE], args, float) cg.add(var.set_color_temperature(template_)) if CONF_EFFECT in config: - template_ = yield cg.templatable(config[CONF_EFFECT], args, cg.std_string) + template_ = await cg.templatable(config[CONF_EFFECT], args, cg.std_string) cg.add(var.set_effect(template_)) - yield var + return var CONF_RELATIVE_BRIGHTNESS = "relative_brightness" @@ -152,15 +152,15 @@ LIGHT_DIM_RELATIVE_ACTION_SCHEMA = cv.Schema( @automation.register_action( "light.dim_relative", DimRelativeAction, LIGHT_DIM_RELATIVE_ACTION_SCHEMA ) -def light_dim_relative_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def light_dim_relative_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) - templ = yield cg.templatable(config[CONF_RELATIVE_BRIGHTNESS], args, float) + templ = await cg.templatable(config[CONF_RELATIVE_BRIGHTNESS], args, float) cg.add(var.set_relative_brightness(templ)) if CONF_TRANSITION_LENGTH in config: - templ = yield cg.templatable(config[CONF_TRANSITION_LENGTH], args, cg.uint32) + templ = await cg.templatable(config[CONF_TRANSITION_LENGTH], args, cg.uint32) cg.add(var.set_transition_length(templ)) - yield var + return var LIGHT_ADDRESSABLE_SET_ACTION_SCHEMA = cv.Schema( @@ -179,40 +179,40 @@ LIGHT_ADDRESSABLE_SET_ACTION_SCHEMA = cv.Schema( @automation.register_action( "light.addressable_set", AddressableSet, LIGHT_ADDRESSABLE_SET_ACTION_SCHEMA ) -def light_addressable_set_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def light_addressable_set_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) if CONF_RANGE_FROM in config: - templ = yield cg.templatable(config[CONF_RANGE_FROM], args, cg.int32) + templ = await cg.templatable(config[CONF_RANGE_FROM], args, cg.int32) cg.add(var.set_range_from(templ)) if CONF_RANGE_TO in config: - templ = yield cg.templatable(config[CONF_RANGE_TO], args, cg.int32) + templ = await cg.templatable(config[CONF_RANGE_TO], args, cg.int32) cg.add(var.set_range_to(templ)) def rgbw_to_exp(x): return int(round(x * 255)) if CONF_RED in config: - templ = yield cg.templatable( + templ = await cg.templatable( config[CONF_RED], args, cg.uint8, to_exp=rgbw_to_exp ) cg.add(var.set_red(templ)) if CONF_GREEN in config: - templ = yield cg.templatable( + templ = await cg.templatable( config[CONF_GREEN], args, cg.uint8, to_exp=rgbw_to_exp ) cg.add(var.set_green(templ)) if CONF_BLUE in config: - templ = yield cg.templatable( + templ = await cg.templatable( config[CONF_BLUE], args, cg.uint8, to_exp=rgbw_to_exp ) cg.add(var.set_blue(templ)) if CONF_WHITE in config: - templ = yield cg.templatable( + templ = await cg.templatable( config[CONF_WHITE], args, cg.uint8, to_exp=rgbw_to_exp ) cg.add(var.set_white(templ)) - yield var + return var @automation.register_condition( @@ -233,6 +233,6 @@ def light_addressable_set_to_code(config, action_id, template_arg, args): } ), ) -def light_is_on_off_to_code(config, condition_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) - yield cg.new_Pvariable(condition_id, template_arg, paren) +async def light_is_on_off_to_code(config, condition_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(condition_id, template_arg, paren) diff --git a/esphome/components/light/effects.py b/esphome/components/light/effects.py index 48785df523..c213de0ae6 100644 --- a/esphome/components/light/effects.py +++ b/esphome/components/light/effects.py @@ -133,9 +133,9 @@ def register_addressable_effect( cv.Optional(CONF_UPDATE_INTERVAL, default="0ms"): cv.update_interval, }, ) -def lambda_effect_to_code(config, effect_id): - lambda_ = yield cg.process_lambda(config[CONF_LAMBDA], [], return_type=cg.void) - yield cg.new_Pvariable( +async def lambda_effect_to_code(config, effect_id): + lambda_ = await cg.process_lambda(config[CONF_LAMBDA], [], return_type=cg.void) + return cg.new_Pvariable( effect_id, config[CONF_NAME], lambda_, config[CONF_UPDATE_INTERVAL] ) @@ -148,10 +148,10 @@ def lambda_effect_to_code(config, effect_id): cv.Required(CONF_SEQUENCE): automation.validate_automation(single=True), }, ) -def automation_effect_to_code(config, effect_id): - var = yield cg.new_Pvariable(effect_id, config[CONF_NAME]) - yield automation.build_automation(var.get_trig(), [], config[CONF_SEQUENCE]) - yield var +async def automation_effect_to_code(config, effect_id): + var = cg.new_Pvariable(effect_id, config[CONF_NAME]) + await automation.build_automation(var.get_trig(), [], config[CONF_SEQUENCE]) + return var @register_monochromatic_effect( @@ -167,11 +167,11 @@ def automation_effect_to_code(config, effect_id): ): cv.positive_time_period_milliseconds, }, ) -def pulse_effect_to_code(config, effect_id): +async def pulse_effect_to_code(config, effect_id): effect = cg.new_Pvariable(effect_id, config[CONF_NAME]) cg.add(effect.set_transition_length(config[CONF_TRANSITION_LENGTH])) cg.add(effect.set_update_interval(config[CONF_UPDATE_INTERVAL])) - yield effect + return effect @register_monochromatic_effect( @@ -187,11 +187,11 @@ def pulse_effect_to_code(config, effect_id): ): cv.positive_time_period_milliseconds, }, ) -def random_effect_to_code(config, effect_id): +async def random_effect_to_code(config, effect_id): effect = cg.new_Pvariable(effect_id, config[CONF_NAME]) cg.add(effect.set_transition_length(config[CONF_TRANSITION_LENGTH])) cg.add(effect.set_update_interval(config[CONF_UPDATE_INTERVAL])) - yield effect + return effect @register_binary_effect( @@ -233,7 +233,7 @@ def random_effect_to_code(config, effect_id): ), }, ) -def strobe_effect_to_code(config, effect_id): +async def strobe_effect_to_code(config, effect_id): var = cg.new_Pvariable(effect_id, config[CONF_NAME]) colors = [] for color in config.get(CONF_COLORS, []): @@ -255,7 +255,7 @@ def strobe_effect_to_code(config, effect_id): ) ) cg.add(var.set_colors(colors)) - yield var + return var @register_monochromatic_effect( @@ -267,11 +267,11 @@ def strobe_effect_to_code(config, effect_id): cv.Optional(CONF_INTENSITY, default=0.015): cv.percentage, }, ) -def flicker_effect_to_code(config, effect_id): +async def flicker_effect_to_code(config, effect_id): var = cg.new_Pvariable(effect_id, config[CONF_NAME]) cg.add(var.set_alpha(config[CONF_ALPHA])) cg.add(var.set_intensity(config[CONF_INTENSITY])) - yield var + return var @register_addressable_effect( @@ -285,17 +285,17 @@ def flicker_effect_to_code(config, effect_id): ): cv.positive_time_period_milliseconds, }, ) -def addressable_lambda_effect_to_code(config, effect_id): +async def addressable_lambda_effect_to_code(config, effect_id): args = [ (AddressableLightRef, "it"), (Color, "current_color"), (bool, "initial_run"), ] - lambda_ = yield cg.process_lambda(config[CONF_LAMBDA], args, return_type=cg.void) + lambda_ = await cg.process_lambda(config[CONF_LAMBDA], args, return_type=cg.void) var = cg.new_Pvariable( effect_id, config[CONF_NAME], lambda_, config[CONF_UPDATE_INTERVAL] ) - yield var + return var @register_addressable_effect( @@ -307,11 +307,11 @@ def addressable_lambda_effect_to_code(config, effect_id): cv.Optional(CONF_WIDTH, default=50): cv.uint32_t, }, ) -def addressable_rainbow_effect_to_code(config, effect_id): +async def addressable_rainbow_effect_to_code(config, effect_id): var = cg.new_Pvariable(effect_id, config[CONF_NAME]) cg.add(var.set_speed(config[CONF_SPEED])) cg.add(var.set_width(config[CONF_WIDTH])) - yield var + return var @register_addressable_effect( @@ -337,7 +337,7 @@ def addressable_rainbow_effect_to_code(config, effect_id): cv.Optional(CONF_REVERSE, default=False): cv.boolean, }, ) -def addressable_color_wipe_effect_to_code(config, effect_id): +async def addressable_color_wipe_effect_to_code(config, effect_id): var = cg.new_Pvariable(effect_id, config[CONF_NAME]) cg.add(var.set_add_led_interval(config[CONF_ADD_LED_INTERVAL])) cg.add(var.set_reverse(config[CONF_REVERSE])) @@ -355,7 +355,7 @@ def addressable_color_wipe_effect_to_code(config, effect_id): ) ) cg.add(var.set_colors(colors)) - yield var + return var @register_addressable_effect( @@ -369,11 +369,11 @@ def addressable_color_wipe_effect_to_code(config, effect_id): cv.Optional(CONF_SCAN_WIDTH, default=1): cv.int_range(min=1), }, ) -def addressable_scan_effect_to_code(config, effect_id): +async def addressable_scan_effect_to_code(config, effect_id): var = cg.new_Pvariable(effect_id, config[CONF_NAME]) cg.add(var.set_move_interval(config[CONF_MOVE_INTERVAL])) cg.add(var.set_scan_width(config[CONF_SCAN_WIDTH])) - yield var + return var @register_addressable_effect( @@ -387,11 +387,11 @@ def addressable_scan_effect_to_code(config, effect_id): ): cv.positive_time_period_milliseconds, }, ) -def addressable_twinkle_effect_to_code(config, effect_id): +async def addressable_twinkle_effect_to_code(config, effect_id): var = cg.new_Pvariable(effect_id, config[CONF_NAME]) cg.add(var.set_twinkle_probability(config[CONF_TWINKLE_PROBABILITY])) cg.add(var.set_progress_interval(config[CONF_PROGRESS_INTERVAL])) - yield var + return var @register_addressable_effect( @@ -405,11 +405,11 @@ def addressable_twinkle_effect_to_code(config, effect_id): ): cv.positive_time_period_milliseconds, }, ) -def addressable_random_twinkle_effect_to_code(config, effect_id): +async def addressable_random_twinkle_effect_to_code(config, effect_id): var = cg.new_Pvariable(effect_id, config[CONF_NAME]) cg.add(var.set_twinkle_probability(config[CONF_TWINKLE_PROBABILITY])) cg.add(var.set_progress_interval(config[CONF_PROGRESS_INTERVAL])) - yield var + return var @register_addressable_effect( @@ -425,13 +425,13 @@ def addressable_random_twinkle_effect_to_code(config, effect_id): cv.Optional(CONF_FADE_OUT_RATE, default=120): cv.uint8_t, }, ) -def addressable_fireworks_effect_to_code(config, effect_id): +async def addressable_fireworks_effect_to_code(config, effect_id): var = cg.new_Pvariable(effect_id, config[CONF_NAME]) cg.add(var.set_update_interval(config[CONF_UPDATE_INTERVAL])) cg.add(var.set_spark_probability(config[CONF_SPARK_PROBABILITY])) cg.add(var.set_use_random_color(config[CONF_USE_RANDOM_COLOR])) cg.add(var.set_fade_out_rate(config[CONF_FADE_OUT_RATE])) - yield var + return var @register_addressable_effect( @@ -445,11 +445,11 @@ def addressable_fireworks_effect_to_code(config, effect_id): cv.Optional(CONF_INTENSITY, default="5%"): cv.percentage, }, ) -def addressable_flicker_effect_to_code(config, effect_id): +async def addressable_flicker_effect_to_code(config, effect_id): var = cg.new_Pvariable(effect_id, config[CONF_NAME]) cg.add(var.set_update_interval(config[CONF_UPDATE_INTERVAL])) cg.add(var.set_intensity(config[CONF_INTENSITY])) - yield var + return var def validate_effects(allowed_effects): diff --git a/esphome/components/mcp23016/__init__.py b/esphome/components/mcp23016/__init__.py index d1f0dad2b7..4d9657e794 100644 --- a/esphome/components/mcp23016/__init__.py +++ b/esphome/components/mcp23016/__init__.py @@ -60,8 +60,8 @@ MCP23016_INPUT_PIN_SCHEMA = cv.Schema( @pins.PIN_SCHEMA_REGISTRY.register( CONF_MCP23016, (MCP23016_OUTPUT_PIN_SCHEMA, MCP23016_INPUT_PIN_SCHEMA) ) -def mcp23016_pin_to_code(config): - parent = yield cg.get_variable(config[CONF_MCP23016]) - yield MCP23016GPIOPin.new( +async def mcp23016_pin_to_code(config): + parent = await cg.get_variable(config[CONF_MCP23016]) + return MCP23016GPIOPin.new( parent, config[CONF_NUMBER], config[CONF_MODE], config[CONF_INVERTED] ) diff --git a/esphome/components/mcp23xxx_base/__init__.py b/esphome/components/mcp23xxx_base/__init__.py index f8ab224193..019b7c7e64 100644 --- a/esphome/components/mcp23xxx_base/__init__.py +++ b/esphome/components/mcp23xxx_base/__init__.py @@ -40,9 +40,9 @@ MCP23XXX_CONFIG_SCHEMA = cv.Schema( @coroutine -def register_mcp23xxx(config): +async def register_mcp23xxx(config): var = cg.new_Pvariable(config[CONF_ID]) - yield cg.register_component(var, config) + await cg.register_component(var, config) cg.add(var.set_open_drain_ints(config[CONF_OPEN_DRAIN_INTERRUPT])) return var @@ -79,9 +79,9 @@ MCP23XXX_INPUT_PIN_SCHEMA = cv.Schema( @pins.PIN_SCHEMA_REGISTRY.register( CONF_MCP23XXX, (MCP23XXX_OUTPUT_PIN_SCHEMA, MCP23XXX_INPUT_PIN_SCHEMA) ) -def mcp23xxx_pin_to_code(config): - parent = yield cg.get_variable(config[CONF_MCP23XXX]) - yield MCP23XXXGPIOPin.new( +async def mcp23xxx_pin_to_code(config): + parent = await cg.get_variable(config[CONF_MCP23XXX]) + return MCP23XXXGPIOPin.new( parent, config[CONF_NUMBER], config[CONF_MODE], diff --git a/esphome/components/mhz19/sensor.py b/esphome/components/mhz19/sensor.py index abe33cae7e..54a0e3a366 100644 --- a/esphome/components/mhz19/sensor.py +++ b/esphome/components/mhz19/sensor.py @@ -78,6 +78,6 @@ CALIBRATION_ACTION_SCHEMA = maybe_simple_id( @automation.register_action( "mhz19.abc_disable", MHZ19ABCDisableAction, CALIBRATION_ACTION_SCHEMA ) -def mhz19_calibration_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) - yield cg.new_Pvariable(action_id, template_arg, paren) +async def mhz19_calibration_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, paren) diff --git a/esphome/components/modbus/__init__.py b/esphome/components/modbus/__init__.py index c8e58431da..08186ca46f 100644 --- a/esphome/components/modbus/__init__.py +++ b/esphome/components/modbus/__init__.py @@ -2,7 +2,6 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import uart from esphome.const import CONF_ID, CONF_ADDRESS -from esphome.core import coroutine DEPENDENCIES = ["uart"] @@ -42,9 +41,8 @@ def modbus_device_schema(default_address): return cv.Schema(schema) -@coroutine -def register_modbus_device(var, config): - parent = yield cg.get_variable(config[CONF_MODBUS_ID]) +async def register_modbus_device(var, config): + parent = await cg.get_variable(config[CONF_MODBUS_ID]) cg.add(var.set_parent(parent)) cg.add(var.set_address(config[CONF_ADDRESS])) cg.add(parent.register_device(var)) diff --git a/esphome/components/pcf8574/__init__.py b/esphome/components/pcf8574/__init__.py index 9c0aeb2e12..e96c526cb0 100644 --- a/esphome/components/pcf8574/__init__.py +++ b/esphome/components/pcf8574/__init__.py @@ -69,8 +69,8 @@ PCF8574_INPUT_PIN_SCHEMA = cv.Schema( @pins.PIN_SCHEMA_REGISTRY.register( "pcf8574", (PCF8574_OUTPUT_PIN_SCHEMA, PCF8574_INPUT_PIN_SCHEMA) ) -def pcf8574_pin_to_code(config): - parent = yield cg.get_variable(config[CONF_PCF8574]) - yield PCF8574GPIOPin.new( +async def pcf8574_pin_to_code(config): + parent = await cg.get_variable(config[CONF_PCF8574]) + return PCF8574GPIOPin.new( parent, config[CONF_NUMBER], config[CONF_MODE], config[CONF_INVERTED] ) diff --git a/esphome/components/pid/climate.py b/esphome/components/pid/climate.py index 8b9b090893..ffc6392ec2 100644 --- a/esphome/components/pid/climate.py +++ b/esphome/components/pid/climate.py @@ -86,9 +86,9 @@ async def to_code(config): } ), ) -def pid_reset_integral_term(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) - yield cg.new_Pvariable(action_id, template_arg, paren) +async def pid_reset_integral_term(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, paren) @automation.register_action( @@ -107,13 +107,13 @@ def pid_reset_integral_term(config, action_id, template_arg, args): } ), ) -def esp8266_set_frequency_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def esp8266_set_frequency_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) cg.add(var.set_noiseband(config[CONF_NOISEBAND])) cg.add(var.set_positive_output(config[CONF_POSITIVE_OUTPUT])) cg.add(var.set_negative_output(config[CONF_NEGATIVE_OUTPUT])) - yield var + return var @automation.register_action( @@ -128,16 +128,16 @@ def esp8266_set_frequency_to_code(config, action_id, template_arg, args): } ), ) -def set_control_parameters(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def set_control_parameters(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) - kp_template_ = yield cg.templatable(config[CONF_KP], args, float) + kp_template_ = await cg.templatable(config[CONF_KP], args, float) cg.add(var.set_kp(kp_template_)) - ki_template_ = yield cg.templatable(config[CONF_KI], args, float) + ki_template_ = await cg.templatable(config[CONF_KI], args, float) cg.add(var.set_ki(ki_template_)) - kd_template_ = yield cg.templatable(config[CONF_KD], args, float) + kd_template_ = await cg.templatable(config[CONF_KD], args, float) cg.add(var.set_kd(kd_template_)) - yield var + return var diff --git a/esphome/components/pn532/__init__.py b/esphome/components/pn532/__init__.py index 83e6409f54..b902e8e3d0 100644 --- a/esphome/components/pn532/__init__.py +++ b/esphome/components/pn532/__init__.py @@ -3,7 +3,6 @@ import esphome.config_validation as cv from esphome import automation from esphome.components import nfc from esphome.const import CONF_ID, CONF_ON_TAG_REMOVED, CONF_ON_TAG, CONF_TRIGGER_ID -from esphome.core import coroutine CODEOWNERS = ["@OttoWinter", "@jesserockz"] AUTO_LOAD = ["binary_sensor", "nfc"] @@ -58,27 +57,26 @@ def CONFIG_SCHEMA(conf): ) -@coroutine -def setup_pn532(var, config): - yield cg.register_component(var, config) +async def setup_pn532(var, config): + await cg.register_component(var, config) for conf in config.get(CONF_ON_TAG, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID]) cg.add(var.register_ontag_trigger(trigger)) - yield automation.build_automation( + await automation.build_automation( trigger, [(cg.std_string, "x"), (nfc.NfcTag, "tag")], conf ) for conf in config.get(CONF_ON_TAG_REMOVED, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID]) cg.add(var.register_ontagremoved_trigger(trigger)) - yield automation.build_automation( + await automation.build_automation( trigger, [(cg.std_string, "x"), (nfc.NfcTag, "tag")], conf ) for conf in config.get(CONF_ON_FINISHED_WRITE, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) - yield automation.build_automation(trigger, [], conf) + await automation.build_automation(trigger, [], conf) @automation.register_condition( @@ -90,7 +88,7 @@ def setup_pn532(var, config): } ), ) -def pn532_is_writing_to_code(config, condition_id, template_arg, args): +async def pn532_is_writing_to_code(config, condition_id, template_arg, args): var = cg.new_Pvariable(condition_id, template_arg) - yield cg.register_parented(var, config[CONF_ID]) - yield var + await cg.register_parented(var, config[CONF_ID]) + return var diff --git a/esphome/components/pulse_meter/sensor.py b/esphome/components/pulse_meter/sensor.py index 9bf4bfddd6..5811863405 100644 --- a/esphome/components/pulse_meter/sensor.py +++ b/esphome/components/pulse_meter/sensor.py @@ -88,9 +88,9 @@ async def to_code(config): } ), ) -def set_total_action_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def set_total_action_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) - template_ = yield cg.templatable(config[CONF_VALUE], args, int) + template_ = await cg.templatable(config[CONF_VALUE], args, int) cg.add(var.set_total_pulses(template_)) - yield var + return var diff --git a/esphome/components/rc522/__init__.py b/esphome/components/rc522/__init__.py index 7858213f06..d64cf3c085 100644 --- a/esphome/components/rc522/__init__.py +++ b/esphome/components/rc522/__init__.py @@ -3,7 +3,6 @@ import esphome.config_validation as cv from esphome import automation, pins from esphome.components import i2c from esphome.const import CONF_ON_TAG, CONF_TRIGGER_ID, CONF_RESET_PIN -from esphome.core import coroutine CODEOWNERS = ["@glmnet"] AUTO_LOAD = ["binary_sensor"] @@ -29,15 +28,14 @@ RC522_SCHEMA = cv.Schema( ).extend(cv.polling_component_schema("1s")) -@coroutine -def setup_rc522(var, config): - yield cg.register_component(var, config) +async def setup_rc522(var, config): + await cg.register_component(var, config) if CONF_RESET_PIN in config: - reset = yield cg.gpio_pin_expression(config[CONF_RESET_PIN]) + reset = await cg.gpio_pin_expression(config[CONF_RESET_PIN]) cg.add(var.set_reset_pin(reset)) for conf in config.get(CONF_ON_TAG, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID]) cg.add(var.register_trigger(trigger)) - yield automation.build_automation(trigger, [(cg.std_string, "x")], conf) + await automation.build_automation(trigger, [(cg.std_string, "x")], conf) diff --git a/esphome/components/remote_base/__init__.py b/esphome/components/remote_base/__init__.py index 96579c05bb..99778c3088 100644 --- a/esphome/components/remote_base/__init__.py +++ b/esphome/components/remote_base/__init__.py @@ -63,9 +63,8 @@ def templatize(value): return cv.Schema(ret) -@coroutine -def register_listener(var, config): - receiver = yield cg.get_variable(config[CONF_RECEIVER_ID]) +async def register_listener(var, config): + receiver = await cg.get_variable(config[CONF_RECEIVER_ID]) cg.add(receiver.register_listener(var)) @@ -83,13 +82,12 @@ def register_trigger(name, type, data_type): registerer = TRIGGER_REGISTRY.register(f"on_{name}", validator) def decorator(func): - @coroutine - def new_func(config): + async def new_func(config): var = cg.new_Pvariable(config[CONF_TRIGGER_ID]) - yield register_listener(var, config) - yield coroutine(func)(var, config) - yield automation.build_automation(var, [(data_type, "x")], config) - yield var + await register_listener(var, config) + await coroutine(func)(var, config) + await automation.build_automation(var, [(data_type, "x")], config) + return var return registerer(new_func) @@ -100,11 +98,10 @@ def register_dumper(name, type): registerer = DUMPER_REGISTRY.register(name, type, {}) def decorator(func): - @coroutine - def new_func(config, dumper_id): + async def new_func(config, dumper_id): var = cg.new_Pvariable(dumper_id) - yield coroutine(func)(var, config) - yield var + await coroutine(func)(var, config) + return var return registerer(new_func) @@ -139,19 +136,18 @@ def register_action(name, type_, schema): ) def decorator(func): - @coroutine - def new_func(config, action_id, template_arg, args): - transmitter = yield cg.get_variable(config[CONF_TRANSMITTER_ID]) + async def new_func(config, action_id, template_arg, args): + transmitter = await cg.get_variable(config[CONF_TRANSMITTER_ID]) var = cg.new_Pvariable(action_id, template_arg) cg.add(var.set_parent(transmitter)) if CONF_REPEAT in config: conf = config[CONF_REPEAT] - template_ = yield cg.templatable(conf[CONF_TIMES], args, cg.uint32) + template_ = await cg.templatable(conf[CONF_TIMES], args, cg.uint32) cg.add(var.set_send_times(template_)) - template_ = yield cg.templatable(conf[CONF_WAIT_TIME], args, cg.uint32) + template_ = await cg.templatable(conf[CONF_WAIT_TIME], args, cg.uint32) cg.add(var.set_send_wait(template_)) - yield coroutine(func)(var, config, args) - yield var + await coroutine(func)(var, config, args) + return var return registerer(new_func) @@ -208,37 +204,34 @@ def validate_triggers(base_schema): return validator -@coroutine -def build_binary_sensor(full_config): +async def build_binary_sensor(full_config): registry_entry, config = cg.extract_registry_entry_config( BINARY_SENSOR_REGISTRY, full_config ) type_id = full_config[CONF_TYPE_ID] builder = registry_entry.coroutine_fun var = cg.new_Pvariable(type_id) - yield cg.register_component(var, full_config) - yield register_listener(var, full_config) - yield builder(var, config) - yield var + await cg.register_component(var, full_config) + await register_listener(var, full_config) + await builder(var, config) + return var -@coroutine -def build_triggers(full_config): +async def build_triggers(full_config): for key in TRIGGER_REGISTRY: for config in full_config.get(key, []): func = TRIGGER_REGISTRY[key][0] - yield func(config) + await func(config) -@coroutine -def build_dumpers(config): +async def build_dumpers(config): dumpers = [] for conf in config: - dumper = yield cg.build_registry_entry(DUMPER_REGISTRY, conf) - receiver = yield cg.get_variable(conf[CONF_RECEIVER_ID]) + dumper = await cg.build_registry_entry(DUMPER_REGISTRY, conf) + receiver = await cg.get_variable(conf[CONF_RECEIVER_ID]) cg.add(receiver.register_dumper(dumper)) dumpers.append(dumper) - yield dumpers + return dumpers # JVC @@ -269,8 +262,8 @@ def jvc_dumper(var, config): @register_action("jvc", JVCAction, JVC_SCHEMA) -def jvc_action(var, config, args): - template_ = yield cg.templatable(config[CONF_DATA], args, cg.uint32) +async def jvc_action(var, config, args): + template_ = await cg.templatable(config[CONF_DATA], args, cg.uint32) cg.add(var.set_data(template_)) @@ -308,10 +301,10 @@ def lg_dumper(var, config): @register_action("lg", LGAction, LG_SCHEMA) -def lg_action(var, config, args): - template_ = yield cg.templatable(config[CONF_DATA], args, cg.uint32) +async def lg_action(var, config, args): + template_ = await cg.templatable(config[CONF_DATA], args, cg.uint32) cg.add(var.set_data(template_)) - template_ = yield cg.templatable(config[CONF_NBITS], args, cg.uint8) + template_ = await cg.templatable(config[CONF_NBITS], args, cg.uint8) cg.add(var.set_nbits(template_)) @@ -349,10 +342,10 @@ def nec_dumper(var, config): @register_action("nec", NECAction, NEC_SCHEMA) -def nec_action(var, config, args): - template_ = yield cg.templatable(config[CONF_ADDRESS], args, cg.uint16) +async def nec_action(var, config, args): + template_ = await cg.templatable(config[CONF_ADDRESS], args, cg.uint16) cg.add(var.set_address(template_)) - template_ = yield cg.templatable(config[CONF_COMMAND], args, cg.uint16) + template_ = await cg.templatable(config[CONF_COMMAND], args, cg.uint16) cg.add(var.set_command(template_)) @@ -396,10 +389,10 @@ def pioneer_dumper(var, config): @register_action("pioneer", PioneerAction, PIONEER_SCHEMA) -def pioneer_action(var, config, args): - template_ = yield cg.templatable(config[CONF_RC_CODE_1], args, cg.uint16) +async def pioneer_action(var, config, args): + template_ = await cg.templatable(config[CONF_RC_CODE_1], args, cg.uint16) cg.add(var.set_rc_code_1(template_)) - template_ = yield cg.templatable(config[CONF_RC_CODE_2], args, cg.uint16) + template_ = await cg.templatable(config[CONF_RC_CODE_2], args, cg.uint16) cg.add(var.set_rc_code_2(template_)) @@ -439,10 +432,10 @@ def sony_dumper(var, config): @register_action("sony", SonyAction, SONY_SCHEMA) -def sony_action(var, config, args): - template_ = yield cg.templatable(config[CONF_DATA], args, cg.uint16) +async def sony_action(var, config, args): + template_ = await cg.templatable(config[CONF_DATA], args, cg.uint16) cg.add(var.set_data(template_)) - template_ = yield cg.templatable(config[CONF_NBITS], args, cg.uint32) + template_ = await cg.templatable(config[CONF_NBITS], args, cg.uint32) cg.add(var.set_nbits(template_)) @@ -506,16 +499,16 @@ def raw_dumper(var, config): } ), ) -def raw_action(var, config, args): +async def raw_action(var, config, args): code_ = config[CONF_CODE] if cg.is_template(code_): - template_ = yield cg.templatable(code_, args, cg.std_vector.template(cg.int32)) + template_ = await cg.templatable(code_, args, cg.std_vector.template(cg.int32)) cg.add(var.set_code_template(template_)) else: code_ = config[CONF_CODE] arr = cg.progmem_array(config[CONF_CODE_STORAGE_ID], code_) cg.add(var.set_code_static(arr, len(code_))) - templ = yield cg.templatable(config[CONF_CARRIER_FREQUENCY], args, cg.uint32) + templ = await cg.templatable(config[CONF_CARRIER_FREQUENCY], args, cg.uint32) cg.add(var.set_carrier_frequency(templ)) @@ -553,10 +546,10 @@ def rc5_dumper(var, config): @register_action("rc5", RC5Action, RC5_SCHEMA) -def rc5_action(var, config, args): - template_ = yield cg.templatable(config[CONF_ADDRESS], args, cg.uint8) +async def rc5_action(var, config, args): + template_ = await cg.templatable(config[CONF_ADDRESS], args, cg.uint8) cg.add(var.set_address(template_)) - template_ = yield cg.templatable(config[CONF_COMMAND], args, cg.uint8) + template_ = await cg.templatable(config[CONF_COMMAND], args, cg.uint8) cg.add(var.set_command(template_)) @@ -729,12 +722,12 @@ def rc_switch_raw_binary_sensor(var, config): RCSwitchRawAction, RC_SWITCH_RAW_SCHEMA.extend(RC_SWITCH_TRANSMITTER), ) -def rc_switch_raw_action(var, config, args): - proto = yield cg.templatable( +async def rc_switch_raw_action(var, config, args): + proto = await cg.templatable( config[CONF_PROTOCOL], args, RCSwitchBase, to_exp=build_rc_switch_protocol ) cg.add(var.set_protocol(proto)) - cg.add(var.set_code((yield cg.templatable(config[CONF_CODE], args, cg.std_string)))) + cg.add(var.set_code((await cg.templatable(config[CONF_CODE], args, cg.std_string)))) @register_binary_sensor( @@ -750,18 +743,18 @@ def rc_switch_type_a_binary_sensor(var, config): RCSwitchTypeAAction, RC_SWITCH_TYPE_A_SCHEMA.extend(RC_SWITCH_TRANSMITTER), ) -def rc_switch_type_a_action(var, config, args): - proto = yield cg.templatable( +async def rc_switch_type_a_action(var, config, args): + proto = await cg.templatable( config[CONF_PROTOCOL], args, RCSwitchBase, to_exp=build_rc_switch_protocol ) cg.add(var.set_protocol(proto)) cg.add( - var.set_group((yield cg.templatable(config[CONF_GROUP], args, cg.std_string))) + var.set_group((await cg.templatable(config[CONF_GROUP], args, cg.std_string))) ) cg.add( - var.set_device((yield cg.templatable(config[CONF_DEVICE], args, cg.std_string))) + var.set_device((await cg.templatable(config[CONF_DEVICE], args, cg.std_string))) ) - cg.add(var.set_state((yield cg.templatable(config[CONF_STATE], args, bool)))) + cg.add(var.set_state((await cg.templatable(config[CONF_STATE], args, bool)))) @register_binary_sensor( @@ -779,18 +772,18 @@ def rc_switch_type_b_binary_sensor(var, config): RCSwitchTypeBAction, RC_SWITCH_TYPE_B_SCHEMA.extend(RC_SWITCH_TRANSMITTER), ) -def rc_switch_type_b_action(var, config, args): - proto = yield cg.templatable( +async def rc_switch_type_b_action(var, config, args): + proto = await cg.templatable( config[CONF_PROTOCOL], args, RCSwitchBase, to_exp=build_rc_switch_protocol ) cg.add(var.set_protocol(proto)) cg.add( - var.set_address((yield cg.templatable(config[CONF_ADDRESS], args, cg.uint8))) + var.set_address((await cg.templatable(config[CONF_ADDRESS], args, cg.uint8))) ) cg.add( - var.set_channel((yield cg.templatable(config[CONF_CHANNEL], args, cg.uint8))) + var.set_channel((await cg.templatable(config[CONF_CHANNEL], args, cg.uint8))) ) - cg.add(var.set_state((yield cg.templatable(config[CONF_STATE], args, bool)))) + cg.add(var.set_state((await cg.templatable(config[CONF_STATE], args, bool)))) @register_binary_sensor( @@ -813,17 +806,17 @@ def rc_switch_type_c_binary_sensor(var, config): RCSwitchTypeCAction, RC_SWITCH_TYPE_C_SCHEMA.extend(RC_SWITCH_TRANSMITTER), ) -def rc_switch_type_c_action(var, config, args): - proto = yield cg.templatable( +async def rc_switch_type_c_action(var, config, args): + proto = await cg.templatable( config[CONF_PROTOCOL], args, RCSwitchBase, to_exp=build_rc_switch_protocol ) cg.add(var.set_protocol(proto)) cg.add( - var.set_family((yield cg.templatable(config[CONF_FAMILY], args, cg.std_string))) + var.set_family((await cg.templatable(config[CONF_FAMILY], args, cg.std_string))) ) - cg.add(var.set_group((yield cg.templatable(config[CONF_GROUP], args, cg.uint8)))) - cg.add(var.set_device((yield cg.templatable(config[CONF_DEVICE], args, cg.uint8)))) - cg.add(var.set_state((yield cg.templatable(config[CONF_STATE], args, bool)))) + cg.add(var.set_group((await cg.templatable(config[CONF_GROUP], args, cg.uint8)))) + cg.add(var.set_device((await cg.templatable(config[CONF_DEVICE], args, cg.uint8)))) + cg.add(var.set_state((await cg.templatable(config[CONF_STATE], args, bool)))) @register_binary_sensor( @@ -841,16 +834,16 @@ def rc_switch_type_d_binary_sensor(var, config): RCSwitchTypeDAction, RC_SWITCH_TYPE_D_SCHEMA.extend(RC_SWITCH_TRANSMITTER), ) -def rc_switch_type_d_action(var, config, args): - proto = yield cg.templatable( +async def rc_switch_type_d_action(var, config, args): + proto = await cg.templatable( config[CONF_PROTOCOL], args, RCSwitchBase, to_exp=build_rc_switch_protocol ) cg.add(var.set_protocol(proto)) cg.add( - var.set_group((yield cg.templatable(config[CONF_GROUP], args, cg.std_string))) + var.set_group((await cg.templatable(config[CONF_GROUP], args, cg.std_string))) ) - cg.add(var.set_device((yield cg.templatable(config[CONF_DEVICE], args, cg.uint8)))) - cg.add(var.set_state((yield cg.templatable(config[CONF_STATE], args, bool)))) + cg.add(var.set_device((await cg.templatable(config[CONF_DEVICE], args, cg.uint8)))) + cg.add(var.set_state((await cg.templatable(config[CONF_STATE], args, bool)))) @register_trigger("rc_switch", RCSwitchTrigger, RCSwitchData) @@ -901,8 +894,8 @@ def samsung_dumper(var, config): @register_action("samsung", SamsungAction, SAMSUNG_SCHEMA) -def samsung_action(var, config, args): - template_ = yield cg.templatable(config[CONF_DATA], args, cg.uint32) +async def samsung_action(var, config, args): + template_ = await cg.templatable(config[CONF_DATA], args, cg.uint32) cg.add(var.set_data(template_)) @@ -946,10 +939,10 @@ def samsung36_dumper(var, config): @register_action("samsung36", Samsung36Action, SAMSUNG36_SCHEMA) -def samsung36_action(var, config, args): - template_ = yield cg.templatable(config[CONF_ADDRESS], args, cg.uint16) +async def samsung36_action(var, config, args): + template_ = await cg.templatable(config[CONF_ADDRESS], args, cg.uint16) cg.add(var.set_address(template_)) - template_ = yield cg.templatable(config[CONF_COMMAND], args, cg.uint32) + template_ = await cg.templatable(config[CONF_COMMAND], args, cg.uint32) cg.add(var.set_command(template_)) @@ -993,8 +986,8 @@ def panasonic_dumper(var, config): @register_action("panasonic", PanasonicAction, PANASONIC_SCHEMA) -def panasonic_action(var, config, args): - template_ = yield cg.templatable(config[CONF_ADDRESS], args, cg.uint16) +async def panasonic_action(var, config, args): + template_ = await cg.templatable(config[CONF_ADDRESS], args, cg.uint16) cg.add(var.set_address(template_)) - template_ = yield cg.templatable(config[CONF_COMMAND], args, cg.uint32) + template_ = await cg.templatable(config[CONF_COMMAND], args, cg.uint32) cg.add(var.set_command(template_)) diff --git a/esphome/components/rf_bridge/__init__.py b/esphome/components/rf_bridge/__init__.py index 1eda99e7af..c7f1b819b8 100644 --- a/esphome/components/rf_bridge/__init__.py +++ b/esphome/components/rf_bridge/__init__.py @@ -109,28 +109,28 @@ RFBRIDGE_SEND_CODE_SCHEMA = cv.Schema( @automation.register_action( "rf_bridge.send_code", RFBridgeSendCodeAction, RFBRIDGE_SEND_CODE_SCHEMA ) -def rf_bridge_send_code_to_code(config, action_id, template_args, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def rf_bridge_send_code_to_code(config, action_id, template_args, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_args, paren) - template_ = yield cg.templatable(config[CONF_SYNC], args, cg.uint16) + template_ = await cg.templatable(config[CONF_SYNC], args, cg.uint16) cg.add(var.set_sync(template_)) - template_ = yield cg.templatable(config[CONF_LOW], args, cg.uint16) + template_ = await cg.templatable(config[CONF_LOW], args, cg.uint16) cg.add(var.set_low(template_)) - template_ = yield cg.templatable(config[CONF_HIGH], args, cg.uint16) + template_ = await cg.templatable(config[CONF_HIGH], args, cg.uint16) cg.add(var.set_high(template_)) - template_ = yield cg.templatable(config[CONF_CODE], args, cg.uint32) + template_ = await cg.templatable(config[CONF_CODE], args, cg.uint32) cg.add(var.set_code(template_)) - yield var + return var RFBRIDGE_ID_SCHEMA = cv.Schema({cv.GenerateID(): cv.use_id(RFBridgeComponent)}) @automation.register_action("rf_bridge.learn", RFBridgeLearnAction, RFBRIDGE_ID_SCHEMA) -def rf_bridge_learnx_to_code(config, action_id, template_args, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def rf_bridge_learnx_to_code(config, action_id, template_args, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_args, paren) - yield var + return var @automation.register_action( @@ -138,10 +138,12 @@ def rf_bridge_learnx_to_code(config, action_id, template_args, args): RFBridgeStartAdvancedSniffingAction, RFBRIDGE_ID_SCHEMA, ) -def rf_bridge_start_advanced_sniffing_to_code(config, action_id, template_args, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def rf_bridge_start_advanced_sniffing_to_code( + config, action_id, template_args, args +): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_args, paren) - yield var + return var @automation.register_action( @@ -149,10 +151,12 @@ def rf_bridge_start_advanced_sniffing_to_code(config, action_id, template_args, RFBridgeStopAdvancedSniffingAction, RFBRIDGE_ID_SCHEMA, ) -def rf_bridge_stop_advanced_sniffing_to_code(config, action_id, template_args, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def rf_bridge_stop_advanced_sniffing_to_code( + config, action_id, template_args, args +): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_args, paren) - yield var + return var RFBRIDGE_SEND_ADVANCED_CODE_SCHEMA = cv.Schema( @@ -170,16 +174,16 @@ RFBRIDGE_SEND_ADVANCED_CODE_SCHEMA = cv.Schema( RFBridgeSendAdvancedCodeAction, RFBRIDGE_SEND_ADVANCED_CODE_SCHEMA, ) -def rf_bridge_send_advanced_code_to_code(config, action_id, template_args, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def rf_bridge_send_advanced_code_to_code(config, action_id, template_args, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_args, paren) - template_ = yield cg.templatable(config[CONF_LENGTH], args, cg.uint16) + template_ = await cg.templatable(config[CONF_LENGTH], args, cg.uint16) cg.add(var.set_length(template_)) - template_ = yield cg.templatable(config[CONF_PROTOCOL], args, cg.uint16) + template_ = await cg.templatable(config[CONF_PROTOCOL], args, cg.uint16) cg.add(var.set_protocol(template_)) - template_ = yield cg.templatable(config[CONF_CODE], args, cg.std_string) + template_ = await cg.templatable(config[CONF_CODE], args, cg.std_string) cg.add(var.set_code(template_)) - yield var + return var RFBRIDGE_SEND_RAW_SCHEMA = cv.Schema( @@ -193,9 +197,9 @@ RFBRIDGE_SEND_RAW_SCHEMA = cv.Schema( @automation.register_action( "rf_bridge.send_raw", RFBridgeSendRawAction, RFBRIDGE_SEND_RAW_SCHEMA ) -def rf_bridge_send_raw_to_code(config, action_id, template_args, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def rf_bridge_send_raw_to_code(config, action_id, template_args, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_args, paren) - template_ = yield cg.templatable(config[CONF_RAW], args, cg.std_string) + template_ = await cg.templatable(config[CONF_RAW], args, cg.std_string) cg.add(var.set_raw(template_)) - yield var + return var diff --git a/esphome/components/rotary_encoder/sensor.py b/esphome/components/rotary_encoder/sensor.py index 4af1d75139..d4ced4b91f 100644 --- a/esphome/components/rotary_encoder/sensor.py +++ b/esphome/components/rotary_encoder/sensor.py @@ -127,9 +127,9 @@ async def to_code(config): } ), ) -def sensor_template_publish_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def sensor_template_publish_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) - template_ = yield cg.templatable(config[CONF_VALUE], args, int) + template_ = await cg.templatable(config[CONF_VALUE], args, int) cg.add(var.set_value(template_)) - yield var + return var diff --git a/esphome/components/rtttl/__init__.py b/esphome/components/rtttl/__init__.py index fb193c5b92..3441a63b9a 100644 --- a/esphome/components/rtttl/__init__.py +++ b/esphome/components/rtttl/__init__.py @@ -56,12 +56,12 @@ async def to_code(config): key=CONF_RTTTL, ), ) -def rtttl_play_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def rtttl_play_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) - template_ = yield cg.templatable(config[CONF_RTTTL], args, cg.std_string) + template_ = await cg.templatable(config[CONF_RTTTL], args, cg.std_string) cg.add(var.set_value(template_)) - yield var + return var @automation.register_action( @@ -73,10 +73,10 @@ def rtttl_play_to_code(config, action_id, template_arg, args): } ), ) -def rtttl_stop_to_code(config, action_id, template_arg, args): +async def rtttl_stop_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) - yield cg.register_parented(var, config[CONF_ID]) - yield var + await cg.register_parented(var, config[CONF_ID]) + return var @automation.register_condition( @@ -88,7 +88,7 @@ def rtttl_stop_to_code(config, action_id, template_arg, args): } ), ) -def rtttl_is_playing_to_code(config, condition_id, template_arg, args): +async def rtttl_is_playing_to_code(config, condition_id, template_arg, args): var = cg.new_Pvariable(condition_id, template_arg) - yield cg.register_parented(var, config[CONF_ID]) - yield var + await cg.register_parented(var, config[CONF_ID]) + return var diff --git a/esphome/components/script/__init__.py b/esphome/components/script/__init__.py index a14f48a547..43356c0036 100644 --- a/esphome/components/script/__init__.py +++ b/esphome/components/script/__init__.py @@ -90,9 +90,9 @@ async def to_code(config): } ), ) -def script_execute_action_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) - yield cg.new_Pvariable(action_id, template_arg, paren) +async def script_execute_action_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, paren) @automation.register_action( @@ -100,9 +100,9 @@ def script_execute_action_to_code(config, action_id, template_arg, args): ScriptStopAction, maybe_simple_id({cv.Required(CONF_ID): cv.use_id(Script)}), ) -def script_stop_action_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) - yield cg.new_Pvariable(action_id, template_arg, paren) +async def script_stop_action_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, paren) @automation.register_action( @@ -110,11 +110,11 @@ def script_stop_action_to_code(config, action_id, template_arg, args): ScriptWaitAction, maybe_simple_id({cv.Required(CONF_ID): cv.use_id(Script)}), ) -def script_wait_action_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) - var = yield cg.new_Pvariable(action_id, template_arg, paren) - yield cg.register_component(var, {}) - yield var +async def script_wait_action_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, paren) + await cg.register_component(var, {}) + return var @automation.register_condition( @@ -122,6 +122,6 @@ def script_wait_action_to_code(config, action_id, template_arg, args): IsRunningCondition, automation.maybe_simple_id({cv.Required(CONF_ID): cv.use_id(Script)}), ) -def script_is_running_to_code(config, condition_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) - yield cg.new_Pvariable(condition_id, template_arg, paren) +async def script_is_running_to_code(config, condition_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(condition_id, template_arg, paren) diff --git a/esphome/components/senseair/sensor.py b/esphome/components/senseair/sensor.py index a2690f37ed..f37a2dd5ff 100644 --- a/esphome/components/senseair/sensor.py +++ b/esphome/components/senseair/sensor.py @@ -83,6 +83,6 @@ CALIBRATION_ACTION_SCHEMA = maybe_simple_id( @automation.register_action( "senseair.abc_get_period", SenseAirABCGetPeriodAction, CALIBRATION_ACTION_SCHEMA ) -def senseair_action_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) - yield cg.new_Pvariable(action_id, template_arg, paren) +async def senseair_action_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, paren) diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py index 2f5ada6930..d449568f0e 100644 --- a/esphome/components/sensor/__init__.py +++ b/esphome/components/sensor/__init__.py @@ -214,18 +214,18 @@ def sensor_schema( @FILTER_REGISTRY.register("offset", OffsetFilter, cv.float_) -def offset_filter_to_code(config, filter_id): - yield cg.new_Pvariable(filter_id, config) +async def offset_filter_to_code(config, filter_id): + return cg.new_Pvariable(filter_id, config) @FILTER_REGISTRY.register("multiply", MultiplyFilter, cv.float_) -def multiply_filter_to_code(config, filter_id): - yield cg.new_Pvariable(filter_id, config) +async def multiply_filter_to_code(config, filter_id): + return cg.new_Pvariable(filter_id, config) @FILTER_REGISTRY.register("filter_out", FilterOutValueFilter, cv.float_) -def filter_out_filter_to_code(config, filter_id): - yield cg.new_Pvariable(filter_id, config) +async def filter_out_filter_to_code(config, filter_id): + return cg.new_Pvariable(filter_id, config) MEDIAN_SCHEMA = cv.All( @@ -241,8 +241,8 @@ MEDIAN_SCHEMA = cv.All( @FILTER_REGISTRY.register("median", MedianFilter, MEDIAN_SCHEMA) -def median_filter_to_code(config, filter_id): - yield cg.new_Pvariable( +async def median_filter_to_code(config, filter_id): + return cg.new_Pvariable( filter_id, config[CONF_WINDOW_SIZE], config[CONF_SEND_EVERY], @@ -263,8 +263,8 @@ MIN_SCHEMA = cv.All( @FILTER_REGISTRY.register("min", MinFilter, MIN_SCHEMA) -def min_filter_to_code(config, filter_id): - yield cg.new_Pvariable( +async def min_filter_to_code(config, filter_id): + return cg.new_Pvariable( filter_id, config[CONF_WINDOW_SIZE], config[CONF_SEND_EVERY], @@ -285,8 +285,8 @@ MAX_SCHEMA = cv.All( @FILTER_REGISTRY.register("max", MaxFilter, MAX_SCHEMA) -def max_filter_to_code(config, filter_id): - yield cg.new_Pvariable( +async def max_filter_to_code(config, filter_id): + return cg.new_Pvariable( filter_id, config[CONF_WINDOW_SIZE], config[CONF_SEND_EVERY], @@ -311,8 +311,8 @@ SLIDING_AVERAGE_SCHEMA = cv.All( SlidingWindowMovingAverageFilter, SLIDING_AVERAGE_SCHEMA, ) -def sliding_window_moving_average_filter_to_code(config, filter_id): - yield cg.new_Pvariable( +async def sliding_window_moving_average_filter_to_code(config, filter_id): + return cg.new_Pvariable( filter_id, config[CONF_WINDOW_SIZE], config[CONF_SEND_EVERY], @@ -330,52 +330,52 @@ def sliding_window_moving_average_filter_to_code(config, filter_id): } ), ) -def exponential_moving_average_filter_to_code(config, filter_id): - yield cg.new_Pvariable(filter_id, config[CONF_ALPHA], config[CONF_SEND_EVERY]) +async def exponential_moving_average_filter_to_code(config, filter_id): + return cg.new_Pvariable(filter_id, config[CONF_ALPHA], config[CONF_SEND_EVERY]) @FILTER_REGISTRY.register("lambda", LambdaFilter, cv.returning_lambda) -def lambda_filter_to_code(config, filter_id): - lambda_ = yield cg.process_lambda( +async def lambda_filter_to_code(config, filter_id): + lambda_ = await cg.process_lambda( config, [(float, "x")], return_type=cg.optional.template(float) ) - yield cg.new_Pvariable(filter_id, lambda_) + return cg.new_Pvariable(filter_id, lambda_) @FILTER_REGISTRY.register("delta", DeltaFilter, cv.float_) -def delta_filter_to_code(config, filter_id): - yield cg.new_Pvariable(filter_id, config) +async def delta_filter_to_code(config, filter_id): + return cg.new_Pvariable(filter_id, config) @FILTER_REGISTRY.register("or", OrFilter, validate_filters) -def or_filter_to_code(config, filter_id): - filters = yield build_filters(config) - yield cg.new_Pvariable(filter_id, filters) +async def or_filter_to_code(config, filter_id): + filters = await build_filters(config) + return cg.new_Pvariable(filter_id, filters) @FILTER_REGISTRY.register( "throttle", ThrottleFilter, cv.positive_time_period_milliseconds ) -def throttle_filter_to_code(config, filter_id): - yield cg.new_Pvariable(filter_id, config) +async def throttle_filter_to_code(config, filter_id): + return cg.new_Pvariable(filter_id, config) @FILTER_REGISTRY.register( "heartbeat", HeartbeatFilter, cv.positive_time_period_milliseconds ) -def heartbeat_filter_to_code(config, filter_id): +async def heartbeat_filter_to_code(config, filter_id): var = cg.new_Pvariable(filter_id, config) - yield cg.register_component(var, {}) - yield var + await cg.register_component(var, {}) + return var @FILTER_REGISTRY.register( "debounce", DebounceFilter, cv.positive_time_period_milliseconds ) -def debounce_filter_to_code(config, filter_id): +async def debounce_filter_to_code(config, filter_id): var = cg.new_Pvariable(filter_id, config) - yield cg.register_component(var, {}) - yield var + await cg.register_component(var, {}) + return var def validate_not_all_from_same(config): @@ -394,11 +394,11 @@ def validate_not_all_from_same(config): cv.ensure_list(validate_datapoint), cv.Length(min=2), validate_not_all_from_same ), ) -def calibrate_linear_filter_to_code(config, filter_id): +async def calibrate_linear_filter_to_code(config, filter_id): x = [conf[CONF_FROM] for conf in config] y = [conf[CONF_TO] for conf in config] k, b = fit_linear(x, y) - yield cg.new_Pvariable(filter_id, k, b) + return cg.new_Pvariable(filter_id, k, b) CONF_DATAPOINTS = "datapoints" @@ -430,7 +430,7 @@ def validate_calibrate_polynomial(config): validate_calibrate_polynomial, ), ) -def calibrate_polynomial_filter_to_code(config, filter_id): +async def calibrate_polynomial_filter_to_code(config, filter_id): x = [conf[CONF_FROM] for conf in config[CONF_DATAPOINTS]] y = [conf[CONF_TO] for conf in config[CONF_DATAPOINTS]] degree = config[CONF_DEGREE] @@ -438,7 +438,7 @@ def calibrate_polynomial_filter_to_code(config, filter_id): # Column vector b = [[v] for v in y] res = [v[0] for v in _lstsq(a, b)] - yield cg.new_Pvariable(filter_id, res) + return cg.new_Pvariable(filter_id, res) async def build_filters(config): diff --git a/esphome/components/servo/__init__.py b/esphome/components/servo/__init__.py index e54dd27dea..7147828a07 100644 --- a/esphome/components/servo/__init__.py +++ b/esphome/components/servo/__init__.py @@ -63,12 +63,12 @@ async def to_code(config): } ), ) -def servo_write_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def servo_write_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) - template_ = yield cg.templatable(config[CONF_LEVEL], args, float) + template_ = await cg.templatable(config[CONF_LEVEL], args, float) cg.add(var.set_value(template_)) - yield var + return var @automation.register_action( @@ -80,6 +80,6 @@ def servo_write_to_code(config, action_id, template_arg, args): } ), ) -def servo_detach_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) - yield cg.new_Pvariable(action_id, template_arg, paren) +async def servo_detach_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, paren) diff --git a/esphome/components/sim800l/__init__.py b/esphome/components/sim800l/__init__.py index 4fa1661d21..f9f6d71cd2 100644 --- a/esphome/components/sim800l/__init__.py +++ b/esphome/components/sim800l/__init__.py @@ -66,14 +66,14 @@ SIM800L_SEND_SMS_SCHEMA = cv.Schema( @automation.register_action( "sim800l.send_sms", Sim800LSendSmsAction, SIM800L_SEND_SMS_SCHEMA ) -def sim800l_send_sms_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def sim800l_send_sms_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) - template_ = yield cg.templatable(config[CONF_RECIPIENT], args, cg.std_string) + template_ = await cg.templatable(config[CONF_RECIPIENT], args, cg.std_string) cg.add(var.set_recipient(template_)) - template_ = yield cg.templatable(config[CONF_MESSAGE], args, cg.std_string) + template_ = await cg.templatable(config[CONF_MESSAGE], args, cg.std_string) cg.add(var.set_message(template_)) - yield var + return var SIM800L_DIAL_SCHEMA = cv.Schema( @@ -85,9 +85,9 @@ SIM800L_DIAL_SCHEMA = cv.Schema( @automation.register_action("sim800l.dial", Sim800LDialAction, SIM800L_DIAL_SCHEMA) -def sim800l_dial_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def sim800l_dial_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) - template_ = yield cg.templatable(config[CONF_RECIPIENT], args, cg.std_string) + template_ = await cg.templatable(config[CONF_RECIPIENT], args, cg.std_string) cg.add(var.set_recipient(template_)) - yield var + return var diff --git a/esphome/components/sn74hc595/__init__.py b/esphome/components/sn74hc595/__init__.py index 67d759cadd..4437878970 100644 --- a/esphome/components/sn74hc595/__init__.py +++ b/esphome/components/sn74hc595/__init__.py @@ -61,6 +61,6 @@ SN74HC595_INPUT_PIN_SCHEMA = cv.Schema({}) @pins.PIN_SCHEMA_REGISTRY.register( CONF_SN74HC595, (SN74HC595_OUTPUT_PIN_SCHEMA, SN74HC595_INPUT_PIN_SCHEMA) ) -def sn74hc595_pin_to_code(config): - parent = yield cg.get_variable(config[CONF_SN74HC595]) - yield SN74HC595GPIOPin.new(parent, config[CONF_NUMBER], config[CONF_INVERTED]) +async def sn74hc595_pin_to_code(config): + parent = await cg.get_variable(config[CONF_SN74HC595]) + return SN74HC595GPIOPin.new(parent, config[CONF_NUMBER], config[CONF_INVERTED]) diff --git a/esphome/components/ssd1306_base/__init__.py b/esphome/components/ssd1306_base/__init__.py index af7c1a019a..9652d01efa 100644 --- a/esphome/components/ssd1306_base/__init__.py +++ b/esphome/components/ssd1306_base/__init__.py @@ -9,7 +9,6 @@ from esphome.const import ( CONF_RESET_PIN, CONF_BRIGHTNESS, ) -from esphome.core import coroutine ssd1306_base_ns = cg.esphome_ns.namespace("ssd1306_base") SSD1306 = ssd1306_base_ns.class_("SSD1306", cg.PollingComponent, display.DisplayBuffer) @@ -38,21 +37,20 @@ SSD1306_SCHEMA = display.FULL_DISPLAY_SCHEMA.extend( ).extend(cv.polling_component_schema("1s")) -@coroutine -def setup_ssd1036(var, config): - yield cg.register_component(var, config) - yield display.register_display(var, config) +async def setup_ssd1036(var, config): + await cg.register_component(var, config) + await display.register_display(var, config) cg.add(var.set_model(config[CONF_MODEL])) if CONF_RESET_PIN in config: - reset = yield cg.gpio_pin_expression(config[CONF_RESET_PIN]) + reset = await cg.gpio_pin_expression(config[CONF_RESET_PIN]) cg.add(var.set_reset_pin(reset)) if CONF_BRIGHTNESS in config: cg.add(var.init_brightness(config[CONF_BRIGHTNESS])) if CONF_EXTERNAL_VCC in config: cg.add(var.set_external_vcc(config[CONF_EXTERNAL_VCC])) if CONF_LAMBDA in config: - lambda_ = yield cg.process_lambda( + lambda_ = await cg.process_lambda( config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void ) cg.add(var.set_writer(lambda_)) diff --git a/esphome/components/ssd1322_base/__init__.py b/esphome/components/ssd1322_base/__init__.py index 0792fd0f89..434caf4e35 100644 --- a/esphome/components/ssd1322_base/__init__.py +++ b/esphome/components/ssd1322_base/__init__.py @@ -9,7 +9,6 @@ from esphome.const import ( CONF_MODEL, CONF_RESET_PIN, ) -from esphome.core import coroutine CODEOWNERS = ["@kbx81"] @@ -33,21 +32,20 @@ SSD1322_SCHEMA = display.FULL_DISPLAY_SCHEMA.extend( ).extend(cv.polling_component_schema("1s")) -@coroutine -def setup_ssd1322(var, config): - yield cg.register_component(var, config) - yield display.register_display(var, config) +async def setup_ssd1322(var, config): + await cg.register_component(var, config) + await display.register_display(var, config) cg.add(var.set_model(config[CONF_MODEL])) if CONF_RESET_PIN in config: - reset = yield cg.gpio_pin_expression(config[CONF_RESET_PIN]) + reset = await cg.gpio_pin_expression(config[CONF_RESET_PIN]) cg.add(var.set_reset_pin(reset)) if CONF_BRIGHTNESS in config: cg.add(var.init_brightness(config[CONF_BRIGHTNESS])) if CONF_EXTERNAL_VCC in config: cg.add(var.set_external_vcc(config[CONF_EXTERNAL_VCC])) if CONF_LAMBDA in config: - lambda_ = yield cg.process_lambda( + lambda_ = await cg.process_lambda( config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void ) cg.add(var.set_writer(lambda_)) diff --git a/esphome/components/ssd1325_base/__init__.py b/esphome/components/ssd1325_base/__init__.py index 1e6535c7ec..68be287d2a 100644 --- a/esphome/components/ssd1325_base/__init__.py +++ b/esphome/components/ssd1325_base/__init__.py @@ -9,7 +9,6 @@ from esphome.const import ( CONF_MODEL, CONF_RESET_PIN, ) -from esphome.core import coroutine CODEOWNERS = ["@kbx81"] @@ -37,21 +36,20 @@ SSD1325_SCHEMA = display.FULL_DISPLAY_SCHEMA.extend( ).extend(cv.polling_component_schema("1s")) -@coroutine -def setup_ssd1325(var, config): - yield cg.register_component(var, config) - yield display.register_display(var, config) +async def setup_ssd1325(var, config): + await cg.register_component(var, config) + await display.register_display(var, config) cg.add(var.set_model(config[CONF_MODEL])) if CONF_RESET_PIN in config: - reset = yield cg.gpio_pin_expression(config[CONF_RESET_PIN]) + reset = await cg.gpio_pin_expression(config[CONF_RESET_PIN]) cg.add(var.set_reset_pin(reset)) if CONF_BRIGHTNESS in config: cg.add(var.init_brightness(config[CONF_BRIGHTNESS])) if CONF_EXTERNAL_VCC in config: cg.add(var.set_external_vcc(config[CONF_EXTERNAL_VCC])) if CONF_LAMBDA in config: - lambda_ = yield cg.process_lambda( + lambda_ = await cg.process_lambda( config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void ) cg.add(var.set_writer(lambda_)) diff --git a/esphome/components/ssd1327_base/__init__.py b/esphome/components/ssd1327_base/__init__.py index 74446d6f09..eada66a6e3 100644 --- a/esphome/components/ssd1327_base/__init__.py +++ b/esphome/components/ssd1327_base/__init__.py @@ -3,7 +3,6 @@ import esphome.config_validation as cv from esphome import pins from esphome.components import display from esphome.const import CONF_BRIGHTNESS, CONF_LAMBDA, CONF_MODEL, CONF_RESET_PIN -from esphome.core import coroutine CODEOWNERS = ["@kbx81"] @@ -26,19 +25,18 @@ SSD1327_SCHEMA = display.FULL_DISPLAY_SCHEMA.extend( ).extend(cv.polling_component_schema("1s")) -@coroutine -def setup_ssd1327(var, config): - yield cg.register_component(var, config) - yield display.register_display(var, config) +async def setup_ssd1327(var, config): + await cg.register_component(var, config) + await display.register_display(var, config) cg.add(var.set_model(config[CONF_MODEL])) if CONF_RESET_PIN in config: - reset = yield cg.gpio_pin_expression(config[CONF_RESET_PIN]) + reset = await cg.gpio_pin_expression(config[CONF_RESET_PIN]) cg.add(var.set_reset_pin(reset)) if CONF_BRIGHTNESS in config: cg.add(var.init_brightness(config[CONF_BRIGHTNESS])) if CONF_LAMBDA in config: - lambda_ = yield cg.process_lambda( + lambda_ = await cg.process_lambda( config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void ) cg.add(var.set_writer(lambda_)) diff --git a/esphome/components/ssd1331_base/__init__.py b/esphome/components/ssd1331_base/__init__.py index e151d3fe17..067f55a252 100644 --- a/esphome/components/ssd1331_base/__init__.py +++ b/esphome/components/ssd1331_base/__init__.py @@ -3,7 +3,6 @@ import esphome.config_validation as cv from esphome import pins from esphome.components import display from esphome.const import CONF_BRIGHTNESS, CONF_LAMBDA, CONF_RESET_PIN -from esphome.core import coroutine CODEOWNERS = ["@kbx81"] @@ -18,18 +17,17 @@ SSD1331_SCHEMA = display.FULL_DISPLAY_SCHEMA.extend( ).extend(cv.polling_component_schema("1s")) -@coroutine -def setup_ssd1331(var, config): - yield cg.register_component(var, config) - yield display.register_display(var, config) +async def setup_ssd1331(var, config): + await cg.register_component(var, config) + await display.register_display(var, config) if CONF_RESET_PIN in config: - reset = yield cg.gpio_pin_expression(config[CONF_RESET_PIN]) + reset = await cg.gpio_pin_expression(config[CONF_RESET_PIN]) cg.add(var.set_reset_pin(reset)) if CONF_BRIGHTNESS in config: cg.add(var.init_brightness(config[CONF_BRIGHTNESS])) if CONF_LAMBDA in config: - lambda_ = yield cg.process_lambda( + lambda_ = await cg.process_lambda( config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void ) cg.add(var.set_writer(lambda_)) diff --git a/esphome/components/ssd1351_base/__init__.py b/esphome/components/ssd1351_base/__init__.py index 5e2c14cb6f..555d6c5e2e 100644 --- a/esphome/components/ssd1351_base/__init__.py +++ b/esphome/components/ssd1351_base/__init__.py @@ -3,7 +3,6 @@ import esphome.config_validation as cv from esphome import pins from esphome.components import display from esphome.const import CONF_BRIGHTNESS, CONF_LAMBDA, CONF_MODEL, CONF_RESET_PIN -from esphome.core import coroutine CODEOWNERS = ["@kbx81"] @@ -27,19 +26,18 @@ SSD1351_SCHEMA = display.FULL_DISPLAY_SCHEMA.extend( ).extend(cv.polling_component_schema("1s")) -@coroutine -def setup_ssd1351(var, config): - yield cg.register_component(var, config) - yield display.register_display(var, config) +async def setup_ssd1351(var, config): + await cg.register_component(var, config) + await display.register_display(var, config) cg.add(var.set_model(config[CONF_MODEL])) if CONF_RESET_PIN in config: - reset = yield cg.gpio_pin_expression(config[CONF_RESET_PIN]) + reset = await cg.gpio_pin_expression(config[CONF_RESET_PIN]) cg.add(var.set_reset_pin(reset)) if CONF_BRIGHTNESS in config: cg.add(var.init_brightness(config[CONF_BRIGHTNESS])) if CONF_LAMBDA in config: - lambda_ = yield cg.process_lambda( + lambda_ = await cg.process_lambda( config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void ) cg.add(var.set_writer(lambda_)) diff --git a/esphome/components/st7735/display.py b/esphome/components/st7735/display.py index bbacc5f55e..c1ede4e0ce 100644 --- a/esphome/components/st7735/display.py +++ b/esphome/components/st7735/display.py @@ -3,7 +3,6 @@ import esphome.config_validation as cv from esphome import pins from esphome.components import spi from esphome.components import display -from esphome.core import coroutine from esphome.const import ( CONF_DC_PIN, CONF_ID, @@ -67,16 +66,15 @@ CONFIG_SCHEMA = cv.All( ) -@coroutine -def setup_st7735(var, config): - yield cg.register_component(var, config) - yield display.register_display(var, config) +async def setup_st7735(var, config): + await cg.register_component(var, config) + await display.register_display(var, config) if CONF_RESET_PIN in config: - reset = yield cg.gpio_pin_expression(config[CONF_RESET_PIN]) + reset = await cg.gpio_pin_expression(config[CONF_RESET_PIN]) cg.add(var.set_reset_pin(reset)) if CONF_LAMBDA in config: - lambda_ = yield cg.process_lambda( + lambda_ = await cg.process_lambda( config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void ) cg.add(var.set_writer(lambda_)) diff --git a/esphome/components/stepper/__init__.py b/esphome/components/stepper/__init__.py index ce7b7ae6f9..41b1db7df2 100644 --- a/esphome/components/stepper/__init__.py +++ b/esphome/components/stepper/__init__.py @@ -10,7 +10,7 @@ from esphome.const import ( CONF_TARGET, CONF_SPEED, ) -from esphome.core import CORE, coroutine, coroutine_with_priority +from esphome.core import CORE, coroutine_with_priority IS_PLATFORM_COMPONENT = True @@ -74,8 +74,7 @@ STEPPER_SCHEMA = cv.Schema( ) -@coroutine -def setup_stepper_core_(stepper_var, config): +async def setup_stepper_core_(stepper_var, config): if CONF_ACCELERATION in config: cg.add(stepper_var.set_acceleration(config[CONF_ACCELERATION])) if CONF_DECELERATION in config: @@ -84,11 +83,10 @@ def setup_stepper_core_(stepper_var, config): cg.add(stepper_var.set_max_speed(config[CONF_MAX_SPEED])) -@coroutine -def register_stepper(var, config): +async def register_stepper(var, config): if not CORE.has_id(config[CONF_ID]): var = cg.Pvariable(config[CONF_ID], var) - yield setup_stepper_core_(var, config) + await setup_stepper_core_(var, config) @automation.register_action( @@ -101,12 +99,12 @@ def register_stepper(var, config): } ), ) -def stepper_set_target_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def stepper_set_target_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) - template_ = yield cg.templatable(config[CONF_TARGET], args, cg.int32) + template_ = await cg.templatable(config[CONF_TARGET], args, cg.int32) cg.add(var.set_target(template_)) - yield var + return var @automation.register_action( @@ -119,12 +117,12 @@ def stepper_set_target_to_code(config, action_id, template_arg, args): } ), ) -def stepper_report_position_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def stepper_report_position_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) - template_ = yield cg.templatable(config[CONF_POSITION], args, cg.int32) + template_ = await cg.templatable(config[CONF_POSITION], args, cg.int32) cg.add(var.set_position(template_)) - yield var + return var @automation.register_action( @@ -137,12 +135,12 @@ def stepper_report_position_to_code(config, action_id, template_arg, args): } ), ) -def stepper_set_speed_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def stepper_set_speed_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) - template_ = yield cg.templatable(config[CONF_SPEED], args, cg.int32) + template_ = await cg.templatable(config[CONF_SPEED], args, cg.int32) cg.add(var.set_speed(template_)) - yield var + return var @coroutine_with_priority(100.0) diff --git a/esphome/components/sun/__init__.py b/esphome/components/sun/__init__.py index 296f2027dc..d00a00661a 100644 --- a/esphome/components/sun/__init__.py +++ b/esphome/components/sun/__init__.py @@ -151,13 +151,13 @@ async def to_code(config): } ), ) -def sun_above_horizon_to_code(config, condition_id, template_arg, args): +async def sun_above_horizon_to_code(config, condition_id, template_arg, args): var = cg.new_Pvariable(condition_id, template_arg) - yield cg.register_parented(var, config[CONF_ID]) - templ = yield cg.templatable(config[CONF_ELEVATION], args, cg.double) + await cg.register_parented(var, config[CONF_ID]) + templ = await cg.templatable(config[CONF_ELEVATION], args, cg.double) cg.add(var.set_elevation(templ)) cg.add(var.set_above(True)) - yield var + return var @automation.register_condition( @@ -172,10 +172,10 @@ def sun_above_horizon_to_code(config, condition_id, template_arg, args): } ), ) -def sun_below_horizon_to_code(config, condition_id, template_arg, args): +async def sun_below_horizon_to_code(config, condition_id, template_arg, args): var = cg.new_Pvariable(condition_id, template_arg) - yield cg.register_parented(var, config[CONF_ID]) - templ = yield cg.templatable(config[CONF_ELEVATION], args, cg.double) + await cg.register_parented(var, config[CONF_ID]) + templ = await cg.templatable(config[CONF_ELEVATION], args, cg.double) cg.add(var.set_elevation(templ)) cg.add(var.set_above(False)) - yield var + return var diff --git a/esphome/components/sx1509/__init__.py b/esphome/components/sx1509/__init__.py index fd0b5befb6..8e1239924a 100644 --- a/esphome/components/sx1509/__init__.py +++ b/esphome/components/sx1509/__init__.py @@ -90,8 +90,8 @@ SX1509_INPUT_PIN_SCHEMA = cv.Schema( @pins.PIN_SCHEMA_REGISTRY.register( CONF_SX1509, (SX1509_OUTPUT_PIN_SCHEMA, SX1509_INPUT_PIN_SCHEMA) ) -def sx1509_pin_to_code(config): - parent = yield cg.get_variable(config[CONF_SX1509]) - yield SX1509GPIOPin.new( +async def sx1509_pin_to_code(config): + parent = await cg.get_variable(config[CONF_SX1509]) + return SX1509GPIOPin.new( parent, config[CONF_NUMBER], config[CONF_MODE], config[CONF_INVERTED] ) diff --git a/esphome/components/template/binary_sensor/__init__.py b/esphome/components/template/binary_sensor/__init__.py index 754b7a4a43..8f551e3215 100644 --- a/esphome/components/template/binary_sensor/__init__.py +++ b/esphome/components/template/binary_sensor/__init__.py @@ -39,9 +39,9 @@ async def to_code(config): } ), ) -def binary_sensor_template_publish_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def binary_sensor_template_publish_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) - template_ = yield cg.templatable(config[CONF_STATE], args, bool) + template_ = await cg.templatable(config[CONF_STATE], args, bool) cg.add(var.set_state(template_)) - yield var + return var diff --git a/esphome/components/template/cover/__init__.py b/esphome/components/template/cover/__init__.py index 3d28e839ad..a628da70d2 100644 --- a/esphome/components/template/cover/__init__.py +++ b/esphome/components/template/cover/__init__.py @@ -111,21 +111,21 @@ async def to_code(config): } ), ) -def cover_template_publish_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def cover_template_publish_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) if CONF_STATE in config: - template_ = yield cg.templatable(config[CONF_STATE], args, float) + template_ = await cg.templatable(config[CONF_STATE], args, float) cg.add(var.set_position(template_)) if CONF_POSITION in config: - template_ = yield cg.templatable(config[CONF_POSITION], args, float) + template_ = await cg.templatable(config[CONF_POSITION], args, float) cg.add(var.set_position(template_)) if CONF_TILT in config: - template_ = yield cg.templatable(config[CONF_TILT], args, float) + template_ = await cg.templatable(config[CONF_TILT], args, float) cg.add(var.set_tilt(template_)) if CONF_CURRENT_OPERATION in config: - template_ = yield cg.templatable( + template_ = await cg.templatable( config[CONF_CURRENT_OPERATION], args, cover.CoverOperation ) cg.add(var.set_current_operation(template_)) - yield var + return var diff --git a/esphome/components/template/sensor/__init__.py b/esphome/components/template/sensor/__init__.py index ea776f6705..f4d2a1831f 100644 --- a/esphome/components/template/sensor/__init__.py +++ b/esphome/components/template/sensor/__init__.py @@ -50,9 +50,9 @@ async def to_code(config): } ), ) -def sensor_template_publish_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def sensor_template_publish_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) - template_ = yield cg.templatable(config[CONF_STATE], args, float) + template_ = await cg.templatable(config[CONF_STATE], args, float) cg.add(var.set_state(template_)) - yield var + return var diff --git a/esphome/components/template/switch/__init__.py b/esphome/components/template/switch/__init__.py index 9fd4baeb3a..b00710dfb7 100644 --- a/esphome/components/template/switch/__init__.py +++ b/esphome/components/template/switch/__init__.py @@ -62,9 +62,9 @@ async def to_code(config): } ), ) -def switch_template_publish_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def switch_template_publish_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) - template_ = yield cg.templatable(config[CONF_STATE], args, bool) + template_ = await cg.templatable(config[CONF_STATE], args, bool) cg.add(var.set_state(template_)) - yield var + return var diff --git a/esphome/components/template/text_sensor/__init__.py b/esphome/components/template/text_sensor/__init__.py index e97632025d..2e098a77c2 100644 --- a/esphome/components/template/text_sensor/__init__.py +++ b/esphome/components/template/text_sensor/__init__.py @@ -40,9 +40,9 @@ async def to_code(config): } ), ) -def text_sensor_template_publish_to_code(config, action_id, template_arg, args): - paren = yield cg.get_variable(config[CONF_ID]) +async def text_sensor_template_publish_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) - template_ = yield cg.templatable(config[CONF_STATE], args, cg.std_string) + template_ = await cg.templatable(config[CONF_STATE], args, cg.std_string) cg.add(var.set_state(template_)) - yield var + return var diff --git a/esphome/components/tm1651/__init__.py b/esphome/components/tm1651/__init__.py index e8c1425d83..f67a9f4512 100644 --- a/esphome/components/tm1651/__init__.py +++ b/esphome/components/tm1651/__init__.py @@ -61,19 +61,19 @@ BINARY_OUTPUT_ACTION_SCHEMA = maybe_simple_id( @automation.register_action("tm1651.turn_on", TurnOnAction, BINARY_OUTPUT_ACTION_SCHEMA) -def output_turn_on_to_code(config, action_id, template_arg, args): +async def output_turn_on_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) - yield cg.register_parented(var, config[CONF_ID]) - yield var + await cg.register_parented(var, config[CONF_ID]) + return var @automation.register_action( "tm1651.turn_off", TurnOffAction, BINARY_OUTPUT_ACTION_SCHEMA ) -def output_turn_off_to_code(config, action_id, template_arg, args): +async def output_turn_off_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) - yield cg.register_parented(var, config[CONF_ID]) - yield var + await cg.register_parented(var, config[CONF_ID]) + return var @automation.register_action( @@ -87,12 +87,12 @@ def output_turn_off_to_code(config, action_id, template_arg, args): key=CONF_LEVEL_PERCENT, ), ) -def tm1651_set_level_percent_to_code(config, action_id, template_arg, args): +async def tm1651_set_level_percent_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) - yield cg.register_parented(var, config[CONF_ID]) - template_ = yield cg.templatable(config[CONF_LEVEL_PERCENT], args, cg.uint8) + await cg.register_parented(var, config[CONF_ID]) + template_ = await cg.templatable(config[CONF_LEVEL_PERCENT], args, cg.uint8) cg.add(var.set_level_percent(template_)) - yield var + return var @automation.register_action( @@ -106,12 +106,12 @@ def tm1651_set_level_percent_to_code(config, action_id, template_arg, args): key=CONF_LEVEL, ), ) -def tm1651_set_level_to_code(config, action_id, template_arg, args): +async def tm1651_set_level_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) - yield cg.register_parented(var, config[CONF_ID]) - template_ = yield cg.templatable(config[CONF_LEVEL], args, cg.uint8) + await cg.register_parented(var, config[CONF_ID]) + template_ = await cg.templatable(config[CONF_LEVEL], args, cg.uint8) cg.add(var.set_level(template_)) - yield var + return var @automation.register_action( @@ -125,9 +125,9 @@ def tm1651_set_level_to_code(config, action_id, template_arg, args): key=CONF_BRIGHTNESS, ), ) -def tm1651_set_brightness_to_code(config, action_id, template_arg, args): +async def tm1651_set_brightness_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg) - yield cg.register_parented(var, config[CONF_ID]) - template_ = yield cg.templatable(config[CONF_BRIGHTNESS], args, cg.uint8) + await cg.register_parented(var, config[CONF_ID]) + template_ = await cg.templatable(config[CONF_BRIGHTNESS], args, cg.uint8) cg.add(var.set_brightness(template_)) - yield var + return var diff --git a/esphome/components/wifi_info/text_sensor.py b/esphome/components/wifi_info/text_sensor.py index 11978f7bfe..50ec3eb272 100644 --- a/esphome/components/wifi_info/text_sensor.py +++ b/esphome/components/wifi_info/text_sensor.py @@ -8,7 +8,6 @@ from esphome.const import ( CONF_SSID, CONF_MAC_ADDRESS, ) -from esphome.core import coroutine DEPENDENCIES = ["wifi"] @@ -50,13 +49,12 @@ CONFIG_SCHEMA = cv.Schema( ) -@coroutine -def setup_conf(config, key): +async def setup_conf(config, key): if key in config: conf = config[key] var = cg.new_Pvariable(conf[CONF_ID]) - yield cg.register_component(var, conf) - yield text_sensor.register_text_sensor(var, conf) + await cg.register_component(var, conf) + await text_sensor.register_text_sensor(var, conf) async def to_code(config): diff --git a/esphome/components/wled/__init__.py b/esphome/components/wled/__init__.py index 31ec318281..c9e23bb7eb 100644 --- a/esphome/components/wled/__init__.py +++ b/esphome/components/wled/__init__.py @@ -18,8 +18,8 @@ CONFIG_SCHEMA = cv.Schema({}) cv.Optional(CONF_PORT, default=21324): cv.port, }, ) -def wled_light_effect_to_code(config, effect_id): +async def wled_light_effect_to_code(config, effect_id): effect = cg.new_Pvariable(effect_id, config[CONF_NAME]) cg.add(effect.set_port(config[CONF_PORT])) - yield effect + return effect diff --git a/esphome/cpp_generator.py b/esphome/cpp_generator.py index 5325526c23..802e9a9d38 100644 --- a/esphome/cpp_generator.py +++ b/esphome/cpp_generator.py @@ -354,7 +354,7 @@ def safe_exp(obj: SafeExpType) -> Expression: if inspect.isgenerator(obj): raise ValueError( "Object {} is a coroutine. Did you forget to await the expression with " - "'yield'?".format(obj) + "'await'?".format(obj) ) raise ValueError("Object is not an expression", obj) @@ -573,7 +573,7 @@ async def get_variable(id_: ID) -> "MockObj": Wait for the given ID to be defined in the code generation and return it as a MockObj. - This is a coroutine, you need to await it with a 'yield' expression! + This is a coroutine, you need to await it with a 'await' expression! :param id_: The ID to retrieve :return: The variable as a MockObj. @@ -586,7 +586,7 @@ async def get_variable_with_full_id(id_: ID) -> Tuple[ID, "MockObj"]: Wait for the given ID to be defined in the code generation and return it as a MockObj. - This is a coroutine, you need to await it with a 'yield' expression! + This is a coroutine, you need to await it with a 'await' expression! :param id_: The ID to retrieve :return: The variable as a MockObj. @@ -603,7 +603,7 @@ async def process_lambda( """Process the given lambda value into a LambdaExpression. This is a coroutine because lambdas can depend on other IDs, - you need to await it with 'yield'! + you need to await it with 'await'! :param value: The lambda to process. :param parameters: The parameters to pass to the Lambda, list of tuples diff --git a/esphome/cpp_helpers.py b/esphome/cpp_helpers.py index e1b1a09133..1c52f38e50 100644 --- a/esphome/cpp_helpers.py +++ b/esphome/cpp_helpers.py @@ -17,7 +17,7 @@ from esphome.util import Registry, RegistryEntry async def gpio_pin_expression(conf): """Generate an expression for the given pin option. - This is a coroutine, you must await it with a 'yield' expression! + This is a coroutine, you must await it with a 'await' expression! """ if conf is None: return @@ -36,7 +36,7 @@ async def gpio_pin_expression(conf): async def register_component(var, config): """Register the given obj as a component. - This is a coroutine, you must await it with a 'yield' expression! + This is a coroutine, you must await it with a 'await' expression! :param var: The variable representing the component. :param config: The configuration for the component. From e3c27a483c40d1db74dbf2a2f32beb35ee7c3b8f Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Mon, 24 May 2021 21:45:51 +0200 Subject: [PATCH 061/104] Update sensor device classes from HA (#1825) --- esphome/components/sensor/__init__.py | 6 +++++- esphome/const.py | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py index d449568f0e..9c0b0bedd1 100644 --- a/esphome/components/sensor/__init__.py +++ b/esphome/components/sensor/__init__.py @@ -33,6 +33,8 @@ from esphome.const import ( ICON_EMPTY, DEVICE_CLASS_EMPTY, DEVICE_CLASS_BATTERY, + DEVICE_CLASS_CARBON_MONOXIDE, + DEVICE_CLASS_CARBON_DIOXIDE, DEVICE_CLASS_CURRENT, DEVICE_CLASS_ENERGY, DEVICE_CLASS_HUMIDITY, @@ -52,16 +54,18 @@ CODEOWNERS = ["@esphome/core"] DEVICE_CLASSES = [ DEVICE_CLASS_EMPTY, DEVICE_CLASS_BATTERY, + DEVICE_CLASS_CARBON_MONOXIDE, + DEVICE_CLASS_CARBON_DIOXIDE, DEVICE_CLASS_CURRENT, DEVICE_CLASS_ENERGY, DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_ILLUMINANCE, DEVICE_CLASS_SIGNAL_STRENGTH, DEVICE_CLASS_TEMPERATURE, + DEVICE_CLASS_TIMESTAMP, DEVICE_CLASS_POWER, DEVICE_CLASS_POWER_FACTOR, DEVICE_CLASS_PRESSURE, - DEVICE_CLASS_TIMESTAMP, DEVICE_CLASS_VOLTAGE, ] diff --git a/esphome/const.py b/esphome/const.py index e93d2b7d25..d44e995fc8 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -746,6 +746,8 @@ DEVICE_CLASS_EMPTY = "" DEVICE_CLASS_BATTERY = "battery" DEVICE_CLASS_POWER = "power" # device classes of sensor component +DEVICE_CLASS_CARBON_MONOXIDE = "carbon_monoxide" +DEVICE_CLASS_CARBON_DIOXIDE = "carbon_dioxide" DEVICE_CLASS_CURRENT = "current" DEVICE_CLASS_ENERGY = "energy" DEVICE_CLASS_HUMIDITY = "humidity" From 824f3187ac7b22abb38df5c503844f4216c4093d Mon Sep 17 00:00:00 2001 From: Oxan van Leeuwen Date: Mon, 24 May 2021 21:47:45 +0200 Subject: [PATCH 062/104] Update platformio.ini settings and fix test apps (#1815) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Co-authored-by: Otto Winter --- .gitignore | 2 + platformio.ini | 46 +++++++++++--------- tests/{livingroom8266.cpp => dummy_main.cpp} | 15 +++++-- tests/livingroom32.cpp | 26 ----------- 4 files changed, 39 insertions(+), 50 deletions(-) rename tests/{livingroom8266.cpp => dummy_main.cpp} (59%) delete mode 100644 tests/livingroom32.cpp diff --git a/.gitignore b/.gitignore index 86a27eb4b4..a24550ad54 100644 --- a/.gitignore +++ b/.gitignore @@ -100,6 +100,8 @@ CMakeLists.txt # CMake cmake-build-debug/ +cmake-build-livingroom8266/ +cmake-build-livingroom32/ cmake-build-release/ CMakeCache.txt diff --git a/platformio.ini b/platformio.ini index 002e0d4695..ba7724ad24 100644 --- a/platformio.ini +++ b/platformio.ini @@ -10,43 +10,49 @@ include_dir = include [common] lib_deps = - esphome/AsyncTCP-esphome@1.2.2 AsyncMqttClient-esphome@0.8.4 ArduinoJson-esphomelib@5.13.3 ESPAsyncWebServer-esphome@1.2.7 - fastled/FastLED@3.3.2 + FastLED@3.3.2 NeoPixelBus-esphome@2.6.2 - ESPAsyncTCP-esphome@1.2.3 1655@1.0.2 ; TinyGPSPlus (has name conflict) 6865@1.0.0 ; TM1651 Battery Display 6306@1.0.3 ; HM3301 build_flags = - -Wno-reorder - -DUSE_WEB_SERVER - -DUSE_FAST_LED_LIGHT - -DUSE_NEO_PIXEL_BUS_LIGHT + -fno-exceptions + -Wno-sign-compare + -Wno-unused-but-set-variable + -Wno-unused-variable -DCLANG_TIDY -DESPHOME_LOG_LEVEL=ESPHOME_LOG_LEVEL_VERY_VERBOSE -; Don't use FlashStringHelper for debug builds because CLion freaks out for all -; log messages -src_filter = + +src_filter = + + + + [env:livingroom8266] -; use Arduino framework v2.3.0 for clang-tidy (latest 2.5.2 breaks static code analysis, see #760) -platform = espressif8266@1.8.0 -board = nodemcuv2 +; use Arduino framework v2.4.2 for clang-tidy (latest 2.5.2 breaks static code analysis, see #760) +platform = platformio/espressif8266@1.8.0 framework = arduino +board = nodemcuv2 lib_deps = ${common.lib_deps} ESP8266WiFi - Hash + ESPAsyncTCP-esphome@1.2.3 + Update build_flags = ${common.build_flags} -src_filter = ${common.src_filter} + +src_filter = ${common.src_filter} [env:livingroom32] -platform = espressif32@1.12.4 -board = nodemcu-32s +platform = platformio/espressif32@3.2.0 framework = arduino -lib_deps = ${common.lib_deps} -build_flags = ${common.build_flags} -DUSE_ETHERNET -src_filter = ${common.src_filter} + +board = nodemcu-32s +lib_deps = + ${common.lib_deps} + esphome/AsyncTCP-esphome@1.2.2 + Update +build_flags = + ${common.build_flags} + -DUSE_ETHERNET +src_filter = + ${common.src_filter} + - diff --git a/tests/livingroom8266.cpp b/tests/dummy_main.cpp similarity index 59% rename from tests/livingroom8266.cpp rename to tests/dummy_main.cpp index ad017ce73b..c3b192d15f 100644 --- a/tests/livingroom8266.cpp +++ b/tests/dummy_main.cpp @@ -1,3 +1,8 @@ +// Dummy main.cpp file for the PlatformIO project in the git repository. +// Primarily used to get IDE integration working (so the contents here don't +// matter at all, as long as it compiles). +// Not used during runtime nor for CI. + #include #include #include @@ -7,7 +12,7 @@ using namespace esphome; void setup() { - App.pre_setup("livingroom", __DATE__ " " __TIME__); + App.pre_setup("livingroom", __DATE__ ", " __TIME__, false); auto *log = new logger::Logger(115200, 512, logger::UART_SELECTION_UART0); log->pre_setup(); App.register_component(log); @@ -19,10 +24,12 @@ void setup() { ap.set_password("password1"); wifi->add_sta(ap); - auto *ota = new ota::OTAComponent(8266); - ota->start_safe_mode(); + auto *ota = new ota::OTAComponent(); + ota->set_port(8266); - auto *gpio = new gpio::GPIOSwitch("GPIO Switch", new GPIOPin(8, OUTPUT)); + auto *gpio = new gpio::GPIOSwitch(); + gpio->set_name("GPIO Switch"); + gpio->set_pin(new GPIOPin(8, OUTPUT, false)); App.register_component(gpio); App.register_switch(gpio); diff --git a/tests/livingroom32.cpp b/tests/livingroom32.cpp deleted file mode 100644 index 7005ec95e0..0000000000 --- a/tests/livingroom32.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include - -using namespace esphome; - -void setup() { - App.set_name("livingroom32"); - App.init_log(); - - App.init_wifi("YOUR_SSID", "YOUR_PASSWORD"); - App.init_mqtt("MQTT_HOST", "USERNAME", "PASSWORD"); - App.init_ota()->start_safe_mode(); - - // LEDC is only available on ESP32! for the ESP8266, take a look at App.make_esp8266_pwm_output(). - auto *red = App.make_ledc_output(32); // on pin 32 - auto *green = App.make_ledc_output(33); - auto *blue = App.make_ledc_output(34); - App.make_rgb_light("Livingroom Light", red, green, blue); - - App.make_dht_sensor("Livingroom Temperature", "Livingroom Humidity", 12); - App.make_status_binary_sensor("Livingroom Node Status"); - App.make_restart_switch("Livingroom Restart"); - - App.setup(); -} - -void loop() { App.loop(); } From 3d917d0b7e2679d5cc46d934dde3013ae4a529c2 Mon Sep 17 00:00:00 2001 From: Guillermo Ruffino Date: Tue, 25 May 2021 17:03:59 -0300 Subject: [PATCH 063/104] lambda condition should return (#1833) --- esphome/automation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/automation.py b/esphome/automation.py index 1cf6bbf542..71c564b906 100644 --- a/esphome/automation.py +++ b/esphome/automation.py @@ -158,7 +158,7 @@ async def not_condition_to_code(config, condition_id, template_arg, args): return cg.new_Pvariable(condition_id, template_arg, condition) -@register_condition("lambda", LambdaCondition, cv.lambda_) +@register_condition("lambda", LambdaCondition, cv.returning_lambda) async def lambda_condition_to_code(config, condition_id, template_arg, args): lambda_ = await cg.process_lambda(config, args, return_type=bool) return cg.new_Pvariable(condition_id, template_arg, lambda_) From 387f249363fd13fcb7435f904acbd318b2ce0fc0 Mon Sep 17 00:00:00 2001 From: Guillermo Ruffino Date: Thu, 27 May 2021 22:15:52 -0300 Subject: [PATCH 064/104] fix dallas pin validation (#1692) --- esphome/components/dallas/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/dallas/__init__.py b/esphome/components/dallas/__init__.py index e889c41175..762bfdc3c3 100644 --- a/esphome/components/dallas/__init__.py +++ b/esphome/components/dallas/__init__.py @@ -15,7 +15,7 @@ CONFIG_SCHEMA = cv.Schema( { cv.GenerateID(): cv.declare_id(DallasComponent), cv.GenerateID(CONF_ONE_WIRE_ID): cv.declare_id(ESPOneWire), - cv.Required(CONF_PIN): pins.gpio_input_pin_schema, + cv.Required(CONF_PIN): pins.internal_gpio_output_pin_schema, } ).extend(cv.polling_component_schema("60s")) From 482a3aebc9c89fe148ec947f94d83481fde8789b Mon Sep 17 00:00:00 2001 From: Thomas Dietrich Date: Fri, 28 May 2021 03:34:54 +0200 Subject: [PATCH 065/104] Fix typo in wizard (#1836) --- esphome/wizard.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/wizard.py b/esphome/wizard.py index 3550e39392..7d875b7dd2 100644 --- a/esphome/wizard.py +++ b/esphome/wizard.py @@ -295,7 +295,7 @@ def wizard(path): safe_print( "First, what's the " + color(Fore.GREEN, "SSID") - + f" (the name) of the WiFi network {name} I should connect to?" + + f" (the name) of the WiFi network {name} should connect to?" ) sleep(1.5) safe_print('For example "{}".'.format(color(Fore.BOLD_WHITE, "Abraham Linksys"))) From c79d700d0325e5ed6c1d9d76889b71c51b392736 Mon Sep 17 00:00:00 2001 From: Guillermo Ruffino Date: Sun, 30 May 2021 19:06:45 -0300 Subject: [PATCH 066/104] Add validate to components (#1631) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/cse7766/sensor.py | 6 ++ esphome/components/dfplayer/__init__.py | 6 ++ esphome/components/ethernet/__init__.py | 4 +- esphome/components/fastled_clockless/light.py | 4 +- esphome/components/gps/__init__.py | 4 ++ esphome/components/hm3301/sensor.py | 4 +- esphome/components/neopixelbus/light.py | 4 +- esphome/components/rc522_spi/__init__.py | 5 ++ esphome/components/rtttl/__init__.py | 32 +++++++++- esphome/components/sim800l/__init__.py | 4 ++ esphome/components/spi/__init__.py | 8 +++ esphome/components/uart/__init__.py | 36 +++++++++++ esphome/components/wifi/__init__.py | 4 +- esphome/config.py | 23 ++++++- esphome/loader.py | 4 ++ tests/test3.yaml | 62 ++++++++++++------- 16 files changed, 174 insertions(+), 36 deletions(-) diff --git a/esphome/components/cse7766/sensor.py b/esphome/components/cse7766/sensor.py index 3e136dae49..ca829cb274 100644 --- a/esphome/components/cse7766/sensor.py +++ b/esphome/components/cse7766/sensor.py @@ -59,3 +59,9 @@ async def to_code(config): conf = config[CONF_POWER] sens = await sensor.new_sensor(conf) cg.add(var.set_power_sensor(sens)) + + +def validate(config, item_config): + uart.validate_device( + "cse7766", config, item_config, baud_rate=4800, require_tx=False + ) diff --git a/esphome/components/dfplayer/__init__.py b/esphome/components/dfplayer/__init__.py index d23e40000e..4c276db63f 100644 --- a/esphome/components/dfplayer/__init__.py +++ b/esphome/components/dfplayer/__init__.py @@ -78,6 +78,12 @@ async def to_code(config): await automation.build_automation(trigger, [], conf) +def validate(config, item_config): + uart.validate_device( + "dfplayer", config, item_config, baud_rate=9600, require_rx=False + ) + + @automation.register_action( "dfplayer.play_next", NextAction, diff --git a/esphome/components/ethernet/__init__.py b/esphome/components/ethernet/__init__.py index c6f81e5046..94c9ddd2e9 100644 --- a/esphome/components/ethernet/__init__.py +++ b/esphome/components/ethernet/__init__.py @@ -59,7 +59,7 @@ IPAddress = cg.global_ns.class_("IPAddress") ManualIP = ethernet_ns.struct("ManualIP") -def validate(config): +def _validate(config): if CONF_USE_ADDRESS not in config: if CONF_MANUAL_IP in config: use_address = str(config[CONF_MANUAL_IP][CONF_STATIC_IP]) @@ -90,7 +90,7 @@ CONFIG_SCHEMA = cv.All( ), } ).extend(cv.COMPONENT_SCHEMA), - validate, + _validate, ) diff --git a/esphome/components/fastled_clockless/light.py b/esphome/components/fastled_clockless/light.py index 17f72427e4..cfc62e930b 100644 --- a/esphome/components/fastled_clockless/light.py +++ b/esphome/components/fastled_clockless/light.py @@ -34,7 +34,7 @@ CHIPSETS = [ ] -def validate(value): +def _validate(value): if value[CONF_CHIPSET] == "NEOPIXEL" and CONF_RGB_ORDER in value: raise cv.Invalid("NEOPIXEL doesn't support RGB order") return value @@ -47,7 +47,7 @@ CONFIG_SCHEMA = cv.All( cv.Required(CONF_PIN): pins.output_pin, } ), - validate, + _validate, ) diff --git a/esphome/components/gps/__init__.py b/esphome/components/gps/__init__.py index e982bd4dfd..57ae11ea4f 100644 --- a/esphome/components/gps/__init__.py +++ b/esphome/components/gps/__init__.py @@ -89,3 +89,7 @@ async def to_code(config): # https://platformio.org/lib/show/1655/TinyGPSPlus cg.add_library("1655", "1.0.2") # TinyGPSPlus, has name conflict + + +def validate(config, item_config): + uart.validate_device("gps", config, item_config, require_tx=False) diff --git a/esphome/components/hm3301/sensor.py b/esphome/components/hm3301/sensor.py index 6d77841d20..34555fdcd6 100644 --- a/esphome/components/hm3301/sensor.py +++ b/esphome/components/hm3301/sensor.py @@ -29,7 +29,7 @@ AQI_CALCULATION_TYPE = { } -def validate(config): +def _validate(config): if CONF_AQI in config and CONF_PM_2_5 not in config: raise cv.Invalid("AQI sensor requires PM 2.5") if CONF_AQI in config and CONF_PM_10_0 not in config: @@ -72,7 +72,7 @@ CONFIG_SCHEMA = cv.All( ) .extend(cv.polling_component_schema("60s")) .extend(i2c.i2c_device_schema(0x40)), - validate, + _validate, ) diff --git a/esphome/components/neopixelbus/light.py b/esphome/components/neopixelbus/light.py index f643b476e8..59d784a614 100644 --- a/esphome/components/neopixelbus/light.py +++ b/esphome/components/neopixelbus/light.py @@ -150,7 +150,7 @@ def format_method(config): raise NotImplementedError -def validate(config): +def _validate(config): if CONF_PIN in config: if CONF_CLOCK_PIN in config or CONF_DATA_PIN in config: raise cv.Invalid("Cannot specify both 'pin' and 'clock_pin'+'data_pin'") @@ -176,7 +176,7 @@ CONFIG_SCHEMA = cv.All( cv.Required(CONF_NUM_LEDS): cv.positive_not_null_int, } ).extend(cv.COMPONENT_SCHEMA), - validate, + _validate, validate_method_pin, ) diff --git a/esphome/components/rc522_spi/__init__.py b/esphome/components/rc522_spi/__init__.py index b21af1d07f..68b1e64145 100644 --- a/esphome/components/rc522_spi/__init__.py +++ b/esphome/components/rc522_spi/__init__.py @@ -24,3 +24,8 @@ async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) await rc522.setup_rc522(var, config) await spi.register_spi_device(var, config) + + +def validate(config, item_config): + # validate given SPI hub is suitable for rc522_spi, it needs both miso and mosi + spi.validate_device("rc522_spi", config, item_config, True, True) diff --git a/esphome/components/rtttl/__init__.py b/esphome/components/rtttl/__init__.py index 3441a63b9a..7f860fe3d7 100644 --- a/esphome/components/rtttl/__init__.py +++ b/esphome/components/rtttl/__init__.py @@ -1,8 +1,11 @@ +import logging import esphome.codegen as cg import esphome.config_validation as cv from esphome import automation from esphome.components.output import FloatOutput -from esphome.const import CONF_ID, CONF_OUTPUT, CONF_TRIGGER_ID +from esphome.const import CONF_ID, CONF_OUTPUT, CONF_PLATFORM, CONF_TRIGGER_ID + +_LOGGER = logging.getLogger(__name__) CODEOWNERS = ["@glmnet"] CONF_RTTTL = "rtttl" @@ -33,6 +36,33 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) +def validate(config, item_config): + # Not adding this to FloatOutput as this is the only component which needs `update_frequency` + + parent_config = config.get_config_by_id(item_config[CONF_OUTPUT]) + platform = parent_config[CONF_PLATFORM] + + PWM_GOOD = ["esp8266_pwm", "ledc"] + PWM_BAD = [ + "ac_dimmer ", + "esp32_dac", + "slow_pwm", + "mcp4725", + "pca9685", + "tlc59208f", + "my9231", + "sm16716", + ] + + if platform in PWM_BAD: + raise ValueError(f"Component rtttl cannot use {platform} as output component") + + if platform not in PWM_GOOD: + _LOGGER.warning( + "Component rtttl is not known to work with the selected output type. Make sure this output supports custom frequency output method." + ) + + async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) diff --git a/esphome/components/sim800l/__init__.py b/esphome/components/sim800l/__init__.py index f9f6d71cd2..40c011a769 100644 --- a/esphome/components/sim800l/__init__.py +++ b/esphome/components/sim800l/__init__.py @@ -54,6 +54,10 @@ async def to_code(config): ) +def validate(config, item_config): + uart.validate_device("sim800l", config, item_config, baud_rate=9600) + + SIM800L_SEND_SMS_SCHEMA = cv.Schema( { cv.GenerateID(): cv.use_id(Sim800LComponent), diff --git a/esphome/components/spi/__init__.py b/esphome/components/spi/__init__.py index 00d21e619e..e6e073c4a4 100644 --- a/esphome/components/spi/__init__.py +++ b/esphome/components/spi/__init__.py @@ -67,3 +67,11 @@ async def register_spi_device(var, config): if CONF_CS_PIN in config: pin = await cg.gpio_pin_expression(config[CONF_CS_PIN]) cg.add(var.set_cs_pin(pin)) + + +def validate_device(name, config, item_config, require_mosi, require_miso): + spi_config = config.get_config_by_id(item_config[CONF_SPI_ID]) + if require_mosi and CONF_MISO_PIN not in spi_config: + raise ValueError(f"Component {name} requires parent spi to declare miso_pin") + if require_miso and CONF_MOSI_PIN not in spi_config: + raise ValueError(f"Component {name} requires parent spi to declare mosi_pin") diff --git a/esphome/components/uart/__init__.py b/esphome/components/uart/__init__.py index fb82fd9aee..aaed333e34 100644 --- a/esphome/components/uart/__init__.py +++ b/esphome/components/uart/__init__.py @@ -92,6 +92,42 @@ async def to_code(config): cg.add(var.set_parity(config[CONF_PARITY])) +def validate_device( + name, config, item_config, baud_rate=None, require_tx=True, require_rx=True +): + if not hasattr(config, "uart_devices"): + config.uart_devices = {} + devices = config.uart_devices + + uart_config = config.get_config_by_id(item_config[CONF_UART_ID]) + + uart_id = uart_config[CONF_ID] + device = devices.setdefault(uart_id, {}) + + if require_tx: + if CONF_TX_PIN not in uart_config: + raise ValueError(f"Component {name} requires parent uart to declare tx_pin") + if CONF_TX_PIN in device: + raise ValueError( + f"Component {name} cannot use the same uart.{CONF_TX_PIN} as component {device[CONF_TX_PIN]} is already using it" + ) + device[CONF_TX_PIN] = name + + if require_rx: + if CONF_RX_PIN not in uart_config: + raise ValueError(f"Component {name} requires parent uart to declare rx_pin") + if CONF_RX_PIN in device: + raise ValueError( + f"Component {name} cannot use the same uart.{CONF_RX_PIN} as component {device[CONF_RX_PIN]} is already using it" + ) + device[CONF_RX_PIN] = name + + if baud_rate and uart_config[CONF_BAUD_RATE] != baud_rate: + raise ValueError( + f"Component {name} requires parent uart baud rate be {baud_rate}" + ) + + # A schema to use for all UART devices, all UART integrations must extend this! UART_DEVICE_SCHEMA = cv.Schema( { diff --git a/esphome/components/wifi/__init__.py b/esphome/components/wifi/__init__.py index d2676bce36..c45e179bc4 100644 --- a/esphome/components/wifi/__init__.py +++ b/esphome/components/wifi/__init__.py @@ -137,7 +137,7 @@ WIFI_NETWORK_STA = WIFI_NETWORK_BASE.extend( ) -def validate(config): +def _validate(config): if CONF_PASSWORD in config and CONF_SSID not in config: raise cv.Invalid("Cannot have WiFi password without SSID!") @@ -207,7 +207,7 @@ CONFIG_SCHEMA = cv.All( ), } ), - validate, + _validate, ) diff --git a/esphome/config.py b/esphome/config.py index a1fc07a21f..fcd2fac90f 100644 --- a/esphome/config.py +++ b/esphome/config.py @@ -63,6 +63,8 @@ class Config(OrderedDict): # The values will be the paths to all "domain", for example (['logger'], 'logger') # or (['sensor', 'ultrasonic'], 'sensor.ultrasonic') self.output_paths = [] # type: List[Tuple[ConfigPath, str]] + # A list of components ids with the config path + self.declare_ids = [] # type: List[Tuple[core.ID, ConfigPath]] def add_error(self, error): # type: (vol.Invalid) -> None @@ -161,6 +163,12 @@ class Config(OrderedDict): part.append(item_index) return part + def get_config_by_id(self, id): + for declared_id, path in self.declare_ids: + if declared_id.id == str(id): + return self.get_nested_item(path[:-1]) + return None + def iter_ids(config, path=None): path = path or [] @@ -181,7 +189,7 @@ def do_id_pass(result): # type: (Config) -> None from esphome.cpp_generator import MockObjClass from esphome.cpp_types import Component - declare_ids = [] # type: List[Tuple[core.ID, ConfigPath]] + declare_ids = result.declare_ids # type: List[Tuple[core.ID, ConfigPath]] searching_ids = [] # type: List[Tuple[core.ID, ConfigPath]] for id, path in iter_ids(result): if id.is_declaration: @@ -546,6 +554,19 @@ def validate_config(config, command_line_substitutions): # Only parse IDs if no validation error. Otherwise # user gets confusing messages do_id_pass(result) + + # 7. Final validation + if not result.errors: + # Inter - components validation + for path, conf, comp in validate_queue: + if comp.config_schema is None: + continue + if callable(comp.validate): + try: + comp.validate(result, result.get_nested_item(path)) + except ValueError as err: + result.add_str_error(err, path) + return result diff --git a/esphome/loader.py b/esphome/loader.py index c418008453..d9d407d787 100644 --- a/esphome/loader.py +++ b/esphome/loader.py @@ -80,6 +80,10 @@ class ComponentManifest: def codeowners(self) -> List[str]: return getattr(self.module, "CODEOWNERS", []) + @property + def validate(self): + return getattr(self.module, "validate", None) + @property def source_files(self) -> Dict[Path, SourceFile]: ret = {} diff --git a/tests/test3.yaml b/tests/test3.yaml index 8104c70fbf..0a01405516 100644 --- a/tests/test3.yaml +++ b/tests/test3.yaml @@ -1,6 +1,6 @@ esphome: - name: $devicename - comment: $devicecomment + name: $device_name + comment: $device_comment platform: ESP8266 board: d1_mini build_path: build/test3 @@ -13,8 +13,8 @@ esphome: - custom.h substitutions: - devicename: test3 - devicecomment: test3 device + device_name: test3 + device_comment: test3 device min_sub: '0.03' max_sub: '12.0%' @@ -213,9 +213,33 @@ spi: miso_pin: GPIO14 uart: - - tx_pin: GPIO1 + - id: uart1 + tx_pin: GPIO1 rx_pin: GPIO3 baud_rate: 115200 + - id: uart2 + tx_pin: GPIO4 + rx_pin: GPIO5 + baud_rate: 9600 + - id: uart3 + tx_pin: GPIO4 + rx_pin: GPIO5 + baud_rate: 4800 + - id: uart4 + tx_pin: GPIO4 + rx_pin: GPIO5 + baud_rate: 9600 + - id: uart5 + tx_pin: GPIO4 + rx_pin: GPIO5 + baud_rate: 9600 + - id: uart6 + tx_pin: GPIO4 + rx_pin: GPIO5 + baud_rate: 9600 + +modbus: + uart_id: uart1 ota: safe_mode: True @@ -369,6 +393,7 @@ sensor: active_power_b: name: ADE7953 Active Power B - platform: pzem004t + uart_id: uart3 voltage: name: 'PZEM00T Voltage' current: @@ -408,6 +433,7 @@ sensor: name: 'AQI' calculation_type: 'AQI' - platform: pmsx003 + uart_id: uart2 type: PMSX003 pm_1_0: name: 'PM 1.0 Concentration' @@ -415,25 +441,8 @@ sensor: name: 'PM 2.5 Concentration' pm_10_0: name: 'PM 10.0 Concentration' - - platform: pmsx003 - type: PMS5003T - pm_2_5: - name: 'PM 2.5 Concentration' - temperature: - name: 'PMS Temperature' - humidity: - name: 'PMS Humidity' - - platform: pmsx003 - type: PMS5003ST - pm_2_5: - name: 'PM 2.5 Concentration' - temperature: - name: 'PMS Temperature' - humidity: - name: 'PMS Humidity' - formaldehyde: - name: 'PMS Formaldehyde Concentration' - platform: cse7766 + uart_id: uart3 voltage: name: 'CSE7766 Voltage' current: @@ -443,7 +452,7 @@ sensor: - platform: ezo id: ph_ezo address: 99 - unit_of_measurement: 'pH' + unit_of_measurement: 'pH' - platform: tof10120 name: "Distance sensor" update_interval: 5s @@ -867,6 +876,7 @@ light: effects: - wled: - adalight: + uart_id: uart3 - e131: universe: 1 - platform: hbridge @@ -888,6 +898,7 @@ ttp229_bsf: scl_pin: D1 sim800l: + uart_id: uart4 on_sms_received: - lambda: |- std::string str; @@ -900,6 +911,7 @@ sim800l: recipient: '+1234' dfplayer: + uart_id: uart5 on_finished_playback: then: if: @@ -913,6 +925,7 @@ tm1651: dio_pin: D5 rf_bridge: + uart_id: uart5 on_code_received: - lambda: |- uint32_t test; @@ -1006,3 +1019,4 @@ fingerprint_grow: event: esphome.${devicename}_fingerprint_grow_enrollment_failed data: finger_id: !lambda 'return finger_id;' + uart_id: uart6 From 9a2cf05c5f38a50e74377b2443cad7be36821fd9 Mon Sep 17 00:00:00 2001 From: testbughub <30836300+testbughub@users.noreply.github.com> Date: Mon, 31 May 2021 01:54:26 +0200 Subject: [PATCH 067/104] Added bottom segment to digit 9 (#1847) --- esphome/components/max7219/max7219.cpp | 2 +- esphome/components/tm1637/tm1637.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/max7219/max7219.cpp b/esphome/components/max7219/max7219.cpp index f58f203442..9c5c729487 100644 --- a/esphome/components/max7219/max7219.cpp +++ b/esphome/components/max7219/max7219.cpp @@ -41,7 +41,7 @@ const uint8_t MAX7219_ASCII_TO_RAW[95] PROGMEM = { 0b01011111, // '6', ord 0x36 0b01110000, // '7', ord 0x37 0b01111111, // '8', ord 0x38 - 0b01110011, // '9', ord 0x39 + 0b01111011, // '9', ord 0x39 0b01001000, // ':', ord 0x3A 0b01011000, // ';', ord 0x3B MAX7219_UNKNOWN_CHAR, // '<', ord 0x3C diff --git a/esphome/components/tm1637/tm1637.cpp b/esphome/components/tm1637/tm1637.cpp index b58cec4748..df904ad9ab 100644 --- a/esphome/components/tm1637/tm1637.cpp +++ b/esphome/components/tm1637/tm1637.cpp @@ -46,7 +46,7 @@ const uint8_t TM1637_ASCII_TO_RAW[] PROGMEM = { 0b01011111, // '6', ord 0x36 0b01110000, // '7', ord 0x37 0b01111111, // '8', ord 0x38 - 0b01110011, // '9', ord 0x39 + 0b01111011, // '9', ord 0x39 0b01001000, // ':', ord 0x3A 0b01011000, // ';', ord 0x3B TM1637_UNKNOWN_CHAR, // '<', ord 0x3C From bb759d52c8198bfac79f25f203bc41f48adf2156 Mon Sep 17 00:00:00 2001 From: polyfaces Date: Mon, 31 May 2021 12:05:49 +0800 Subject: [PATCH 068/104] Add support for SDMXXX energy meters (#1260) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/atm90e32/sensor.py | 2 +- esphome/components/modbus/__init__.py | 9 +- esphome/components/modbus/modbus.cpp | 13 ++ esphome/components/modbus/modbus.h | 6 + esphome/components/sdm_meter/__init__.py | 0 esphome/components/sdm_meter/sdm_meter.cpp | 106 ++++++++++++++ esphome/components/sdm_meter/sdm_meter.h | 79 +++++++++++ .../sdm_meter/sdm_meter_registers.h | 114 +++++++++++++++ esphome/components/sdm_meter/sensor.py | 131 ++++++++++++++++++ esphome/const.py | 10 ++ tests/test3.yaml | 56 ++++++++ 12 files changed, 525 insertions(+), 2 deletions(-) create mode 100644 esphome/components/sdm_meter/__init__.py create mode 100644 esphome/components/sdm_meter/sdm_meter.cpp create mode 100644 esphome/components/sdm_meter/sdm_meter.h create mode 100644 esphome/components/sdm_meter/sdm_meter_registers.h create mode 100644 esphome/components/sdm_meter/sensor.py diff --git a/CODEOWNERS b/CODEOWNERS index b8f00aa368..30be9e74b1 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -81,6 +81,7 @@ esphome/components/restart/* @esphome/core esphome/components/rf_bridge/* @jesserockz esphome/components/rtttl/* @glmnet esphome/components/script/* @esphome/core +esphome/components/sdm_meter/* @jesserockz @polyfaces esphome/components/sensor/* @esphome/core esphome/components/sgp40/* @SenexCrenshaw esphome/components/sht4x/* @sjtrny diff --git a/esphome/components/atm90e32/sensor.py b/esphome/components/atm90e32/sensor.py index b0e43559f9..aaf9320b9e 100644 --- a/esphome/components/atm90e32/sensor.py +++ b/esphome/components/atm90e32/sensor.py @@ -3,6 +3,7 @@ import esphome.config_validation as cv from esphome.components import sensor, spi from esphome.const import ( CONF_ID, + CONF_REACTIVE_POWER, CONF_VOLTAGE, CONF_CURRENT, CONF_POWER, @@ -34,7 +35,6 @@ CONF_PHASE_A = "phase_a" CONF_PHASE_B = "phase_b" CONF_PHASE_C = "phase_c" -CONF_REACTIVE_POWER = "reactive_power" CONF_LINE_FREQUENCY = "line_frequency" CONF_CHIP_TEMPERATURE = "chip_temperature" CONF_GAIN_PGA = "gain_pga" diff --git a/esphome/components/modbus/__init__.py b/esphome/components/modbus/__init__.py index 08186ca46f..6b454cbaf0 100644 --- a/esphome/components/modbus/__init__.py +++ b/esphome/components/modbus/__init__.py @@ -1,7 +1,9 @@ import esphome.codegen as cg import esphome.config_validation as cv +from esphome.cpp_helpers import gpio_pin_expression from esphome.components import uart -from esphome.const import CONF_ID, CONF_ADDRESS +from esphome.const import CONF_FLOW_CONTROL_PIN, CONF_ID, CONF_ADDRESS +from esphome import pins DEPENDENCIES = ["uart"] @@ -15,6 +17,7 @@ CONFIG_SCHEMA = ( cv.Schema( { cv.GenerateID(): cv.declare_id(Modbus), + cv.Optional(CONF_FLOW_CONTROL_PIN): pins.gpio_output_pin_schema, } ) .extend(cv.COMPONENT_SCHEMA) @@ -29,6 +32,10 @@ async def to_code(config): await uart.register_uart_device(var, config) + if CONF_FLOW_CONTROL_PIN in config: + pin = await gpio_pin_expression(config[CONF_FLOW_CONTROL_PIN]) + cg.add(var.set_flow_control_pin(pin)) + def modbus_device_schema(default_address): schema = { diff --git a/esphome/components/modbus/modbus.cpp b/esphome/components/modbus/modbus.cpp index 74d0c40986..08eace9ef5 100644 --- a/esphome/components/modbus/modbus.cpp +++ b/esphome/components/modbus/modbus.cpp @@ -6,6 +6,11 @@ namespace modbus { static const char *TAG = "modbus"; +void Modbus::setup() { + if (this->flow_control_pin_ != nullptr) { + this->flow_control_pin_->setup(); + } +} void Modbus::loop() { const uint32_t now = millis(); if (now - this->last_modbus_byte_ > 50) { @@ -94,6 +99,7 @@ bool Modbus::parse_modbus_byte_(uint8_t byte) { void Modbus::dump_config() { ESP_LOGCONFIG(TAG, "Modbus:"); + LOG_PIN(" Flow Control Pin: ", this->flow_control_pin_); this->check_uart_settings(9600, 2); } float Modbus::get_setup_priority() const { @@ -112,7 +118,14 @@ void Modbus::send(uint8_t address, uint8_t function, uint16_t start_address, uin frame[6] = crc >> 0; frame[7] = crc >> 8; + if (this->flow_control_pin_ != nullptr) + this->flow_control_pin_->digital_write(true); + this->write_array(frame, 8); + this->flush(); + + if (this->flow_control_pin_ != nullptr) + this->flow_control_pin_->digital_write(false); } } // namespace modbus diff --git a/esphome/components/modbus/modbus.h b/esphome/components/modbus/modbus.h index b75de147b1..91fc55b998 100644 --- a/esphome/components/modbus/modbus.h +++ b/esphome/components/modbus/modbus.h @@ -12,6 +12,8 @@ class Modbus : public uart::UARTDevice, public Component { public: Modbus() = default; + void setup() override; + void loop() override; void dump_config() override; @@ -22,7 +24,11 @@ class Modbus : public uart::UARTDevice, public Component { void send(uint8_t address, uint8_t function, uint16_t start_address, uint16_t register_count); + void set_flow_control_pin(GPIOPin *flow_control_pin) { this->flow_control_pin_ = flow_control_pin; } + protected: + GPIOPin *flow_control_pin_{nullptr}; + bool parse_modbus_byte_(uint8_t byte); std::vector rx_buffer_; diff --git a/esphome/components/sdm_meter/__init__.py b/esphome/components/sdm_meter/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/sdm_meter/sdm_meter.cpp b/esphome/components/sdm_meter/sdm_meter.cpp new file mode 100644 index 0000000000..de7c42421e --- /dev/null +++ b/esphome/components/sdm_meter/sdm_meter.cpp @@ -0,0 +1,106 @@ +#include "sdm_meter.h" +#include "sdm_meter_registers.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace sdm_meter { + +static const char *TAG = "sdm_meter"; + +static const uint8_t MODBUS_CMD_READ_IN_REGISTERS = 0x04; +static const uint8_t MODBUS_REGISTER_COUNT = 80; // 74 x 16-bit registers + +void SDMMeter::on_modbus_data(const std::vector &data) { + if (data.size() < MODBUS_REGISTER_COUNT * 2) { + ESP_LOGW(TAG, "Invalid size for SDMMeter!"); + return; + } + + auto sdm_meter_get_float = [&](size_t i) -> float { + uint32_t temp = encode_uint32(data[i], data[i + 1], data[i + 2], data[i + 3]); + float f; + memcpy(&f, &temp, sizeof(f)); + return f; + }; + + for (uint8_t i = 0; i < 3; i++) { + auto phase = this->phases_[i]; + if (!phase.setup) + continue; + + float voltage = sdm_meter_get_float(SDM_PHASE_1_VOLTAGE * 2 + (i * 4)); + float current = sdm_meter_get_float(SDM_PHASE_1_CURRENT * 2 + (i * 4)); + float active_power = sdm_meter_get_float(SDM_PHASE_1_ACTIVE_POWER * 2 + (i * 4)); + float apparent_power = sdm_meter_get_float(SDM_PHASE_1_APPARENT_POWER * 2 + (i * 4)); + float reactive_power = sdm_meter_get_float(SDM_PHASE_1_REACTIVE_POWER * 2 + (i * 4)); + float power_factor = sdm_meter_get_float(SDM_PHASE_1_POWER_FACTOR * 2 + (i * 4)); + float phase_angle = sdm_meter_get_float(SDM_PHASE_1_ANGLE * 2 + (i * 4)); + + ESP_LOGD( + TAG, + "SDMMeter Phase %c: V=%.3f V, I=%.3f A, Active P=%.3f W, Apparent P=%.3f VA, Reactive P=%.3f VAR, PF=%.3f, " + "PA=%.3f °", + i + 'A', voltage, current, active_power, apparent_power, reactive_power, power_factor, phase_angle); + if (phase.voltage_sensor_ != nullptr) + phase.voltage_sensor_->publish_state(voltage); + if (phase.current_sensor_ != nullptr) + phase.current_sensor_->publish_state(current); + if (phase.active_power_sensor_ != nullptr) + phase.active_power_sensor_->publish_state(active_power); + if (phase.apparent_power_sensor_ != nullptr) + phase.apparent_power_sensor_->publish_state(apparent_power); + if (phase.reactive_power_sensor_ != nullptr) + phase.reactive_power_sensor_->publish_state(reactive_power); + if (phase.power_factor_sensor_ != nullptr) + phase.power_factor_sensor_->publish_state(power_factor); + if (phase.phase_angle_sensor_ != nullptr) + phase.phase_angle_sensor_->publish_state(phase_angle); + } + + float frequency = sdm_meter_get_float(SDM_FREQUENCY * 2); + float import_active_energy = sdm_meter_get_float(SDM_IMPORT_ACTIVE_ENERGY * 2); + float export_active_energy = sdm_meter_get_float(SDM_EXPORT_ACTIVE_ENERGY * 2); + float import_reactive_energy = sdm_meter_get_float(SDM_IMPORT_REACTIVE_ENERGY * 2); + float export_reactive_energy = sdm_meter_get_float(SDM_EXPORT_REACTIVE_ENERGY * 2); + + ESP_LOGD(TAG, "SDMMeter: F=%.3f Hz, Im.A.E=%.3f Wh, Ex.A.E=%.3f Wh, Im.R.E=%.3f VARh, Ex.R.E=%.3f VARh", frequency, + import_active_energy, export_active_energy, import_reactive_energy, export_reactive_energy); + + if (this->frequency_sensor_ != nullptr) + this->frequency_sensor_->publish_state(frequency); + if (this->import_active_energy_sensor_ != nullptr) + this->import_active_energy_sensor_->publish_state(import_active_energy); + if (this->export_active_energy_sensor_ != nullptr) + this->export_active_energy_sensor_->publish_state(export_active_energy); + if (this->import_reactive_energy_sensor_ != nullptr) + this->import_reactive_energy_sensor_->publish_state(import_reactive_energy); + if (this->export_reactive_energy_sensor_ != nullptr) + this->export_reactive_energy_sensor_->publish_state(export_reactive_energy); +} + +void SDMMeter::update() { this->send(MODBUS_CMD_READ_IN_REGISTERS, 0, MODBUS_REGISTER_COUNT); } +void SDMMeter::dump_config() { + ESP_LOGCONFIG(TAG, "SDM Meter:"); + ESP_LOGCONFIG(TAG, " Address: 0x%02X", this->address_); + for (uint8_t i = 0; i < 3; i++) { + auto phase = this->phases_[i]; + if (!phase.setup) + continue; + ESP_LOGCONFIG(TAG, " Phase %c", i + 'A'); + LOG_SENSOR(" ", "Voltage", phase.voltage_sensor_); + LOG_SENSOR(" ", "Current", phase.current_sensor_); + LOG_SENSOR(" ", "Active Power", phase.active_power_sensor_); + LOG_SENSOR(" ", "Apparent Power", phase.apparent_power_sensor_); + LOG_SENSOR(" ", "Reactive Power", phase.reactive_power_sensor_); + LOG_SENSOR(" ", "Power Factor", phase.power_factor_sensor_); + LOG_SENSOR(" ", "Phase Angle", phase.phase_angle_sensor_); + } + LOG_SENSOR(" ", "Frequency", this->frequency_sensor_); + LOG_SENSOR(" ", "Import Active Energy", this->import_active_energy_sensor_); + LOG_SENSOR(" ", "Export Active Energy", this->export_active_energy_sensor_); + LOG_SENSOR(" ", "Import Reactive Energy", this->import_reactive_energy_sensor_); + LOG_SENSOR(" ", "Export Reactive Energy", this->export_reactive_energy_sensor_); +} + +} // namespace sdm_meter +} // namespace esphome diff --git a/esphome/components/sdm_meter/sdm_meter.h b/esphome/components/sdm_meter/sdm_meter.h new file mode 100644 index 0000000000..07ebe65bb7 --- /dev/null +++ b/esphome/components/sdm_meter/sdm_meter.h @@ -0,0 +1,79 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/modbus/modbus.h" + +namespace esphome { +namespace sdm_meter { + +class SDMMeter : public PollingComponent, public modbus::ModbusDevice { + public: + void set_voltage_sensor(uint8_t phase, sensor::Sensor *voltage_sensor) { + this->phases_[phase].setup = true; + this->phases_[phase].voltage_sensor_ = voltage_sensor; + } + void set_current_sensor(uint8_t phase, sensor::Sensor *current_sensor) { + this->phases_[phase].setup = true; + this->phases_[phase].current_sensor_ = current_sensor; + } + void set_active_power_sensor(uint8_t phase, sensor::Sensor *active_power_sensor) { + this->phases_[phase].setup = true; + this->phases_[phase].active_power_sensor_ = active_power_sensor; + } + void set_apparent_power_sensor(uint8_t phase, sensor::Sensor *apparent_power_sensor) { + this->phases_[phase].setup = true; + this->phases_[phase].apparent_power_sensor_ = apparent_power_sensor; + } + void set_reactive_power_sensor(uint8_t phase, sensor::Sensor *reactive_power_sensor) { + this->phases_[phase].setup = true; + this->phases_[phase].reactive_power_sensor_ = reactive_power_sensor; + } + void set_power_factor_sensor(uint8_t phase, sensor::Sensor *power_factor_sensor) { + this->phases_[phase].setup = true; + this->phases_[phase].power_factor_sensor_ = power_factor_sensor; + } + void set_phase_angle_sensor(uint8_t phase, sensor::Sensor *phase_angle_sensor) { + this->phases_[phase].setup = true; + this->phases_[phase].phase_angle_sensor_ = phase_angle_sensor; + } + void set_frequency_sensor(sensor::Sensor *frequency_sensor) { this->frequency_sensor_ = frequency_sensor; } + void set_import_active_energy_sensor(sensor::Sensor *import_active_energy_sensor) { + this->import_active_energy_sensor_ = import_active_energy_sensor; + } + void set_export_active_energy_sensor(sensor::Sensor *export_active_energy_sensor) { + this->export_active_energy_sensor_ = export_active_energy_sensor; + } + void set_import_reactive_energy_sensor(sensor::Sensor *import_reactive_energy_sensor) { + this->import_reactive_energy_sensor_ = import_reactive_energy_sensor; + } + void set_export_reactive_energy_sensor(sensor::Sensor *export_reactive_energy_sensor) { + this->export_reactive_energy_sensor_ = export_reactive_energy_sensor; + } + + void update() override; + + void on_modbus_data(const std::vector &data) override; + + void dump_config() override; + + protected: + struct SDMPhase { + bool setup{false}; + sensor::Sensor *voltage_sensor_{nullptr}; + sensor::Sensor *current_sensor_{nullptr}; + sensor::Sensor *active_power_sensor_{nullptr}; + sensor::Sensor *apparent_power_sensor_{nullptr}; + sensor::Sensor *reactive_power_sensor_{nullptr}; + sensor::Sensor *power_factor_sensor_{nullptr}; + sensor::Sensor *phase_angle_sensor_{nullptr}; + } phases_[3]; + sensor::Sensor *frequency_sensor_{nullptr}; + sensor::Sensor *import_active_energy_sensor_{nullptr}; + sensor::Sensor *export_active_energy_sensor_{nullptr}; + sensor::Sensor *import_reactive_energy_sensor_{nullptr}; + sensor::Sensor *export_reactive_energy_sensor_{nullptr}; +}; + +} // namespace sdm_meter +} // namespace esphome diff --git a/esphome/components/sdm_meter/sdm_meter_registers.h b/esphome/components/sdm_meter/sdm_meter_registers.h new file mode 100644 index 0000000000..dd981d6f00 --- /dev/null +++ b/esphome/components/sdm_meter/sdm_meter_registers.h @@ -0,0 +1,114 @@ +#pragma once + +namespace esphome { +namespace sdm_meter { + +/* PHASE STATUS REGISTERS */ +static const uint16_t SDM_PHASE_1_VOLTAGE = 0x0000; +static const uint16_t SDM_PHASE_2_VOLTAGE = 0x0002; +static const uint16_t SDM_PHASE_3_VOLTAGE = 0x0004; +static const uint16_t SDM_PHASE_1_CURRENT = 0x0006; +static const uint16_t SDM_PHASE_2_CURRENT = 0x0008; +static const uint16_t SDM_PHASE_3_CURRENT = 0x000A; +static const uint16_t SDM_PHASE_1_ACTIVE_POWER = 0x000C; +static const uint16_t SDM_PHASE_2_ACTIVE_POWER = 0x000E; +static const uint16_t SDM_PHASE_3_ACTIVE_POWER = 0x0010; +static const uint16_t SDM_PHASE_1_APPARENT_POWER = 0x0012; +static const uint16_t SDM_PHASE_2_APPARENT_POWER = 0x0014; +static const uint16_t SDM_PHASE_3_APPARENT_POWER = 0x0016; +static const uint16_t SDM_PHASE_1_REACTIVE_POWER = 0x0018; +static const uint16_t SDM_PHASE_2_REACTIVE_POWER = 0x001A; +static const uint16_t SDM_PHASE_3_REACTIVE_POWER = 0x001C; +static const uint16_t SDM_PHASE_1_POWER_FACTOR = 0x001E; +static const uint16_t SDM_PHASE_2_POWER_FACTOR = 0x0020; +static const uint16_t SDM_PHASE_3_POWER_FACTOR = 0x0022; +static const uint16_t SDM_PHASE_1_ANGLE = 0x0024; +static const uint16_t SDM_PHASE_2_ANGLE = 0x0026; +static const uint16_t SDM_PHASE_3_ANGLE = 0x0028; + +static const uint16_t SDM_AVERAGE_L_TO_N_VOLTS = 0x002A; +static const uint16_t SDM_AVERAGE_LINE_CURRENT = 0x002E; +static const uint16_t SDM_SUM_LINE_CURRENT = 0x0030; +static const uint16_t SDM_TOTAL_SYSTEM_POWER = 0x0034; +static const uint16_t SDM_TOTAL_SYSTEM_APPARENT_POWER = 0x0038; +static const uint16_t SDM_TOTAL_SYSTEM_REACTIVE_POWER = 0x003C; +static const uint16_t SDM_TOTAL_SYSTEM_POWER_FACTOR = 0x003E; +static const uint16_t SDM_TOTAL_SYSTEM_PHASE_ANGLE = 0x0042; + +static const uint16_t SDM_FREQUENCY = 0x0046; + +static const uint16_t SDM_IMPORT_ACTIVE_ENERGY = 0x0048; +static const uint16_t SDM_EXPORT_ACTIVE_ENERGY = 0x004A; +static const uint16_t SDM_IMPORT_REACTIVE_ENERGY = 0x004C; +static const uint16_t SDM_EXPORT_REACTIVE_ENERGY = 0x004E; + +static const uint16_t SDM_VAH_SINCE_LAST_RESET = 0x0050; +static const uint16_t SDM_AH_SINCE_LAST_RESET = 0x0052; +static const uint16_t SDM_TOTAL_SYSTEM_POWER_DEMAND = 0x0054; +static const uint16_t SDM_MAXIMUM_TOTAL_SYSTEM_POWER_DEMAND = 0x0056; +static const uint16_t SDM_CURRENT_SYSTEM_POSITIVE_POWER_DEMAND = 0x0058; +static const uint16_t SDM_MAXIMUM_SYSTEM_POSITIVE_POWER_DEMAND = 0x005A; +static const uint16_t SDM_CURRENT_SYSTEM_REVERSE_POWER_DEMAND = 0x005C; +static const uint16_t SDM_MAXIMUM_SYSTEM_REVERSE_POWER_DEMAND = 0x005E; +static const uint16_t SDM_TOTAL_SYSTEM_VA_DEMAND = 0x0064; +static const uint16_t SDM_MAXIMUM_TOTAL_SYSTEM_VA_DEMAND = 0x0066; +static const uint16_t SDM_NEUTRAL_CURRENT_DEMAND = 0x0068; +static const uint16_t SDM_MAXIMUM_NEUTRAL_CURRENT = 0x006A; +static const uint16_t SDM_LINE_1_TO_LINE_2_VOLTS = 0x00C8; +static const uint16_t SDM_LINE_2_TO_LINE_3_VOLTS = 0x00CA; +static const uint16_t SDM_LINE_3_TO_LINE_1_VOLTS = 0x00CC; +static const uint16_t SDM_AVERAGE_LINE_TO_LINE_VOLTS = 0x00CE; +static const uint16_t SDM_NEUTRAL_CURRENT = 0x00E0; + +static const uint16_t SDM_PHASE_1_LN_VOLTS_THD = 0x00EA; +static const uint16_t SDM_PHASE_2_LN_VOLTS_THD = 0x00EC; +static const uint16_t SDM_PHASE_3_LN_VOLTS_THD = 0x00EE; +static const uint16_t SDM_PHASE_1_CURRENT_THD = 0x00F0; +static const uint16_t SDM_PHASE_2_CURRENT_THD = 0x00F2; +static const uint16_t SDM_PHASE_3_CURRENT_THD = 0x00F4; + +static const uint16_t SDM_AVERAGE_LINE_TO_NEUTRAL_VOLTS_THD = 0x00F8; +static const uint16_t SDM_AVERAGE_LINE_CURRENT_THD = 0x00FA; +static const uint16_t SDM_TOTAL_SYSTEM_POWER_FACTOR_INV = 0x00FE; +static const uint16_t SDM_PHASE_1_CURRENT_DEMAND = 0x0102; +static const uint16_t SDM_PHASE_2_CURRENT_DEMAND = 0x0104; +static const uint16_t SDM_PHASE_3_CURRENT_DEMAND = 0x0106; +static const uint16_t SDM_MAXIMUM_PHASE_1_CURRENT_DEMAND = 0x0108; +static const uint16_t SDM_MAXIMUM_PHASE_2_CURRENT_DEMAND = 0x010A; +static const uint16_t SDM_MAXIMUM_PHASE_3_CURRENT_DEMAND = 0x010C; +static const uint16_t SDM_LINE_1_TO_LINE_2_VOLTS_THD = 0x014E; +static const uint16_t SDM_LINE_2_TO_LINE_3_VOLTS_THD = 0x0150; +static const uint16_t SDM_LINE_3_TO_LINE_1_VOLTS_THD = 0x0152; +static const uint16_t SDM_AVERAGE_LINE_TO_LINE_VOLTS_THD = 0x0154; + +static const uint16_t SDM_TOTAL_ACTIVE_ENERGY = 0x0156; +static const uint16_t SDM_TOTAL_REACTIVE_ENERGY = 0x0158; + +static const uint16_t SDM_L1_IMPORT_ACTIVE_ENERGY = 0x015A; +static const uint16_t SDM_L2_IMPORT_ACTIVE_ENERGY = 0x015C; +static const uint16_t SDM_L3_IMPORT_ACTIVE_ENERGY = 0x015E; +static const uint16_t SDM_L1_EXPORT_ACTIVE_ENERGY = 0x0160; +static const uint16_t SDM_L2_EXPORT_ACTIVE_ENERGY = 0x0162; +static const uint16_t SDM_L3_EXPORT_ACTIVE_ENERGY = 0x0164; +static const uint16_t SDM_L1_TOTAL_ACTIVE_ENERGY = 0x0166; +static const uint16_t SDM_L2_TOTAL_ACTIVE_ENERGY = 0x0168; +static const uint16_t SDM_L3_TOTAL_ACTIVE_ENERGY = 0x016a; +static const uint16_t SDM_L1_IMPORT_REACTIVE_ENERGY = 0x016C; +static const uint16_t SDM_L2_IMPORT_REACTIVE_ENERGY = 0x016E; +static const uint16_t SDM_L3_IMPORT_REACTIVE_ENERGY = 0x0170; +static const uint16_t SDM_L1_EXPORT_REACTIVE_ENERGY = 0x0172; +static const uint16_t SDM_L2_EXPORT_REACTIVE_ENERGY = 0x0174; +static const uint16_t SDM_L3_EXPORT_REACTIVE_ENERGY = 0x0176; +static const uint16_t SDM_L1_TOTAL_REACTIVE_ENERGY = 0x0178; +static const uint16_t SDM_L2_TOTAL_REACTIVE_ENERGY = 0x017A; +static const uint16_t SDM_L3_TOTAL_REACTIVE_ENERGY = 0x017C; + +static const uint16_t SDM_CURRENT_RESETTABLE_TOTAL_ACTIVE_ENERGY = 0x0180; +static const uint16_t SDM_CURRENT_RESETTABLE_TOTAL_REACTIVE_ENERGY = 0x0182; +static const uint16_t SDM_CURRENT_RESETTABLE_IMPORT_ENERGY = 0x0184; +static const uint16_t SDM_CURRENT_RESETTABLE_EXPORT_ENERGY = 0x0186; +static const uint16_t SDM_IMPORT_POWER = 0x0500; +static const uint16_t SDM_EXPORT_POWER = 0x0502; + +} // namespace sdm_meter +} // namespace esphome diff --git a/esphome/components/sdm_meter/sensor.py b/esphome/components/sdm_meter/sensor.py new file mode 100644 index 0000000000..0f7a4c928b --- /dev/null +++ b/esphome/components/sdm_meter/sensor.py @@ -0,0 +1,131 @@ +from esphome.components.atm90e32.sensor import CONF_PHASE_A, CONF_PHASE_B, CONF_PHASE_C +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import sensor, modbus +from esphome.const import ( + CONF_ACTIVE_POWER, + CONF_APPARENT_POWER, + CONF_CURRENT, + CONF_EXPORT_ACTIVE_ENERGY, + CONF_EXPORT_REACTIVE_ENERGY, + CONF_FREQUENCY, + CONF_ID, + CONF_IMPORT_ACTIVE_ENERGY, + CONF_IMPORT_REACTIVE_ENERGY, + CONF_PHASE_ANGLE, + CONF_POWER_FACTOR, + CONF_REACTIVE_POWER, + CONF_VOLTAGE, + DEVICE_CLASS_CURRENT, + DEVICE_CLASS_ENERGY, + DEVICE_CLASS_POWER, + DEVICE_CLASS_POWER_FACTOR, + DEVICE_CLASS_VOLTAGE, + ICON_CURRENT_AC, + ICON_EMPTY, + ICON_FLASH, + UNIT_AMPERE, + UNIT_DEGREES, + UNIT_EMPTY, + UNIT_HERTZ, + UNIT_VOLT, + UNIT_VOLT_AMPS, + UNIT_VOLT_AMPS_REACTIVE, + UNIT_VOLT_AMPS_REACTIVE_HOURS, + UNIT_WATT, + UNIT_WATT_HOURS, +) + +AUTO_LOAD = ["modbus"] +CODEOWNERS = ["@polyfaces", "@jesserockz"] + +sdm_meter_ns = cg.esphome_ns.namespace("sdm_meter") +SDMMeter = sdm_meter_ns.class_("SDMMeter", cg.PollingComponent, modbus.ModbusDevice) + +PHASE_SENSORS = { + CONF_VOLTAGE: sensor.sensor_schema(UNIT_VOLT, ICON_EMPTY, 2, DEVICE_CLASS_VOLTAGE), + CONF_CURRENT: sensor.sensor_schema( + UNIT_AMPERE, ICON_EMPTY, 3, DEVICE_CLASS_CURRENT + ), + CONF_ACTIVE_POWER: sensor.sensor_schema( + UNIT_WATT, ICON_EMPTY, 2, DEVICE_CLASS_POWER + ), + CONF_APPARENT_POWER: sensor.sensor_schema( + UNIT_VOLT_AMPS, ICON_EMPTY, 2, DEVICE_CLASS_POWER + ), + CONF_REACTIVE_POWER: sensor.sensor_schema( + UNIT_VOLT_AMPS_REACTIVE, ICON_EMPTY, 2, DEVICE_CLASS_POWER + ), + CONF_POWER_FACTOR: sensor.sensor_schema( + UNIT_EMPTY, ICON_EMPTY, 3, DEVICE_CLASS_POWER_FACTOR + ), + CONF_PHASE_ANGLE: sensor.sensor_schema(UNIT_DEGREES, ICON_FLASH, 3), +} + +PHASE_SCHEMA = cv.Schema( + {cv.Optional(sensor): schema for sensor, schema in PHASE_SENSORS.items()} +) + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(SDMMeter), + cv.Optional(CONF_PHASE_A): PHASE_SCHEMA, + cv.Optional(CONF_PHASE_B): PHASE_SCHEMA, + cv.Optional(CONF_PHASE_C): PHASE_SCHEMA, + cv.Optional(CONF_FREQUENCY): sensor.sensor_schema( + UNIT_HERTZ, ICON_CURRENT_AC, 3 + ), + cv.Optional(CONF_IMPORT_ACTIVE_ENERGY): sensor.sensor_schema( + UNIT_WATT_HOURS, ICON_EMPTY, 2, DEVICE_CLASS_ENERGY + ), + cv.Optional(CONF_EXPORT_ACTIVE_ENERGY): sensor.sensor_schema( + UNIT_WATT_HOURS, ICON_EMPTY, 2, DEVICE_CLASS_ENERGY + ), + cv.Optional(CONF_IMPORT_REACTIVE_ENERGY): sensor.sensor_schema( + UNIT_VOLT_AMPS_REACTIVE_HOURS, ICON_EMPTY, 2, DEVICE_CLASS_ENERGY + ), + cv.Optional(CONF_EXPORT_REACTIVE_ENERGY): sensor.sensor_schema( + UNIT_VOLT_AMPS_REACTIVE_HOURS, ICON_EMPTY, 2, DEVICE_CLASS_ENERGY + ), + } + ) + .extend(cv.polling_component_schema("10s")) + .extend(modbus.modbus_device_schema(0x01)) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await modbus.register_modbus_device(var, config) + + if CONF_FREQUENCY in config: + sens = await sensor.new_sensor(config[CONF_FREQUENCY]) + cg.add(var.set_frequency_sensor(sens)) + + if CONF_IMPORT_ACTIVE_ENERGY in config: + sens = await sensor.new_sensor(config[CONF_IMPORT_ACTIVE_ENERGY]) + cg.add(var.set_import_active_energy_sensor(sens)) + + if CONF_EXPORT_ACTIVE_ENERGY in config: + sens = await sensor.new_sensor(config[CONF_EXPORT_ACTIVE_ENERGY]) + cg.add(var.set_export_active_energy_sensor(sens)) + + if CONF_IMPORT_REACTIVE_ENERGY in config: + sens = await sensor.new_sensor(config[CONF_IMPORT_REACTIVE_ENERGY]) + cg.add(var.set_import_reactive_energy_sensor(sens)) + + if CONF_EXPORT_REACTIVE_ENERGY in config: + sens = await sensor.new_sensor(config[CONF_EXPORT_REACTIVE_ENERGY]) + cg.add(var.set_export_reactive_energy_sensor(sens)) + + for i, phase in enumerate([CONF_PHASE_A, CONF_PHASE_B, CONF_PHASE_C]): + if phase not in config: + continue + + phase_config = config[phase] + for sensor_type in PHASE_SENSORS: + if sensor_type in phase_config: + sens = await sensor.new_sensor(phase_config[sensor_type]) + cg.add(getattr(var, f"set_{sensor_type}_sensor")(i, sens)) diff --git a/esphome/const.py b/esphome/const.py index d44e995fc8..2316cee7dc 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -55,12 +55,14 @@ CONF_ACCELERATION_Z = "acceleration_z" CONF_ACCURACY = "accuracy" CONF_ACCURACY_DECIMALS = "accuracy_decimals" CONF_ACTION_ID = "action_id" +CONF_ACTIVE_POWER = "active_power" CONF_ADDRESS = "address" CONF_ADDRESSABLE_LIGHT_ID = "addressable_light_id" CONF_ALPHA = "alpha" CONF_ALTITUDE = "altitude" CONF_AND = "and" CONF_AP = "ap" +CONF_APPARENT_POWER = "apparent_power" CONF_ARDUINO_VERSION = "arduino_version" CONF_ARGS = "args" CONF_ASSUMED_STATE = "assumed_state" @@ -194,6 +196,8 @@ CONF_ESPHOME = "esphome" CONF_ETHERNET = "ethernet" CONF_EVENT = "event" CONF_EXPIRE_AFTER = "expire_after" +CONF_EXPORT_ACTIVE_ENERGY = "export_active_energy" +CONF_EXPORT_REACTIVE_ENERGY = "export_reactive_energy" CONF_EXTERNAL_COMPONENTS = "external_components" CONF_EXTERNAL_VCC = "external_vcc" CONF_FALLING_EDGE = "falling_edge" @@ -218,6 +222,7 @@ CONF_FILTERS = "filters" CONF_FINGER_ID = "finger_id" CONF_FINGERPRINT_COUNT = "fingerprint_count" CONF_FLASH_LENGTH = "flash_length" +CONF_FLOW_CONTROL_PIN = "flow_control_pin" CONF_FOR = "for" CONF_FORCE_UPDATE = "force_update" CONF_FORMALDEHYDE = "formaldehyde" @@ -261,6 +266,8 @@ CONF_IF = "if" CONF_IIR_FILTER = "iir_filter" CONF_ILLUMINANCE = "illuminance" CONF_IMPEDANCE = "impedance" +CONF_IMPORT_ACTIVE_ENERGY = "import_active_energy" +CONF_IMPORT_REACTIVE_ENERGY = "import_reactive_energy" CONF_INCLUDES = "includes" CONF_INDEX = "index" CONF_INDOOR = "indoor" @@ -413,6 +420,7 @@ CONF_PAYLOAD = "payload" CONF_PAYLOAD_AVAILABLE = "payload_available" CONF_PAYLOAD_NOT_AVAILABLE = "payload_not_available" CONF_PERIOD = "period" +CONF_PHASE_ANGLE = "phase_angle" CONF_PHASE_BALANCER = "phase_balancer" CONF_PIN = "pin" CONF_PIN_A = "pin_a" @@ -455,6 +463,7 @@ CONF_RATE = "rate" CONF_RAW = "raw" CONF_RC_CODE_1 = "rc_code_1" CONF_RC_CODE_2 = "rc_code_2" +CONF_REACTIVE_POWER = "reactive_power" CONF_REBOOT_TIMEOUT = "reboot_timeout" CONF_RECEIVE_TIMEOUT = "receive_timeout" CONF_RED = "red" @@ -715,6 +724,7 @@ UNIT_STEPS = "steps" UNIT_VOLT = "V" UNIT_VOLT_AMPS = "VA" UNIT_VOLT_AMPS_REACTIVE = "VAR" +UNIT_VOLT_AMPS_REACTIVE_HOURS = "VARh" UNIT_WATT = "W" UNIT_WATT_HOURS = "Wh" diff --git a/tests/test3.yaml b/tests/test3.yaml index 0a01405516..dcffdb8504 100644 --- a/tests/test3.yaml +++ b/tests/test3.yaml @@ -469,6 +469,62 @@ sensor: name: "Fingerprint Last Finger ID" last_confidence: name: "Fingerprint Last Confidence" + - platform: sdm_meter + phase_a: + current: + name: 'Phase A Current' + voltage: + name: 'Phase A Voltage' + active_power: + name: 'Phase A Power' + power_factor: + name: 'Phase A Power Factor' + apparent_power: + name: 'Phase A Apparent Power' + reactive_power: + name: 'Phase A Reactive Power' + phase_angle: + name: 'Phase A Phase Angle' + phase_b: + current: + name: 'Phase B Current' + voltage: + name: 'Phase B Voltage' + active_power: + name: 'Phase B Power' + power_factor: + name: 'Phase B Power Factor' + apparent_power: + name: 'Phase B Apparent Power' + reactive_power: + name: 'Phase B Reactive Power' + phase_angle: + name: 'Phase B Phase Angle' + phase_c: + current: + name: 'Phase C Current' + voltage: + name: 'Phase C Voltage' + active_power: + name: 'Phase C Power' + power_factor: + name: 'Phase C Power Factor' + apparent_power: + name: 'Phase C Apparent Power' + reactive_power: + name: 'Phase C Reactive Power' + phase_angle: + name: 'Phase C Phase Angle' + frequency: + name: 'Frequency' + import_active_energy: + name: 'Import Active Energy' + export_active_energy: + name: 'Export Active Energy' + import_reactive_energy: + name: 'Import Reactive Energy' + export_reactive_energy: + name: 'Export Reactive Energy' time: - platform: homeassistant From 4d586b14461fe8c95ec4f10b4161fc849945c273 Mon Sep 17 00:00:00 2001 From: Andrew Zaborowski Date: Mon, 31 May 2021 06:07:33 +0200 Subject: [PATCH 069/104] Add CS5460A power-meter component (#1474) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/cs5460a/__init__.py | 0 esphome/components/cs5460a/cs5460a.cpp | 342 +++++++++++++++++++++++++ esphome/components/cs5460a/cs5460a.h | 123 +++++++++ esphome/components/cs5460a/sensor.py | 136 ++++++++++ tests/test1.yaml | 22 ++ 6 files changed, 624 insertions(+) create mode 100644 esphome/components/cs5460a/__init__.py create mode 100644 esphome/components/cs5460a/cs5460a.cpp create mode 100644 esphome/components/cs5460a/cs5460a.h create mode 100644 esphome/components/cs5460a/sensor.py diff --git a/CODEOWNERS b/CODEOWNERS index 30be9e74b1..576af1459e 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -29,6 +29,7 @@ esphome/components/climate/* @esphome/core esphome/components/climate_ir/* @glmnet esphome/components/coolix/* @glmnet esphome/components/cover/* @esphome/core +esphome/components/cs5460a/* @balrog-kun esphome/components/ct_clamp/* @jesserockz esphome/components/debug/* @OttoWinter esphome/components/dfplayer/* @glmnet diff --git a/esphome/components/cs5460a/__init__.py b/esphome/components/cs5460a/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/cs5460a/cs5460a.cpp b/esphome/components/cs5460a/cs5460a.cpp new file mode 100644 index 0000000000..03cbd83513 --- /dev/null +++ b/esphome/components/cs5460a/cs5460a.cpp @@ -0,0 +1,342 @@ +#include "cs5460a.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace cs5460a { + +static const char *TAG = "cs5460a"; + +void CS5460AComponent::write_register_(enum CS5460ARegister addr, uint32_t value) { + this->write_byte(CMD_WRITE | (addr << 1)); + this->write_byte(value >> 16); + this->write_byte(value >> 8); + this->write_byte(value >> 0); +} + +uint32_t CS5460AComponent::read_register_(uint8_t addr) { + uint32_t value; + + this->write_byte(CMD_READ | (addr << 1)); + value = (uint32_t) this->transfer_byte(CMD_SYNC0) << 16; + value |= (uint32_t) this->transfer_byte(CMD_SYNC0) << 8; + value |= this->transfer_byte(CMD_SYNC0) << 0; + + return value; +} + +bool CS5460AComponent::softreset_() { + uint32_t pc = ((uint8_t) phase_offset_ & 0x3f) | (phase_offset_ < 0 ? 0x40 : 0); + uint32_t config = (1 << 0) | /* K = 0b0001 */ + (current_hpf_ ? 1 << 5 : 0) | /* IHPF */ + (voltage_hpf_ ? 1 << 6 : 0) | /* VHPF */ + (pga_gain_ << 16) | /* Gi */ + (pc << 17); /* PC */ + int cnt = 0; + + /* Serial resynchronization */ + this->write_byte(CMD_SYNC1); + this->write_byte(CMD_SYNC1); + this->write_byte(CMD_SYNC1); + this->write_byte(CMD_SYNC0); + + /* Reset */ + this->write_register_(REG_CONFIG, 1 << 7); + delay(10); + while (cnt++ < 50 && (this->read_register_(REG_CONFIG) & 0x81) != 0x000001) + ; + if (cnt > 50) + return false; + + this->write_register_(REG_CONFIG, config); + return true; +} + +void CS5460AComponent::setup() { + ESP_LOGCONFIG(TAG, "Setting up CS5460A..."); + + float current_full_scale = (pga_gain_ == CS5460A_PGA_GAIN_10X) ? 0.25 : 0.10; + float voltage_full_scale = 0.25; + current_multiplier_ = current_full_scale / (fabsf(current_gain_) * 0x1000000); + voltage_multiplier_ = voltage_full_scale / (voltage_gain_ * 0x1000000); + + /* + * Calculate power from the Energy register because the Power register + * stores instantaneous power which varies a lot in each AC cycle, + * while the Energy value is accumulated over the "computation cycle" + * which should be an integer number of AC cycles. + */ + power_multiplier_ = + (current_full_scale * voltage_full_scale * 4096) / (current_gain_ * voltage_gain_ * samples_ * 0x800000); + + pulse_freq_ = + (current_full_scale * voltage_full_scale) / (fabsf(current_gain_) * voltage_gain_ * pulse_energy_wh_ * 3600); + + hw_init_(); +} + +void CS5460AComponent::hw_init_() { + this->spi_setup(); + this->enable(); + + if (!this->softreset_()) { + this->disable(); + ESP_LOGE(TAG, "CS5460A reset failed!"); + this->mark_failed(); + return; + } + + uint32_t status = this->read_register_(REG_STATUS); + ESP_LOGCONFIG(TAG, " Version: %x", (status >> 6) & 7); + + this->write_register_(REG_CYCLE_COUNT, samples_); + this->write_register_(REG_PULSE_RATE, lroundf(pulse_freq_ * 32.0f)); + + /* Use one of the power saving features (assuming external oscillator), reset other CONTROL bits, + * sometimes softreset_() is not enough */ + this->write_register_(REG_CONTROL, 0x000004); + + this->restart_(); + this->disable(); + ESP_LOGCONFIG(TAG, " Init ok"); +} + +/* Doesn't reset the register values etc., just restarts the "computation cycle" */ +void CS5460AComponent::restart_() { + int cnt; + + this->enable(); + /* Stop running conversion, wake up if needed */ + this->write_byte(CMD_POWER_UP); + /* Start continuous conversion */ + this->write_byte(CMD_START_CONT); + this->disable(); + + this->started_(); +} + +void CS5460AComponent::started_() { + /* + * Try to guess when the next batch of results is going to be ready and + * schedule next STATUS check some time before that moment. This assumes + * two things: + * * a new "computation cycle" started just now. If it started some + * time ago we may be a late next time, but hopefully less late in each + * iteration -- that's why we schedule the next check in some 0.8 of + * the time we actually expect the next reading ready. + * * MCLK rate is 4.096MHz and K == 1. If there's a CS5460A module in + * use with a different clock this will need to be parametrised. + */ + expect_data_ts_ = millis() + samples_ * 1024 / 4096; + + schedule_next_check_(); +} + +void CS5460AComponent::schedule_next_check_() { + int32_t time_left = expect_data_ts_ - millis(); + + /* First try at 0.8 of the actual expected time (if it's in the future) */ + if (time_left > 0) + time_left -= time_left / 5; + + if (time_left > -500) { + /* But not sooner than in 30ms from now */ + if (time_left < 30) + time_left = 30; + } else { + /* + * If the measurement is more than 0.5s overdue start worrying. The + * device may be stuck because of an overcurrent error or similar, + * from now on just retry every 1s. After 15s try a reset, if it + * fails we give up and mark the component "failed". + */ + if (time_left > -15000) { + time_left = 1000; + this->status_momentary_warning("warning", 1000); + } else { + ESP_LOGCONFIG(TAG, "Device officially stuck, resetting"); + this->cancel_timeout("status-check"); + this->hw_init_(); + return; + } + } + + this->set_timeout("status-check", time_left, [this]() { + if (!this->check_status_()) + this->schedule_next_check_(); + }); +} + +bool CS5460AComponent::check_status_() { + this->enable(); + uint32_t status = this->read_register_(REG_STATUS); + + if (!(status & 0xcbf83c)) { + this->disable(); + return false; + } + + uint32_t clear = 1 << 20; + + /* TODO: Report if IC=0 but only once as it can't be cleared */ + + if (status & (1 << 2)) { + clear |= 1 << 2; + ESP_LOGE(TAG, "Low supply detected"); + this->status_momentary_warning("warning", 500); + } + + if (status & (1 << 3)) { + clear |= 1 << 3; + ESP_LOGE(TAG, "Modulator oscillation on current channel"); + this->status_momentary_warning("warning", 500); + } + + if (status & (1 << 4)) { + clear |= 1 << 4; + ESP_LOGE(TAG, "Modulator oscillation on voltage channel"); + this->status_momentary_warning("warning", 500); + } + + if (status & (1 << 5)) { + clear |= 1 << 5; + ESP_LOGE(TAG, "Watch-dog timeout"); + this->status_momentary_warning("warning", 500); + } + + if (status & (1 << 11)) { + clear |= 1 << 11; + ESP_LOGE(TAG, "EOUT Energy Accumulation Register out of range"); + this->status_momentary_warning("warning", 500); + } + + if (status & (1 << 12)) { + clear |= 1 << 12; + ESP_LOGE(TAG, "Energy out of range"); + this->status_momentary_warning("warning", 500); + } + + if (status & (1 << 13)) { + clear |= 1 << 13; + ESP_LOGE(TAG, "RMS voltage out of range"); + this->status_momentary_warning("warning", 500); + } + + if (status & (1 << 14)) { + clear |= 1 << 14; + ESP_LOGE(TAG, "RMS current out of range"); + this->status_momentary_warning("warning", 500); + } + + if (status & (1 << 15)) { + clear |= 1 << 15; + ESP_LOGE(TAG, "Power calculation out of range"); + this->status_momentary_warning("warning", 500); + } + + if (status & (1 << 16)) { + clear |= 1 << 16; + ESP_LOGE(TAG, "Voltage out of range"); + this->status_momentary_warning("warning", 500); + } + + if (status & (1 << 17)) { + clear |= 1 << 17; + ESP_LOGE(TAG, "Current out of range"); + this->status_momentary_warning("warning", 500); + } + + if (status & (1 << 19)) { + clear |= 1 << 19; + ESP_LOGE(TAG, "Divide overflowed"); + } + + if (status & (1 << 22)) { + bool dir = status & (1 << 21); + if (current_gain_ < 0) + dir = !dir; + ESP_LOGI(TAG, "Energy counter %s pulse", dir ? "negative" : "positive"); + clear |= 1 << 22; + } + + uint32_t raw_current = 0; /* Calm the validators */ + uint32_t raw_voltage = 0; + uint32_t raw_energy = 0; + + if (status & (1 << 23)) { + clear |= 1 << 23; + + if (current_sensor_ != nullptr) + raw_current = this->read_register_(REG_IRMS); + + if (voltage_sensor_ != nullptr) + raw_voltage = this->read_register_(REG_VRMS); + } + + if (status & ((1 << 23) | (1 << 5))) { + /* Read to clear the WDT bit */ + raw_energy = this->read_register_(REG_E); + } + + this->write_register_(REG_STATUS, clear); + this->disable(); + + /* + * Schedule the next STATUS check assuming that DRDY was asserted very + * recently, then publish the new values. Do this last for reentrancy in + * case the publish triggers a restart() or for whatever reason needs to + * cancel the timeout set in schedule_next_check_(), or needs to use SPI. + * If the current or power values haven't changed one bit it may be that + * the chip somehow forgot to update the registers -- seen happening very + * rarely. In that case don't publish them because the user may have + * the input connected to a multiplexer and may have switched channels + * since the previous reading and we'd be publishing the stale value for + * the new channel. If the value *was* updated it's very unlikely that + * it wouldn't have changed, especially power/energy which are affected + * by the noise on both the current and value channels (in case of energy, + * accumulated over many conversion cycles.) + */ + if (status & (1 << 23)) { + this->started_(); + + if (current_sensor_ != nullptr && raw_current != prev_raw_current_) { + current_sensor_->publish_state(raw_current * current_multiplier_); + prev_raw_current_ = raw_current; + } + + if (voltage_sensor_ != nullptr) + voltage_sensor_->publish_state(raw_voltage * voltage_multiplier_); + + if (power_sensor_ != nullptr && raw_energy != prev_raw_energy_) { + int32_t raw = (int32_t)(raw_energy << 8) >> 8; /* Sign-extend */ + power_sensor_->publish_state(raw * power_multiplier_); + prev_raw_energy_ = raw_energy; + } + + return true; + } + + return false; +} + +void CS5460AComponent::dump_config() { + uint32_t state = this->get_component_state(); + + ESP_LOGCONFIG(TAG, "CS5460A:"); + ESP_LOGCONFIG(TAG, " Init status: %s", + state == COMPONENT_STATE_LOOP ? "OK" : (state == COMPONENT_STATE_FAILED ? "failed" : "other")); + LOG_PIN(" CS Pin: ", cs_); + ESP_LOGCONFIG(TAG, " Samples / cycle: %u", samples_); + ESP_LOGCONFIG(TAG, " Phase offset: %i", phase_offset_); + ESP_LOGCONFIG(TAG, " PGA Gain: %s", pga_gain_ == CS5460A_PGA_GAIN_50X ? "50x" : "10x"); + ESP_LOGCONFIG(TAG, " Current gain: %.5f", current_gain_); + ESP_LOGCONFIG(TAG, " Voltage gain: %.5f", voltage_gain_); + ESP_LOGCONFIG(TAG, " Current HPF: %s", current_hpf_ ? "enabled" : "disabled"); + ESP_LOGCONFIG(TAG, " Voltage HPF: %s", voltage_hpf_ ? "enabled" : "disabled"); + ESP_LOGCONFIG(TAG, " Pulse energy: %.2f Wh", pulse_energy_wh_); + LOG_SENSOR(" ", "Voltage", voltage_sensor_); + LOG_SENSOR(" ", "Current", current_sensor_); + LOG_SENSOR(" ", "Power", power_sensor_); +} + +} // namespace cs5460a +} // namespace esphome diff --git a/esphome/components/cs5460a/cs5460a.h b/esphome/components/cs5460a/cs5460a.h new file mode 100644 index 0000000000..699049757c --- /dev/null +++ b/esphome/components/cs5460a/cs5460a.h @@ -0,0 +1,123 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/automation.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/spi/spi.h" + +namespace esphome { +namespace cs5460a { + +enum CS5460ACommand { + CMD_SYNC0 = 0xfe, + CMD_SYNC1 = 0xff, + CMD_START_SINGLE = 0xe0, + CMD_START_CONT = 0xe8, + CMD_POWER_UP = 0xa0, + CMD_POWER_STANDBY = 0x88, + CMD_POWER_SLEEP = 0x90, + CMD_CALIBRATION = 0xc0, + CMD_READ = 0x00, + CMD_WRITE = 0x40, +}; + +enum CS5460ARegister { + REG_CONFIG = 0x00, + REG_IDCOFF = 0x01, + REG_IGN = 0x02, + REG_VDCOFF = 0x03, + REG_VGN = 0x04, + REG_CYCLE_COUNT = 0x05, + REG_PULSE_RATE = 0x06, + REG_I = 0x07, + REG_V = 0x08, + REG_P = 0x09, + REG_E = 0x0a, + REG_IRMS = 0x0b, + REG_VRMS = 0x0c, + REG_TBC = 0x0d, + REG_POFF = 0x0e, + REG_STATUS = 0x0f, + REG_IACOFF = 0x10, + REG_VACOFF = 0x11, + REG_MASK = 0x1a, + REG_CONTROL = 0x1c, +}; + +/** Enum listing the current channel aplifiergain settings for the CS5460A. + */ +enum CS5460APGAGain { + CS5460A_PGA_GAIN_10X = 0b0, + CS5460A_PGA_GAIN_50X = 0b1, +}; + +class CS5460AComponent : public Component, + public spi::SPIDevice { + public: + void set_samples(uint32_t samples) { samples_ = samples; } + void set_phase_offset(int8_t phase_offset) { phase_offset_ = phase_offset; } + void set_pga_gain(CS5460APGAGain pga_gain) { pga_gain_ = pga_gain; } + void set_gains(float current_gain, float voltage_gain) { + current_gain_ = current_gain; + voltage_gain_ = voltage_gain; + } + void set_hpf_enable(bool current_hpf, bool voltage_hpf) { + current_hpf_ = current_hpf; + voltage_hpf_ = voltage_hpf; + } + void set_pulse_energy_wh(float pulse_energy_wh) { pulse_energy_wh_ = pulse_energy_wh; } + void set_current_sensor(sensor::Sensor *current_sensor) { current_sensor_ = current_sensor; } + void set_voltage_sensor(sensor::Sensor *voltage_sensor) { voltage_sensor_ = voltage_sensor; } + void set_power_sensor(sensor::Sensor *power_sensor) { power_sensor_ = power_sensor; } + + void restart() { restart_(); } + + void setup() override; + void loop() override {} + float get_setup_priority() const override { return setup_priority::DATA; } + void dump_config() override; + + protected: + uint32_t samples_; + int8_t phase_offset_; + CS5460APGAGain pga_gain_; + float current_gain_; + float voltage_gain_; + bool current_hpf_; + bool voltage_hpf_; + float pulse_energy_wh_; + sensor::Sensor *current_sensor_{nullptr}; + sensor::Sensor *voltage_sensor_{nullptr}; + sensor::Sensor *power_sensor_{nullptr}; + + void write_register_(enum CS5460ARegister addr, uint32_t value); + uint32_t read_register_(uint8_t addr); + bool softreset_(); + void hw_init_(); + void restart_(); + void started_(); + void schedule_next_check_(); + bool check_status_(); + + float current_multiplier_; + float voltage_multiplier_; + float power_multiplier_; + float pulse_freq_; + uint32_t expect_data_ts_; + uint32_t prev_raw_current_{0}; + uint32_t prev_raw_energy_{0}; +}; + +template class CS5460ARestartAction : public Action { + public: + CS5460ARestartAction(CS5460AComponent *cs5460a) : cs5460a_(cs5460a) {} + + void play(Ts... x) override { cs5460a_->restart(); } + + protected: + CS5460AComponent *cs5460a_; +}; + +} // namespace cs5460a +} // namespace esphome diff --git a/esphome/components/cs5460a/sensor.py b/esphome/components/cs5460a/sensor.py new file mode 100644 index 0000000000..efb1d1d426 --- /dev/null +++ b/esphome/components/cs5460a/sensor.py @@ -0,0 +1,136 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import spi, sensor +from esphome.const import ( + CONF_CURRENT, + CONF_ID, + CONF_POWER, + CONF_VOLTAGE, + UNIT_VOLT, + UNIT_AMPERE, + UNIT_WATT, + ICON_EMPTY, + DEVICE_CLASS_POWER, + DEVICE_CLASS_CURRENT, + DEVICE_CLASS_VOLTAGE, +) +from esphome import automation +from esphome.automation import maybe_simple_id + +CODEOWNERS = ["@balrog-kun"] +DEPENDENCIES = ["spi"] + +cs5460a_ns = cg.esphome_ns.namespace("cs5460a") +CS5460APGAGain = cs5460a_ns.enum("CS5460APGAGain") +PGA_GAIN_OPTIONS = { + "10X": CS5460APGAGain.CS5460A_PGA_GAIN_10X, + "50X": CS5460APGAGain.CS5460A_PGA_GAIN_50X, +} + +CS5460AComponent = cs5460a_ns.class_("CS5460AComponent", spi.SPIDevice, cg.Component) +CS5460ARestartAction = cs5460a_ns.class_("CS5460ARestartAction", automation.Action) + +CONF_SAMPLES = "samples" +CONF_PHASE_OFFSET = "phase_offset" +CONF_PGA_GAIN = "pga_gain" +CONF_CURRENT_GAIN = "current_gain" +CONF_VOLTAGE_GAIN = "voltage_gain" +CONF_CURRENT_HPF = "current_hpf" +CONF_VOLTAGE_HPF = "voltage_hpf" +CONF_PULSE_ENERGY = "pulse_energy" + + +def validate_config(config): + current_gain = abs(config[CONF_CURRENT_GAIN]) * ( + 1.0 if config[CONF_PGA_GAIN] == "10X" else 5.0 + ) + voltage_gain = config[CONF_VOLTAGE_GAIN] + pulse_energy = config[CONF_PULSE_ENERGY] + + if current_gain == 0.0 or voltage_gain == 0.0: + raise cv.Invalid("The gains can't be zero") + + max_energy = (0.25 * 0.25 / 3600 / (2 ** -4)) / (voltage_gain * current_gain) + min_energy = (0.25 * 0.25 / 3600 / (2 ** 18)) / (voltage_gain * current_gain) + mech_min_energy = (0.25 * 0.25 / 3600 / 7.8) / (voltage_gain * current_gain) + if pulse_energy < min_energy or pulse_energy > max_energy: + raise cv.Invalid( + "For given current&voltage gains, the pulse energy must be between " + f"{min_energy} Wh and {max_energy} Wh and in mechanical counter mode " + f"between {mech_min_energy} Wh and {max_energy} Wh" + ) + + return config + + +validate_energy = cv.float_with_unit("energy", "(Wh|WH|wh)?", optional_unit=True) + +CONFIG_SCHEMA = cv.All( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(CS5460AComponent), + cv.Optional(CONF_SAMPLES, default=4000): cv.int_range(min=1, max=0xFFFFFF), + cv.Optional(CONF_PHASE_OFFSET, default=0): cv.int_range(min=-64, max=63), + cv.Optional(CONF_PGA_GAIN, default="10X"): cv.enum( + PGA_GAIN_OPTIONS, upper=True + ), + cv.Optional(CONF_CURRENT_GAIN, default=0.001): cv.negative_one_to_one_float, + cv.Optional(CONF_VOLTAGE_GAIN, default=0.001): cv.zero_to_one_float, + cv.Optional(CONF_CURRENT_HPF, default=True): cv.boolean, + cv.Optional(CONF_VOLTAGE_HPF, default=True): cv.boolean, + cv.Optional(CONF_PULSE_ENERGY, default=10.0): validate_energy, + cv.Optional(CONF_VOLTAGE): sensor.sensor_schema( + UNIT_VOLT, ICON_EMPTY, 0, DEVICE_CLASS_VOLTAGE + ), + cv.Optional(CONF_CURRENT): sensor.sensor_schema( + UNIT_AMPERE, ICON_EMPTY, 1, DEVICE_CLASS_CURRENT + ), + cv.Optional(CONF_POWER): sensor.sensor_schema( + UNIT_WATT, ICON_EMPTY, 0, DEVICE_CLASS_POWER + ), + } + ) + .extend(cv.COMPONENT_SCHEMA) + .extend(spi.spi_device_schema(cs_pin_required=False)), + validate_config, +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await spi.register_spi_device(var, config) + + cg.add(var.set_samples(config[CONF_SAMPLES])) + cg.add(var.set_phase_offset(config[CONF_PHASE_OFFSET])) + cg.add(var.set_pga_gain(config[CONF_PGA_GAIN])) + cg.add(var.set_gains(config[CONF_CURRENT_GAIN], config[CONF_VOLTAGE_GAIN])) + cg.add(var.set_hpf_enable(config[CONF_CURRENT_HPF], config[CONF_VOLTAGE_HPF])) + cg.add(var.set_pulse_energy_wh(config[CONF_PULSE_ENERGY])) + + if CONF_VOLTAGE in config: + conf = config[CONF_VOLTAGE] + sens = await sensor.new_sensor(conf) + cg.add(var.set_voltage_sensor(sens)) + if CONF_CURRENT in config: + conf = config[CONF_CURRENT] + sens = await sensor.new_sensor(conf) + cg.add(var.set_current_sensor(sens)) + if CONF_POWER in config: + conf = config[CONF_POWER] + sens = await sensor.new_sensor(conf) + cg.add(var.set_power_sensor(sens)) + + +@automation.register_action( + "cs5460a.restart", + CS5460ARestartAction, + maybe_simple_id( + { + cv.Required(CONF_ID): cv.use_id(CS5460AComponent), + } + ), +) +async def restart_action_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, paren) diff --git a/tests/test1.yaml b/tests/test1.yaml index 6f87166490..31bfc5e9f0 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -914,6 +914,28 @@ sensor: id: ph_ezo address: 99 unit_of_measurement: 'pH' + - platform: cs5460a + id: cs5460a1 + current: + name: "Socket current" + voltage: + name: "Mains voltage" + power: + name: "Socket power" + on_value: + then: + cs5460a.restart: cs5460a1 + samples: 1600 + pga_gain: 10X + current_gain: 0.01 + voltage_gain: 0.000573 + current_hpf: on + voltage_hpf: on + phase_offset: 20 + pulse_energy: 0.01 kWh + cs_pin: + mcp23xxx: mcp23017_hub + number: 14 esp32_touch: setup_mode: False From 25af5ab7c61f15e61212da6d0963651da66c2368 Mon Sep 17 00:00:00 2001 From: Oxan van Leeuwen Date: Mon, 31 May 2021 12:27:41 +0200 Subject: [PATCH 070/104] Drop 128x160 ESP-32 camera resolution (#1813) --- esphome/components/esp32_camera/__init__.py | 2 -- .../components/esp32_camera/esp32_camera.cpp | 6 ------ esphome/components/esp32_camera/esp32_camera.h | 1 - tests/test4.yaml | 17 +++++++++++++++++ 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/esphome/components/esp32_camera/__init__.py b/esphome/components/esp32_camera/__init__.py index f3c0e0f165..abbb4b1b7e 100644 --- a/esphome/components/esp32_camera/__init__.py +++ b/esphome/components/esp32_camera/__init__.py @@ -25,8 +25,6 @@ ESP32CameraFrameSize = esp32_camera_ns.enum("ESP32CameraFrameSize") FRAME_SIZES = { "160X120": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_160X120, "QQVGA": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_160X120, - "128X160": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_128X160, - "QQVGA2": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_128X160, "176X144": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_176X144, "QCIF": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_176X144, "240X176": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_240X176, diff --git a/esphome/components/esp32_camera/esp32_camera.cpp b/esphome/components/esp32_camera/esp32_camera.cpp index 1d9faf7ea2..6bb57a8304 100644 --- a/esphome/components/esp32_camera/esp32_camera.cpp +++ b/esphome/components/esp32_camera/esp32_camera.cpp @@ -55,9 +55,6 @@ void ESP32Camera::dump_config() { case FRAMESIZE_QQVGA: ESP_LOGCONFIG(TAG, " Resolution: 160x120 (QQVGA)"); break; - case FRAMESIZE_QQVGA2: - ESP_LOGCONFIG(TAG, " Resolution: 128x160 (QQVGA2)"); - break; case FRAMESIZE_QCIF: ESP_LOGCONFIG(TAG, " Resolution: 176x155 (QCIF)"); break; @@ -209,9 +206,6 @@ void ESP32Camera::set_frame_size(ESP32CameraFrameSize size) { case ESP32_CAMERA_SIZE_160X120: this->config_.frame_size = FRAMESIZE_QQVGA; break; - case ESP32_CAMERA_SIZE_128X160: - this->config_.frame_size = FRAMESIZE_QQVGA2; - break; case ESP32_CAMERA_SIZE_176X144: this->config_.frame_size = FRAMESIZE_QCIF; break; diff --git a/esphome/components/esp32_camera/esp32_camera.h b/esphome/components/esp32_camera/esp32_camera.h index fd8597d0c1..03272d3b32 100644 --- a/esphome/components/esp32_camera/esp32_camera.h +++ b/esphome/components/esp32_camera/esp32_camera.h @@ -37,7 +37,6 @@ class CameraImageReader { enum ESP32CameraFrameSize { ESP32_CAMERA_SIZE_160X120, // QQVGA - ESP32_CAMERA_SIZE_128X160, // QQVGA2 ESP32_CAMERA_SIZE_176X144, // QCIF ESP32_CAMERA_SIZE_240X176, // HQVGA ESP32_CAMERA_SIZE_320X240, // QVGA diff --git a/tests/test4.yaml b/tests/test4.yaml index fb2bce82a4..08213fab87 100644 --- a/tests/test4.yaml +++ b/tests/test4.yaml @@ -183,6 +183,23 @@ display: lambda: |- it.rectangle(0, 0, it.get_width(), it.get_height()); +esp32_camera: + name: ESP-32 Camera + data_pins: [GPIO17, GPIO35, GPIO34, GPIO5, GPIO39, GPIO18, GPIO36, GPIO19] + vsync_pin: GPIO22 + href_pin: GPIO26 + pixel_clock_pin: GPIO21 + external_clock: + pin: GPIO27 + frequency: 20MHz + i2c_pins: + sda: GPIO25 + scl: GPIO23 + reset_pin: GPIO15 + power_down_pin: GPIO1 + resolution: 640x480 + jpeg_quality: 10 + external_components: - source: github://esphome/esphome@dev refresh: 1d From 5c3268b8d40ea42ba7f3b1fd83eab49d99e32e6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Panella?= Date: Mon, 31 May 2021 14:24:22 -0500 Subject: [PATCH 071/104] Rf Bridge: add bucket sniffing and beep functionality (#1819) Co-authored-by: Otto winter Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/rf_bridge/__init__.py | 37 ++++++++++++++++++++++ esphome/components/rf_bridge/rf_bridge.cpp | 19 +++++++++++ esphome/components/rf_bridge/rf_bridge.h | 24 ++++++++++++++ 3 files changed, 80 insertions(+) diff --git a/esphome/components/rf_bridge/__init__.py b/esphome/components/rf_bridge/__init__.py index c7f1b819b8..228e7d882b 100644 --- a/esphome/components/rf_bridge/__init__.py +++ b/esphome/components/rf_bridge/__init__.py @@ -12,6 +12,7 @@ from esphome.const import ( CONF_RAW, CONF_SYNC, CONF_TRIGGER_ID, + CONF_DURATION, ) DEPENDENCIES = ["uart"] @@ -49,6 +50,12 @@ RFBridgeStopAdvancedSniffingAction = rf_bridge_ns.class_( "RFBridgeStopAdvancedSniffingAction", automation.Action ) +RFBridgeStartBucketSniffingAction = rf_bridge_ns.class_( + "RFBridgeStartBucketSniffingAction", automation.Action +) + +RFBridgeBeepAction = rf_bridge_ns.class_("RFBridgeBeepAction", automation.Action) + RFBridgeSendRawAction = rf_bridge_ns.class_("RFBridgeSendRawAction", automation.Action) CONF_ON_CODE_RECEIVED = "on_code_received" @@ -159,6 +166,19 @@ async def rf_bridge_stop_advanced_sniffing_to_code( return var +@automation.register_action( + "rf_bridge.start_bucket_sniffing", + RFBridgeStartBucketSniffingAction, + RFBRIDGE_ID_SCHEMA, +) +async def rf_bridge_start_bucket_sniffing_to_code( + config, action_id, template_args, args +): + paren = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_args, paren) + return var + + RFBRIDGE_SEND_ADVANCED_CODE_SCHEMA = cv.Schema( { cv.GenerateID(): cv.use_id(RFBridgeComponent), @@ -203,3 +223,20 @@ async def rf_bridge_send_raw_to_code(config, action_id, template_args, args): template_ = await cg.templatable(config[CONF_RAW], args, cg.std_string) cg.add(var.set_raw(template_)) return var + + +RFBRIDGE_BEEP_SCHEMA = cv.Schema( + { + cv.GenerateID(): cv.use_id(RFBridgeComponent), + cv.Required(CONF_DURATION): cv.templatable(cv.uint16_t), + } +) + + +@automation.register_action("rf_bridge.beep", RFBridgeBeepAction, RFBRIDGE_BEEP_SCHEMA) +async def rf_bridge_beep_to_code(config, action_id, template_args, args): + paren = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_args, paren) + template_ = await cg.templatable(config[CONF_DURATION], args, cg.uint16) + cg.add(var.set_duration(template_)) + return var diff --git a/esphome/components/rf_bridge/rf_bridge.cpp b/esphome/components/rf_bridge/rf_bridge.cpp index 32e72453e0..b284a969b1 100644 --- a/esphome/components/rf_bridge/rf_bridge.cpp +++ b/esphome/components/rf_bridge/rf_bridge.cpp @@ -201,6 +201,14 @@ void RFBridgeComponent::stop_advanced_sniffing() { this->flush(); } +void RFBridgeComponent::start_bucket_sniffing() { + ESP_LOGD(TAG, "Raw Bucket Sniffing on"); + this->write(RF_CODE_START); + this->write(RF_CODE_RFIN_BUCKET); + this->write(RF_CODE_STOP); + this->flush(); +} + void RFBridgeComponent::send_raw(std::string raw_code) { ESP_LOGD(TAG, "Sending Raw Code: %s", raw_code.c_str()); @@ -208,5 +216,16 @@ void RFBridgeComponent::send_raw(std::string raw_code) { this->flush(); } +void RFBridgeComponent::beep(uint16_t ms) { + ESP_LOGD(TAG, "Beeping for %hu ms", ms); + + this->write(RF_CODE_START); + this->write(RF_CODE_BEEP); + this->write((ms >> 8) & 0xFF); + this->write(ms & 0xFF); + this->write(RF_CODE_STOP); + this->flush(); +} + } // namespace rf_bridge } // namespace esphome diff --git a/esphome/components/rf_bridge/rf_bridge.h b/esphome/components/rf_bridge/rf_bridge.h index b850140b75..573bb2df3f 100644 --- a/esphome/components/rf_bridge/rf_bridge.h +++ b/esphome/components/rf_bridge/rf_bridge.h @@ -24,6 +24,7 @@ static const uint8_t RF_CODE_LEARN_KO_NEW = 0xAA; static const uint8_t RF_CODE_LEARN_OK_NEW = 0xAB; static const uint8_t RF_CODE_RFOUT_BUCKET = 0xB0; static const uint8_t RF_CODE_RFIN_BUCKET = 0xB1; +static const uint8_t RF_CODE_BEEP = 0xC0; static const uint8_t RF_CODE_STOP = 0x55; static const uint8_t RF_DEBOUNCE = 200; @@ -55,7 +56,9 @@ class RFBridgeComponent : public uart::UARTDevice, public Component { void learn(); void start_advanced_sniffing(); void stop_advanced_sniffing(); + void start_bucket_sniffing(); void send_raw(std::string code); + void beep(uint16_t ms); protected: void ack_(); @@ -154,6 +157,16 @@ template class RFBridgeStopAdvancedSniffingAction : public Actio RFBridgeComponent *parent_; }; +template class RFBridgeStartBucketSniffingAction : public Action { + public: + RFBridgeStartBucketSniffingAction(RFBridgeComponent *parent) : parent_(parent) {} + + void play(Ts... x) { this->parent_->start_bucket_sniffing(); } + + protected: + RFBridgeComponent *parent_; +}; + template class RFBridgeSendRawAction : public Action { public: RFBridgeSendRawAction(RFBridgeComponent *parent) : parent_(parent) {} @@ -165,5 +178,16 @@ template class RFBridgeSendRawAction : public Action { RFBridgeComponent *parent_; }; +template class RFBridgeBeepAction : public Action { + public: + RFBridgeBeepAction(RFBridgeComponent *parent) : parent_(parent) {} + TEMPLATABLE_VALUE(uint16_t, duration) + + void play(Ts... x) { this->parent_->beep(this->duration_.value(x...)); } + + protected: + RFBridgeComponent *parent_; +}; + } // namespace rf_bridge } // namespace esphome From d1c6368283ac5231dfaf0edc8822105773b70a89 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Mon, 31 May 2021 21:40:57 +0200 Subject: [PATCH 072/104] Use built-in validation for altitude (#1831) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/scd30/sensor.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/esphome/components/scd30/sensor.py b/esphome/components/scd30/sensor.py index a5eb5d8ca4..aad2a1811c 100644 --- a/esphome/components/scd30/sensor.py +++ b/esphome/components/scd30/sensor.py @@ -1,4 +1,3 @@ -import re import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import i2c, sensor @@ -28,10 +27,6 @@ CONF_AMBIENT_PRESSURE_COMPENSATION = "ambient_pressure_compensation" CONF_TEMPERATURE_OFFSET = "temperature_offset" -def remove_altitude_suffix(value): - return re.sub(r"\s*(?:m(?:\s+a\.s\.l)?)|(?:MAM?SL)$", "", value) - - CONFIG_SCHEMA = ( cv.Schema( { @@ -47,7 +42,7 @@ CONFIG_SCHEMA = ( ), cv.Optional(CONF_AUTOMATIC_SELF_CALIBRATION, default=True): cv.boolean, cv.Optional(CONF_ALTITUDE_COMPENSATION): cv.All( - remove_altitude_suffix, + cv.float_with_unit("altitude", "(m|m a.s.l.|MAMSL|MASL)"), cv.int_range(min=0, max=0xFFFF, max_included=False), ), cv.Optional(CONF_AMBIENT_PRESSURE_COMPENSATION, default=0): cv.pressure, From 9a2cd715716e3237bfb2e15f89b8b912e70f15ce Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 1 Jun 2021 09:57:03 +1200 Subject: [PATCH 073/104] Don't check uart settings for modbus (#1850) --- esphome/components/modbus/modbus.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/esphome/components/modbus/modbus.cpp b/esphome/components/modbus/modbus.cpp index 08eace9ef5..7820e14bf9 100644 --- a/esphome/components/modbus/modbus.cpp +++ b/esphome/components/modbus/modbus.cpp @@ -100,7 +100,6 @@ bool Modbus::parse_modbus_byte_(uint8_t byte) { void Modbus::dump_config() { ESP_LOGCONFIG(TAG, "Modbus:"); LOG_PIN(" Flow Control Pin: ", this->flow_control_pin_); - this->check_uart_settings(9600, 2); } float Modbus::get_setup_priority() const { // After UART bus From 56974153f1106c0b14b52cec08ea9d535fd4d3c4 Mon Sep 17 00:00:00 2001 From: Maurice Makaay Date: Tue, 1 Jun 2021 00:36:25 +0200 Subject: [PATCH 074/104] I2c raw cmds with multiplexer (#1817) Co-authored-by: Maurice Makaay --- esphome/components/i2c/i2c.cpp | 30 +++++++++++++++++++ esphome/components/i2c/i2c.h | 14 ++++----- esphome/components/mcp4725/mcp4725.cpp | 4 +-- .../components/ssd1306_i2c/ssd1306_i2c.cpp | 4 +-- .../components/ssd1327_i2c/ssd1327_i2c.cpp | 4 +-- 5 files changed, 41 insertions(+), 15 deletions(-) diff --git a/esphome/components/i2c/i2c.cpp b/esphome/components/i2c/i2c.cpp index e9a7e72932..2111711264 100644 --- a/esphome/components/i2c/i2c.cpp +++ b/esphome/components/i2c/i2c.cpp @@ -193,12 +193,36 @@ void I2CDevice::check_multiplexer_() { } #endif +void I2CDevice::raw_begin_transmission() { // NOLINT +#ifdef USE_I2C_MULTIPLEXER + this->check_multiplexer_(); +#endif + this->parent_->raw_begin_transmission(this->address_); +} +bool I2CDevice::raw_end_transmission(bool send_stop) { // NOLINT +#ifdef USE_I2C_MULTIPLEXER + this->check_multiplexer_(); +#endif + return this->parent_->raw_end_transmission(this->address_, send_stop); +} +void I2CDevice::raw_write(const uint8_t *data, uint8_t len) { // NOLINT +#ifdef USE_I2C_MULTIPLEXER + this->check_multiplexer_(); +#endif + this->parent_->raw_write(this->address_, data, len); +} bool I2CDevice::read_bytes(uint8_t a_register, uint8_t *data, uint8_t len, uint32_t conversion) { // NOLINT #ifdef USE_I2C_MULTIPLEXER this->check_multiplexer_(); #endif return this->parent_->read_bytes(this->address_, a_register, data, len, conversion); } +bool I2CDevice::read_bytes_raw(uint8_t *data, uint8_t len) { // NOLINT +#ifdef USE_I2C_MULTIPLEXER + this->check_multiplexer_(); +#endif + return this->parent_->read_bytes_raw(this->address_, data, len); +} bool I2CDevice::read_byte(uint8_t a_register, uint8_t *data, uint32_t conversion) { // NOLINT #ifdef USE_I2C_MULTIPLEXER this->check_multiplexer_(); @@ -211,6 +235,12 @@ bool I2CDevice::write_bytes(uint8_t a_register, const uint8_t *data, uint8_t len #endif return this->parent_->write_bytes(this->address_, a_register, data, len); } +bool I2CDevice::write_bytes_raw(const uint8_t *data, uint8_t len) { // NOLINT +#ifdef USE_I2C_MULTIPLEXER + this->check_multiplexer_(); +#endif + return this->parent_->write_bytes_raw(this->address_, data, len); +} bool I2CDevice::write_byte(uint8_t a_register, uint8_t data) { // NOLINT #ifdef USE_I2C_MULTIPLEXER this->check_multiplexer_(); diff --git a/esphome/components/i2c/i2c.h b/esphome/components/i2c/i2c.h index 56da64c218..da791ec633 100644 --- a/esphome/components/i2c/i2c.h +++ b/esphome/components/i2c/i2c.h @@ -178,15 +178,13 @@ class I2CDevice { I2CRegister reg(uint8_t a_register) { return {this, a_register}; } /// Begin a write transmission. - void raw_begin_transmission() { this->parent_->raw_begin_transmission(this->address_); }; + void raw_begin_transmission(); /// End a write transmission, return true if successful. - bool raw_end_transmission(bool send_stop = true) { - return this->parent_->raw_end_transmission(this->address_, send_stop); - }; + bool raw_end_transmission(bool send_stop = true); /// Write len amount of bytes from data. begin_transmission_ must be called before this. - void raw_write(const uint8_t *data, uint8_t len) { this->parent_->raw_write(this->address_, data, len); }; + void raw_write(const uint8_t *data, uint8_t len); /** Read len amount of bytes from a register into data. Optionally with a conversion time after * writing the register value to the bus. @@ -198,7 +196,7 @@ class I2CDevice { * @return If the operation was successful. */ bool read_bytes(uint8_t a_register, uint8_t *data, uint8_t len, uint32_t conversion = 0); - bool read_bytes_raw(uint8_t *data, uint8_t len) { return this->parent_->read_bytes_raw(this->address_, data, len); } + bool read_bytes_raw(uint8_t *data, uint8_t len); template optional> read_bytes(uint8_t a_register) { std::array res; @@ -246,9 +244,7 @@ class I2CDevice { * @return If the operation was successful. */ bool write_bytes(uint8_t a_register, const uint8_t *data, uint8_t len); - bool write_bytes_raw(const uint8_t *data, uint8_t len) { - return this->parent_->write_bytes_raw(this->address_, data, len); - } + bool write_bytes_raw(const uint8_t *data, uint8_t len); /** Write a vector of data to a register. * diff --git a/esphome/components/mcp4725/mcp4725.cpp b/esphome/components/mcp4725/mcp4725.cpp index 85028d2f39..37ae7ac2b8 100644 --- a/esphome/components/mcp4725/mcp4725.cpp +++ b/esphome/components/mcp4725/mcp4725.cpp @@ -9,9 +9,9 @@ static const char *TAG = "mcp4725"; void MCP4725::setup() { ESP_LOGCONFIG(TAG, "Setting up MCP4725 (0x%02X)...", this->address_); - this->parent_->raw_begin_transmission(this->address_); + this->raw_begin_transmission(); - if (!this->parent_->raw_end_transmission(this->address_)) { + if (!this->raw_end_transmission()) { this->error_code_ = COMMUNICATION_FAILED; this->mark_failed(); diff --git a/esphome/components/ssd1306_i2c/ssd1306_i2c.cpp b/esphome/components/ssd1306_i2c/ssd1306_i2c.cpp index 34a963e532..8c535094ac 100644 --- a/esphome/components/ssd1306_i2c/ssd1306_i2c.cpp +++ b/esphome/components/ssd1306_i2c/ssd1306_i2c.cpp @@ -10,8 +10,8 @@ void I2CSSD1306::setup() { ESP_LOGCONFIG(TAG, "Setting up I2C SSD1306..."); this->init_reset_(); - this->parent_->raw_begin_transmission(this->address_); - if (!this->parent_->raw_end_transmission(this->address_)) { + this->raw_begin_transmission(); + if (!this->raw_end_transmission()) { this->error_code_ = COMMUNICATION_FAILED; this->mark_failed(); return; diff --git a/esphome/components/ssd1327_i2c/ssd1327_i2c.cpp b/esphome/components/ssd1327_i2c/ssd1327_i2c.cpp index f256c9df77..16cada0ef2 100644 --- a/esphome/components/ssd1327_i2c/ssd1327_i2c.cpp +++ b/esphome/components/ssd1327_i2c/ssd1327_i2c.cpp @@ -10,8 +10,8 @@ void I2CSSD1327::setup() { ESP_LOGCONFIG(TAG, "Setting up I2C SSD1327..."); this->init_reset_(); - this->parent_->raw_begin_transmission(this->address_); - if (!this->parent_->raw_end_transmission(this->address_)) { + this->raw_begin_transmission(); + if (!this->raw_end_transmission()) { this->error_code_ = COMMUNICATION_FAILED; this->mark_failed(); return; From 48b5ea9e59fe0c0ff8efdf749ee06956ce1e14cb Mon Sep 17 00:00:00 2001 From: Roberto Wagner Date: Mon, 31 May 2021 21:22:09 -0300 Subject: [PATCH 075/104] Update fingerprint count after enroll (#1811) --- esphome/components/fingerprint_grow/fingerprint_grow.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/fingerprint_grow/fingerprint_grow.cpp b/esphome/components/fingerprint_grow/fingerprint_grow.cpp index 77ddf8ec37..370bdc782b 100644 --- a/esphome/components/fingerprint_grow/fingerprint_grow.cpp +++ b/esphome/components/fingerprint_grow/fingerprint_grow.cpp @@ -75,6 +75,7 @@ void FingerprintGrowComponent::enroll_fingerprint(uint16_t finger_id, uint8_t nu void FingerprintGrowComponent::finish_enrollment(uint8_t result) { if (result == OK) { this->enrollment_done_callback_.call(this->enrollment_slot_); + this->get_fingerprint_count_(); } else { this->enrollment_failed_callback_.call(this->enrollment_slot_); } From afa436fe8f6f4ffccd99157c2d9539d957c384a6 Mon Sep 17 00:00:00 2001 From: 0hax <43876620+0hax@users.noreply.github.com> Date: Tue, 1 Jun 2021 03:32:09 +0200 Subject: [PATCH 076/104] teleinfo: use text_sensor and sensor. (#1403) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Co-authored-by: Otto winter --- esphome/components/teleinfo/__init__.py | 27 ++++++++++ esphome/components/teleinfo/sensor.py | 50 ------------------- .../components/teleinfo/sensor/__init__.py | 26 ++++++++++ .../teleinfo/sensor/teleinfo_sensor.cpp | 14 ++++++ .../teleinfo/sensor/teleinfo_sensor.h | 16 ++++++ esphome/components/teleinfo/teleinfo.cpp | 17 +++---- esphome/components/teleinfo/teleinfo.h | 13 +++-- .../teleinfo/text_sensor/__init__.py | 28 +++++++++++ .../text_sensor/teleinfo_text_sensor.cpp | 11 ++++ .../text_sensor/teleinfo_text_sensor.h | 13 +++++ tests/test1.yaml | 35 ++++++------- 11 files changed, 163 insertions(+), 87 deletions(-) delete mode 100644 esphome/components/teleinfo/sensor.py create mode 100644 esphome/components/teleinfo/sensor/__init__.py create mode 100644 esphome/components/teleinfo/sensor/teleinfo_sensor.cpp create mode 100644 esphome/components/teleinfo/sensor/teleinfo_sensor.h create mode 100644 esphome/components/teleinfo/text_sensor/__init__.py create mode 100644 esphome/components/teleinfo/text_sensor/teleinfo_text_sensor.cpp create mode 100644 esphome/components/teleinfo/text_sensor/teleinfo_text_sensor.h diff --git a/esphome/components/teleinfo/__init__.py b/esphome/components/teleinfo/__init__.py index 2e279e892e..d7bf8999ef 100644 --- a/esphome/components/teleinfo/__init__.py +++ b/esphome/components/teleinfo/__init__.py @@ -1 +1,28 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import uart +from esphome.const import CONF_ID + CODEOWNERS = ["@0hax"] + +teleinfo_ns = cg.esphome_ns.namespace("teleinfo") +TeleInfo = teleinfo_ns.class_("TeleInfo", cg.PollingComponent, uart.UARTDevice) +CONF_TELEINFO_ID = "teleinfo_id" + +CONF_HISTORICAL_MODE = "historical_mode" +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(TeleInfo), + cv.Optional(CONF_HISTORICAL_MODE, default=False): cv.boolean, + } + ) + .extend(cv.polling_component_schema("60s")) + .extend(uart.UART_DEVICE_SCHEMA) +) + + +def to_code(config): + var = cg.new_Pvariable(config[CONF_ID], config[CONF_HISTORICAL_MODE]) + yield cg.register_component(var, config) + yield uart.register_uart_device(var, config) diff --git a/esphome/components/teleinfo/sensor.py b/esphome/components/teleinfo/sensor.py deleted file mode 100644 index d8b4dbade7..0000000000 --- a/esphome/components/teleinfo/sensor.py +++ /dev/null @@ -1,50 +0,0 @@ -import esphome.codegen as cg -import esphome.config_validation as cv -from esphome.components import sensor, uart -from esphome.const import ( - CONF_ID, - CONF_SENSOR, - DEVICE_CLASS_POWER, - ICON_EMPTY, - UNIT_WATT_HOURS, -) - -DEPENDENCIES = ["uart"] - -teleinfo_ns = cg.esphome_ns.namespace("teleinfo") -TeleInfo = teleinfo_ns.class_("TeleInfo", cg.PollingComponent, uart.UARTDevice) - -CONF_TAG_NAME = "tag_name" -TELEINFO_TAG_SCHEMA = cv.Schema( - { - cv.Required(CONF_TAG_NAME): cv.string, - cv.Required(CONF_SENSOR): sensor.sensor_schema( - UNIT_WATT_HOURS, ICON_EMPTY, 0, DEVICE_CLASS_POWER - ), - } -) - -CONF_TAGS = "tags" -CONF_HISTORICAL_MODE = "historical_mode" -CONFIG_SCHEMA = ( - cv.Schema( - { - cv.GenerateID(): cv.declare_id(TeleInfo), - cv.Optional(CONF_HISTORICAL_MODE, default=False): cv.boolean, - cv.Optional(CONF_TAGS): cv.ensure_list(TELEINFO_TAG_SCHEMA), - } - ) - .extend(cv.polling_component_schema("60s")) - .extend(uart.UART_DEVICE_SCHEMA) -) - - -async def to_code(config): - var = cg.new_Pvariable(config[CONF_ID], config[CONF_HISTORICAL_MODE]) - await cg.register_component(var, config) - await uart.register_uart_device(var, config) - - if CONF_TAGS in config: - for tag in config[CONF_TAGS]: - sens = await sensor.new_sensor(tag[CONF_SENSOR]) - cg.add(var.register_teleinfo_sensor(tag[CONF_TAG_NAME], sens)) diff --git a/esphome/components/teleinfo/sensor/__init__.py b/esphome/components/teleinfo/sensor/__init__.py new file mode 100644 index 0000000000..ffdb1509be --- /dev/null +++ b/esphome/components/teleinfo/sensor/__init__.py @@ -0,0 +1,26 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import sensor +from esphome.const import CONF_ID, ICON_FLASH, UNIT_WATT_HOURS + +from .. import teleinfo_ns, TeleInfo, CONF_TELEINFO_ID + +CONF_TAG_NAME = "tag_name" + +TeleInfoSensor = teleinfo_ns.class_("TeleInfoSensor", sensor.Sensor, cg.Component) + +CONFIG_SCHEMA = sensor.sensor_schema(UNIT_WATT_HOURS, ICON_FLASH, 0).extend( + { + cv.GenerateID(): cv.declare_id(TeleInfoSensor), + cv.GenerateID(CONF_TELEINFO_ID): cv.use_id(TeleInfo), + cv.Required(CONF_TAG_NAME): cv.string, + } +) + + +def to_code(config): + var = cg.new_Pvariable(config[CONF_ID], config[CONF_TAG_NAME]) + yield cg.register_component(var, config) + yield sensor.register_sensor(var, config) + teleinfo = yield cg.get_variable(config[CONF_TELEINFO_ID]) + cg.add(teleinfo.register_teleinfo_listener(var)) diff --git a/esphome/components/teleinfo/sensor/teleinfo_sensor.cpp b/esphome/components/teleinfo/sensor/teleinfo_sensor.cpp new file mode 100644 index 0000000000..c00bf8f441 --- /dev/null +++ b/esphome/components/teleinfo/sensor/teleinfo_sensor.cpp @@ -0,0 +1,14 @@ +#include "esphome/core/log.h" +#include "teleinfo_sensor.h" +namespace esphome { +namespace teleinfo { + +static const char *TAG = "teleinfo_sensor"; +TeleInfoSensor::TeleInfoSensor(const char *tag) { this->tag = std::string(tag); } +void TeleInfoSensor::publish_val(std::string val) { + auto newval = parse_float(val); + publish_state(*newval); +} +void TeleInfoSensor::dump_config() { LOG_SENSOR(" ", tag.c_str(), this); } +} // namespace teleinfo +} // namespace esphome diff --git a/esphome/components/teleinfo/sensor/teleinfo_sensor.h b/esphome/components/teleinfo/sensor/teleinfo_sensor.h new file mode 100644 index 0000000000..de46cbfd1a --- /dev/null +++ b/esphome/components/teleinfo/sensor/teleinfo_sensor.h @@ -0,0 +1,16 @@ +#pragma once +#include "esphome/components/teleinfo/teleinfo.h" +#include "esphome/components/sensor/sensor.h" + +namespace esphome { +namespace teleinfo { + +class TeleInfoSensor : public TeleInfoListener, public sensor::Sensor, public Component { + public: + TeleInfoSensor(const char *tag); + void publish_val(std::string val) override; + void dump_config() override; +}; + +} // namespace teleinfo +} // namespace esphome diff --git a/esphome/components/teleinfo/teleinfo.cpp b/esphome/components/teleinfo/teleinfo.cpp index 7c0a83d103..bd233c9595 100644 --- a/esphome/components/teleinfo/teleinfo.cpp +++ b/esphome/components/teleinfo/teleinfo.cpp @@ -149,16 +149,14 @@ void TeleInfo::loop() { } } void TeleInfo::publish_value_(std::string tag, std::string val) { - /* It will return 0 if tag is not a float. */ - auto newval = parse_float(val); - for (auto element : teleinfo_sensors_) - if (tag == element->tag) - element->sensor->publish_state(*newval); + for (auto element : teleinfo_listeners_) { + if (tag != element->tag) + continue; + element->publish_val(val); + } } void TeleInfo::dump_config() { ESP_LOGCONFIG(TAG, "TeleInfo:"); - for (auto element : teleinfo_sensors_) - LOG_SENSOR(" ", element->tag, element->sensor); this->check_uart_settings(baud_rate_, 1, uart::UART_CONFIG_PARITY_EVEN, 7); } TeleInfo::TeleInfo(bool historical_mode) { @@ -175,10 +173,7 @@ TeleInfo::TeleInfo(bool historical_mode) { baud_rate_ = 9600; } } -void TeleInfo::register_teleinfo_sensor(const char *tag, sensor::Sensor *sensor) { - const TeleinfoSensorElement *teleinfo_sensor = new TeleinfoSensorElement{tag, sensor}; - teleinfo_sensors_.push_back(teleinfo_sensor); -} +void TeleInfo::register_teleinfo_listener(TeleInfoListener *listener) { teleinfo_listeners_.push_back(listener); } } // namespace teleinfo } // namespace esphome diff --git a/esphome/components/teleinfo/teleinfo.h b/esphome/components/teleinfo/teleinfo.h index de9cf646c4..3932c4758e 100644 --- a/esphome/components/teleinfo/teleinfo.h +++ b/esphome/components/teleinfo/teleinfo.h @@ -1,7 +1,6 @@ #pragma once #include "esphome/core/component.h" -#include "esphome/components/sensor/sensor.h" #include "esphome/components/uart/uart.h" namespace esphome { @@ -14,20 +13,20 @@ static const uint8_t MAX_TAG_SIZE = 64; static const uint16_t MAX_VAL_SIZE = 256; static const uint16_t MAX_BUF_SIZE = 1024; -struct TeleinfoSensorElement { - const char *tag; - sensor::Sensor *sensor; +class TeleInfoListener { + public: + std::string tag; + virtual void publish_val(std::string val){}; }; - class TeleInfo : public PollingComponent, public uart::UARTDevice { public: TeleInfo(bool historical_mode); - void register_teleinfo_sensor(const char *tag, sensor::Sensor *sensors); + void register_teleinfo_listener(TeleInfoListener *listener); void loop() override; void setup() override; void update() override; void dump_config() override; - std::vector teleinfo_sensors_{}; + std::vector teleinfo_listeners_{}; protected: uint32_t baud_rate_; diff --git a/esphome/components/teleinfo/text_sensor/__init__.py b/esphome/components/teleinfo/text_sensor/__init__.py new file mode 100644 index 0000000000..b1ade4df41 --- /dev/null +++ b/esphome/components/teleinfo/text_sensor/__init__.py @@ -0,0 +1,28 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import text_sensor +from esphome.const import CONF_ID + +from .. import teleinfo_ns, TeleInfo, CONF_TELEINFO_ID + +CONF_TAG_NAME = "tag_name" + +TeleInfoTextSensor = teleinfo_ns.class_( + "TeleInfoTextSensor", text_sensor.TextSensor, cg.Component +) + +CONFIG_SCHEMA = text_sensor.TEXT_SENSOR_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(TeleInfoTextSensor), + cv.GenerateID(CONF_TELEINFO_ID): cv.use_id(TeleInfo), + cv.Required(CONF_TAG_NAME): cv.string, + } +) + + +def to_code(config): + var = cg.new_Pvariable(config[CONF_ID], config[CONF_TAG_NAME]) + yield cg.register_component(var, config) + yield text_sensor.register_text_sensor(var, config) + teleinfo = yield cg.get_variable(config[CONF_TELEINFO_ID]) + cg.add(teleinfo.register_teleinfo_listener(var)) diff --git a/esphome/components/teleinfo/text_sensor/teleinfo_text_sensor.cpp b/esphome/components/teleinfo/text_sensor/teleinfo_text_sensor.cpp new file mode 100644 index 0000000000..ac48aeabbd --- /dev/null +++ b/esphome/components/teleinfo/text_sensor/teleinfo_text_sensor.cpp @@ -0,0 +1,11 @@ +#include "esphome/core/log.h" +#include "teleinfo_text_sensor.h" +namespace esphome { +namespace teleinfo { + +static const char *TAG = "teleinfo_text_sensor"; +TeleInfoTextSensor::TeleInfoTextSensor(const char *tag) { this->tag = std::string(tag); } +void TeleInfoTextSensor::publish_val(std::string val) { publish_state(val); } +void TeleInfoTextSensor::dump_config() { LOG_TEXT_SENSOR(" ", tag.c_str(), this); } +} // namespace teleinfo +} // namespace esphome diff --git a/esphome/components/teleinfo/text_sensor/teleinfo_text_sensor.h b/esphome/components/teleinfo/text_sensor/teleinfo_text_sensor.h new file mode 100644 index 0000000000..be355151ce --- /dev/null +++ b/esphome/components/teleinfo/text_sensor/teleinfo_text_sensor.h @@ -0,0 +1,13 @@ +#pragma once +#include "esphome/components/teleinfo/teleinfo.h" +#include "esphome/components/text_sensor/text_sensor.h" +namespace esphome { +namespace teleinfo { +class TeleInfoTextSensor : public TeleInfoListener, public text_sensor::TextSensor, public Component { + public: + TeleInfoTextSensor(const char *tag); + void publish_val(std::string val) override; + void dump_config() override; +}; +} // namespace teleinfo +} // namespace esphome diff --git a/tests/test1.yaml b/tests/test1.yaml index 31bfc5e9f0..98e7292091 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -888,25 +888,11 @@ sensor: name: 'AQI' calculation_type: 'CAQI' - platform: teleinfo - uart_id: uart0 - tags: - - tag_name: 'HCHC' - sensor: - name: 'hchc' - unit_of_measurement: 'Wh' - icon: mdi:flash - - tag_name: 'HCHP' - sensor: - name: 'hchp' - unit_of_measurement: 'Wh' - icon: mdi:flash - - tag_name: 'PAPP' - sensor: - name: 'papp' - unit_of_measurement: 'VA' - icon: mdi:flash - update_interval: 60s - historical_mode: true + tag_name: "HCHC" + name: "hchc" + unit_of_measurement: "Wh" + icon: mdi:flash + teleinfo_id: myteleinfo - platform: mcp9808 name: 'MCP9808 Temperature' update_interval: 15s @@ -1975,6 +1961,7 @@ display: row_start: 0 lambda: |- it.rectangle(0, 0, it.get_width(), it.get_height()); + tm1651: id: tm1651_battery clk_pin: GPIO23 @@ -2163,6 +2150,10 @@ text_sensor: - platform: version name: 'ESPHome Version No Timestamp' hide_timestamp: True + - platform: teleinfo + tag_name: "OPTARIF" + name: "optarif" + teleinfo_id: myteleinfo sn74hc595: - id: 'sn74hc595_hub' @@ -2193,3 +2184,9 @@ canbus: lambda: 'return x[0] == 0x11;' then: light.toggle: ${roomname}_lights + +teleinfo: + id: myteleinfo + uart_id: uart0 + update_interval: 60s + historical_mode: true From a3756a960037678e92210e7766cc52f1c5c8dd5f Mon Sep 17 00:00:00 2001 From: buxtronix Date: Tue, 1 Jun 2021 17:56:05 +1000 Subject: [PATCH 077/104] Copy missing BLE client characteristic read data (#1818) Co-authored-by: Ben Buxton --- esphome/components/esp32_ble_tracker/queue.h | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/esphome/components/esp32_ble_tracker/queue.h b/esphome/components/esp32_ble_tracker/queue.h index 6f36cf874d..17adb98034 100644 --- a/esphome/components/esp32_ble_tracker/queue.h +++ b/esphome/components/esp32_ble_tracker/queue.h @@ -66,10 +66,19 @@ class BLEEvent { this->event_.gattc.gattc_event = e; this->event_.gattc.gattc_if = i; memcpy(&this->event_.gattc.gattc_param, p, sizeof(esp_ble_gattc_cb_param_t)); - // Need to also make a copy of notify event data. - if (e == ESP_GATTC_NOTIFY_EVT) { - memcpy(this->event_.gattc.notify_data, p->notify.value, p->notify.value_len); - this->event_.gattc.gattc_param.notify.value = this->event_.gattc.notify_data; + // Need to also make a copy of relevant event data. + switch (e) { + case ESP_GATTC_NOTIFY_EVT: + memcpy(this->event_.gattc.data, p->notify.value, p->notify.value_len); + this->event_.gattc.gattc_param.notify.value = this->event_.gattc.data; + break; + case ESP_GATTC_READ_CHAR_EVT: + case ESP_GATTC_READ_DESCR_EVT: + memcpy(this->event_.gattc.data, p->read.value, p->read.value_len); + this->event_.gattc.gattc_param.read.value = this->event_.gattc.data; + break; + default: + break; } this->type_ = 1; }; @@ -84,7 +93,7 @@ class BLEEvent { esp_gattc_cb_event_t gattc_event; esp_gatt_if_t gattc_if; esp_ble_gattc_cb_param_t gattc_param; - uint8_t notify_data[64]; + uint8_t data[64]; } gattc; } event_; uint8_t type_; // 0=gap 1=gattc From f39c0d52eeebc021aed2a480ef23cda6a6aa2df4 Mon Sep 17 00:00:00 2001 From: zaluthar Date: Tue, 1 Jun 2021 10:26:38 +0200 Subject: [PATCH 078/104] Added support for Xiaomi CGDK2 (#1451) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/xiaomi_ble/xiaomi_ble.cpp | 3 + esphome/components/xiaomi_ble/xiaomi_ble.h | 1 + esphome/components/xiaomi_cgdk2/__init__.py | 0 esphome/components/xiaomi_cgdk2/sensor.py | 65 ++++++++++++++++ .../components/xiaomi_cgdk2/xiaomi_cgdk2.cpp | 77 +++++++++++++++++++ .../components/xiaomi_cgdk2/xiaomi_cgdk2.h | 36 +++++++++ 6 files changed, 182 insertions(+) create mode 100644 esphome/components/xiaomi_cgdk2/__init__.py create mode 100644 esphome/components/xiaomi_cgdk2/sensor.py create mode 100644 esphome/components/xiaomi_cgdk2/xiaomi_cgdk2.cpp create mode 100644 esphome/components/xiaomi_cgdk2/xiaomi_cgdk2.h diff --git a/esphome/components/xiaomi_ble/xiaomi_ble.cpp b/esphome/components/xiaomi_ble/xiaomi_ble.cpp index 29a34be81c..5806ceb72b 100644 --- a/esphome/components/xiaomi_ble/xiaomi_ble.cpp +++ b/esphome/components/xiaomi_ble/xiaomi_ble.cpp @@ -189,6 +189,9 @@ optional parse_xiaomi_header(const esp32_ble_tracker::Service } else if ((raw[2] == 0x76) && (raw[3] == 0x05)) { // Cleargrass (Qingping) alarm clock, segment LCD result.type = XiaomiParseResult::TYPE_CGD1; result.name = "CGD1"; + } else if ((raw[2] == 0x6F) && (raw[3] == 0x06)) { // Cleargrass (Qingping) Temp & RH Lite + result.type = XiaomiParseResult::TYPE_CGDK2; + result.name = "CGDK2"; } else if ((raw[2] == 0x5b) && (raw[3] == 0x05)) { // small square body, segment LCD, encrypted result.type = XiaomiParseResult::TYPE_LYWSD03MMC; result.name = "LYWSD03MMC"; diff --git a/esphome/components/xiaomi_ble/xiaomi_ble.h b/esphome/components/xiaomi_ble/xiaomi_ble.h index 3973dac80f..f431eca11e 100644 --- a/esphome/components/xiaomi_ble/xiaomi_ble.h +++ b/esphome/components/xiaomi_ble/xiaomi_ble.h @@ -18,6 +18,7 @@ struct XiaomiParseResult { TYPE_CGG1, TYPE_LYWSD03MMC, TYPE_CGD1, + TYPE_CGDK2, TYPE_JQJCY01YM, TYPE_MUE4094RT, TYPE_WX08ZM, diff --git a/esphome/components/xiaomi_cgdk2/__init__.py b/esphome/components/xiaomi_cgdk2/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/xiaomi_cgdk2/sensor.py b/esphome/components/xiaomi_cgdk2/sensor.py new file mode 100644 index 0000000000..50509b7af7 --- /dev/null +++ b/esphome/components/xiaomi_cgdk2/sensor.py @@ -0,0 +1,65 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import sensor, esp32_ble_tracker +from esphome.const import ( + CONF_BATTERY_LEVEL, + CONF_HUMIDITY, + CONF_MAC_ADDRESS, + CONF_TEMPERATURE, + DEVICE_CLASS_BATTERY, + DEVICE_CLASS_HUMIDITY, + DEVICE_CLASS_TEMPERATURE, + ICON_EMPTY, + UNIT_CELSIUS, + UNIT_PERCENT, + CONF_ID, + CONF_BINDKEY, +) + +DEPENDENCIES = ["esp32_ble_tracker"] +AUTO_LOAD = ["xiaomi_ble"] + +xiaomi_cgd1_ns = cg.esphome_ns.namespace("xiaomi_cgdk2") +XiaomiCGD1 = xiaomi_cgd1_ns.class_( + "XiaomiCGDK2", esp32_ble_tracker.ESPBTDeviceListener, cg.Component +) + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(XiaomiCGD1), + cv.Required(CONF_BINDKEY): cv.bind_key, + cv.Required(CONF_MAC_ADDRESS): cv.mac_address, + cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( + UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE + ), + cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( + UNIT_PERCENT, ICON_EMPTY, 1, DEVICE_CLASS_HUMIDITY + ), + cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema( + UNIT_PERCENT, ICON_EMPTY, 0, DEVICE_CLASS_BATTERY + ), + } + ) + .extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA) + .extend(cv.COMPONENT_SCHEMA) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await esp32_ble_tracker.register_ble_device(var, config) + + cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) + cg.add(var.set_bindkey(config[CONF_BINDKEY])) + + if CONF_TEMPERATURE in config: + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) + cg.add(var.set_temperature(sens)) + if CONF_HUMIDITY in config: + sens = await sensor.new_sensor(config[CONF_HUMIDITY]) + cg.add(var.set_humidity(sens)) + if CONF_BATTERY_LEVEL in config: + sens = await sensor.new_sensor(config[CONF_BATTERY_LEVEL]) + cg.add(var.set_battery_level(sens)) diff --git a/esphome/components/xiaomi_cgdk2/xiaomi_cgdk2.cpp b/esphome/components/xiaomi_cgdk2/xiaomi_cgdk2.cpp new file mode 100644 index 0000000000..cd18c12afc --- /dev/null +++ b/esphome/components/xiaomi_cgdk2/xiaomi_cgdk2.cpp @@ -0,0 +1,77 @@ +#include "xiaomi_cgdk2.h" +#include "esphome/core/log.h" + +#ifdef ARDUINO_ARCH_ESP32 + +namespace esphome { +namespace xiaomi_cgdk2 { + +static const char *TAG = "xiaomi_cgdk2"; + +void XiaomiCGDK2::dump_config() { + ESP_LOGCONFIG(TAG, "Xiaomi CGDK2"); + ESP_LOGCONFIG(TAG, " Bindkey: %s", hexencode(this->bindkey_, 16).c_str()); + LOG_SENSOR(" ", "Temperature", this->temperature_); + LOG_SENSOR(" ", "Humidity", this->humidity_); + LOG_SENSOR(" ", "Battery Level", this->battery_level_); +} + +bool XiaomiCGDK2::parse_device(const esp32_ble_tracker::ESPBTDevice &device) { + if (device.address_uint64() != this->address_) { + ESP_LOGVV(TAG, "parse_device(): unknown MAC address."); + return false; + } + ESP_LOGV(TAG, "parse_device(): MAC address %s found.", device.address_str().c_str()); + + bool success = false; + for (auto &service_data : device.get_service_datas()) { + auto res = xiaomi_ble::parse_xiaomi_header(service_data); + if (!res.has_value()) { + continue; + } + if (res->is_duplicate) { + continue; + } + if (res->has_encryption && + (!(xiaomi_ble::decrypt_xiaomi_payload(const_cast &>(service_data.data), this->bindkey_, + this->address_)))) { + continue; + } + if (!(xiaomi_ble::parse_xiaomi_message(service_data.data, *res))) { + continue; + } + if (!(xiaomi_ble::report_xiaomi_results(res, device.address_str()))) { + continue; + } + if (res->temperature.has_value() && this->temperature_ != nullptr) + this->temperature_->publish_state(*res->temperature); + if (res->humidity.has_value() && this->humidity_ != nullptr) + this->humidity_->publish_state(*res->humidity); + if (res->battery_level.has_value() && this->battery_level_ != nullptr) + this->battery_level_->publish_state(*res->battery_level); + success = true; + } + + if (!success) { + return false; + } + + return true; +} + +void XiaomiCGDK2::set_bindkey(const std::string &bindkey) { + memset(bindkey_, 0, 16); + if (bindkey.size() != 32) { + return; + } + char temp[3] = {0}; + for (int i = 0; i < 16; i++) { + strncpy(temp, &(bindkey.c_str()[i * 2]), 2); + bindkey_[i] = std::strtoul(temp, NULL, 16); + } +} + +} // namespace xiaomi_cgdk2 +} // namespace esphome + +#endif diff --git a/esphome/components/xiaomi_cgdk2/xiaomi_cgdk2.h b/esphome/components/xiaomi_cgdk2/xiaomi_cgdk2.h new file mode 100644 index 0000000000..70f2ae9e2e --- /dev/null +++ b/esphome/components/xiaomi_cgdk2/xiaomi_cgdk2.h @@ -0,0 +1,36 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h" +#include "esphome/components/xiaomi_ble/xiaomi_ble.h" + +#ifdef ARDUINO_ARCH_ESP32 + +namespace esphome { +namespace xiaomi_cgdk2 { + +class XiaomiCGDK2 : public Component, public esp32_ble_tracker::ESPBTDeviceListener { + public: + void set_address(uint64_t address) { address_ = address; }; + void set_bindkey(const std::string &bindkey); + + bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override; + void dump_config() override; + float get_setup_priority() const override { return setup_priority::DATA; } + void set_temperature(sensor::Sensor *temperature) { temperature_ = temperature; } + void set_humidity(sensor::Sensor *humidity) { humidity_ = humidity; } + void set_battery_level(sensor::Sensor *battery_level) { battery_level_ = battery_level; } + + protected: + uint64_t address_; + uint8_t bindkey_[16]; + sensor::Sensor *temperature_{nullptr}; + sensor::Sensor *humidity_{nullptr}; + sensor::Sensor *battery_level_{nullptr}; +}; + +} // namespace xiaomi_cgdk2 +} // namespace esphome + +#endif From 7b112840082eda7f393f65e1e23d9feb316dd232 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 1 Jun 2021 21:12:41 +1200 Subject: [PATCH 079/104] Fix ble client esp_gatt_if comparison (#1852) --- esphome/components/ble_client/ble_client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/ble_client/ble_client.cpp b/esphome/components/ble_client/ble_client.cpp index 3819a6e560..f12d3a21c9 100644 --- a/esphome/components/ble_client/ble_client.cpp +++ b/esphome/components/ble_client/ble_client.cpp @@ -94,7 +94,7 @@ void BLEClient::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t es esp_ble_gattc_cb_param_t *param) { if (event == ESP_GATTC_REG_EVT && this->app_id != param->reg.app_id) return; - if (event != ESP_GATTC_REG_EVT && esp_gattc_if != ESP_GATT_IF_NONE && gattc_if != this->gattc_if) + if (event != ESP_GATTC_REG_EVT && esp_gattc_if != ESP_GATT_IF_NONE && esp_gattc_if != this->gattc_if) return; bool all_established = this->all_nodes_established(); From f968713be863a7a2f16528c33646149f5389060f Mon Sep 17 00:00:00 2001 From: David Kiliani Date: Tue, 1 Jun 2021 11:46:54 +0200 Subject: [PATCH 080/104] Add optional lambda to BLESensor for raw data parsing (#1851) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/ble_client/sensor/__init__.py | 11 +++++++++++ esphome/components/ble_client/sensor/ble_sensor.cpp | 13 +++++++++++-- esphome/components/ble_client/sensor/ble_sensor.h | 5 +++++ tests/test1.yaml | 3 +++ 4 files changed, 30 insertions(+), 2 deletions(-) diff --git a/esphome/components/ble_client/sensor/__init__.py b/esphome/components/ble_client/sensor/__init__.py index a7ab0acd73..a0bc996d87 100644 --- a/esphome/components/ble_client/sensor/__init__.py +++ b/esphome/components/ble_client/sensor/__init__.py @@ -4,6 +4,7 @@ from esphome.components import sensor, ble_client, esp32_ble_tracker from esphome.const import ( DEVICE_CLASS_EMPTY, CONF_ID, + CONF_LAMBDA, UNIT_EMPTY, ICON_EMPTY, CONF_TRIGGER_ID, @@ -20,6 +21,9 @@ CONF_DESCRIPTOR_UUID = "descriptor_uuid" CONF_NOTIFY = "notify" CONF_ON_NOTIFY = "on_notify" +adv_data_t = cg.std_vector.template(cg.uint8) +adv_data_t_const_ref = adv_data_t.operator("ref").operator("const") + BLESensor = ble_client_ns.class_( "BLESensor", sensor.Sensor, cg.PollingComponent, ble_client.BLEClientNode ) @@ -35,6 +39,7 @@ CONFIG_SCHEMA = cv.All( cv.Required(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid, cv.Required(CONF_CHARACTERISTIC_UUID): esp32_ble_tracker.bt_uuid, cv.Optional(CONF_DESCRIPTOR_UUID): esp32_ble_tracker.bt_uuid, + cv.Optional(CONF_LAMBDA): cv.returning_lambda, cv.Optional(CONF_NOTIFY, default=False): cv.boolean, cv.Optional(CONF_ON_NOTIFY): automation.validate_automation( { @@ -105,6 +110,12 @@ async def to_code(config): uuid128 = esp32_ble_tracker.as_hex_array(config[CONF_DESCRIPTOR_UUID]) cg.add(var.set_descr_uuid128(uuid128)) + if CONF_LAMBDA in config: + lambda_ = await cg.process_lambda( + config[CONF_LAMBDA], [(adv_data_t_const_ref, "x")], return_type=cg.float_ + ) + cg.add(var.set_data_to_value(lambda_)) + await cg.register_component(var, config) await ble_client.register_ble_node(var, config) cg.add(var.set_enable_notify(config[CONF_NOTIFY])) diff --git a/esphome/components/ble_client/sensor/ble_sensor.cpp b/esphome/components/ble_client/sensor/ble_sensor.cpp index ef1d6c120f..69a4b23313 100644 --- a/esphome/components/ble_client/sensor/ble_sensor.cpp +++ b/esphome/components/ble_client/sensor/ble_sensor.cpp @@ -84,7 +84,7 @@ void BLESensor::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t ga } if (param->read.handle == this->handle) { this->status_clear_warning(); - this->publish_state((float) param->read.value[0]); + this->publish_state(this->parse_data(param->read.value, param->read.value_len)); } break; } @@ -93,7 +93,7 @@ void BLESensor::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t ga break; ESP_LOGV(TAG, "[%s] ESP_GATTC_NOTIFY_EVT: handle=0x%x, value=0x%x", this->get_name().c_str(), param->notify.handle, param->notify.value[0]); - this->publish_state((float) param->notify.value[0]); + this->publish_state(this->parse_data(param->notify.value, param->notify.value_len)); break; } case ESP_GATTC_REG_FOR_NOTIFY_EVT: { @@ -105,6 +105,15 @@ void BLESensor::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t ga } } +float BLESensor::parse_data(uint8_t *value, uint16_t value_len) { + if (this->data_to_value_func_.has_value()) { + std::vector data(value, value + value_len); + return (*this->data_to_value_func_)(data); + } else { + return value[0]; + } +} + void BLESensor::update() { if (this->node_state != espbt::ClientState::Established) { ESP_LOGW(TAG, "[%s] Cannot poll, not connected", this->get_name().c_str()); diff --git a/esphome/components/ble_client/sensor/ble_sensor.h b/esphome/components/ble_client/sensor/ble_sensor.h index e3a8a8ea25..25e996b6ee 100644 --- a/esphome/components/ble_client/sensor/ble_sensor.h +++ b/esphome/components/ble_client/sensor/ble_sensor.h @@ -13,6 +13,8 @@ namespace ble_client { namespace espbt = esphome::esp32_ble_tracker; +using data_to_value_t = std::function)>; + class BLESensor : public sensor::Sensor, public PollingComponent, public BLEClientNode { public: void loop() override; @@ -30,11 +32,14 @@ class BLESensor : public sensor::Sensor, public PollingComponent, public BLEClie void set_descr_uuid16(uint16_t uuid) { this->descr_uuid_ = espbt::ESPBTUUID::from_uint16(uuid); } void set_descr_uuid32(uint32_t uuid) { this->descr_uuid_ = espbt::ESPBTUUID::from_uint32(uuid); } void set_descr_uuid128(uint8_t *uuid) { this->descr_uuid_ = espbt::ESPBTUUID::from_raw(uuid); } + void set_data_to_value(data_to_value_t &&lambda_) { this->data_to_value_func_ = lambda_; } void set_enable_notify(bool notify) { this->notify_ = notify; } uint16_t handle; protected: uint32_t hash_base() override; + float parse_data(uint8_t *value, uint16_t value_len); + optional data_to_value_func_{}; bool notify_; espbt::ESPBTUUID service_uuid_; espbt::ESPBTUUID char_uuid_; diff --git a/tests/test1.yaml b/tests/test1.yaml index 98e7292091..e9e89defd3 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -271,6 +271,9 @@ sensor: descriptor_uuid: 'ffe2' notify: true update_interval: never + lambda: |- + ESP_LOGD("main", "Length of data is %i", x.size()); + return x[0]; on_notify: then: - lambda: |- From c3938d04f3b1c01afc8d69c498793072687a9aa6 Mon Sep 17 00:00:00 2001 From: Ryan Mounce Date: Wed, 2 Jun 2021 07:02:16 +0930 Subject: [PATCH 081/104] Support Tuya light color temperature control (#1412) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/tuya/light/__init__.py | 28 ++++++++++++++++++++ esphome/components/tuya/light/tuya_light.cpp | 25 +++++++++++++++++ esphome/components/tuya/light/tuya_light.h | 14 ++++++++++ tests/test4.yaml | 11 ++++++++ 4 files changed, 78 insertions(+) diff --git a/esphome/components/tuya/light/__init__.py b/esphome/components/tuya/light/__init__.py index 6dd8b6b775..979082d636 100644 --- a/esphome/components/tuya/light/__init__.py +++ b/esphome/components/tuya/light/__init__.py @@ -8,6 +8,8 @@ from esphome.const import ( CONF_GAMMA_CORRECT, CONF_DEFAULT_TRANSITION_LENGTH, CONF_SWITCH_DATAPOINT, + CONF_COLD_WHITE_COLOR_TEMPERATURE, + CONF_WARM_WHITE_COLOR_TEMPERATURE, ) from .. import tuya_ns, CONF_TUYA_ID, Tuya @@ -15,6 +17,8 @@ DEPENDENCIES = ["tuya"] CONF_DIMMER_DATAPOINT = "dimmer_datapoint" CONF_MIN_VALUE_DATAPOINT = "min_value_datapoint" +CONF_COLOR_TEMPERATURE_DATAPOINT = "color_temperature_datapoint" +CONF_COLOR_TEMPERATURE_MAX_VALUE = "color_temperature_max_value" TuyaLight = tuya_ns.class_("TuyaLight", light.LightOutput, cg.Component) @@ -26,8 +30,18 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_DIMMER_DATAPOINT): cv.uint8_t, cv.Optional(CONF_MIN_VALUE_DATAPOINT): cv.uint8_t, cv.Optional(CONF_SWITCH_DATAPOINT): cv.uint8_t, + cv.Inclusive( + CONF_COLOR_TEMPERATURE_DATAPOINT, "color_temperature" + ): cv.uint8_t, cv.Optional(CONF_MIN_VALUE): cv.int_, cv.Optional(CONF_MAX_VALUE): cv.int_, + cv.Optional(CONF_COLOR_TEMPERATURE_MAX_VALUE): cv.int_, + cv.Inclusive( + CONF_COLD_WHITE_COLOR_TEMPERATURE, "color_temperature" + ): cv.color_temperature, + cv.Inclusive( + CONF_WARM_WHITE_COLOR_TEMPERATURE, "color_temperature" + ): cv.color_temperature, # Change the default gamma_correct and default transition length settings. # The Tuya MCU handles transitions and gamma correction on its own. cv.Optional(CONF_GAMMA_CORRECT, default=1.0): cv.positive_float, @@ -51,9 +65,23 @@ async def to_code(config): cg.add(var.set_min_value_datapoint_id(config[CONF_MIN_VALUE_DATAPOINT])) if CONF_SWITCH_DATAPOINT in config: cg.add(var.set_switch_id(config[CONF_SWITCH_DATAPOINT])) + if CONF_COLOR_TEMPERATURE_DATAPOINT in config: + cg.add(var.set_color_temperature_id(config[CONF_COLOR_TEMPERATURE_DATAPOINT])) + cg.add( + var.set_cold_white_temperature(config[CONF_COLD_WHITE_COLOR_TEMPERATURE]) + ) + cg.add( + var.set_warm_white_temperature(config[CONF_WARM_WHITE_COLOR_TEMPERATURE]) + ) if CONF_MIN_VALUE in config: cg.add(var.set_min_value(config[CONF_MIN_VALUE])) if CONF_MAX_VALUE in config: cg.add(var.set_max_value(config[CONF_MAX_VALUE])) + if CONF_COLOR_TEMPERATURE_MAX_VALUE in config: + cg.add( + var.set_color_temperature_max_value( + config[CONF_COLOR_TEMPERATURE_MAX_VALUE] + ) + ) paren = await cg.get_variable(config[CONF_TUYA_ID]) cg.add(var.set_tuya_parent(paren)) diff --git a/esphome/components/tuya/light/tuya_light.cpp b/esphome/components/tuya/light/tuya_light.cpp index e7b44882a1..f03e66e150 100644 --- a/esphome/components/tuya/light/tuya_light.cpp +++ b/esphome/components/tuya/light/tuya_light.cpp @@ -7,6 +7,15 @@ namespace tuya { static const char *TAG = "tuya.light"; void TuyaLight::setup() { + if (this->color_temperature_id_.has_value()) { + this->parent_->register_listener(*this->color_temperature_id_, [this](TuyaDatapoint datapoint) { + auto call = this->state_->make_call(); + call.set_color_temperature(this->cold_white_temperature_ + + (this->warm_white_temperature_ - this->cold_white_temperature_) * + (float(datapoint.value_uint) / float(this->color_temperature_max_value_))); + call.perform(); + }); + } if (this->dimmer_id_.has_value()) { this->parent_->register_listener(*this->dimmer_id_, [this](TuyaDatapoint datapoint) { auto call = this->state_->make_call(); @@ -41,6 +50,11 @@ void TuyaLight::dump_config() { light::LightTraits TuyaLight::get_traits() { auto traits = light::LightTraits(); traits.set_supports_brightness(this->dimmer_id_.has_value()); + traits.set_supports_color_temperature(this->color_temperature_id_.has_value()); + if (this->color_temperature_id_.has_value()) { + traits.set_min_mireds(this->cold_white_temperature_); + traits.set_max_mireds(this->warm_white_temperature_); + } return traits; } @@ -69,6 +83,17 @@ void TuyaLight::write_state(light::LightState *state) { return; } + if (this->color_temperature_id_.has_value()) { + TuyaDatapoint datapoint{}; + datapoint.id = *this->color_temperature_id_; + datapoint.type = TuyaDatapointType::INTEGER; + datapoint.value_int = + static_cast(this->color_temperature_max_value_ * + (state->current_values.get_color_temperature() - this->cold_white_temperature_) / + (this->warm_white_temperature_ - this->cold_white_temperature_)); + parent_->set_datapoint_value(datapoint); + } + auto brightness_int = static_cast(brightness * this->max_value_); brightness_int = std::max(brightness_int, this->min_value_); diff --git a/esphome/components/tuya/light/tuya_light.h b/esphome/components/tuya/light/tuya_light.h index 896c0cc7ef..72422bc9e7 100644 --- a/esphome/components/tuya/light/tuya_light.h +++ b/esphome/components/tuya/light/tuya_light.h @@ -16,9 +16,19 @@ class TuyaLight : public Component, public light::LightOutput { this->min_value_datapoint_id_ = min_value_datapoint_id; } void set_switch_id(uint8_t switch_id) { this->switch_id_ = switch_id; } + void set_color_temperature_id(uint8_t color_temperature_id) { this->color_temperature_id_ = color_temperature_id; } void set_tuya_parent(Tuya *parent) { this->parent_ = parent; } void set_min_value(uint32_t min_value) { min_value_ = min_value; } void set_max_value(uint32_t max_value) { max_value_ = max_value; } + void set_color_temperature_max_value(uint32_t color_temperature_max_value) { + this->color_temperature_max_value_ = color_temperature_max_value; + } + void set_cold_white_temperature(float cold_white_temperature) { + this->cold_white_temperature_ = cold_white_temperature; + } + void set_warm_white_temperature(float warm_white_temperature) { + this->warm_white_temperature_ = warm_white_temperature; + } light::LightTraits get_traits() override; void setup_state(light::LightState *state) override; void write_state(light::LightState *state) override; @@ -31,8 +41,12 @@ class TuyaLight : public Component, public light::LightOutput { optional dimmer_id_{}; optional min_value_datapoint_id_{}; optional switch_id_{}; + optional color_temperature_id_{}; uint32_t min_value_ = 0; uint32_t max_value_ = 255; + uint32_t color_temperature_max_value_ = 255; + float cold_white_temperature_; + float warm_white_temperature_; light::LightState *state_{nullptr}; }; diff --git a/tests/test4.yaml b/tests/test4.yaml index 08213fab87..9e09f20449 100644 --- a/tests/test4.yaml +++ b/tests/test4.yaml @@ -133,6 +133,17 @@ light: rgb_order: GRB default_transition_length: 0s color_correct: [50%, 50%, 50%] + - platform: tuya + id: tuya_light + switch_datapoint: 1 + dimmer_datapoint: 2 + min_value_datapoint: 3 + color_temperature_datapoint: 4 + min_value: 1 + max_value: 100 + cold_white_color_temperature: 153 mireds + warm_white_color_temperature: 500 mireds + gamma_correct: 1 display: - platform: addressable_light From c5c24c198921f207b97a0ee91c2874cee7019697 Mon Sep 17 00:00:00 2001 From: Trevor North Date: Wed, 2 Jun 2021 10:31:56 +0100 Subject: [PATCH 082/104] Tuya improvements (#1491) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .../tuya/binary_sensor/tuya_binary_sensor.cpp | 2 +- esphome/components/tuya/climate/__init__.py | 41 ++- .../components/tuya/climate/tuya_climate.cpp | 91 +++---- .../components/tuya/climate/tuya_climate.h | 12 + esphome/components/tuya/fan/tuya_fan.cpp | 38 +-- esphome/components/tuya/light/tuya_light.cpp | 38 +-- .../components/tuya/sensor/tuya_sensor.cpp | 8 +- .../components/tuya/switch/tuya_switch.cpp | 11 +- esphome/components/tuya/tuya.cpp | 254 +++++++++++------- esphome/components/tuya/tuya.h | 12 +- esphome/core/util.cpp | 24 ++ esphome/core/util.h | 9 + 12 files changed, 321 insertions(+), 219 deletions(-) diff --git a/esphome/components/tuya/binary_sensor/tuya_binary_sensor.cpp b/esphome/components/tuya/binary_sensor/tuya_binary_sensor.cpp index ad3d18efae..6b2954a6a0 100644 --- a/esphome/components/tuya/binary_sensor/tuya_binary_sensor.cpp +++ b/esphome/components/tuya/binary_sensor/tuya_binary_sensor.cpp @@ -8,8 +8,8 @@ static const char *TAG = "tuya.binary_sensor"; void TuyaBinarySensor::setup() { this->parent_->register_listener(this->sensor_id_, [this](TuyaDatapoint datapoint) { + ESP_LOGV(TAG, "MCU reported binary sensor %u is: %s", datapoint.id, ONOFF(datapoint.value_bool)); this->publish_state(datapoint.value_bool); - ESP_LOGD(TAG, "MCU reported binary sensor is: %s", ONOFF(datapoint.value_bool)); }); } diff --git a/esphome/components/tuya/climate/__init__.py b/esphome/components/tuya/climate/__init__.py index a24ae23edc..06c80964ee 100644 --- a/esphome/components/tuya/climate/__init__.py +++ b/esphome/components/tuya/climate/__init__.py @@ -1,12 +1,20 @@ from esphome.components import climate import esphome.config_validation as cv import esphome.codegen as cg -from esphome.const import CONF_ID, CONF_SWITCH_DATAPOINT +from esphome.const import ( + CONF_ID, + CONF_SWITCH_DATAPOINT, + CONF_SUPPORTS_COOL, + CONF_SUPPORTS_HEAT, +) from .. import tuya_ns, CONF_TUYA_ID, Tuya DEPENDENCIES = ["tuya"] CODEOWNERS = ["@jesserockz"] +CONF_ACTIVE_STATE_DATAPOINT = "active_state_datapoint" +CONF_ACTIVE_STATE_HEATING_VALUE = "active_state_heating_value" +CONF_ACTIVE_STATE_COOLING_VALUE = "active_state_cooling_value" CONF_TARGET_TEMPERATURE_DATAPOINT = "target_temperature_datapoint" CONF_CURRENT_TEMPERATURE_DATAPOINT = "current_temperature_datapoint" CONF_TEMPERATURE_MULTIPLIER = "temperature_multiplier" @@ -59,12 +67,30 @@ def validate_temperature_multipliers(value): return value +def validate_active_state_values(value): + if CONF_ACTIVE_STATE_DATAPOINT not in value: + return value + if value[CONF_SUPPORTS_COOL] and CONF_ACTIVE_STATE_COOLING_VALUE not in value: + raise cv.Invalid( + ( + f"{CONF_ACTIVE_STATE_COOLING_VALUE} required if using " + f"{CONF_ACTIVE_STATE_DATAPOINT} and device supports cooling" + ) + ) + return value + + CONFIG_SCHEMA = cv.All( climate.CLIMATE_SCHEMA.extend( { cv.GenerateID(): cv.declare_id(TuyaClimate), cv.GenerateID(CONF_TUYA_ID): cv.use_id(Tuya), + cv.Optional(CONF_SUPPORTS_HEAT, default=True): cv.boolean, + cv.Optional(CONF_SUPPORTS_COOL, default=False): cv.boolean, cv.Optional(CONF_SWITCH_DATAPOINT): cv.uint8_t, + cv.Optional(CONF_ACTIVE_STATE_DATAPOINT): cv.uint8_t, + cv.Optional(CONF_ACTIVE_STATE_HEATING_VALUE, default=1): cv.uint8_t, + cv.Optional(CONF_ACTIVE_STATE_COOLING_VALUE): cv.uint8_t, cv.Optional(CONF_TARGET_TEMPERATURE_DATAPOINT): cv.uint8_t, cv.Optional(CONF_CURRENT_TEMPERATURE_DATAPOINT): cv.uint8_t, cv.Optional(CONF_TEMPERATURE_MULTIPLIER): cv.positive_float, @@ -74,6 +100,7 @@ CONFIG_SCHEMA = cv.All( ).extend(cv.COMPONENT_SCHEMA), cv.has_at_least_one_key(CONF_TARGET_TEMPERATURE_DATAPOINT, CONF_SWITCH_DATAPOINT), validate_temperature_multipliers, + validate_active_state_values, ) @@ -85,8 +112,20 @@ async def to_code(config): paren = await cg.get_variable(config[CONF_TUYA_ID]) cg.add(var.set_tuya_parent(paren)) + cg.add(var.set_supports_heat(config[CONF_SUPPORTS_HEAT])) + cg.add(var.set_supports_cool(config[CONF_SUPPORTS_COOL])) if CONF_SWITCH_DATAPOINT in config: cg.add(var.set_switch_id(config[CONF_SWITCH_DATAPOINT])) + if CONF_ACTIVE_STATE_DATAPOINT in config: + cg.add(var.set_active_state_id(config[CONF_ACTIVE_STATE_DATAPOINT])) + if CONF_ACTIVE_STATE_HEATING_VALUE in config: + cg.add( + var.set_active_state_heating_value(config[CONF_ACTIVE_STATE_HEATING_VALUE]) + ) + if CONF_ACTIVE_STATE_COOLING_VALUE in config: + cg.add( + var.set_active_state_cooling_value(config[CONF_ACTIVE_STATE_COOLING_VALUE]) + ) if CONF_TARGET_TEMPERATURE_DATAPOINT in config: cg.add(var.set_target_temperature_id(config[CONF_TARGET_TEMPERATURE_DATAPOINT])) if CONF_CURRENT_TEMPERATURE_DATAPOINT in config: diff --git a/esphome/components/tuya/climate/tuya_climate.cpp b/esphome/components/tuya/climate/tuya_climate.cpp index d1f6829e72..962d18a391 100644 --- a/esphome/components/tuya/climate/tuya_climate.cpp +++ b/esphome/components/tuya/climate/tuya_climate.cpp @@ -9,65 +9,67 @@ static const char *TAG = "tuya.climate"; void TuyaClimate::setup() { if (this->switch_id_.has_value()) { this->parent_->register_listener(*this->switch_id_, [this](TuyaDatapoint datapoint) { + ESP_LOGV(TAG, "MCU reported switch is: %s", ONOFF(datapoint.value_bool)); + this->mode = climate::CLIMATE_MODE_OFF; if (datapoint.value_bool) { - this->mode = climate::CLIMATE_MODE_HEAT; - } else { - this->mode = climate::CLIMATE_MODE_OFF; + if (this->supports_heat_ && this->supports_cool_) { + this->mode = climate::CLIMATE_MODE_AUTO; + } else if (this->supports_heat_) { + this->mode = climate::CLIMATE_MODE_HEAT; + } else if (this->supports_cool_) { + this->mode = climate::CLIMATE_MODE_COOL; + } } this->compute_state_(); this->publish_state(); - ESP_LOGD(TAG, "MCU reported switch is: %s", ONOFF(datapoint.value_bool)); + }); + } + if (this->active_state_id_.has_value()) { + this->parent_->register_listener(*this->active_state_id_, [this](TuyaDatapoint datapoint) { + ESP_LOGV(TAG, "MCU reported active state is: %u", datapoint.value_enum); + this->active_state_ = datapoint.value_enum; + this->compute_state_(); + this->publish_state(); }); } if (this->target_temperature_id_.has_value()) { this->parent_->register_listener(*this->target_temperature_id_, [this](TuyaDatapoint datapoint) { this->target_temperature = datapoint.value_int * this->target_temperature_multiplier_; + ESP_LOGV(TAG, "MCU reported target temperature is: %.1f", this->target_temperature); this->compute_state_(); this->publish_state(); - ESP_LOGD(TAG, "MCU reported target temperature is: %.1f", this->target_temperature); }); } if (this->current_temperature_id_.has_value()) { this->parent_->register_listener(*this->current_temperature_id_, [this](TuyaDatapoint datapoint) { this->current_temperature = datapoint.value_int * this->current_temperature_multiplier_; + ESP_LOGV(TAG, "MCU reported current temperature is: %.1f", this->current_temperature); this->compute_state_(); this->publish_state(); - ESP_LOGD(TAG, "MCU reported current temperature is: %.1f", this->current_temperature); }); } } void TuyaClimate::control(const climate::ClimateCall &call) { if (call.get_mode().has_value()) { - this->mode = *call.get_mode(); - - TuyaDatapoint datapoint{}; - datapoint.id = *this->switch_id_; - datapoint.type = TuyaDatapointType::BOOLEAN; - datapoint.value_bool = this->mode != climate::CLIMATE_MODE_OFF; - this->parent_->set_datapoint_value(datapoint); - ESP_LOGD(TAG, "Setting switch: %s", ONOFF(datapoint.value_bool)); + const bool switch_state = *call.get_mode() != climate::CLIMATE_MODE_OFF; + ESP_LOGV(TAG, "Setting switch: %s", ONOFF(switch_state)); + this->parent_->set_datapoint_value(*this->switch_id_, switch_state); } if (call.get_target_temperature().has_value()) { - this->target_temperature = *call.get_target_temperature(); - - TuyaDatapoint datapoint{}; - datapoint.id = *this->target_temperature_id_; - datapoint.type = TuyaDatapointType::INTEGER; - datapoint.value_int = (int) (this->target_temperature / this->target_temperature_multiplier_); - this->parent_->set_datapoint_value(datapoint); - ESP_LOGD(TAG, "Setting target temperature: %.1f", this->target_temperature); + const float target_temperature = *call.get_target_temperature(); + ESP_LOGV(TAG, "Setting target temperature: %.1f", target_temperature); + this->parent_->set_datapoint_value(*this->target_temperature_id_, + (int) (target_temperature / this->target_temperature_multiplier_)); } - - this->compute_state_(); - this->publish_state(); } climate::ClimateTraits TuyaClimate::traits() { auto traits = climate::ClimateTraits(); traits.set_supports_current_temperature(this->current_temperature_id_.has_value()); - traits.set_supports_heat_mode(true); + traits.set_supports_heat_mode(this->supports_heat_); + traits.set_supports_cool_mode(this->supports_cool_); traits.set_supports_action(true); return traits; } @@ -76,6 +78,8 @@ void TuyaClimate::dump_config() { LOG_CLIMATE("", "Tuya Climate", this); if (this->switch_id_.has_value()) ESP_LOGCONFIG(TAG, " Switch has datapoint ID %u", *this->switch_id_); + if (this->active_state_id_.has_value()) + ESP_LOGCONFIG(TAG, " Active state has datapoint ID %u", *this->active_state_id_); if (this->target_temperature_id_.has_value()) ESP_LOGCONFIG(TAG, " Target Temperature has datapoint ID %u", *this->target_temperature_id_); if (this->current_temperature_id_.has_value()) @@ -94,30 +98,27 @@ void TuyaClimate::compute_state_() { return; } - const bool too_cold = this->current_temperature < this->target_temperature - 1; - const bool too_hot = this->current_temperature > this->target_temperature + 1; - const bool on_target = this->current_temperature == this->target_temperature; - - climate::ClimateAction target_action; - if (too_cold) { - // too cold -> show as heating if possible, else idle - if (this->traits().supports_mode(climate::CLIMATE_MODE_HEAT)) { + climate::ClimateAction target_action = climate::CLIMATE_ACTION_IDLE; + if (this->active_state_id_.has_value()) { + if (this->supports_heat_ && this->active_state_heating_value_.has_value() && + this->active_state_ == this->active_state_heating_value_) { target_action = climate::CLIMATE_ACTION_HEATING; - } else { - target_action = climate::CLIMATE_ACTION_IDLE; - } - } else if (too_hot) { - // too hot -> show as cooling if possible, else idle - if (this->traits().supports_mode(climate::CLIMATE_MODE_COOL)) { + } else if (this->supports_cool_ && this->active_state_cooling_value_.has_value() && + this->active_state_ == this->active_state_cooling_value_) { target_action = climate::CLIMATE_ACTION_COOLING; - } else { - target_action = climate::CLIMATE_ACTION_IDLE; } - } else if (on_target) { - target_action = climate::CLIMATE_ACTION_IDLE; } else { - target_action = this->action; + // Fallback to active state calc based on temp and hysteresis + const float temp_diff = this->target_temperature - this->current_temperature; + if (std::abs(temp_diff) > this->hysteresis_) { + if (this->supports_heat_ && temp_diff > 0) { + target_action = climate::CLIMATE_ACTION_HEATING; + } else if (this->supports_cool_ && temp_diff < 0) { + target_action = climate::CLIMATE_ACTION_COOLING; + } + } } + this->switch_to_action_(target_action); } diff --git a/esphome/components/tuya/climate/tuya_climate.h b/esphome/components/tuya/climate/tuya_climate.h index e9c366e898..f015bc337c 100644 --- a/esphome/components/tuya/climate/tuya_climate.h +++ b/esphome/components/tuya/climate/tuya_climate.h @@ -11,7 +11,12 @@ class TuyaClimate : public climate::Climate, public Component { public: void setup() override; void dump_config() override; + void set_supports_heat(bool supports_heat) { this->supports_heat_ = supports_heat; } + void set_supports_cool(bool supports_cool) { this->supports_cool_ = supports_cool; } void set_switch_id(uint8_t switch_id) { this->switch_id_ = switch_id; } + void set_active_state_id(uint8_t state_id) { this->active_state_id_ = state_id; } + void set_active_state_heating_value(uint8_t value) { this->active_state_heating_value_ = value; } + void set_active_state_cooling_value(uint8_t value) { this->active_state_cooling_value_ = value; } void set_target_temperature_id(uint8_t target_temperature_id) { this->target_temperature_id_ = target_temperature_id; } @@ -40,11 +45,18 @@ class TuyaClimate : public climate::Climate, public Component { void switch_to_action_(climate::ClimateAction action); Tuya *parent_; + bool supports_heat_; + bool supports_cool_; optional switch_id_{}; + optional active_state_id_{}; + optional active_state_heating_value_{}; + optional active_state_cooling_value_{}; optional target_temperature_id_{}; optional current_temperature_id_{}; float current_temperature_multiplier_{1.0f}; float target_temperature_multiplier_{1.0f}; + float hysteresis_{1.0f}; + uint8_t active_state_; }; } // namespace tuya diff --git a/esphome/components/tuya/fan/tuya_fan.cpp b/esphome/components/tuya/fan/tuya_fan.cpp index 62f4a78db7..b2326034a1 100644 --- a/esphome/components/tuya/fan/tuya_fan.cpp +++ b/esphome/components/tuya/fan/tuya_fan.cpp @@ -14,29 +14,29 @@ void TuyaFan::setup() { if (this->speed_id_.has_value()) { this->parent_->register_listener(*this->speed_id_, [this](TuyaDatapoint datapoint) { + ESP_LOGV(TAG, "MCU reported speed of: %d", datapoint.value_enum); auto call = this->fan_->make_call(); if (datapoint.value_enum < this->speed_count_) call.set_speed(datapoint.value_enum + 1); else ESP_LOGCONFIG(TAG, "Speed has invalid value %d", datapoint.value_enum); - ESP_LOGD(TAG, "MCU reported speed of: %d", datapoint.value_enum); call.perform(); }); } if (this->switch_id_.has_value()) { this->parent_->register_listener(*this->switch_id_, [this](TuyaDatapoint datapoint) { + ESP_LOGV(TAG, "MCU reported switch is: %s", ONOFF(datapoint.value_bool)); auto call = this->fan_->make_call(); call.set_state(datapoint.value_bool); call.perform(); - ESP_LOGD(TAG, "MCU reported switch is: %s", ONOFF(datapoint.value_bool)); }); } if (this->oscillation_id_.has_value()) { this->parent_->register_listener(*this->oscillation_id_, [this](TuyaDatapoint datapoint) { + ESP_LOGV(TAG, "MCU reported oscillation is: %s", ONOFF(datapoint.value_bool)); auto call = this->fan_->make_call(); call.set_oscillating(datapoint.value_bool); call.perform(); - ESP_LOGD(TAG, "MCU reported oscillation is: %s", ONOFF(datapoint.value_bool)); }); } if (this->direction_id_.has_value()) { @@ -66,37 +66,21 @@ void TuyaFan::dump_config() { void TuyaFan::write_state() { if (this->switch_id_.has_value()) { - TuyaDatapoint datapoint{}; - datapoint.id = *this->switch_id_; - datapoint.type = TuyaDatapointType::BOOLEAN; - datapoint.value_bool = this->fan_->state; - this->parent_->set_datapoint_value(datapoint); - ESP_LOGD(TAG, "Setting switch: %s", ONOFF(this->fan_->state)); + ESP_LOGV(TAG, "Setting switch: %s", ONOFF(this->fan_->state)); + this->parent_->set_datapoint_value(*this->switch_id_, this->fan_->state); } if (this->oscillation_id_.has_value()) { - TuyaDatapoint datapoint{}; - datapoint.id = *this->oscillation_id_; - datapoint.type = TuyaDatapointType::BOOLEAN; - datapoint.value_bool = this->fan_->oscillating; - this->parent_->set_datapoint_value(datapoint); - ESP_LOGD(TAG, "Setting oscillating: %s", ONOFF(this->fan_->oscillating)); + ESP_LOGV(TAG, "Setting oscillating: %s", ONOFF(this->fan_->oscillating)); + this->parent_->set_datapoint_value(*this->oscillation_id_, this->fan_->oscillating); } if (this->direction_id_.has_value()) { - TuyaDatapoint datapoint{}; - datapoint.id = *this->direction_id_; - datapoint.type = TuyaDatapointType::BOOLEAN; bool enable = this->fan_->direction == fan::FAN_DIRECTION_REVERSE; - datapoint.value_bool = enable; - this->parent_->set_datapoint_value(datapoint); - ESP_LOGD(TAG, "Setting reverse direction: %s", ONOFF(enable)); + ESP_LOGV(TAG, "Setting reverse direction: %s", ONOFF(enable)); + this->parent_->set_datapoint_value(*this->direction_id_, enable); } if (this->speed_id_.has_value()) { - TuyaDatapoint datapoint{}; - datapoint.id = *this->speed_id_; - datapoint.type = TuyaDatapointType::ENUM; - datapoint.value_enum = this->fan_->speed - 1; - ESP_LOGD(TAG, "Setting speed: %d", datapoint.value_enum); - this->parent_->set_datapoint_value(datapoint); + ESP_LOGV(TAG, "Setting speed: %d", this->fan_->speed); + this->parent_->set_datapoint_value(*this->speed_id_, this->fan_->speed); } } diff --git a/esphome/components/tuya/light/tuya_light.cpp b/esphome/components/tuya/light/tuya_light.cpp index f03e66e150..4befad401e 100644 --- a/esphome/components/tuya/light/tuya_light.cpp +++ b/esphome/components/tuya/light/tuya_light.cpp @@ -31,11 +31,7 @@ void TuyaLight::setup() { }); } if (min_value_datapoint_id_.has_value()) { - TuyaDatapoint datapoint{}; - datapoint.id = *this->min_value_datapoint_id_; - datapoint.type = TuyaDatapointType::INTEGER; - datapoint.value_int = this->min_value_; - parent_->set_datapoint_value(datapoint); + parent_->set_datapoint_value(*this->min_value_datapoint_id_, this->min_value_); } } @@ -67,49 +63,29 @@ void TuyaLight::write_state(light::LightState *state) { if (brightness == 0.0f) { // turning off, first try via switch (if exists), then dimmer if (switch_id_.has_value()) { - TuyaDatapoint datapoint{}; - datapoint.id = *this->switch_id_; - datapoint.type = TuyaDatapointType::BOOLEAN; - datapoint.value_bool = false; - - parent_->set_datapoint_value(datapoint); + parent_->set_datapoint_value(*this->switch_id_, false); } else if (dimmer_id_.has_value()) { - TuyaDatapoint datapoint{}; - datapoint.id = *this->dimmer_id_; - datapoint.type = TuyaDatapointType::INTEGER; - datapoint.value_int = 0; - parent_->set_datapoint_value(datapoint); + parent_->set_datapoint_value(*this->dimmer_id_, 0); } return; } if (this->color_temperature_id_.has_value()) { - TuyaDatapoint datapoint{}; - datapoint.id = *this->color_temperature_id_; - datapoint.type = TuyaDatapointType::INTEGER; - datapoint.value_int = + uint32_t color_temp_int = static_cast(this->color_temperature_max_value_ * (state->current_values.get_color_temperature() - this->cold_white_temperature_) / (this->warm_white_temperature_ - this->cold_white_temperature_)); - parent_->set_datapoint_value(datapoint); + parent_->set_datapoint_value(*this->color_temperature_id_, color_temp_int); } auto brightness_int = static_cast(brightness * this->max_value_); brightness_int = std::max(brightness_int, this->min_value_); if (this->dimmer_id_.has_value()) { - TuyaDatapoint datapoint{}; - datapoint.id = *this->dimmer_id_; - datapoint.type = TuyaDatapointType::INTEGER; - datapoint.value_int = brightness_int; - parent_->set_datapoint_value(datapoint); + parent_->set_datapoint_value(*this->dimmer_id_, brightness_int); } if (this->switch_id_.has_value()) { - TuyaDatapoint datapoint{}; - datapoint.id = *this->switch_id_; - datapoint.type = TuyaDatapointType::BOOLEAN; - datapoint.value_bool = true; - parent_->set_datapoint_value(datapoint); + parent_->set_datapoint_value(*this->switch_id_, true); } } diff --git a/esphome/components/tuya/sensor/tuya_sensor.cpp b/esphome/components/tuya/sensor/tuya_sensor.cpp index b8e2aa97b7..483552950f 100644 --- a/esphome/components/tuya/sensor/tuya_sensor.cpp +++ b/esphome/components/tuya/sensor/tuya_sensor.cpp @@ -9,17 +9,17 @@ static const char *TAG = "tuya.sensor"; void TuyaSensor::setup() { this->parent_->register_listener(this->sensor_id_, [this](TuyaDatapoint datapoint) { if (datapoint.type == TuyaDatapointType::BOOLEAN) { + ESP_LOGV(TAG, "MCU reported sensor %u is: %s", datapoint.id, ONOFF(datapoint.value_bool)); this->publish_state(datapoint.value_bool); - ESP_LOGD(TAG, "MCU reported sensor is: %s", ONOFF(datapoint.value_bool)); } else if (datapoint.type == TuyaDatapointType::INTEGER) { + ESP_LOGV(TAG, "MCU reported sensor %u is: %d", datapoint.id, datapoint.value_int); this->publish_state(datapoint.value_int); - ESP_LOGD(TAG, "MCU reported sensor is: %d", datapoint.value_int); } else if (datapoint.type == TuyaDatapointType::ENUM) { + ESP_LOGV(TAG, "MCU reported sensor %u is: %u", datapoint.id, datapoint.value_enum); this->publish_state(datapoint.value_enum); - ESP_LOGD(TAG, "MCU reported sensor is: %d", datapoint.value_enum); } else if (datapoint.type == TuyaDatapointType::BITMASK) { + ESP_LOGV(TAG, "MCU reported sensor %u is: %x", datapoint.id, datapoint.value_bitmask); this->publish_state(datapoint.value_bitmask); - ESP_LOGD(TAG, "MCU reported sensor is: %x", datapoint.value_bitmask); } }); } diff --git a/esphome/components/tuya/switch/tuya_switch.cpp b/esphome/components/tuya/switch/tuya_switch.cpp index 8f7c7f170d..c735b32341 100644 --- a/esphome/components/tuya/switch/tuya_switch.cpp +++ b/esphome/components/tuya/switch/tuya_switch.cpp @@ -8,19 +8,14 @@ static const char *TAG = "tuya.switch"; void TuyaSwitch::setup() { this->parent_->register_listener(this->switch_id_, [this](TuyaDatapoint datapoint) { + ESP_LOGV(TAG, "MCU reported switch %u is: %s", this->switch_id_, ONOFF(datapoint.value_bool)); this->publish_state(datapoint.value_bool); - ESP_LOGD(TAG, "MCU reported switch is: %s", ONOFF(datapoint.value_bool)); }); } void TuyaSwitch::write_state(bool state) { - TuyaDatapoint datapoint{}; - datapoint.id = this->switch_id_; - datapoint.type = TuyaDatapointType::BOOLEAN; - datapoint.value_bool = state; - this->parent_->set_datapoint_value(datapoint); - ESP_LOGD(TAG, "Setting switch: %s", ONOFF(state)); - + ESP_LOGV(TAG, "Setting switch %u: %s", this->switch_id_, ONOFF(state)); + this->parent_->set_datapoint_value(this->switch_id_, state); this->publish_state(state); } diff --git a/esphome/components/tuya/tuya.cpp b/esphome/components/tuya/tuya.cpp index f4a72e8109..96e832fe89 100644 --- a/esphome/components/tuya/tuya.cpp +++ b/esphome/components/tuya/tuya.cpp @@ -1,5 +1,6 @@ #include "tuya.h" #include "esphome/core/log.h" +#include "esphome/core/util.h" #include "esphome/core/helpers.h" namespace esphome { @@ -9,7 +10,7 @@ static const char *TAG = "tuya"; static const int COMMAND_DELAY = 50; void Tuya::setup() { - this->set_interval("heartbeat", 1000, [this] { this->send_empty_command_(TuyaCommandType::HEARTBEAT); }); + this->set_interval("heartbeat", 10000, [this] { this->send_empty_command_(TuyaCommandType::HEARTBEAT); }); } void Tuya::loop() { @@ -31,17 +32,17 @@ void Tuya::dump_config() { } for (auto &info : this->datapoints_) { if (info.type == TuyaDatapointType::BOOLEAN) - ESP_LOGCONFIG(TAG, " Datapoint %d: switch (value: %s)", info.id, ONOFF(info.value_bool)); + ESP_LOGCONFIG(TAG, " Datapoint %u: switch (value: %s)", info.id, ONOFF(info.value_bool)); else if (info.type == TuyaDatapointType::INTEGER) - ESP_LOGCONFIG(TAG, " Datapoint %d: int value (value: %d)", info.id, info.value_int); + ESP_LOGCONFIG(TAG, " Datapoint %u: int value (value: %d)", info.id, info.value_int); else if (info.type == TuyaDatapointType::STRING) - ESP_LOGCONFIG(TAG, " Datapoint %d: string value (value: %s)", info.id, info.value_string.c_str()); + ESP_LOGCONFIG(TAG, " Datapoint %u: string value (value: %s)", info.id, info.value_string.c_str()); else if (info.type == TuyaDatapointType::ENUM) - ESP_LOGCONFIG(TAG, " Datapoint %d: enum (value: %d)", info.id, info.value_enum); + ESP_LOGCONFIG(TAG, " Datapoint %u: enum (value: %d)", info.id, info.value_enum); else if (info.type == TuyaDatapointType::BITMASK) - ESP_LOGCONFIG(TAG, " Datapoint %d: bitmask (value: %x)", info.id, info.value_bitmask); + ESP_LOGCONFIG(TAG, " Datapoint %u: bitmask (value: %x)", info.id, info.value_bitmask); else - ESP_LOGCONFIG(TAG, " Datapoint %d: unknown", info.id); + ESP_LOGCONFIG(TAG, " Datapoint %u: unknown", info.id); } if ((this->gpio_status_ != -1) || (this->gpio_reset_ != -1)) { ESP_LOGCONFIG(TAG, " GPIO Configuration: status: pin %d, reset: pin %d (not supported)", this->gpio_status_, @@ -98,8 +99,8 @@ bool Tuya::validate_message_() { // valid message const uint8_t *message_data = data + 6; - ESP_LOGV(TAG, "Received Tuya: CMD=0x%02X VERSION=%u DATA=[%s] INIT_STATE=%u", command, version, // NOLINT - hexencode(message_data, length).c_str(), this->init_state_); + ESP_LOGV(TAG, "Received Tuya: CMD=0x%02X VERSION=%u DATA=[%s] INIT_STATE=%u", command, version, + hexencode(message_data, length).c_str(), static_cast(this->init_state_)); this->handle_command_(command, version, message_data, length); // return false to reset rx buffer @@ -117,6 +118,7 @@ void Tuya::handle_command_(uint8_t command, uint8_t version, const uint8_t *buff switch ((TuyaCommandType) command) { case TuyaCommandType::HEARTBEAT: ESP_LOGV(TAG, "MCU Heartbeat (0x%02X)", buffer[0]); + this->protocol_version_ = version; if (buffer[0] == 0) { ESP_LOGI(TAG, "MCU restarted"); this->init_state_ = TuyaInitState::INIT_HEARTBEAT; @@ -148,8 +150,8 @@ void Tuya::handle_command_(uint8_t command, uint8_t version, const uint8_t *buff } case TuyaCommandType::CONF_QUERY: { if (len >= 2) { - gpio_status_ = buffer[0]; - gpio_reset_ = buffer[1]; + this->gpio_status_ = buffer[0]; + this->gpio_reset_ = buffer[1]; } if (this->init_state_ == TuyaInitState::INIT_CONF) { // If mcu returned status gpio, then we can ommit sending wifi state @@ -158,10 +160,7 @@ void Tuya::handle_command_(uint8_t command, uint8_t version, const uint8_t *buff this->send_empty_command_(TuyaCommandType::DATAPOINT_QUERY); } else { this->init_state_ = TuyaInitState::INIT_WIFI; - // If we were following the spec to the letter we would send - // state updates until connected to both WiFi and API/MQTT. - // Instead we just claim to be connected immediately and move on. - this->send_command_(TuyaCommand{.cmd = TuyaCommandType::WIFI_STATE, .payload = std::vector{0x04}}); + this->set_interval("wifi", 1000, [this] { this->send_wifi_status_(); }); } } break; @@ -173,10 +172,10 @@ void Tuya::handle_command_(uint8_t command, uint8_t version, const uint8_t *buff } break; case TuyaCommandType::WIFI_RESET: - ESP_LOGE(TAG, "TUYA_CMD_WIFI_RESET is not handled"); + ESP_LOGE(TAG, "WIFI_RESET is not handled"); break; case TuyaCommandType::WIFI_SELECT: - ESP_LOGE(TAG, "TUYA_CMD_WIFI_SELECT is not handled"); + ESP_LOGE(TAG, "WIFI_SELECT is not handled"); break; case TuyaCommandType::DATAPOINT_DELIVER: break; @@ -189,48 +188,24 @@ void Tuya::handle_command_(uint8_t command, uint8_t version, const uint8_t *buff break; case TuyaCommandType::DATAPOINT_QUERY: break; - case TuyaCommandType::WIFI_TEST: { + case TuyaCommandType::WIFI_TEST: this->send_command_(TuyaCommand{.cmd = TuyaCommandType::WIFI_TEST, .payload = std::vector{0x00, 0x00}}); break; - } - case TuyaCommandType::LOCAL_TIME_QUERY: { + case TuyaCommandType::LOCAL_TIME_QUERY: #ifdef USE_TIME if (this->time_id_.has_value()) { + this->send_local_time_(); auto time_id = *this->time_id_; - auto now = time_id->now(); - - if (now.is_valid()) { - uint8_t year = now.year - 2000; - uint8_t month = now.month; - uint8_t day_of_month = now.day_of_month; - uint8_t hour = now.hour; - uint8_t minute = now.minute; - uint8_t second = now.second; - // Tuya days starts from Monday, esphome uses Sunday as day 1 - uint8_t day_of_week = now.day_of_week - 1; - if (day_of_week == 0) { - day_of_week = 7; - } - this->send_command_(TuyaCommand{ - .cmd = TuyaCommandType::LOCAL_TIME_QUERY, - .payload = std::vector{0x01, year, month, day_of_month, hour, minute, second, day_of_week}}); - } else { - ESP_LOGW(TAG, "TUYA_CMD_LOCAL_TIME_QUERY is not handled because time is not valid"); - // By spec we need to notify MCU that the time was not obtained - this->send_command_( - TuyaCommand{.cmd = TuyaCommandType::LOCAL_TIME_QUERY, - .payload = std::vector{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}); - } + time_id->add_on_time_sync_callback([this] { this->send_local_time_(); }); } else { - ESP_LOGW(TAG, "TUYA_CMD_LOCAL_TIME_QUERY is not handled because time is not configured"); + ESP_LOGW(TAG, "LOCAL_TIME_QUERY is not handled because time is not configured"); } #else ESP_LOGE(TAG, "LOCAL_TIME_QUERY is not handled"); #endif break; - } default: - ESP_LOGE(TAG, "invalid command (%02x) received", command); + ESP_LOGE(TAG, "Invalid command (0x%02X) received", command); } } @@ -243,8 +218,8 @@ void Tuya::handle_datapoint_(const uint8_t *buffer, size_t len) { datapoint.type = (TuyaDatapointType) buffer[1]; datapoint.value_uint = 0; - // drop update if datapoint is in ignore_mcu_datapoint_update list - for (auto i : this->ignore_mcu_update_on_datapoints_) { + // Drop update if datapoint is in ignore_mcu_datapoint_update list + for (uint8_t i : this->ignore_mcu_update_on_datapoints_) { if (datapoint.id == i) { ESP_LOGV(TAG, "Datapoint %u found in ignore_mcu_update_on_datapoints list, dropping MCU update", datapoint.id); return; @@ -255,38 +230,57 @@ void Tuya::handle_datapoint_(const uint8_t *buffer, size_t len) { const uint8_t *data = buffer + 4; size_t data_len = len - 4; if (data_size != data_len) { - ESP_LOGW(TAG, "invalid datapoint update"); + ESP_LOGW(TAG, "Datapoint %u is not expected size", datapoint.id); return; } + datapoint.len = data_len; switch (datapoint.type) { case TuyaDatapointType::BOOLEAN: - if (data_len != 1) + if (data_len != 1) { + ESP_LOGW(TAG, "Datapoint %u has bad boolean len %zu", datapoint.id, data_len); return; + } datapoint.value_bool = data[0]; break; case TuyaDatapointType::INTEGER: - if (data_len != 4) + if (data_len != 4) { + ESP_LOGW(TAG, "Datapoint %u has bad integer len %zu", datapoint.id, data_len); return; + } datapoint.value_uint = encode_uint32(data[0], data[1], data[2], data[3]); break; case TuyaDatapointType::STRING: datapoint.value_string = std::string(reinterpret_cast(data), data_len); break; case TuyaDatapointType::ENUM: - if (data_len != 1) + if (data_len != 1) { + ESP_LOGW(TAG, "Datapoint %u has bad enum len %zu", datapoint.id, data_len); return; + } datapoint.value_enum = data[0]; break; case TuyaDatapointType::BITMASK: - if (data_len != 2) - return; - datapoint.value_bitmask = (uint16_t(data[0]) << 8) | (uint16_t(data[1]) << 0); + switch (data_len) { + case 1: + datapoint.value_bitmask = encode_uint32(0, 0, 0, data[0]); + break; + case 2: + datapoint.value_bitmask = encode_uint32(0, 0, data[0], data[1]); + break; + case 4: + datapoint.value_bitmask = encode_uint32(data[0], data[1], data[2], data[3]); + break; + default: + ESP_LOGW(TAG, "Datapoint %u has bad bitmask len %zu", datapoint.id, data_len); + return; + } break; default: + ESP_LOGW(TAG, "Datapoint %u has unknown type 0x%02hhX", datapoint.id, datapoint.type); return; } - ESP_LOGV(TAG, "Datapoint %u update to %u", datapoint.id, datapoint.value_uint); + ESP_LOGD(TAG, "Datapoint %u update to %u", datapoint.id, datapoint.value_uint); // Update internal datapoints bool found = false; @@ -313,8 +307,8 @@ void Tuya::send_raw_command_(TuyaCommand command) { this->last_command_timestamp_ = millis(); - ESP_LOGV(TAG, "Sending Tuya: CMD=0x%02X VERSION=%u DATA=[%s] INIT_STATE=%u", command.cmd, version, // NOLINT - hexencode(command.payload).c_str(), this->init_state_); + ESP_LOGV(TAG, "Sending Tuya: CMD=0x%02X VERSION=%u DATA=[%s] INIT_STATE=%u", static_cast(command.cmd), + version, hexencode(command.payload).c_str(), static_cast(this->init_state_)); this->write_array({0x55, 0xAA, version, (uint8_t) command.cmd, len_hi, len_lo}); if (!command.payload.empty()) @@ -344,53 +338,113 @@ void Tuya::send_empty_command_(TuyaCommandType command) { send_command_(TuyaCommand{.cmd = command, .payload = std::vector{0x04}}); } -void Tuya::set_datapoint_value(TuyaDatapoint datapoint) { - std::vector buffer; - ESP_LOGV(TAG, "Datapoint %u set to %u", datapoint.id, datapoint.value_uint); - for (auto &other : this->datapoints_) { - if (other.id == datapoint.id) { - // String value is stored outside the union; must be checked separately. - if (datapoint.type == TuyaDatapointType::STRING) { - if (other.value_string == datapoint.value_string) { - ESP_LOGV(TAG, "Not sending unchanged value"); - return; - } - } else if (other.value_uint == datapoint.value_uint) { - ESP_LOGV(TAG, "Not sending unchanged value"); - return; +void Tuya::send_wifi_status_() { + uint8_t status = 0x02; + if (network_is_connected()) { + status = 0x03; + + // Protocol version 3 also supports specifying when connected to "the cloud" + if (this->protocol_version_ >= 0x03) { + if (remote_is_connected()) { + status = 0x04; } } } - buffer.push_back(datapoint.id); - buffer.push_back(static_cast(datapoint.type)); - std::vector data; - switch (datapoint.type) { - case TuyaDatapointType::BOOLEAN: - data.push_back(datapoint.value_bool); - break; - case TuyaDatapointType::INTEGER: - data.push_back(datapoint.value_uint >> 24); - data.push_back(datapoint.value_uint >> 16); - data.push_back(datapoint.value_uint >> 8); - data.push_back(datapoint.value_uint >> 0); - break; - case TuyaDatapointType::STRING: - for (char const &c : datapoint.value_string) { - data.push_back(c); - } - break; - case TuyaDatapointType::ENUM: - data.push_back(datapoint.value_enum); - break; - case TuyaDatapointType::BITMASK: - data.push_back(datapoint.value_bitmask >> 8); - data.push_back(datapoint.value_bitmask >> 0); - break; - default: - return; + if (status == this->wifi_status_) { + return; } + ESP_LOGD(TAG, "Sending WiFi Status"); + this->wifi_status_ = status; + this->send_command_(TuyaCommand{.cmd = TuyaCommandType::WIFI_STATE, .payload = std::vector{status}}); +} + +#ifdef USE_TIME +void Tuya::send_local_time_() { + std::vector payload; + auto time_id = *this->time_id_; + time::ESPTime now = time_id->now(); + if (now.is_valid()) { + uint8_t year = now.year - 2000; + uint8_t month = now.month; + uint8_t day_of_month = now.day_of_month; + uint8_t hour = now.hour; + uint8_t minute = now.minute; + uint8_t second = now.second; + // Tuya days starts from Monday, esphome uses Sunday as day 1 + uint8_t day_of_week = now.day_of_week - 1; + if (day_of_week == 0) { + day_of_week = 7; + } + ESP_LOGD(TAG, "Sending local time"); + payload = std::vector{0x01, year, month, day_of_month, hour, minute, second, day_of_week}; + } else { + // By spec we need to notify MCU that the time was not obtained if this is a response to a query + ESP_LOGW(TAG, "Sending missing local time"); + payload = std::vector{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + } + this->send_command_(TuyaCommand{.cmd = TuyaCommandType::LOCAL_TIME_QUERY, .payload = payload}); +} +#endif + +void Tuya::set_datapoint_value(uint8_t datapoint_id, uint32_t value) { + ESP_LOGD(TAG, "Setting datapoint %u to %u", datapoint_id, value); + optional datapoint = this->get_datapoint_(datapoint_id); + if (!datapoint.has_value()) { + ESP_LOGE(TAG, "Attempt to set unknown datapoint %u", datapoint_id); + return; + } + if (datapoint->value_uint == value) { + ESP_LOGV(TAG, "Not sending unchanged value"); + return; + } + + std::vector data; + switch (datapoint->len) { + case 4: + data.push_back(value >> 24); + data.push_back(value >> 16); + case 2: + data.push_back(value >> 8); + case 1: + data.push_back(value >> 0); + break; + default: + ESP_LOGE(TAG, "Unexpected datapoint length %zu", datapoint->len); + return; + } + this->send_datapoint_command_(datapoint->id, datapoint->type, data); +} + +void Tuya::set_datapoint_value(uint8_t datapoint_id, std::string value) { + ESP_LOGD(TAG, "Setting datapoint %u to %s", datapoint_id, value.c_str()); + optional datapoint = this->get_datapoint_(datapoint_id); + if (!datapoint.has_value()) { + ESP_LOGE(TAG, "Attempt to set unknown datapoint %u", datapoint_id); + } + if (datapoint->value_string == value) { + ESP_LOGV(TAG, "Not sending unchanged value"); + return; + } + std::vector data; + for (char const &c : value) { + data.push_back(c); + } + this->send_datapoint_command_(datapoint->id, datapoint->type, data); +} + +optional Tuya::get_datapoint_(uint8_t datapoint_id) { + for (auto &datapoint : this->datapoints_) + if (datapoint.id == datapoint_id) + return datapoint; + return {}; +} + +void Tuya::send_datapoint_command_(uint8_t datapoint_id, TuyaDatapointType datapoint_type, std::vector data) { + std::vector buffer; + buffer.push_back(datapoint_id); + buffer.push_back(static_cast(datapoint_type)); buffer.push_back(data.size() >> 8); buffer.push_back(data.size() >> 0); buffer.insert(buffer.end(), data.begin(), data.end()); diff --git a/esphome/components/tuya/tuya.h b/esphome/components/tuya/tuya.h index a2b4040eb3..f98b7522fc 100644 --- a/esphome/components/tuya/tuya.h +++ b/esphome/components/tuya/tuya.h @@ -23,12 +23,13 @@ enum class TuyaDatapointType : uint8_t { struct TuyaDatapoint { uint8_t id; TuyaDatapointType type; + size_t len; union { bool value_bool; int value_int; uint32_t value_uint; uint8_t value_enum; - uint16_t value_bitmask; + uint32_t value_bitmask; }; std::string value_string; }; @@ -73,7 +74,8 @@ class Tuya : public Component, public uart::UARTDevice { void loop() override; void dump_config() override; void register_listener(uint8_t datapoint_id, const std::function &func); - void set_datapoint_value(TuyaDatapoint datapoint); + void set_datapoint_value(uint8_t datapoint_id, uint32_t value); + void set_datapoint_value(uint8_t datapoint_id, std::string value); #ifdef USE_TIME void set_time_id(time::RealTimeClock *time_id) { this->time_id_ = time_id; } #endif @@ -84,6 +86,7 @@ class Tuya : public Component, public uart::UARTDevice { protected: void handle_char_(uint8_t c); void handle_datapoint_(const uint8_t *buffer, size_t len); + optional get_datapoint_(uint8_t datapoint_id); bool validate_message_(); void handle_command_(uint8_t command, uint8_t version, const uint8_t *buffer, size_t len); @@ -91,11 +94,15 @@ class Tuya : public Component, public uart::UARTDevice { void process_command_queue_(); void send_command_(TuyaCommand command); void send_empty_command_(TuyaCommandType command); + void send_datapoint_command_(uint8_t datapoint_id, TuyaDatapointType datapoint_type, std::vector data); + void send_wifi_status_(); #ifdef USE_TIME + void send_local_time_(); optional time_id_{}; #endif TuyaInitState init_state_ = TuyaInitState::INIT_HEARTBEAT; + uint8_t protocol_version_ = -1; int gpio_status_ = -1; int gpio_reset_ = -1; uint32_t last_command_timestamp_ = 0; @@ -105,6 +112,7 @@ class Tuya : public Component, public uart::UARTDevice { std::vector rx_message_; std::vector ignore_mcu_update_on_datapoints_{}; std::vector command_queue_; + uint8_t wifi_status_ = -1; }; } // namespace tuya diff --git a/esphome/core/util.cpp b/esphome/core/util.cpp index 4e15d142be..73086a750a 100644 --- a/esphome/core/util.cpp +++ b/esphome/core/util.cpp @@ -16,6 +16,10 @@ #include "esphome/components/ethernet/ethernet_component.h" #endif +#ifdef USE_MQTT +#include "esphome/components/mqtt/mqtt_client.h" +#endif + #ifdef USE_MDNS #ifdef ARDUINO_ARCH_ESP32 #include @@ -41,6 +45,26 @@ bool network_is_connected() { return false; } +bool api_is_connected() { +#ifdef USE_API + if (api::global_api_server != nullptr) { + return api::global_api_server->is_connected(); + } +#endif + return false; +} + +bool mqtt_is_connected() { +#ifdef USE_MQTT + if (mqtt::global_mqtt_client != nullptr) { + return mqtt::global_mqtt_client->is_connected(); + } +#endif + return false; +} + +bool remote_is_connected() { return api_is_connected() || mqtt_is_connected(); } + #if defined(ARDUINO_ARCH_ESP8266) && defined(USE_MDNS) bool mdns_setup; #endif diff --git a/esphome/core/util.h b/esphome/core/util.h index 4b3e79353a..180c7aaefa 100644 --- a/esphome/core/util.h +++ b/esphome/core/util.h @@ -15,6 +15,15 @@ bool network_is_connected(); /// Get the active network hostname std::string network_get_address(); +/// Return whether the node has at least one client connected to the native API +bool api_is_connected(); + +/// Return whether the node has an active connection to an MQTT broker +bool mqtt_is_connected(); + +/// Return whether the node has any form of "remote" connection via the API or to an MQTT broker +bool remote_is_connected(); + /// Manually set up the network stack (outside of the App.setup() loop, for example in OTA safe mode) #ifdef ARDUINO_ARCH_ESP8266 void network_setup_mdns(IPAddress address, int interface); From 3b18f1b87f07c0c9feee15c00c5debba00a2e012 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Klitzing?= Date: Thu, 3 Jun 2021 00:11:41 +0200 Subject: [PATCH 083/104] Use size_t for length parameter (#1799) --- esphome/core/preferences.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/core/preferences.cpp b/esphome/core/preferences.cpp index 8b41cbc7b5..2d58fc9efb 100644 --- a/esphome/core/preferences.cpp +++ b/esphome/core/preferences.cpp @@ -252,9 +252,9 @@ bool ESPPreferenceObject::load_internal_() { char key[32]; sprintf(key, "%u", this->offset_); - uint32_t len = (this->length_words_ + 1) * 4; + size_t len = (this->length_words_ + 1) * 4; - uint32_t actual_len; + size_t actual_len; esp_err_t err = nvs_get_blob(global_preferences.nvs_handle_, key, nullptr, &actual_len); if (err) { ESP_LOGV(TAG, "nvs_get_blob('%s'): %s - the key might not be set yet", key, esp_err_to_name(err)); From 2b9350ce7695317abf9022ebca95afc18f937803 Mon Sep 17 00:00:00 2001 From: foxsam21 Date: Wed, 2 Jun 2021 18:12:23 -0400 Subject: [PATCH 084/104] Added vol +/- control to dfplayer (#1856) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/dfplayer/__init__.py | 32 +++++++++++++++++++++++++ esphome/components/dfplayer/dfplayer.h | 2 ++ tests/test3.yaml | 8 +++++++ 3 files changed, 42 insertions(+) diff --git a/esphome/components/dfplayer/__init__.py b/esphome/components/dfplayer/__init__.py index 4c276db63f..6af83888ab 100644 --- a/esphome/components/dfplayer/__init__.py +++ b/esphome/components/dfplayer/__init__.py @@ -43,6 +43,8 @@ PreviousAction = dfplayer_ns.class_("PreviousAction", automation.Action) PlayFileAction = dfplayer_ns.class_("PlayFileAction", automation.Action) PlayFolderAction = dfplayer_ns.class_("PlayFolderAction", automation.Action) SetVolumeAction = dfplayer_ns.class_("SetVolumeAction", automation.Action) +VolumeUpAction = dfplayer_ns.class_("VolumeUpAction", automation.Action) +VolumeDownAction = dfplayer_ns.class_("VolumeDownAction", automation.Action) SetEqAction = dfplayer_ns.class_("SetEqAction", automation.Action) SleepAction = dfplayer_ns.class_("SleepAction", automation.Action) ResetAction = dfplayer_ns.class_("ResetAction", automation.Action) @@ -201,6 +203,36 @@ async def dfplayer_set_volume_to_code(config, action_id, template_arg, args): return var +@automation.register_action( + "dfplayer.volume_up", + VolumeUpAction, + cv.Schema( + { + cv.GenerateID(): cv.use_id(DFPlayer), + } + ), +) +async def dfplayer_volume_up_to_code(config, action_id, template_arg, args): + var = cg.new_Pvariable(action_id, template_arg) + await cg.register_parented(var, config[CONF_ID]) + return var + + +@automation.register_action( + "dfplayer.volume_down", + VolumeDownAction, + cv.Schema( + { + cv.GenerateID(): cv.use_id(DFPlayer), + } + ), +) +async def dfplayer_volume_down_to_code(config, action_id, template_arg, args): + var = cg.new_Pvariable(action_id, template_arg) + await cg.register_parented(var, config[CONF_ID]) + return var + + @automation.register_action( "dfplayer.set_eq", SetEqAction, diff --git a/esphome/components/dfplayer/dfplayer.h b/esphome/components/dfplayer/dfplayer.h index cb9686bb64..6742591926 100644 --- a/esphome/components/dfplayer/dfplayer.h +++ b/esphome/components/dfplayer/dfplayer.h @@ -180,6 +180,8 @@ DFPLAYER_SIMPLE_ACTION(StartAction, start) DFPLAYER_SIMPLE_ACTION(PauseAction, pause) DFPLAYER_SIMPLE_ACTION(StopAction, stop) DFPLAYER_SIMPLE_ACTION(RandomAction, random) +DFPLAYER_SIMPLE_ACTION(VolumeUpAction, volume_up) +DFPLAYER_SIMPLE_ACTION(VolumeDownAction, volume_down) template class DFPlayerIsPlayingCondition : public Condition, public Parented { public: diff --git a/tests/test3.yaml b/tests/test3.yaml index dcffdb8504..8f6b33bd5d 100644 --- a/tests/test3.yaml +++ b/tests/test3.yaml @@ -141,6 +141,14 @@ api: then: - dfplayer.random + - service: dfplayer_volume_up + then: + - dfplayer.volume_up + + - service: dfplayer_volume_down + then: + - dfplayer.volume_down + - service: battery_level_percent variables: level_percent: int From 913ac8b7e8323f539b6070a8d82f961dbf528796 Mon Sep 17 00:00:00 2001 From: Stefan Rado Date: Thu, 3 Jun 2021 03:10:29 +0200 Subject: [PATCH 085/104] Support raw datapoints for tuya components (#1669) --- esphome/components/tuya/tuya.cpp | 16 +++++++++++++--- esphome/components/tuya/tuya.h | 1 + 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/esphome/components/tuya/tuya.cpp b/esphome/components/tuya/tuya.cpp index 96e832fe89..3f09db068d 100644 --- a/esphome/components/tuya/tuya.cpp +++ b/esphome/components/tuya/tuya.cpp @@ -31,7 +31,9 @@ void Tuya::dump_config() { return; } for (auto &info : this->datapoints_) { - if (info.type == TuyaDatapointType::BOOLEAN) + if (info.type == TuyaDatapointType::RAW) + ESP_LOGCONFIG(TAG, " Datapoint %u: raw (value: %s)", info.id, hexencode(info.value_raw).c_str()); + else if (info.type == TuyaDatapointType::BOOLEAN) ESP_LOGCONFIG(TAG, " Datapoint %u: switch (value: %s)", info.id, ONOFF(info.value_bool)); else if (info.type == TuyaDatapointType::INTEGER) ESP_LOGCONFIG(TAG, " Datapoint %u: int value (value: %d)", info.id, info.value_int); @@ -236,12 +238,17 @@ void Tuya::handle_datapoint_(const uint8_t *buffer, size_t len) { datapoint.len = data_len; switch (datapoint.type) { + case TuyaDatapointType::RAW: + datapoint.value_raw = std::vector(data, data + data_len); + ESP_LOGD(TAG, "Datapoint %u update to %s", datapoint.id, hexencode(datapoint.value_raw).c_str()); + break; case TuyaDatapointType::BOOLEAN: if (data_len != 1) { ESP_LOGW(TAG, "Datapoint %u has bad boolean len %zu", datapoint.id, data_len); return; } datapoint.value_bool = data[0]; + ESP_LOGD(TAG, "Datapoint %u update to %s", datapoint.id, ONOFF(datapoint.value_bool)); break; case TuyaDatapointType::INTEGER: if (data_len != 4) { @@ -249,9 +256,11 @@ void Tuya::handle_datapoint_(const uint8_t *buffer, size_t len) { return; } datapoint.value_uint = encode_uint32(data[0], data[1], data[2], data[3]); + ESP_LOGD(TAG, "Datapoint %u update to %d", datapoint.id, datapoint.value_int); break; case TuyaDatapointType::STRING: datapoint.value_string = std::string(reinterpret_cast(data), data_len); + ESP_LOGD(TAG, "Datapoint %u update to %s", datapoint.id, datapoint.value_string.c_str()); break; case TuyaDatapointType::ENUM: if (data_len != 1) { @@ -259,6 +268,7 @@ void Tuya::handle_datapoint_(const uint8_t *buffer, size_t len) { return; } datapoint.value_enum = data[0]; + ESP_LOGD(TAG, "Datapoint %u update to %d", datapoint.id, datapoint.value_enum); break; case TuyaDatapointType::BITMASK: switch (data_len) { @@ -275,12 +285,12 @@ void Tuya::handle_datapoint_(const uint8_t *buffer, size_t len) { ESP_LOGW(TAG, "Datapoint %u has bad bitmask len %zu", datapoint.id, data_len); return; } + ESP_LOGD(TAG, "Datapoint %u update to %#08X", datapoint.id, datapoint.value_bitmask); break; default: - ESP_LOGW(TAG, "Datapoint %u has unknown type 0x%02hhX", datapoint.id, datapoint.type); + ESP_LOGW(TAG, "Datapoint %u has unknown type %#02hhX", datapoint.id, datapoint.type); return; } - ESP_LOGD(TAG, "Datapoint %u update to %u", datapoint.id, datapoint.value_uint); // Update internal datapoints bool found = false; diff --git a/esphome/components/tuya/tuya.h b/esphome/components/tuya/tuya.h index f98b7522fc..42848b4914 100644 --- a/esphome/components/tuya/tuya.h +++ b/esphome/components/tuya/tuya.h @@ -32,6 +32,7 @@ struct TuyaDatapoint { uint32_t value_bitmask; }; std::string value_string; + std::vector value_raw; }; struct TuyaDatapointListener { From 11fb54c74e6258e0e770d945c9632494683e77af Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Thu, 3 Jun 2021 03:49:56 +0200 Subject: [PATCH 086/104] Add support for Sensor state class (#1835) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/adc/sensor.py | 5 +- esphome/components/ade7953/sensor.py | 19 +++++-- esphome/components/ads1115/sensor.py | 5 +- esphome/components/aht10/sensor.py | 13 ++++- esphome/components/am2320/sensor.py | 13 ++++- esphome/components/apds9960/sensor.py | 10 +++- esphome/components/api/api.proto | 6 ++ esphome/components/api/api_connection.cpp | 2 + esphome/components/api/api_pb2.cpp | 19 +++++++ esphome/components/api/api_pb2.h | 5 ++ esphome/components/as3935/sensor.py | 9 ++- .../components/atc_mithermometer/sensor.py | 21 +++++-- esphome/components/atm90e32/sensor.py | 39 ++++++++++--- esphome/components/b_parasite/sensor.py | 21 +++++-- esphome/components/bh1750/sensor.py | 5 +- .../components/binary_sensor_map/sensor.py | 7 ++- .../components/ble_client/sensor/__init__.py | 5 +- esphome/components/ble_rssi/sensor.py | 9 ++- esphome/components/bme280/sensor.py | 19 ++++++- esphome/components/bme680/sensor.py | 25 +++++++-- esphome/components/bme680_bsec/sensor.py | 37 +++++++++--- esphome/components/bmp085/sensor.py | 13 ++++- esphome/components/bmp280/sensor.py | 13 ++++- esphome/components/ccs811/sensor.py | 13 ++++- esphome/components/cse7766/sensor.py | 11 +++- esphome/components/ct_clamp/sensor.py | 5 +- esphome/components/dallas/sensor.py | 5 +- esphome/components/dht/sensor.py | 9 ++- esphome/components/dht12/sensor.py | 13 ++++- esphome/components/duty_cycle/sensor.py | 5 +- esphome/components/esp32_hall/sensor.py | 5 +- esphome/components/fingerprint_grow/sensor.py | 13 +++-- esphome/components/gps/__init__.py | 18 ++++-- esphome/components/hdc1080/sensor.py | 13 ++++- esphome/components/hlw8012/sensor.py | 10 ++-- esphome/components/hm3301/sensor.py | 10 +++- esphome/components/hmc5883l/sensor.py | 6 +- .../homeassistant/sensor/__init__.py | 3 +- esphome/components/htu21d/sensor.py | 13 ++++- esphome/components/hx711/sensor.py | 5 +- esphome/components/ina219/sensor.py | 13 +++-- esphome/components/ina226/sensor.py | 13 +++-- esphome/components/ina3221/sensor.py | 9 +-- .../components/inkbird_ibsth1_mini/sensor.py | 19 ++++++- esphome/components/max31855/sensor.py | 7 ++- esphome/components/max31856/sensor.py | 9 ++- esphome/components/max31865/sensor.py | 5 +- esphome/components/max6675/sensor.py | 12 +++- esphome/components/mcp9808/sensor.py | 12 +++- esphome/components/mhz19/sensor.py | 13 ++++- esphome/components/midea_ac/climate.py | 15 ++++- esphome/components/mpu6050/sensor.py | 15 ++++- .../mqtt_subscribe/sensor/__init__.py | 5 +- esphome/components/ms5611/sensor.py | 13 ++++- esphome/components/ntc/sensor.py | 5 +- esphome/components/pid/sensor/__init__.py | 5 +- esphome/components/pmsx003/sensor.py | 17 +++++- esphome/components/pulse_counter/sensor.py | 12 +++- esphome/components/pulse_meter/sensor.py | 6 +- esphome/components/pulse_width/sensor.py | 13 ++++- esphome/components/pzem004t/sensor.py | 18 ++++-- esphome/components/pzemac/sensor.py | 30 ++++++++-- esphome/components/pzemdc/sensor.py | 11 +++- esphome/components/qmc5883l/sensor.py | 6 +- esphome/components/resistance/sensor.py | 13 ++++- esphome/components/rotary_encoder/sensor.py | 5 +- esphome/components/ruuvitag/sensor.py | 56 +++++++++++++++---- esphome/components/scd30/sensor.py | 19 ++++++- esphome/components/sdm_meter/sensor.py | 39 +++++++++---- esphome/components/sds011/sensor.py | 3 + esphome/components/senseair/sensor.py | 7 ++- esphome/components/sensor/__init__.py | 18 ++++++ esphome/components/sensor/sensor.cpp | 18 ++++++ esphome/components/sensor/sensor.h | 18 ++++++ esphome/components/sgp30/sensor.py | 13 ++++- esphome/components/sgp40/sensor.py | 12 +++- esphome/components/sht3xd/sensor.py | 13 ++++- esphome/components/sht4x/sensor.py | 13 ++++- esphome/components/shtcx/sensor.py | 13 ++++- esphome/components/sm300d2/sensor.py | 38 +++++++++++-- esphome/components/sps30/sensor.py | 41 ++++++++++++-- esphome/components/sts3x/sensor.py | 12 +++- esphome/components/sun/sensor/__init__.py | 5 +- esphome/components/tcs34725/sensor.py | 7 ++- .../components/template/sensor/__init__.py | 11 +++- esphome/components/tmp102/sensor.py | 12 +++- esphome/components/tmp117/sensor.py | 5 +- esphome/components/tof10120/sensor.py | 16 +++++- esphome/components/tsl2561/sensor.py | 5 +- esphome/components/tx20/sensor.py | 10 +++- esphome/components/ultrasonic/sensor.py | 9 ++- esphome/components/uptime/sensor.py | 12 +++- esphome/components/vl53l0x/sensor.py | 9 ++- esphome/components/wifi_signal/sensor.py | 7 ++- esphome/components/xiaomi_cgd1/sensor.py | 19 ++++++- esphome/components/xiaomi_cgdk2/sensor.py | 19 ++++++- esphome/components/xiaomi_cgg1/sensor.py | 19 ++++++- esphome/components/xiaomi_gcls002/sensor.py | 25 +++++++-- esphome/components/xiaomi_hhccjcy01/sensor.py | 31 ++++++++-- .../components/xiaomi_hhccpot002/sensor.py | 13 ++++- esphome/components/xiaomi_jqjcy01ym/sensor.py | 20 ++++++- esphome/components/xiaomi_lywsd02/sensor.py | 19 ++++++- .../components/xiaomi_lywsd03mmc/sensor.py | 19 ++++++- esphome/components/xiaomi_lywsdcgq/sensor.py | 19 ++++++- esphome/components/xiaomi_mhoc401/sensor.py | 19 ++++++- esphome/components/xiaomi_miscale/sensor.py | 7 ++- esphome/components/xiaomi_miscale2/sensor.py | 9 ++- .../xiaomi_mjyd02yla/binary_sensor.py | 16 +++++- .../components/xiaomi_wx08zm/binary_sensor.py | 9 ++- esphome/components/zyaura/sensor.py | 15 ++++- esphome/const.py | 7 +++ tests/test1.yaml | 2 +- 112 files changed, 1237 insertions(+), 269 deletions(-) diff --git a/esphome/components/adc/sensor.py b/esphome/components/adc/sensor.py index f988563227..90561679b7 100644 --- a/esphome/components/adc/sensor.py +++ b/esphome/components/adc/sensor.py @@ -8,6 +8,7 @@ from esphome.const import ( CONF_PIN, DEVICE_CLASS_VOLTAGE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_VOLT, ) @@ -35,7 +36,9 @@ ADCSensor = adc_ns.class_( ) CONFIG_SCHEMA = ( - sensor.sensor_schema(UNIT_VOLT, ICON_EMPTY, 2, DEVICE_CLASS_VOLTAGE) + sensor.sensor_schema( + UNIT_VOLT, ICON_EMPTY, 2, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT + ) .extend( { cv.GenerateID(): cv.declare_id(ADCSensor), diff --git a/esphome/components/ade7953/sensor.py b/esphome/components/ade7953/sensor.py index b91e8d3bea..90873f1a5e 100644 --- a/esphome/components/ade7953/sensor.py +++ b/esphome/components/ade7953/sensor.py @@ -9,6 +9,7 @@ from esphome.const import ( DEVICE_CLASS_POWER, DEVICE_CLASS_VOLTAGE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_VOLT, UNIT_AMPERE, UNIT_WATT, @@ -31,19 +32,27 @@ CONFIG_SCHEMA = ( cv.GenerateID(): cv.declare_id(ADE7953), cv.Optional(CONF_IRQ_PIN): pins.input_pin, cv.Optional(CONF_VOLTAGE): sensor.sensor_schema( - UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE + UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT ), cv.Optional(CONF_CURRENT_A): sensor.sensor_schema( - UNIT_AMPERE, ICON_EMPTY, 2, DEVICE_CLASS_CURRENT + UNIT_AMPERE, + ICON_EMPTY, + 2, + DEVICE_CLASS_CURRENT, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_CURRENT_B): sensor.sensor_schema( - UNIT_AMPERE, ICON_EMPTY, 2, DEVICE_CLASS_CURRENT + UNIT_AMPERE, + ICON_EMPTY, + 2, + DEVICE_CLASS_CURRENT, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_ACTIVE_POWER_A): sensor.sensor_schema( - UNIT_WATT, ICON_EMPTY, 1, DEVICE_CLASS_POWER + UNIT_WATT, ICON_EMPTY, 1, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT ), cv.Optional(CONF_ACTIVE_POWER_B): sensor.sensor_schema( - UNIT_WATT, ICON_EMPTY, 1, DEVICE_CLASS_POWER + UNIT_WATT, ICON_EMPTY, 1, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT ), } ) diff --git a/esphome/components/ads1115/sensor.py b/esphome/components/ads1115/sensor.py index 4585a758b5..c521769279 100644 --- a/esphome/components/ads1115/sensor.py +++ b/esphome/components/ads1115/sensor.py @@ -6,6 +6,7 @@ from esphome.const import ( CONF_MULTIPLEXER, DEVICE_CLASS_VOLTAGE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_VOLT, CONF_ID, ) @@ -51,7 +52,9 @@ ADS1115Sensor = ads1115_ns.class_( CONF_ADS1115_ID = "ads1115_id" CONFIG_SCHEMA = ( - sensor.sensor_schema(UNIT_VOLT, ICON_EMPTY, 3, DEVICE_CLASS_VOLTAGE) + sensor.sensor_schema( + UNIT_VOLT, ICON_EMPTY, 3, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT + ) .extend( { cv.GenerateID(): cv.declare_id(ADS1115Sensor), diff --git a/esphome/components/aht10/sensor.py b/esphome/components/aht10/sensor.py index 2e553638d1..35168be54a 100644 --- a/esphome/components/aht10/sensor.py +++ b/esphome/components/aht10/sensor.py @@ -8,6 +8,7 @@ from esphome.const import ( DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_TEMPERATURE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, UNIT_PERCENT, ) @@ -22,10 +23,18 @@ CONFIG_SCHEMA = ( { cv.GenerateID(): cv.declare_id(AHT10Component), cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 2, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_EMPTY, + 2, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 2, DEVICE_CLASS_HUMIDITY + UNIT_PERCENT, + ICON_EMPTY, + 2, + DEVICE_CLASS_HUMIDITY, + STATE_CLASS_MEASUREMENT, ), } ) diff --git a/esphome/components/am2320/sensor.py b/esphome/components/am2320/sensor.py index c0a6a60437..5d6cb9eded 100644 --- a/esphome/components/am2320/sensor.py +++ b/esphome/components/am2320/sensor.py @@ -7,6 +7,7 @@ from esphome.const import ( CONF_TEMPERATURE, DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ICON_EMPTY, UNIT_PERCENT, @@ -24,10 +25,18 @@ CONFIG_SCHEMA = ( { cv.GenerateID(): cv.declare_id(AM2320Component), cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_EMPTY, + 1, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 1, DEVICE_CLASS_HUMIDITY + UNIT_PERCENT, + ICON_EMPTY, + 1, + DEVICE_CLASS_HUMIDITY, + STATE_CLASS_MEASUREMENT, ), } ) diff --git a/esphome/components/apds9960/sensor.py b/esphome/components/apds9960/sensor.py index 53633693a2..cb0c52735d 100644 --- a/esphome/components/apds9960/sensor.py +++ b/esphome/components/apds9960/sensor.py @@ -1,7 +1,13 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import sensor -from esphome.const import CONF_TYPE, DEVICE_CLASS_EMPTY, UNIT_PERCENT, ICON_LIGHTBULB +from esphome.const import ( + CONF_TYPE, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, + UNIT_PERCENT, + ICON_LIGHTBULB, +) from . import APDS9960, CONF_APDS9960_ID DEPENDENCIES = ["apds9960"] @@ -15,7 +21,7 @@ TYPES = { } CONFIG_SCHEMA = sensor.sensor_schema( - UNIT_PERCENT, ICON_LIGHTBULB, 1, DEVICE_CLASS_EMPTY + UNIT_PERCENT, ICON_LIGHTBULB, 1, DEVICE_CLASS_EMPTY, STATE_CLASS_MEASUREMENT ).extend( { cv.Required(CONF_TYPE): cv.one_of(*TYPES, upper=True), diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index e228fe6874..43e23f640b 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -409,6 +409,11 @@ message LightCommandRequest { } // ==================== SENSOR ==================== +enum SensorStateClass { + STATE_CLASS_NONE = 0; + STATE_CLASS_MEASUREMENT = 1; +} + message ListEntitiesSensorResponse { option (id) = 16; option (source) = SOURCE_SERVER; @@ -424,6 +429,7 @@ message ListEntitiesSensorResponse { int32 accuracy_decimals = 7; bool force_update = 8; string device_class = 9; + SensorStateClass state_class = 10; } message SensorStateResponse { option (id) = 25; diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index ac04e1f09f..b5fc9b245c 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -395,6 +395,8 @@ bool APIConnection::send_sensor_info(sensor::Sensor *sensor) { msg.accuracy_decimals = sensor->get_accuracy_decimals(); msg.force_update = sensor->get_force_update(); msg.device_class = sensor->get_device_class(); + msg.state_class = static_cast(sensor->state_class); + return this->send_list_entities_sensor_response(msg); } #endif diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 8f8e2abf58..38efbc2ec4 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -62,6 +62,16 @@ template<> const char *proto_enum_to_string(enums::FanDirec return "UNKNOWN"; } } +template<> const char *proto_enum_to_string(enums::SensorStateClass value) { + switch (value) { + case enums::STATE_CLASS_NONE: + return "STATE_CLASS_NONE"; + case enums::STATE_CLASS_MEASUREMENT: + return "STATE_CLASS_MEASUREMENT"; + default: + return "UNKNOWN"; + } +} template<> const char *proto_enum_to_string(enums::LogLevel value) { switch (value) { case enums::LOG_LEVEL_NONE: @@ -1507,6 +1517,10 @@ bool ListEntitiesSensorResponse::decode_varint(uint32_t field_id, ProtoVarInt va this->force_update = value.as_bool(); return true; } + case 10: { + this->state_class = value.as_enum(); + return true; + } default: return false; } @@ -1561,6 +1575,7 @@ void ListEntitiesSensorResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_int32(7, this->accuracy_decimals); buffer.encode_bool(8, this->force_update); buffer.encode_string(9, this->device_class); + buffer.encode_enum(10, this->state_class); } void ListEntitiesSensorResponse::dump_to(std::string &out) const { char buffer[64]; @@ -1602,6 +1617,10 @@ void ListEntitiesSensorResponse::dump_to(std::string &out) const { out.append(" device_class: "); out.append("'").append(this->device_class).append("'"); out.append("\n"); + + out.append(" state_class: "); + out.append(proto_enum_to_string(this->state_class)); + out.append("\n"); out.append("}"); } bool SensorStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index 5715a7f50f..e49136b442 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -32,6 +32,10 @@ enum FanDirection : uint32_t { FAN_DIRECTION_FORWARD = 0, FAN_DIRECTION_REVERSE = 1, }; +enum SensorStateClass : uint32_t { + STATE_CLASS_NONE = 0, + STATE_CLASS_MEASUREMENT = 1, +}; enum LogLevel : uint32_t { LOG_LEVEL_NONE = 0, LOG_LEVEL_ERROR = 1, @@ -408,6 +412,7 @@ class ListEntitiesSensorResponse : public ProtoMessage { int32_t accuracy_decimals{0}; bool force_update{false}; std::string device_class{}; + enums::SensorStateClass state_class{}; void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; diff --git a/esphome/components/as3935/sensor.py b/esphome/components/as3935/sensor.py index 6afe890d65..a571121742 100644 --- a/esphome/components/as3935/sensor.py +++ b/esphome/components/as3935/sensor.py @@ -5,6 +5,7 @@ from esphome.const import ( CONF_DISTANCE, CONF_LIGHTNING_ENERGY, DEVICE_CLASS_EMPTY, + STATE_CLASS_NONE, UNIT_KILOMETER, UNIT_EMPTY, ICON_SIGNAL_DISTANCE_VARIANT, @@ -18,10 +19,14 @@ CONFIG_SCHEMA = cv.Schema( { cv.GenerateID(CONF_AS3935_ID): cv.use_id(AS3935), cv.Optional(CONF_DISTANCE): sensor.sensor_schema( - UNIT_KILOMETER, ICON_SIGNAL_DISTANCE_VARIANT, 1, DEVICE_CLASS_EMPTY + UNIT_KILOMETER, + ICON_SIGNAL_DISTANCE_VARIANT, + 1, + DEVICE_CLASS_EMPTY, + STATE_CLASS_NONE, ), cv.Optional(CONF_LIGHTNING_ENERGY): sensor.sensor_schema( - UNIT_EMPTY, ICON_FLASH, 1, DEVICE_CLASS_EMPTY + UNIT_EMPTY, ICON_FLASH, 1, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE ), } ).extend(cv.COMPONENT_SCHEMA) diff --git a/esphome/components/atc_mithermometer/sensor.py b/esphome/components/atc_mithermometer/sensor.py index 161f1f021b..efa3f2b51a 100644 --- a/esphome/components/atc_mithermometer/sensor.py +++ b/esphome/components/atc_mithermometer/sensor.py @@ -13,6 +13,7 @@ from esphome.const import ( DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_VOLTAGE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, UNIT_PERCENT, UNIT_VOLT, @@ -33,16 +34,28 @@ CONFIG_SCHEMA = ( cv.GenerateID(): cv.declare_id(ATCMiThermometer), cv.Required(CONF_MAC_ADDRESS): cv.mac_address, cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_EMPTY, + 1, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 0, DEVICE_CLASS_HUMIDITY + UNIT_PERCENT, + ICON_EMPTY, + 0, + DEVICE_CLASS_HUMIDITY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 0, DEVICE_CLASS_BATTERY + UNIT_PERCENT, + ICON_EMPTY, + 0, + DEVICE_CLASS_BATTERY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_BATTERY_VOLTAGE): sensor.sensor_schema( - UNIT_VOLT, ICON_EMPTY, 3, DEVICE_CLASS_VOLTAGE + UNIT_VOLT, ICON_EMPTY, 3, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT ), } ) diff --git a/esphome/components/atm90e32/sensor.py b/esphome/components/atm90e32/sensor.py index aaf9320b9e..68ec199bff 100644 --- a/esphome/components/atm90e32/sensor.py +++ b/esphome/components/atm90e32/sensor.py @@ -21,6 +21,7 @@ from esphome.const import ( ICON_EMPTY, ICON_LIGHTBULB, ICON_CURRENT_AC, + STATE_CLASS_MEASUREMENT, UNIT_HERTZ, UNIT_VOLT, UNIT_AMPERE, @@ -63,25 +64,37 @@ ATM90E32Component = atm90e32_ns.class_( ATM90E32_PHASE_SCHEMA = cv.Schema( { cv.Optional(CONF_VOLTAGE): sensor.sensor_schema( - UNIT_VOLT, ICON_EMPTY, 2, DEVICE_CLASS_VOLTAGE + UNIT_VOLT, + ICON_EMPTY, + 2, + DEVICE_CLASS_VOLTAGE, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_CURRENT): sensor.sensor_schema( - UNIT_AMPERE, ICON_EMPTY, 2, DEVICE_CLASS_CURRENT + UNIT_AMPERE, ICON_EMPTY, 2, DEVICE_CLASS_CURRENT, STATE_CLASS_MEASUREMENT ), cv.Optional(CONF_POWER): sensor.sensor_schema( - UNIT_WATT, ICON_EMPTY, 2, DEVICE_CLASS_POWER + UNIT_WATT, ICON_EMPTY, 2, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT ), cv.Optional(CONF_REACTIVE_POWER): sensor.sensor_schema( - UNIT_VOLT_AMPS_REACTIVE, ICON_LIGHTBULB, 2, DEVICE_CLASS_EMPTY + UNIT_VOLT_AMPS_REACTIVE, + ICON_LIGHTBULB, + 2, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_POWER_FACTOR): sensor.sensor_schema( - UNIT_EMPTY, ICON_EMPTY, 2, DEVICE_CLASS_POWER_FACTOR + UNIT_EMPTY, + ICON_EMPTY, + 2, + DEVICE_CLASS_POWER_FACTOR, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_FORWARD_ACTIVE_ENERGY): sensor.sensor_schema( - UNIT_WATT_HOURS, ICON_EMPTY, 2, DEVICE_CLASS_ENERGY + UNIT_WATT_HOURS, ICON_EMPTY, 2, DEVICE_CLASS_ENERGY, STATE_CLASS_MEASUREMENT ), cv.Optional(CONF_REVERSE_ACTIVE_ENERGY): sensor.sensor_schema( - UNIT_WATT_HOURS, ICON_EMPTY, 2, DEVICE_CLASS_ENERGY + UNIT_WATT_HOURS, ICON_EMPTY, 2, DEVICE_CLASS_ENERGY, STATE_CLASS_MEASUREMENT ), cv.Optional(CONF_GAIN_VOLTAGE, default=7305): cv.uint16_t, cv.Optional(CONF_GAIN_CT, default=27961): cv.uint16_t, @@ -96,10 +109,18 @@ CONFIG_SCHEMA = ( cv.Optional(CONF_PHASE_B): ATM90E32_PHASE_SCHEMA, cv.Optional(CONF_PHASE_C): ATM90E32_PHASE_SCHEMA, cv.Optional(CONF_FREQUENCY): sensor.sensor_schema( - UNIT_HERTZ, ICON_CURRENT_AC, 1, DEVICE_CLASS_EMPTY + UNIT_HERTZ, + ICON_CURRENT_AC, + 1, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_CHIP_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_EMPTY, + 1, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ), cv.Required(CONF_LINE_FREQUENCY): cv.enum(LINE_FREQS, upper=True), cv.Optional(CONF_CURRENT_PHASES, default="3"): cv.enum( diff --git a/esphome/components/b_parasite/sensor.py b/esphome/components/b_parasite/sensor.py index 415cae454f..d93e41816b 100644 --- a/esphome/components/b_parasite/sensor.py +++ b/esphome/components/b_parasite/sensor.py @@ -12,6 +12,7 @@ from esphome.const import ( DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_VOLTAGE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, UNIT_PERCENT, UNIT_VOLT, @@ -32,16 +33,28 @@ CONFIG_SCHEMA = ( cv.GenerateID(): cv.declare_id(BParasite), cv.Required(CONF_MAC_ADDRESS): cv.mac_address, cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_EMPTY, + 1, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 1, DEVICE_CLASS_HUMIDITY + UNIT_PERCENT, + ICON_EMPTY, + 1, + DEVICE_CLASS_HUMIDITY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_BATTERY_VOLTAGE): sensor.sensor_schema( - UNIT_VOLT, ICON_EMPTY, 3, DEVICE_CLASS_VOLTAGE + UNIT_VOLT, ICON_EMPTY, 3, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT ), cv.Optional(CONF_MOISTURE): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 1, DEVICE_CLASS_HUMIDITY + UNIT_PERCENT, + ICON_EMPTY, + 1, + DEVICE_CLASS_HUMIDITY, + STATE_CLASS_MEASUREMENT, ), } ) diff --git a/esphome/components/bh1750/sensor.py b/esphome/components/bh1750/sensor.py index 6c3c20d9c4..e688241dcc 100644 --- a/esphome/components/bh1750/sensor.py +++ b/esphome/components/bh1750/sensor.py @@ -6,6 +6,7 @@ from esphome.const import ( CONF_RESOLUTION, DEVICE_CLASS_ILLUMINANCE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_LUX, CONF_MEASUREMENT_DURATION, ) @@ -26,7 +27,9 @@ BH1750Sensor = bh1750_ns.class_( CONF_MEASUREMENT_TIME = "measurement_time" CONFIG_SCHEMA = ( - sensor.sensor_schema(UNIT_LUX, ICON_EMPTY, 1, DEVICE_CLASS_ILLUMINANCE) + sensor.sensor_schema( + UNIT_LUX, ICON_EMPTY, 1, DEVICE_CLASS_ILLUMINANCE, STATE_CLASS_MEASUREMENT + ) .extend( { cv.GenerateID(): cv.declare_id(BH1750Sensor), diff --git a/esphome/components/binary_sensor_map/sensor.py b/esphome/components/binary_sensor_map/sensor.py index 406a1b7bd1..131a050052 100644 --- a/esphome/components/binary_sensor_map/sensor.py +++ b/esphome/components/binary_sensor_map/sensor.py @@ -12,6 +12,7 @@ from esphome.const import ( ICON_CHECK_CIRCLE_OUTLINE, CONF_BINARY_SENSOR, CONF_GROUP, + STATE_CLASS_NONE, ) DEPENDENCIES = ["binary_sensor"] @@ -34,7 +35,11 @@ entry = { CONFIG_SCHEMA = cv.typed_schema( { CONF_GROUP: sensor.sensor_schema( - UNIT_EMPTY, ICON_CHECK_CIRCLE_OUTLINE, 0, DEVICE_CLASS_EMPTY + UNIT_EMPTY, + ICON_CHECK_CIRCLE_OUTLINE, + 0, + DEVICE_CLASS_EMPTY, + STATE_CLASS_NONE, ).extend( { cv.GenerateID(): cv.declare_id(BinarySensorMap), diff --git a/esphome/components/ble_client/sensor/__init__.py b/esphome/components/ble_client/sensor/__init__.py index a0bc996d87..c6f05932ef 100644 --- a/esphome/components/ble_client/sensor/__init__.py +++ b/esphome/components/ble_client/sensor/__init__.py @@ -5,6 +5,7 @@ from esphome.const import ( DEVICE_CLASS_EMPTY, CONF_ID, CONF_LAMBDA, + STATE_CLASS_NONE, UNIT_EMPTY, ICON_EMPTY, CONF_TRIGGER_ID, @@ -32,7 +33,9 @@ BLESensorNotifyTrigger = ble_client_ns.class_( ) CONFIG_SCHEMA = cv.All( - sensor.sensor_schema(UNIT_EMPTY, ICON_EMPTY, 0, DEVICE_CLASS_EMPTY) + sensor.sensor_schema( + UNIT_EMPTY, ICON_EMPTY, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE + ) .extend( { cv.GenerateID(): cv.declare_id(BLESensor), diff --git a/esphome/components/ble_rssi/sensor.py b/esphome/components/ble_rssi/sensor.py index 279fc4ae19..819b7c6fd7 100644 --- a/esphome/components/ble_rssi/sensor.py +++ b/esphome/components/ble_rssi/sensor.py @@ -6,6 +6,7 @@ from esphome.const import ( CONF_MAC_ADDRESS, CONF_ID, DEVICE_CLASS_SIGNAL_STRENGTH, + STATE_CLASS_MEASUREMENT, UNIT_DECIBEL, ICON_EMPTY, ) @@ -18,7 +19,13 @@ BLERSSISensor = ble_rssi_ns.class_( ) CONFIG_SCHEMA = cv.All( - sensor.sensor_schema(UNIT_DECIBEL, ICON_EMPTY, 0, DEVICE_CLASS_SIGNAL_STRENGTH) + sensor.sensor_schema( + UNIT_DECIBEL, + ICON_EMPTY, + 0, + DEVICE_CLASS_SIGNAL_STRENGTH, + STATE_CLASS_MEASUREMENT, + ) .extend( { cv.GenerateID(): cv.declare_id(BLERSSISensor), diff --git a/esphome/components/bme280/sensor.py b/esphome/components/bme280/sensor.py index 2b1b8825f8..8c6cc7ae56 100644 --- a/esphome/components/bme280/sensor.py +++ b/esphome/components/bme280/sensor.py @@ -12,6 +12,7 @@ from esphome.const import ( DEVICE_CLASS_PRESSURE, DEVICE_CLASS_TEMPERATURE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, UNIT_HECTOPASCAL, UNIT_PERCENT, @@ -48,7 +49,11 @@ CONFIG_SCHEMA = ( { cv.GenerateID(): cv.declare_id(BME280Component), cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_EMPTY, + 1, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ).extend( { cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum( @@ -57,7 +62,11 @@ CONFIG_SCHEMA = ( } ), cv.Optional(CONF_PRESSURE): sensor.sensor_schema( - UNIT_HECTOPASCAL, ICON_EMPTY, 1, DEVICE_CLASS_PRESSURE + UNIT_HECTOPASCAL, + ICON_EMPTY, + 1, + DEVICE_CLASS_PRESSURE, + STATE_CLASS_MEASUREMENT, ).extend( { cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum( @@ -66,7 +75,11 @@ CONFIG_SCHEMA = ( } ), cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 1, DEVICE_CLASS_HUMIDITY + UNIT_PERCENT, + ICON_EMPTY, + 1, + DEVICE_CLASS_HUMIDITY, + STATE_CLASS_MEASUREMENT, ).extend( { cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum( diff --git a/esphome/components/bme680/sensor.py b/esphome/components/bme680/sensor.py index 08a5b3b0a2..eaa158c9f8 100644 --- a/esphome/components/bme680/sensor.py +++ b/esphome/components/bme680/sensor.py @@ -16,6 +16,7 @@ from esphome.const import ( DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_PRESSURE, DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, UNIT_OHM, ICON_GAS_CYLINDER, UNIT_CELSIUS, @@ -58,7 +59,11 @@ CONFIG_SCHEMA = ( { cv.GenerateID(): cv.declare_id(BME680Component), cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_EMPTY, + 1, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ).extend( { cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum( @@ -67,7 +72,11 @@ CONFIG_SCHEMA = ( } ), cv.Optional(CONF_PRESSURE): sensor.sensor_schema( - UNIT_HECTOPASCAL, ICON_EMPTY, 1, DEVICE_CLASS_PRESSURE + UNIT_HECTOPASCAL, + ICON_EMPTY, + 1, + DEVICE_CLASS_PRESSURE, + STATE_CLASS_MEASUREMENT, ).extend( { cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum( @@ -76,7 +85,11 @@ CONFIG_SCHEMA = ( } ), cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 1, DEVICE_CLASS_HUMIDITY + UNIT_PERCENT, + ICON_EMPTY, + 1, + DEVICE_CLASS_HUMIDITY, + STATE_CLASS_MEASUREMENT, ).extend( { cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum( @@ -85,7 +98,11 @@ CONFIG_SCHEMA = ( } ), cv.Optional(CONF_GAS_RESISTANCE): sensor.sensor_schema( - UNIT_OHM, ICON_GAS_CYLINDER, 1, DEVICE_CLASS_EMPTY + UNIT_OHM, + ICON_GAS_CYLINDER, + 1, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_IIR_FILTER, default="OFF"): cv.enum( IIR_FILTER_OPTIONS, upper=True diff --git a/esphome/components/bme680_bsec/sensor.py b/esphome/components/bme680_bsec/sensor.py index 5634b21e75..4520bf3480 100644 --- a/esphome/components/bme680_bsec/sensor.py +++ b/esphome/components/bme680_bsec/sensor.py @@ -10,6 +10,7 @@ from esphome.const import ( DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_PRESSURE, DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, UNIT_EMPTY, UNIT_HECTOPASCAL, @@ -53,34 +54,54 @@ CONFIG_SCHEMA = cv.Schema( { cv.GenerateID(CONF_BME680_BSEC_ID): cv.use_id(BME680BSECComponent), cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_THERMOMETER, 1, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_THERMOMETER, + 1, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ).extend( {cv.Optional(CONF_SAMPLE_RATE): cv.enum(SAMPLE_RATE_OPTIONS, upper=True)} ), cv.Optional(CONF_PRESSURE): sensor.sensor_schema( - UNIT_HECTOPASCAL, ICON_GAUGE, 1, DEVICE_CLASS_PRESSURE + UNIT_HECTOPASCAL, + ICON_GAUGE, + 1, + DEVICE_CLASS_PRESSURE, + STATE_CLASS_MEASUREMENT, ).extend( {cv.Optional(CONF_SAMPLE_RATE): cv.enum(SAMPLE_RATE_OPTIONS, upper=True)} ), cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( - UNIT_PERCENT, ICON_WATER_PERCENT, 1, DEVICE_CLASS_HUMIDITY + UNIT_PERCENT, + ICON_WATER_PERCENT, + 1, + DEVICE_CLASS_HUMIDITY, + STATE_CLASS_MEASUREMENT, ).extend( {cv.Optional(CONF_SAMPLE_RATE): cv.enum(SAMPLE_RATE_OPTIONS, upper=True)} ), cv.Optional(CONF_GAS_RESISTANCE): sensor.sensor_schema( - UNIT_OHM, ICON_GAS_CYLINDER, 0, DEVICE_CLASS_EMPTY + UNIT_OHM, ICON_GAS_CYLINDER, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_MEASUREMENT ), cv.Optional(CONF_IAQ): sensor.sensor_schema( - UNIT_IAQ, ICON_GAUGE, 0, DEVICE_CLASS_EMPTY + UNIT_IAQ, ICON_GAUGE, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_MEASUREMENT ), cv.Optional(CONF_IAQ_ACCURACY): sensor.sensor_schema( - UNIT_EMPTY, ICON_ACCURACY, 0, DEVICE_CLASS_EMPTY + UNIT_EMPTY, ICON_ACCURACY, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_MEASUREMENT ), cv.Optional(CONF_CO2_EQUIVALENT): sensor.sensor_schema( - UNIT_PARTS_PER_MILLION, ICON_TEST_TUBE, 1, DEVICE_CLASS_EMPTY + UNIT_PARTS_PER_MILLION, + ICON_TEST_TUBE, + 1, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_BREATH_VOC_EQUIVALENT): sensor.sensor_schema( - UNIT_PARTS_PER_MILLION, ICON_TEST_TUBE, 1, DEVICE_CLASS_EMPTY + UNIT_PARTS_PER_MILLION, + ICON_TEST_TUBE, + 1, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), } ) diff --git a/esphome/components/bmp085/sensor.py b/esphome/components/bmp085/sensor.py index eca5283d5d..1b48f2e440 100644 --- a/esphome/components/bmp085/sensor.py +++ b/esphome/components/bmp085/sensor.py @@ -7,6 +7,7 @@ from esphome.const import ( CONF_TEMPERATURE, DEVICE_CLASS_PRESSURE, DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ICON_EMPTY, UNIT_HECTOPASCAL, @@ -24,10 +25,18 @@ CONFIG_SCHEMA = ( { cv.GenerateID(): cv.declare_id(BMP085Component), cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_EMPTY, + 1, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_PRESSURE): sensor.sensor_schema( - UNIT_HECTOPASCAL, ICON_EMPTY, 1, DEVICE_CLASS_PRESSURE + UNIT_HECTOPASCAL, + ICON_EMPTY, + 1, + DEVICE_CLASS_PRESSURE, + STATE_CLASS_MEASUREMENT, ), } ) diff --git a/esphome/components/bmp280/sensor.py b/esphome/components/bmp280/sensor.py index d86767ecd5..48953d0259 100644 --- a/esphome/components/bmp280/sensor.py +++ b/esphome/components/bmp280/sensor.py @@ -7,6 +7,7 @@ from esphome.const import ( CONF_TEMPERATURE, DEVICE_CLASS_PRESSURE, DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ICON_EMPTY, UNIT_HECTOPASCAL, @@ -45,7 +46,11 @@ CONFIG_SCHEMA = ( { cv.GenerateID(): cv.declare_id(BMP280Component), cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_EMPTY, + 1, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ).extend( { cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum( @@ -54,7 +59,11 @@ CONFIG_SCHEMA = ( } ), cv.Optional(CONF_PRESSURE): sensor.sensor_schema( - UNIT_HECTOPASCAL, ICON_EMPTY, 1, DEVICE_CLASS_PRESSURE + UNIT_HECTOPASCAL, + ICON_EMPTY, + 1, + DEVICE_CLASS_PRESSURE, + STATE_CLASS_MEASUREMENT, ).extend( { cv.Optional(CONF_OVERSAMPLING, default="16X"): cv.enum( diff --git a/esphome/components/ccs811/sensor.py b/esphome/components/ccs811/sensor.py index e86d8f9b83..4c4f8802d4 100644 --- a/esphome/components/ccs811/sensor.py +++ b/esphome/components/ccs811/sensor.py @@ -5,6 +5,7 @@ from esphome.const import ( CONF_ID, DEVICE_CLASS_EMPTY, ICON_RADIATOR, + STATE_CLASS_MEASUREMENT, UNIT_PARTS_PER_MILLION, UNIT_PARTS_PER_BILLION, CONF_TEMPERATURE, @@ -28,10 +29,18 @@ CONFIG_SCHEMA = ( { cv.GenerateID(): cv.declare_id(CCS811Component), cv.Required(CONF_ECO2): sensor.sensor_schema( - UNIT_PARTS_PER_MILLION, ICON_MOLECULE_CO2, 0, DEVICE_CLASS_EMPTY + UNIT_PARTS_PER_MILLION, + ICON_MOLECULE_CO2, + 0, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Required(CONF_TVOC): sensor.sensor_schema( - UNIT_PARTS_PER_BILLION, ICON_RADIATOR, 0, DEVICE_CLASS_EMPTY + UNIT_PARTS_PER_BILLION, + ICON_RADIATOR, + 0, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_BASELINE): cv.hex_uint16_t, cv.Optional(CONF_TEMPERATURE): cv.use_id(sensor.Sensor), diff --git a/esphome/components/cse7766/sensor.py b/esphome/components/cse7766/sensor.py index ca829cb274..98cf4da96d 100644 --- a/esphome/components/cse7766/sensor.py +++ b/esphome/components/cse7766/sensor.py @@ -10,6 +10,7 @@ from esphome.const import ( DEVICE_CLASS_POWER, DEVICE_CLASS_VOLTAGE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_VOLT, UNIT_AMPERE, UNIT_WATT, @@ -27,13 +28,17 @@ CONFIG_SCHEMA = ( { cv.GenerateID(): cv.declare_id(CSE7766Component), cv.Optional(CONF_VOLTAGE): sensor.sensor_schema( - UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE + UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT ), cv.Optional(CONF_CURRENT): sensor.sensor_schema( - UNIT_AMPERE, ICON_EMPTY, 2, DEVICE_CLASS_CURRENT + UNIT_AMPERE, + ICON_EMPTY, + 2, + DEVICE_CLASS_CURRENT, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_POWER): sensor.sensor_schema( - UNIT_WATT, ICON_EMPTY, 1, DEVICE_CLASS_POWER + UNIT_WATT, ICON_EMPTY, 1, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT ), } ) diff --git a/esphome/components/ct_clamp/sensor.py b/esphome/components/ct_clamp/sensor.py index 8b15c9309d..e44d46e7f4 100644 --- a/esphome/components/ct_clamp/sensor.py +++ b/esphome/components/ct_clamp/sensor.py @@ -6,6 +6,7 @@ from esphome.const import ( CONF_ID, DEVICE_CLASS_CURRENT, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_AMPERE, ) @@ -18,7 +19,9 @@ ct_clamp_ns = cg.esphome_ns.namespace("ct_clamp") CTClampSensor = ct_clamp_ns.class_("CTClampSensor", sensor.Sensor, cg.PollingComponent) CONFIG_SCHEMA = ( - sensor.sensor_schema(UNIT_AMPERE, ICON_EMPTY, 2, DEVICE_CLASS_CURRENT) + sensor.sensor_schema( + UNIT_AMPERE, ICON_EMPTY, 2, DEVICE_CLASS_CURRENT, STATE_CLASS_MEASUREMENT + ) .extend( { cv.GenerateID(): cv.declare_id(CTClampSensor), diff --git a/esphome/components/dallas/sensor.py b/esphome/components/dallas/sensor.py index 21ba7b9154..1c8db8fa2f 100644 --- a/esphome/components/dallas/sensor.py +++ b/esphome/components/dallas/sensor.py @@ -8,6 +8,7 @@ from esphome.const import ( CONF_RESOLUTION, DEVICE_CLASS_TEMPERATURE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, CONF_ID, ) @@ -16,7 +17,9 @@ from . import DallasComponent, dallas_ns DallasTemperatureSensor = dallas_ns.class_("DallasTemperatureSensor", sensor.Sensor) CONFIG_SCHEMA = cv.All( - sensor.sensor_schema(UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE).extend( + sensor.sensor_schema( + UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE, STATE_CLASS_MEASUREMENT + ).extend( { cv.GenerateID(): cv.declare_id(DallasTemperatureSensor), cv.GenerateID(CONF_DALLAS_ID): cv.use_id(DallasComponent), diff --git a/esphome/components/dht/sensor.py b/esphome/components/dht/sensor.py index 57971e8202..c33ddd2286 100644 --- a/esphome/components/dht/sensor.py +++ b/esphome/components/dht/sensor.py @@ -9,6 +9,7 @@ from esphome.const import ( CONF_PIN, CONF_TEMPERATURE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, UNIT_PERCENT, DEVICE_CLASS_TEMPERATURE, @@ -35,10 +36,14 @@ CONFIG_SCHEMA = cv.Schema( cv.GenerateID(): cv.declare_id(DHT), cv.Required(CONF_PIN): pins.gpio_input_pin_schema, cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_EMPTY, + 1, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 0, DEVICE_CLASS_HUMIDITY + UNIT_PERCENT, ICON_EMPTY, 0, DEVICE_CLASS_HUMIDITY, STATE_CLASS_MEASUREMENT ), cv.Optional(CONF_MODEL, default="auto detect"): cv.enum( DHT_MODELS, upper=True, space="_" diff --git a/esphome/components/dht12/sensor.py b/esphome/components/dht12/sensor.py index 68ff6ae1bb..14c01f5d34 100644 --- a/esphome/components/dht12/sensor.py +++ b/esphome/components/dht12/sensor.py @@ -5,6 +5,7 @@ from esphome.const import ( CONF_HUMIDITY, CONF_ID, CONF_TEMPERATURE, + STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ICON_EMPTY, UNIT_PERCENT, @@ -22,10 +23,18 @@ CONFIG_SCHEMA = ( { cv.GenerateID(): cv.declare_id(DHT12Component), cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_EMPTY, + 1, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 1, DEVICE_CLASS_HUMIDITY + UNIT_PERCENT, + ICON_EMPTY, + 1, + DEVICE_CLASS_HUMIDITY, + STATE_CLASS_MEASUREMENT, ), } ) diff --git a/esphome/components/duty_cycle/sensor.py b/esphome/components/duty_cycle/sensor.py index e3d2318b51..39f6ebc88f 100644 --- a/esphome/components/duty_cycle/sensor.py +++ b/esphome/components/duty_cycle/sensor.py @@ -6,6 +6,7 @@ from esphome.const import ( CONF_ID, CONF_PIN, DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_PERCENT, ICON_PERCENT, ) @@ -16,7 +17,9 @@ DutyCycleSensor = duty_cycle_ns.class_( ) CONFIG_SCHEMA = ( - sensor.sensor_schema(UNIT_PERCENT, ICON_PERCENT, 1, DEVICE_CLASS_EMPTY) + sensor.sensor_schema( + UNIT_PERCENT, ICON_PERCENT, 1, DEVICE_CLASS_EMPTY, STATE_CLASS_MEASUREMENT + ) .extend( { cv.GenerateID(): cv.declare_id(DutyCycleSensor), diff --git a/esphome/components/esp32_hall/sensor.py b/esphome/components/esp32_hall/sensor.py index 0f1cbb373c..b800b3436a 100644 --- a/esphome/components/esp32_hall/sensor.py +++ b/esphome/components/esp32_hall/sensor.py @@ -5,6 +5,7 @@ from esphome.const import ( CONF_ID, DEVICE_CLASS_EMPTY, ESP_PLATFORM_ESP32, + STATE_CLASS_MEASUREMENT, UNIT_MICROTESLA, ICON_MAGNET, ) @@ -17,7 +18,9 @@ ESP32HallSensor = esp32_hall_ns.class_( ) CONFIG_SCHEMA = ( - sensor.sensor_schema(UNIT_MICROTESLA, ICON_MAGNET, 1, DEVICE_CLASS_EMPTY) + sensor.sensor_schema( + UNIT_MICROTESLA, ICON_MAGNET, 1, DEVICE_CLASS_EMPTY, STATE_CLASS_MEASUREMENT + ) .extend( { cv.GenerateID(): cv.declare_id(ESP32HallSensor), diff --git a/esphome/components/fingerprint_grow/sensor.py b/esphome/components/fingerprint_grow/sensor.py index 11f61a6a71..f8a44eb0da 100644 --- a/esphome/components/fingerprint_grow/sensor.py +++ b/esphome/components/fingerprint_grow/sensor.py @@ -15,6 +15,7 @@ from esphome.const import ( ICON_EMPTY, ICON_FINGERPRINT, ICON_SECURITY, + STATE_CLASS_NONE, UNIT_EMPTY, ) from . import CONF_FINGERPRINT_GROW_ID, FingerprintGrowComponent @@ -25,22 +26,22 @@ CONFIG_SCHEMA = cv.Schema( { cv.GenerateID(CONF_FINGERPRINT_GROW_ID): cv.use_id(FingerprintGrowComponent), cv.Optional(CONF_FINGERPRINT_COUNT): sensor.sensor_schema( - UNIT_EMPTY, ICON_FINGERPRINT, 0, DEVICE_CLASS_EMPTY + UNIT_EMPTY, ICON_FINGERPRINT, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE ), cv.Optional(CONF_STATUS): sensor.sensor_schema( - UNIT_EMPTY, ICON_EMPTY, 0, DEVICE_CLASS_EMPTY + UNIT_EMPTY, ICON_EMPTY, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE ), cv.Optional(CONF_CAPACITY): sensor.sensor_schema( - UNIT_EMPTY, ICON_DATABASE, 0, DEVICE_CLASS_EMPTY + UNIT_EMPTY, ICON_DATABASE, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE ), cv.Optional(CONF_SECURITY_LEVEL): sensor.sensor_schema( - UNIT_EMPTY, ICON_SECURITY, 0, DEVICE_CLASS_EMPTY + UNIT_EMPTY, ICON_SECURITY, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE ), cv.Optional(CONF_LAST_FINGER_ID): sensor.sensor_schema( - UNIT_EMPTY, ICON_ACCOUNT, 0, DEVICE_CLASS_EMPTY + UNIT_EMPTY, ICON_ACCOUNT, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE ), cv.Optional(CONF_LAST_CONFIDENCE): sensor.sensor_schema( - UNIT_EMPTY, ICON_ACCOUNT_CHECK, 0, DEVICE_CLASS_EMPTY + UNIT_EMPTY, ICON_ACCOUNT_CHECK, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE ), } ) diff --git a/esphome/components/gps/__init__.py b/esphome/components/gps/__init__.py index 57ae11ea4f..de3eae1115 100644 --- a/esphome/components/gps/__init__.py +++ b/esphome/components/gps/__init__.py @@ -10,6 +10,8 @@ from esphome.const import ( CONF_COURSE, CONF_ALTITUDE, CONF_SATELLITES, + STATE_CLASS_MEASUREMENT, + STATE_CLASS_NONE, UNIT_DEGREES, UNIT_KILOMETER_PER_HOUR, UNIT_METER, @@ -34,22 +36,26 @@ CONFIG_SCHEMA = ( { cv.GenerateID(): cv.declare_id(GPS), cv.Optional(CONF_LATITUDE): sensor.sensor_schema( - UNIT_DEGREES, ICON_EMPTY, 6, DEVICE_CLASS_EMPTY + UNIT_DEGREES, ICON_EMPTY, 6, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE ), cv.Optional(CONF_LONGITUDE): sensor.sensor_schema( - UNIT_DEGREES, ICON_EMPTY, 6, DEVICE_CLASS_EMPTY + UNIT_DEGREES, ICON_EMPTY, 6, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE ), cv.Optional(CONF_SPEED): sensor.sensor_schema( - UNIT_KILOMETER_PER_HOUR, ICON_EMPTY, 6, DEVICE_CLASS_EMPTY + UNIT_KILOMETER_PER_HOUR, + ICON_EMPTY, + 6, + DEVICE_CLASS_EMPTY, + STATE_CLASS_NONE, ), cv.Optional(CONF_COURSE): sensor.sensor_schema( - UNIT_DEGREES, ICON_EMPTY, 2, DEVICE_CLASS_EMPTY + UNIT_DEGREES, ICON_EMPTY, 2, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE ), cv.Optional(CONF_ALTITUDE): sensor.sensor_schema( - UNIT_METER, ICON_EMPTY, 1, DEVICE_CLASS_EMPTY + UNIT_METER, ICON_EMPTY, 1, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE ), cv.Optional(CONF_SATELLITES): sensor.sensor_schema( - UNIT_EMPTY, ICON_EMPTY, 0, DEVICE_CLASS_EMPTY + UNIT_EMPTY, ICON_EMPTY, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_MEASUREMENT ), } ) diff --git a/esphome/components/hdc1080/sensor.py b/esphome/components/hdc1080/sensor.py index 0995f98589..26ec3ad0a9 100644 --- a/esphome/components/hdc1080/sensor.py +++ b/esphome/components/hdc1080/sensor.py @@ -8,6 +8,7 @@ from esphome.const import ( DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_TEMPERATURE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, UNIT_PERCENT, ) @@ -24,10 +25,18 @@ CONFIG_SCHEMA = ( { cv.GenerateID(): cv.declare_id(HDC1080Component), cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_EMPTY, + 1, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 0, DEVICE_CLASS_HUMIDITY + UNIT_PERCENT, + ICON_EMPTY, + 0, + DEVICE_CLASS_HUMIDITY, + STATE_CLASS_MEASUREMENT, ), } ) diff --git a/esphome/components/hlw8012/sensor.py b/esphome/components/hlw8012/sensor.py index aeab94a05c..6454a9fcc9 100644 --- a/esphome/components/hlw8012/sensor.py +++ b/esphome/components/hlw8012/sensor.py @@ -18,6 +18,8 @@ from esphome.const import ( DEVICE_CLASS_POWER, DEVICE_CLASS_VOLTAGE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, + STATE_CLASS_NONE, UNIT_VOLT, UNIT_AMPERE, UNIT_WATT, @@ -47,16 +49,16 @@ CONFIG_SCHEMA = cv.Schema( pins.internal_gpio_input_pullup_pin_schema, pins.validate_has_interrupt ), cv.Optional(CONF_VOLTAGE): sensor.sensor_schema( - UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE + UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT ), cv.Optional(CONF_CURRENT): sensor.sensor_schema( - UNIT_AMPERE, ICON_EMPTY, 2, DEVICE_CLASS_CURRENT + UNIT_AMPERE, ICON_EMPTY, 2, DEVICE_CLASS_CURRENT, STATE_CLASS_MEASUREMENT ), cv.Optional(CONF_POWER): sensor.sensor_schema( - UNIT_WATT, ICON_EMPTY, 1, DEVICE_CLASS_POWER + UNIT_WATT, ICON_EMPTY, 1, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT ), cv.Optional(CONF_ENERGY): sensor.sensor_schema( - UNIT_WATT_HOURS, ICON_EMPTY, 1, DEVICE_CLASS_ENERGY + UNIT_WATT_HOURS, ICON_EMPTY, 1, DEVICE_CLASS_ENERGY, STATE_CLASS_NONE ), cv.Optional(CONF_CURRENT_RESISTOR, default=0.001): cv.resistance, cv.Optional(CONF_VOLTAGE_DIVIDER, default=2351): cv.positive_float, diff --git a/esphome/components/hm3301/sensor.py b/esphome/components/hm3301/sensor.py index 34555fdcd6..48a29ed5f8 100644 --- a/esphome/components/hm3301/sensor.py +++ b/esphome/components/hm3301/sensor.py @@ -7,6 +7,7 @@ from esphome.const import ( CONF_PM_10_0, CONF_PM_1_0, DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_MICROGRAMS_PER_CUBIC_METER, ICON_CHEMICAL_WEAPON, ) @@ -46,21 +47,28 @@ CONFIG_SCHEMA = cv.All( ICON_CHEMICAL_WEAPON, 0, DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_PM_2_5): sensor.sensor_schema( UNIT_MICROGRAMS_PER_CUBIC_METER, ICON_CHEMICAL_WEAPON, 0, DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_PM_10_0): sensor.sensor_schema( UNIT_MICROGRAMS_PER_CUBIC_METER, ICON_CHEMICAL_WEAPON, 0, DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_AQI): sensor.sensor_schema( - UNIT_INDEX, ICON_CHEMICAL_WEAPON, 0, DEVICE_CLASS_EMPTY + UNIT_INDEX, + ICON_CHEMICAL_WEAPON, + 0, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ).extend( { cv.Required(CONF_CALCULATION_TYPE): cv.enum( diff --git a/esphome/components/hmc5883l/sensor.py b/esphome/components/hmc5883l/sensor.py index c615f929ee..65469003ed 100644 --- a/esphome/components/hmc5883l/sensor.py +++ b/esphome/components/hmc5883l/sensor.py @@ -8,6 +8,8 @@ from esphome.const import ( CONF_RANGE, DEVICE_CLASS_EMPTY, ICON_MAGNET, + STATE_CLASS_MEASUREMENT, + STATE_CLASS_NONE, UNIT_MICROTESLA, UNIT_DEGREES, ICON_SCREEN_ROTATION, @@ -78,10 +80,10 @@ def validate_enum(enum_values, units=None, int=True): field_strength_schema = sensor.sensor_schema( - UNIT_MICROTESLA, ICON_MAGNET, 1, DEVICE_CLASS_EMPTY + UNIT_MICROTESLA, ICON_MAGNET, 1, DEVICE_CLASS_EMPTY, STATE_CLASS_MEASUREMENT ) heading_schema = sensor.sensor_schema( - UNIT_DEGREES, ICON_SCREEN_ROTATION, 1, DEVICE_CLASS_EMPTY + UNIT_DEGREES, ICON_SCREEN_ROTATION, 1, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE ) CONFIG_SCHEMA = ( diff --git a/esphome/components/homeassistant/sensor/__init__.py b/esphome/components/homeassistant/sensor/__init__.py index 771db25b85..0dadb78b73 100644 --- a/esphome/components/homeassistant/sensor/__init__.py +++ b/esphome/components/homeassistant/sensor/__init__.py @@ -6,6 +6,7 @@ from esphome.const import ( CONF_ENTITY_ID, CONF_ID, ICON_EMPTY, + STATE_CLASS_NONE, UNIT_EMPTY, DEVICE_CLASS_EMPTY, ) @@ -18,7 +19,7 @@ HomeassistantSensor = homeassistant_ns.class_( ) CONFIG_SCHEMA = sensor.sensor_schema( - UNIT_EMPTY, ICON_EMPTY, 1, DEVICE_CLASS_EMPTY + UNIT_EMPTY, ICON_EMPTY, 1, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE ).extend( { cv.GenerateID(): cv.declare_id(HomeassistantSensor), diff --git a/esphome/components/htu21d/sensor.py b/esphome/components/htu21d/sensor.py index 596a7d4531..435c5bf1bb 100644 --- a/esphome/components/htu21d/sensor.py +++ b/esphome/components/htu21d/sensor.py @@ -8,6 +8,7 @@ from esphome.const import ( DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_TEMPERATURE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, UNIT_PERCENT, ) @@ -24,10 +25,18 @@ CONFIG_SCHEMA = ( { cv.GenerateID(): cv.declare_id(HTU21DComponent), cv.Required(CONF_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_EMPTY, + 1, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ), cv.Required(CONF_HUMIDITY): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 1, DEVICE_CLASS_HUMIDITY + UNIT_PERCENT, + ICON_EMPTY, + 1, + DEVICE_CLASS_HUMIDITY, + STATE_CLASS_MEASUREMENT, ), } ) diff --git a/esphome/components/hx711/sensor.py b/esphome/components/hx711/sensor.py index b249ca8f77..17a4e35d5f 100644 --- a/esphome/components/hx711/sensor.py +++ b/esphome/components/hx711/sensor.py @@ -8,6 +8,7 @@ from esphome.const import ( CONF_ID, DEVICE_CLASS_EMPTY, ICON_SCALE, + STATE_CLASS_MEASUREMENT, UNIT_EMPTY, ) @@ -24,7 +25,9 @@ GAINS = { } CONFIG_SCHEMA = ( - sensor.sensor_schema(UNIT_EMPTY, ICON_SCALE, 0, DEVICE_CLASS_EMPTY) + sensor.sensor_schema( + UNIT_EMPTY, ICON_SCALE, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_MEASUREMENT + ) .extend( { cv.GenerateID(): cv.declare_id(HX711Sensor), diff --git a/esphome/components/ina219/sensor.py b/esphome/components/ina219/sensor.py index 29241c062e..ed88ace967 100644 --- a/esphome/components/ina219/sensor.py +++ b/esphome/components/ina219/sensor.py @@ -14,6 +14,7 @@ from esphome.const import ( DEVICE_CLASS_POWER, DEVICE_CLASS_VOLTAGE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_VOLT, UNIT_AMPERE, UNIT_WATT, @@ -31,16 +32,20 @@ CONFIG_SCHEMA = ( { cv.GenerateID(): cv.declare_id(INA219Component), cv.Optional(CONF_BUS_VOLTAGE): sensor.sensor_schema( - UNIT_VOLT, ICON_EMPTY, 2, DEVICE_CLASS_VOLTAGE + UNIT_VOLT, ICON_EMPTY, 2, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT ), cv.Optional(CONF_SHUNT_VOLTAGE): sensor.sensor_schema( - UNIT_VOLT, ICON_EMPTY, 2, DEVICE_CLASS_VOLTAGE + UNIT_VOLT, ICON_EMPTY, 2, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT ), cv.Optional(CONF_CURRENT): sensor.sensor_schema( - UNIT_AMPERE, ICON_EMPTY, 3, DEVICE_CLASS_CURRENT + UNIT_AMPERE, + ICON_EMPTY, + 3, + DEVICE_CLASS_CURRENT, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_POWER): sensor.sensor_schema( - UNIT_WATT, ICON_EMPTY, 2, DEVICE_CLASS_POWER + UNIT_WATT, ICON_EMPTY, 2, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT ), cv.Optional(CONF_SHUNT_RESISTANCE, default=0.1): cv.All( cv.resistance, cv.Range(min=0.0, max=32.0) diff --git a/esphome/components/ina226/sensor.py b/esphome/components/ina226/sensor.py index d6d385f5cb..e4ceda39c1 100644 --- a/esphome/components/ina226/sensor.py +++ b/esphome/components/ina226/sensor.py @@ -13,6 +13,7 @@ from esphome.const import ( DEVICE_CLASS_CURRENT, DEVICE_CLASS_POWER, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_VOLT, UNIT_AMPERE, UNIT_WATT, @@ -30,16 +31,20 @@ CONFIG_SCHEMA = ( { cv.GenerateID(): cv.declare_id(INA226Component), cv.Optional(CONF_BUS_VOLTAGE): sensor.sensor_schema( - UNIT_VOLT, ICON_EMPTY, 2, DEVICE_CLASS_VOLTAGE + UNIT_VOLT, ICON_EMPTY, 2, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT ), cv.Optional(CONF_SHUNT_VOLTAGE): sensor.sensor_schema( - UNIT_VOLT, ICON_EMPTY, 2, DEVICE_CLASS_VOLTAGE + UNIT_VOLT, ICON_EMPTY, 2, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT ), cv.Optional(CONF_CURRENT): sensor.sensor_schema( - UNIT_AMPERE, ICON_EMPTY, 3, DEVICE_CLASS_CURRENT + UNIT_AMPERE, + ICON_EMPTY, + 3, + DEVICE_CLASS_CURRENT, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_POWER): sensor.sensor_schema( - UNIT_WATT, ICON_EMPTY, 2, DEVICE_CLASS_POWER + UNIT_WATT, ICON_EMPTY, 2, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT ), cv.Optional(CONF_SHUNT_RESISTANCE, default=0.1): cv.All( cv.resistance, cv.Range(min=0.0) diff --git a/esphome/components/ina3221/sensor.py b/esphome/components/ina3221/sensor.py index b97022ca27..8b861d972d 100644 --- a/esphome/components/ina3221/sensor.py +++ b/esphome/components/ina3221/sensor.py @@ -12,6 +12,7 @@ from esphome.const import ( DEVICE_CLASS_CURRENT, DEVICE_CLASS_POWER, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_VOLT, UNIT_AMPERE, UNIT_WATT, @@ -31,16 +32,16 @@ INA3221Component = ina3221_ns.class_( INA3221_CHANNEL_SCHEMA = cv.Schema( { cv.Optional(CONF_BUS_VOLTAGE): sensor.sensor_schema( - UNIT_VOLT, ICON_EMPTY, 2, DEVICE_CLASS_VOLTAGE + UNIT_VOLT, ICON_EMPTY, 2, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT ), cv.Optional(CONF_SHUNT_VOLTAGE): sensor.sensor_schema( - UNIT_VOLT, ICON_EMPTY, 2, DEVICE_CLASS_VOLTAGE + UNIT_VOLT, ICON_EMPTY, 2, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT ), cv.Optional(CONF_CURRENT): sensor.sensor_schema( - UNIT_AMPERE, ICON_EMPTY, 2, DEVICE_CLASS_CURRENT + UNIT_AMPERE, ICON_EMPTY, 2, DEVICE_CLASS_CURRENT, STATE_CLASS_MEASUREMENT ), cv.Optional(CONF_POWER): sensor.sensor_schema( - UNIT_WATT, ICON_EMPTY, 2, DEVICE_CLASS_POWER + UNIT_WATT, ICON_EMPTY, 2, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT ), cv.Optional(CONF_SHUNT_RESISTANCE, default=0.1): cv.All( cv.resistance, cv.Range(min=0.0, max=32.0) diff --git a/esphome/components/inkbird_ibsth1_mini/sensor.py b/esphome/components/inkbird_ibsth1_mini/sensor.py index cc12be3bf4..044e7fe67d 100644 --- a/esphome/components/inkbird_ibsth1_mini/sensor.py +++ b/esphome/components/inkbird_ibsth1_mini/sensor.py @@ -10,6 +10,7 @@ from esphome.const import ( DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_TEMPERATURE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, UNIT_PERCENT, CONF_ID, @@ -29,13 +30,25 @@ CONFIG_SCHEMA = ( cv.GenerateID(): cv.declare_id(InkbirdUBSTH1_MINI), cv.Required(CONF_MAC_ADDRESS): cv.mac_address, cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_EMPTY, + 1, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 1, DEVICE_CLASS_HUMIDITY + UNIT_PERCENT, + ICON_EMPTY, + 1, + DEVICE_CLASS_HUMIDITY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 0, DEVICE_CLASS_BATTERY + UNIT_PERCENT, + ICON_EMPTY, + 0, + DEVICE_CLASS_BATTERY, + STATE_CLASS_MEASUREMENT, ), } ) diff --git a/esphome/components/max31855/sensor.py b/esphome/components/max31855/sensor.py index 55de8d681e..a8b5d25c61 100644 --- a/esphome/components/max31855/sensor.py +++ b/esphome/components/max31855/sensor.py @@ -6,6 +6,7 @@ from esphome.const import ( CONF_REFERENCE_TEMPERATURE, DEVICE_CLASS_TEMPERATURE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ) @@ -20,7 +21,11 @@ CONFIG_SCHEMA = ( { cv.GenerateID(): cv.declare_id(MAX31855Sensor), cv.Optional(CONF_REFERENCE_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 2, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_EMPTY, + 2, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ), } ) diff --git a/esphome/components/max31856/sensor.py b/esphome/components/max31856/sensor.py index 5c7b7f1f0e..9583c0bcf9 100644 --- a/esphome/components/max31856/sensor.py +++ b/esphome/components/max31856/sensor.py @@ -6,6 +6,7 @@ from esphome.const import ( CONF_MAINS_FILTER, DEVICE_CLASS_TEMPERATURE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ) @@ -21,7 +22,13 @@ FILTER = { } CONFIG_SCHEMA = ( - sensor.sensor_schema(UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE) + sensor.sensor_schema( + UNIT_CELSIUS, + ICON_EMPTY, + 1, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, + ) .extend( { cv.GenerateID(): cv.declare_id(MAX31856Sensor), diff --git a/esphome/components/max31865/sensor.py b/esphome/components/max31865/sensor.py index addedc8296..64495ebd7a 100644 --- a/esphome/components/max31865/sensor.py +++ b/esphome/components/max31865/sensor.py @@ -9,6 +9,7 @@ from esphome.const import ( CONF_RTD_WIRES, DEVICE_CLASS_TEMPERATURE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ) @@ -24,7 +25,9 @@ FILTER = { } CONFIG_SCHEMA = ( - sensor.sensor_schema(UNIT_CELSIUS, ICON_EMPTY, 2, DEVICE_CLASS_TEMPERATURE) + sensor.sensor_schema( + UNIT_CELSIUS, ICON_EMPTY, 2, DEVICE_CLASS_TEMPERATURE, STATE_CLASS_MEASUREMENT + ) .extend( { cv.GenerateID(): cv.declare_id(MAX31865Sensor), diff --git a/esphome/components/max6675/sensor.py b/esphome/components/max6675/sensor.py index 6697f2ae90..ad0e89c028 100644 --- a/esphome/components/max6675/sensor.py +++ b/esphome/components/max6675/sensor.py @@ -1,7 +1,13 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import sensor, spi -from esphome.const import CONF_ID, DEVICE_CLASS_TEMPERATURE, ICON_EMPTY, UNIT_CELSIUS +from esphome.const import ( + CONF_ID, + DEVICE_CLASS_TEMPERATURE, + ICON_EMPTY, + STATE_CLASS_MEASUREMENT, + UNIT_CELSIUS, +) max6675_ns = cg.esphome_ns.namespace("max6675") MAX6675Sensor = max6675_ns.class_( @@ -9,7 +15,9 @@ MAX6675Sensor = max6675_ns.class_( ) CONFIG_SCHEMA = ( - sensor.sensor_schema(UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE) + sensor.sensor_schema( + UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE, STATE_CLASS_MEASUREMENT + ) .extend( { cv.GenerateID(): cv.declare_id(MAX6675Sensor), diff --git a/esphome/components/mcp9808/sensor.py b/esphome/components/mcp9808/sensor.py index f11d5cd755..d417f45955 100644 --- a/esphome/components/mcp9808/sensor.py +++ b/esphome/components/mcp9808/sensor.py @@ -1,7 +1,13 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import i2c, sensor -from esphome.const import CONF_ID, DEVICE_CLASS_TEMPERATURE, ICON_EMPTY, UNIT_CELSIUS +from esphome.const import ( + CONF_ID, + DEVICE_CLASS_TEMPERATURE, + ICON_EMPTY, + STATE_CLASS_MEASUREMENT, + UNIT_CELSIUS, +) CODEOWNERS = ["@k7hpn"] DEPENDENCIES = ["i2c"] @@ -12,7 +18,9 @@ MCP9808Sensor = mcp9808_ns.class_( ) CONFIG_SCHEMA = ( - sensor.sensor_schema(UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE) + sensor.sensor_schema( + UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE, STATE_CLASS_MEASUREMENT + ) .extend( { cv.GenerateID(): cv.declare_id(MCP9808Sensor), diff --git a/esphome/components/mhz19/sensor.py b/esphome/components/mhz19/sensor.py index 54a0e3a366..ebcecb84e2 100644 --- a/esphome/components/mhz19/sensor.py +++ b/esphome/components/mhz19/sensor.py @@ -10,6 +10,7 @@ from esphome.const import ( DEVICE_CLASS_EMPTY, DEVICE_CLASS_TEMPERATURE, ICON_MOLECULE_CO2, + STATE_CLASS_MEASUREMENT, UNIT_PARTS_PER_MILLION, UNIT_CELSIUS, ICON_EMPTY, @@ -32,10 +33,18 @@ CONFIG_SCHEMA = ( { cv.GenerateID(): cv.declare_id(MHZ19Component), cv.Required(CONF_CO2): sensor.sensor_schema( - UNIT_PARTS_PER_MILLION, ICON_MOLECULE_CO2, 0, DEVICE_CLASS_EMPTY + UNIT_PARTS_PER_MILLION, + ICON_MOLECULE_CO2, + 0, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 0, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_EMPTY, + 0, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_AUTOMATIC_BASELINE_CALIBRATION): cv.boolean, } diff --git a/esphome/components/midea_ac/climate.py b/esphome/components/midea_ac/climate.py index e0128febfb..7bf77d7c6b 100644 --- a/esphome/components/midea_ac/climate.py +++ b/esphome/components/midea_ac/climate.py @@ -3,6 +3,7 @@ import esphome.config_validation as cv import esphome.codegen as cg from esphome.const import ( CONF_ID, + STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, UNIT_PERCENT, UNIT_WATT, @@ -36,13 +37,21 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_SWING_HORIZONTAL, default=False): cv.boolean, cv.Optional(CONF_SWING_BOTH, default=False): cv.boolean, cv.Optional(CONF_OUTDOOR_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_THERMOMETER, 0, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_THERMOMETER, + 0, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_POWER_USAGE): sensor.sensor_schema( - UNIT_WATT, ICON_POWER, 0, DEVICE_CLASS_POWER + UNIT_WATT, ICON_POWER, 0, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT ), cv.Optional(CONF_HUMIDITY_SETPOINT): sensor.sensor_schema( - UNIT_PERCENT, ICON_WATER_PERCENT, 0, DEVICE_CLASS_HUMIDITY + UNIT_PERCENT, + ICON_WATER_PERCENT, + 0, + DEVICE_CLASS_HUMIDITY, + STATE_CLASS_MEASUREMENT, ), } ).extend(cv.COMPONENT_SCHEMA) diff --git a/esphome/components/mpu6050/sensor.py b/esphome/components/mpu6050/sensor.py index 2054897dfb..05c26289b4 100644 --- a/esphome/components/mpu6050/sensor.py +++ b/esphome/components/mpu6050/sensor.py @@ -8,6 +8,7 @@ from esphome.const import ( DEVICE_CLASS_TEMPERATURE, ICON_BRIEFCASE_DOWNLOAD, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_METER_PER_SECOND_SQUARED, ICON_SCREEN_ROTATION, UNIT_DEGREE_PER_SECOND, @@ -29,13 +30,21 @@ MPU6050Component = mpu6050_ns.class_( ) accel_schema = sensor.sensor_schema( - UNIT_METER_PER_SECOND_SQUARED, ICON_BRIEFCASE_DOWNLOAD, 2, DEVICE_CLASS_EMPTY + UNIT_METER_PER_SECOND_SQUARED, + ICON_BRIEFCASE_DOWNLOAD, + 2, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ) gyro_schema = sensor.sensor_schema( - UNIT_DEGREE_PER_SECOND, ICON_SCREEN_ROTATION, 2, DEVICE_CLASS_EMPTY + UNIT_DEGREE_PER_SECOND, + ICON_SCREEN_ROTATION, + 2, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ) temperature_schema = sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE, STATE_CLASS_MEASUREMENT ) CONFIG_SCHEMA = ( diff --git a/esphome/components/mqtt_subscribe/sensor/__init__.py b/esphome/components/mqtt_subscribe/sensor/__init__.py index 25a2079f81..d640b254de 100644 --- a/esphome/components/mqtt_subscribe/sensor/__init__.py +++ b/esphome/components/mqtt_subscribe/sensor/__init__.py @@ -5,6 +5,7 @@ from esphome.const import ( CONF_ID, CONF_QOS, CONF_TOPIC, + STATE_CLASS_NONE, UNIT_EMPTY, ICON_EMPTY, DEVICE_CLASS_EMPTY, @@ -19,7 +20,9 @@ MQTTSubscribeSensor = mqtt_subscribe_ns.class_( ) CONFIG_SCHEMA = ( - sensor.sensor_schema(UNIT_EMPTY, ICON_EMPTY, 1, DEVICE_CLASS_EMPTY) + sensor.sensor_schema( + UNIT_EMPTY, ICON_EMPTY, 1, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE + ) .extend( { cv.GenerateID(): cv.declare_id(MQTTSubscribeSensor), diff --git a/esphome/components/ms5611/sensor.py b/esphome/components/ms5611/sensor.py index ebf1a949e7..34198e04eb 100644 --- a/esphome/components/ms5611/sensor.py +++ b/esphome/components/ms5611/sensor.py @@ -8,6 +8,7 @@ from esphome.const import ( DEVICE_CLASS_PRESSURE, DEVICE_CLASS_TEMPERATURE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ICON_GAUGE, UNIT_HECTOPASCAL, @@ -25,10 +26,18 @@ CONFIG_SCHEMA = ( { cv.GenerateID(): cv.declare_id(MS5611Component), cv.Required(CONF_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_EMPTY, + 1, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ), cv.Required(CONF_PRESSURE): sensor.sensor_schema( - UNIT_HECTOPASCAL, ICON_GAUGE, 1, DEVICE_CLASS_PRESSURE + UNIT_HECTOPASCAL, + ICON_GAUGE, + 1, + DEVICE_CLASS_PRESSURE, + STATE_CLASS_MEASUREMENT, ), } ) diff --git a/esphome/components/ntc/sensor.py b/esphome/components/ntc/sensor.py index d83afae350..e7b8c03586 100644 --- a/esphome/components/ntc/sensor.py +++ b/esphome/components/ntc/sensor.py @@ -13,6 +13,7 @@ from esphome.const import ( CONF_VALUE, DEVICE_CLASS_TEMPERATURE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ) @@ -118,7 +119,9 @@ def process_calibration(value): CONFIG_SCHEMA = ( - sensor.sensor_schema(UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE) + sensor.sensor_schema( + UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE, STATE_CLASS_MEASUREMENT + ) .extend( { cv.GenerateID(): cv.declare_id(NTC), diff --git a/esphome/components/pid/sensor/__init__.py b/esphome/components/pid/sensor/__init__.py index d958f239de..61669d4716 100644 --- a/esphome/components/pid/sensor/__init__.py +++ b/esphome/components/pid/sensor/__init__.py @@ -4,6 +4,7 @@ from esphome.components import sensor from esphome.const import ( CONF_ID, DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_PERCENT, ICON_GAUGE, CONF_TYPE, @@ -28,7 +29,9 @@ PID_CLIMATE_SENSOR_TYPES = { CONF_CLIMATE_ID = "climate_id" CONFIG_SCHEMA = ( - sensor.sensor_schema(UNIT_PERCENT, ICON_GAUGE, 1, DEVICE_CLASS_EMPTY) + sensor.sensor_schema( + UNIT_PERCENT, ICON_GAUGE, 1, DEVICE_CLASS_EMPTY, STATE_CLASS_MEASUREMENT + ) .extend( { cv.GenerateID(): cv.declare_id(PIDClimateSensor), diff --git a/esphome/components/pmsx003/sensor.py b/esphome/components/pmsx003/sensor.py index bdbe2b1811..80f2b80e5e 100644 --- a/esphome/components/pmsx003/sensor.py +++ b/esphome/components/pmsx003/sensor.py @@ -15,6 +15,7 @@ from esphome.const import ( DEVICE_CLASS_TEMPERATURE, ICON_CHEMICAL_WEAPON, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_MICROGRAMS_PER_CUBIC_METER, UNIT_CELSIUS, UNIT_PERCENT, @@ -66,30 +67,42 @@ CONFIG_SCHEMA = ( ICON_CHEMICAL_WEAPON, 0, DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_PM_2_5): sensor.sensor_schema( UNIT_MICROGRAMS_PER_CUBIC_METER, ICON_CHEMICAL_WEAPON, 0, DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_PM_10_0): sensor.sensor_schema( UNIT_MICROGRAMS_PER_CUBIC_METER, ICON_CHEMICAL_WEAPON, 0, DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_EMPTY, + 1, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 1, DEVICE_CLASS_HUMIDITY + UNIT_PERCENT, + ICON_EMPTY, + 1, + DEVICE_CLASS_HUMIDITY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_FORMALDEHYDE): sensor.sensor_schema( UNIT_MICROGRAMS_PER_CUBIC_METER, ICON_CHEMICAL_WEAPON, 0, DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), } ) diff --git a/esphome/components/pulse_counter/sensor.py b/esphome/components/pulse_counter/sensor.py index d6e4dfc1a3..71227ec491 100644 --- a/esphome/components/pulse_counter/sensor.py +++ b/esphome/components/pulse_counter/sensor.py @@ -13,6 +13,8 @@ from esphome.const import ( CONF_TOTAL, DEVICE_CLASS_EMPTY, ICON_PULSE, + STATE_CLASS_MEASUREMENT, + STATE_CLASS_NONE, UNIT_PULSES_PER_MINUTE, UNIT_PULSES, ) @@ -64,7 +66,13 @@ def validate_count_mode(value): CONFIG_SCHEMA = ( - sensor.sensor_schema(UNIT_PULSES_PER_MINUTE, ICON_PULSE, 2, DEVICE_CLASS_EMPTY) + sensor.sensor_schema( + UNIT_PULSES_PER_MINUTE, + ICON_PULSE, + 2, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, + ) .extend( { cv.GenerateID(): cv.declare_id(PulseCounterSensor), @@ -86,7 +94,7 @@ CONFIG_SCHEMA = ( ), cv.Optional(CONF_INTERNAL_FILTER, default="13us"): validate_internal_filter, cv.Optional(CONF_TOTAL): sensor.sensor_schema( - UNIT_PULSES, ICON_PULSE, 0, DEVICE_CLASS_EMPTY + UNIT_PULSES, ICON_PULSE, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE ), } ) diff --git a/esphome/components/pulse_meter/sensor.py b/esphome/components/pulse_meter/sensor.py index 5811863405..e732971c3a 100644 --- a/esphome/components/pulse_meter/sensor.py +++ b/esphome/components/pulse_meter/sensor.py @@ -11,6 +11,8 @@ from esphome.const import ( CONF_TOTAL, CONF_VALUE, ICON_PULSE, + STATE_CLASS_MEASUREMENT, + STATE_CLASS_NONE, UNIT_PULSES, UNIT_PULSES_PER_MINUTE, DEVICE_CLASS_EMPTY, @@ -49,7 +51,7 @@ def validate_pulse_meter_pin(value): CONFIG_SCHEMA = sensor.sensor_schema( - UNIT_PULSES_PER_MINUTE, ICON_PULSE, 2, DEVICE_CLASS_EMPTY + UNIT_PULSES_PER_MINUTE, ICON_PULSE, 2, DEVICE_CLASS_EMPTY, STATE_CLASS_MEASUREMENT ).extend( { cv.GenerateID(): cv.declare_id(PulseMeterSensor), @@ -57,7 +59,7 @@ CONFIG_SCHEMA = sensor.sensor_schema( cv.Optional(CONF_INTERNAL_FILTER, default="13us"): validate_internal_filter, cv.Optional(CONF_TIMEOUT, default="5min"): validate_timeout, cv.Optional(CONF_TOTAL): sensor.sensor_schema( - UNIT_PULSES, ICON_PULSE, 0, DEVICE_CLASS_EMPTY + UNIT_PULSES, ICON_PULSE, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE ), } ) diff --git a/esphome/components/pulse_width/sensor.py b/esphome/components/pulse_width/sensor.py index 358ffd2962..6a6147c6aa 100644 --- a/esphome/components/pulse_width/sensor.py +++ b/esphome/components/pulse_width/sensor.py @@ -2,7 +2,14 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import pins from esphome.components import sensor -from esphome.const import CONF_ID, CONF_PIN, DEVICE_CLASS_EMPTY, UNIT_SECOND, ICON_TIMER +from esphome.const import ( + CONF_ID, + CONF_PIN, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, + UNIT_SECOND, + ICON_TIMER, +) pulse_width_ns = cg.esphome_ns.namespace("pulse_width") @@ -11,7 +18,9 @@ PulseWidthSensor = pulse_width_ns.class_( ) CONFIG_SCHEMA = ( - sensor.sensor_schema(UNIT_SECOND, ICON_TIMER, 3, DEVICE_CLASS_EMPTY) + sensor.sensor_schema( + UNIT_SECOND, ICON_TIMER, 3, DEVICE_CLASS_EMPTY, STATE_CLASS_MEASUREMENT + ) .extend( { cv.GenerateID(): cv.declare_id(PulseWidthSensor), diff --git a/esphome/components/pzem004t/sensor.py b/esphome/components/pzem004t/sensor.py index b463e58f94..e3859f090c 100644 --- a/esphome/components/pzem004t/sensor.py +++ b/esphome/components/pzem004t/sensor.py @@ -12,6 +12,8 @@ from esphome.const import ( DEVICE_CLASS_POWER, DEVICE_CLASS_VOLTAGE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, + STATE_CLASS_NONE, UNIT_VOLT, UNIT_AMPERE, UNIT_WATT, @@ -28,16 +30,24 @@ CONFIG_SCHEMA = ( { cv.GenerateID(): cv.declare_id(PZEM004T), cv.Optional(CONF_VOLTAGE): sensor.sensor_schema( - UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE + UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT ), cv.Optional(CONF_CURRENT): sensor.sensor_schema( - UNIT_AMPERE, ICON_EMPTY, 2, DEVICE_CLASS_CURRENT + UNIT_AMPERE, + ICON_EMPTY, + 2, + DEVICE_CLASS_CURRENT, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_POWER): sensor.sensor_schema( - UNIT_WATT, ICON_EMPTY, 0, DEVICE_CLASS_POWER + UNIT_WATT, ICON_EMPTY, 0, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT ), cv.Optional(CONF_ENERGY): sensor.sensor_schema( - UNIT_WATT_HOURS, ICON_EMPTY, 0, DEVICE_CLASS_ENERGY + UNIT_WATT_HOURS, + ICON_EMPTY, + 0, + DEVICE_CLASS_ENERGY, + STATE_CLASS_NONE, ), } ) diff --git a/esphome/components/pzemac/sensor.py b/esphome/components/pzemac/sensor.py index bac2f1b60e..778c5054a0 100644 --- a/esphome/components/pzemac/sensor.py +++ b/esphome/components/pzemac/sensor.py @@ -17,6 +17,8 @@ from esphome.const import ( DEVICE_CLASS_ENERGY, ICON_EMPTY, ICON_CURRENT_AC, + STATE_CLASS_MEASUREMENT, + STATE_CLASS_NONE, UNIT_HERTZ, UNIT_VOLT, UNIT_AMPERE, @@ -35,22 +37,38 @@ CONFIG_SCHEMA = ( { cv.GenerateID(): cv.declare_id(PZEMAC), cv.Optional(CONF_VOLTAGE): sensor.sensor_schema( - UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE + UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT ), cv.Optional(CONF_CURRENT): sensor.sensor_schema( - UNIT_AMPERE, ICON_EMPTY, 3, DEVICE_CLASS_CURRENT + UNIT_AMPERE, + ICON_EMPTY, + 3, + DEVICE_CLASS_CURRENT, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_POWER): sensor.sensor_schema( - UNIT_WATT, ICON_EMPTY, 2, DEVICE_CLASS_POWER + UNIT_WATT, ICON_EMPTY, 2, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT ), cv.Optional(CONF_ENERGY): sensor.sensor_schema( - UNIT_WATT_HOURS, ICON_EMPTY, 0, DEVICE_CLASS_ENERGY + UNIT_WATT_HOURS, + ICON_EMPTY, + 0, + DEVICE_CLASS_ENERGY, + STATE_CLASS_NONE, ), cv.Optional(CONF_FREQUENCY): sensor.sensor_schema( - UNIT_HERTZ, ICON_CURRENT_AC, 1, DEVICE_CLASS_EMPTY + UNIT_HERTZ, + ICON_CURRENT_AC, + 1, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_POWER_FACTOR): sensor.sensor_schema( - UNIT_EMPTY, ICON_EMPTY, 2, DEVICE_CLASS_POWER_FACTOR + UNIT_EMPTY, + ICON_EMPTY, + 2, + DEVICE_CLASS_POWER_FACTOR, + STATE_CLASS_MEASUREMENT, ), } ) diff --git a/esphome/components/pzemdc/sensor.py b/esphome/components/pzemdc/sensor.py index 0bf4c9ba2a..58afea8e30 100644 --- a/esphome/components/pzemdc/sensor.py +++ b/esphome/components/pzemdc/sensor.py @@ -10,6 +10,7 @@ from esphome.const import ( DEVICE_CLASS_POWER, DEVICE_CLASS_VOLTAGE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_VOLT, UNIT_AMPERE, UNIT_WATT, @@ -25,13 +26,17 @@ CONFIG_SCHEMA = ( { cv.GenerateID(): cv.declare_id(PZEMDC), cv.Optional(CONF_VOLTAGE): sensor.sensor_schema( - UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE + UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT ), cv.Optional(CONF_CURRENT): sensor.sensor_schema( - UNIT_AMPERE, ICON_EMPTY, 3, DEVICE_CLASS_CURRENT + UNIT_AMPERE, + ICON_EMPTY, + 3, + DEVICE_CLASS_CURRENT, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_POWER): sensor.sensor_schema( - UNIT_WATT, ICON_EMPTY, 1, DEVICE_CLASS_POWER + UNIT_WATT, ICON_EMPTY, 1, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT ), } ) diff --git a/esphome/components/qmc5883l/sensor.py b/esphome/components/qmc5883l/sensor.py index 395cb681a3..d0fdf1b77a 100644 --- a/esphome/components/qmc5883l/sensor.py +++ b/esphome/components/qmc5883l/sensor.py @@ -8,6 +8,8 @@ from esphome.const import ( CONF_RANGE, DEVICE_CLASS_EMPTY, ICON_MAGNET, + STATE_CLASS_MEASUREMENT, + STATE_CLASS_NONE, UNIT_MICROTESLA, UNIT_DEGREES, ICON_SCREEN_ROTATION, @@ -69,10 +71,10 @@ def validate_enum(enum_values, units=None, int=True): field_strength_schema = sensor.sensor_schema( - UNIT_MICROTESLA, ICON_MAGNET, 1, DEVICE_CLASS_EMPTY + UNIT_MICROTESLA, ICON_MAGNET, 1, DEVICE_CLASS_EMPTY, STATE_CLASS_MEASUREMENT ) heading_schema = sensor.sensor_schema( - UNIT_DEGREES, ICON_SCREEN_ROTATION, 1, DEVICE_CLASS_EMPTY + UNIT_DEGREES, ICON_SCREEN_ROTATION, 1, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE ) CONFIG_SCHEMA = ( diff --git a/esphome/components/resistance/sensor.py b/esphome/components/resistance/sensor.py index 8ee00b25be..ca1501195a 100644 --- a/esphome/components/resistance/sensor.py +++ b/esphome/components/resistance/sensor.py @@ -1,7 +1,14 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import sensor -from esphome.const import CONF_SENSOR, DEVICE_CLASS_EMPTY, UNIT_OHM, ICON_FLASH, CONF_ID +from esphome.const import ( + CONF_SENSOR, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, + UNIT_OHM, + ICON_FLASH, + CONF_ID, +) resistance_ns = cg.esphome_ns.namespace("resistance") ResistanceSensor = resistance_ns.class_("ResistanceSensor", cg.Component, sensor.Sensor) @@ -17,7 +24,9 @@ CONFIGURATIONS = { } CONFIG_SCHEMA = ( - sensor.sensor_schema(UNIT_OHM, ICON_FLASH, 1, DEVICE_CLASS_EMPTY) + sensor.sensor_schema( + UNIT_OHM, ICON_FLASH, 1, DEVICE_CLASS_EMPTY, STATE_CLASS_MEASUREMENT + ) .extend( { cv.GenerateID(): cv.declare_id(ResistanceSensor), diff --git a/esphome/components/rotary_encoder/sensor.py b/esphome/components/rotary_encoder/sensor.py index d4ced4b91f..079f00d284 100644 --- a/esphome/components/rotary_encoder/sensor.py +++ b/esphome/components/rotary_encoder/sensor.py @@ -8,6 +8,7 @@ from esphome.const import ( CONF_MIN_VALUE, CONF_MAX_VALUE, DEVICE_CLASS_EMPTY, + STATE_CLASS_NONE, UNIT_STEPS, ICON_ROTATE_RIGHT, CONF_VALUE, @@ -56,7 +57,9 @@ def validate_min_max_value(config): CONFIG_SCHEMA = cv.All( - sensor.sensor_schema(UNIT_STEPS, ICON_ROTATE_RIGHT, 0, DEVICE_CLASS_EMPTY) + sensor.sensor_schema( + UNIT_STEPS, ICON_ROTATE_RIGHT, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE + ) .extend( { cv.GenerateID(): cv.declare_id(RotaryEncoderSensor), diff --git a/esphome/components/ruuvitag/sensor.py b/esphome/components/ruuvitag/sensor.py index d59dc094fb..12b8425d14 100644 --- a/esphome/components/ruuvitag/sensor.py +++ b/esphome/components/ruuvitag/sensor.py @@ -21,6 +21,8 @@ from esphome.const import ( DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_VOLTAGE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, + STATE_CLASS_NONE, UNIT_CELSIUS, UNIT_PERCENT, UNIT_VOLT, @@ -50,37 +52,69 @@ CONFIG_SCHEMA = ( cv.GenerateID(): cv.declare_id(RuuviTag), cv.Required(CONF_MAC_ADDRESS): cv.mac_address, cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 2, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_EMPTY, + 2, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 2, DEVICE_CLASS_HUMIDITY + UNIT_PERCENT, + ICON_EMPTY, + 2, + DEVICE_CLASS_HUMIDITY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_PRESSURE): sensor.sensor_schema( - UNIT_HECTOPASCAL, ICON_EMPTY, 2, DEVICE_CLASS_PRESSURE + UNIT_HECTOPASCAL, + ICON_EMPTY, + 2, + DEVICE_CLASS_PRESSURE, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_ACCELERATION): sensor.sensor_schema( - UNIT_G, ICON_ACCELERATION, 3, DEVICE_CLASS_EMPTY + UNIT_G, + ICON_ACCELERATION, + 3, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_ACCELERATION_X): sensor.sensor_schema( - UNIT_G, ICON_ACCELERATION_X, 3, DEVICE_CLASS_EMPTY + UNIT_G, + ICON_ACCELERATION_X, + 3, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_ACCELERATION_Y): sensor.sensor_schema( - UNIT_G, ICON_ACCELERATION_Y, 3, DEVICE_CLASS_EMPTY + UNIT_G, + ICON_ACCELERATION_Y, + 3, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_ACCELERATION_Z): sensor.sensor_schema( - UNIT_G, ICON_ACCELERATION_Z, 3, DEVICE_CLASS_EMPTY + UNIT_G, + ICON_ACCELERATION_Z, + 3, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_BATTERY_VOLTAGE): sensor.sensor_schema( - UNIT_VOLT, ICON_EMPTY, 3, DEVICE_CLASS_VOLTAGE + UNIT_VOLT, ICON_EMPTY, 3, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT ), cv.Optional(CONF_TX_POWER): sensor.sensor_schema( - UNIT_DECIBEL_MILLIWATT, ICON_EMPTY, 0, DEVICE_CLASS_SIGNAL_STRENGTH + UNIT_DECIBEL_MILLIWATT, + ICON_EMPTY, + 0, + DEVICE_CLASS_SIGNAL_STRENGTH, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_MOVEMENT_COUNTER): sensor.sensor_schema( - UNIT_EMPTY, ICON_GAUGE, 0, DEVICE_CLASS_EMPTY + UNIT_EMPTY, ICON_GAUGE, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE ), cv.Optional(CONF_MEASUREMENT_SEQUENCE_NUMBER): sensor.sensor_schema( - UNIT_EMPTY, ICON_GAUGE, 0, DEVICE_CLASS_EMPTY + UNIT_EMPTY, ICON_GAUGE, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE ), } ) diff --git a/esphome/components/scd30/sensor.py b/esphome/components/scd30/sensor.py index aad2a1811c..7a08289474 100644 --- a/esphome/components/scd30/sensor.py +++ b/esphome/components/scd30/sensor.py @@ -10,6 +10,7 @@ from esphome.const import ( DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_TEMPERATURE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_PARTS_PER_MILLION, ICON_MOLECULE_CO2, UNIT_CELSIUS, @@ -32,13 +33,25 @@ CONFIG_SCHEMA = ( { cv.GenerateID(): cv.declare_id(SCD30Component), cv.Optional(CONF_CO2): sensor.sensor_schema( - UNIT_PARTS_PER_MILLION, ICON_MOLECULE_CO2, 0, DEVICE_CLASS_EMPTY + UNIT_PARTS_PER_MILLION, + ICON_MOLECULE_CO2, + 0, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_EMPTY, + 1, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 1, DEVICE_CLASS_HUMIDITY + UNIT_PERCENT, + ICON_EMPTY, + 1, + DEVICE_CLASS_HUMIDITY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_AUTOMATIC_SELF_CALIBRATION, default=True): cv.boolean, cv.Optional(CONF_ALTITUDE_COMPENSATION): cv.All( diff --git a/esphome/components/sdm_meter/sensor.py b/esphome/components/sdm_meter/sensor.py index 0f7a4c928b..39ef280fef 100644 --- a/esphome/components/sdm_meter/sensor.py +++ b/esphome/components/sdm_meter/sensor.py @@ -17,6 +17,7 @@ from esphome.const import ( CONF_REACTIVE_POWER, CONF_VOLTAGE, DEVICE_CLASS_CURRENT, + DEVICE_CLASS_EMPTY, DEVICE_CLASS_ENERGY, DEVICE_CLASS_POWER, DEVICE_CLASS_POWER_FACTOR, @@ -24,6 +25,8 @@ from esphome.const import ( ICON_CURRENT_AC, ICON_EMPTY, ICON_FLASH, + STATE_CLASS_MEASUREMENT, + STATE_CLASS_NONE, UNIT_AMPERE, UNIT_DEGREES, UNIT_EMPTY, @@ -45,19 +48,23 @@ SDMMeter = sdm_meter_ns.class_("SDMMeter", cg.PollingComponent, modbus.ModbusDev PHASE_SENSORS = { CONF_VOLTAGE: sensor.sensor_schema(UNIT_VOLT, ICON_EMPTY, 2, DEVICE_CLASS_VOLTAGE), CONF_CURRENT: sensor.sensor_schema( - UNIT_AMPERE, ICON_EMPTY, 3, DEVICE_CLASS_CURRENT + UNIT_AMPERE, ICON_EMPTY, 3, DEVICE_CLASS_CURRENT, STATE_CLASS_MEASUREMENT ), CONF_ACTIVE_POWER: sensor.sensor_schema( - UNIT_WATT, ICON_EMPTY, 2, DEVICE_CLASS_POWER + UNIT_WATT, ICON_EMPTY, 2, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT ), CONF_APPARENT_POWER: sensor.sensor_schema( - UNIT_VOLT_AMPS, ICON_EMPTY, 2, DEVICE_CLASS_POWER + UNIT_VOLT_AMPS, ICON_EMPTY, 2, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT ), CONF_REACTIVE_POWER: sensor.sensor_schema( - UNIT_VOLT_AMPS_REACTIVE, ICON_EMPTY, 2, DEVICE_CLASS_POWER + UNIT_VOLT_AMPS_REACTIVE, + ICON_EMPTY, + 2, + DEVICE_CLASS_POWER, + STATE_CLASS_MEASUREMENT, ), CONF_POWER_FACTOR: sensor.sensor_schema( - UNIT_EMPTY, ICON_EMPTY, 3, DEVICE_CLASS_POWER_FACTOR + UNIT_EMPTY, ICON_EMPTY, 3, DEVICE_CLASS_POWER_FACTOR, STATE_CLASS_MEASUREMENT ), CONF_PHASE_ANGLE: sensor.sensor_schema(UNIT_DEGREES, ICON_FLASH, 3), } @@ -74,19 +81,31 @@ CONFIG_SCHEMA = ( cv.Optional(CONF_PHASE_B): PHASE_SCHEMA, cv.Optional(CONF_PHASE_C): PHASE_SCHEMA, cv.Optional(CONF_FREQUENCY): sensor.sensor_schema( - UNIT_HERTZ, ICON_CURRENT_AC, 3 + UNIT_HERTZ, + ICON_CURRENT_AC, + 3, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_IMPORT_ACTIVE_ENERGY): sensor.sensor_schema( - UNIT_WATT_HOURS, ICON_EMPTY, 2, DEVICE_CLASS_ENERGY + UNIT_WATT_HOURS, ICON_EMPTY, 2, DEVICE_CLASS_ENERGY, STATE_CLASS_NONE ), cv.Optional(CONF_EXPORT_ACTIVE_ENERGY): sensor.sensor_schema( - UNIT_WATT_HOURS, ICON_EMPTY, 2, DEVICE_CLASS_ENERGY + UNIT_WATT_HOURS, ICON_EMPTY, 2, DEVICE_CLASS_ENERGY, STATE_CLASS_NONE ), cv.Optional(CONF_IMPORT_REACTIVE_ENERGY): sensor.sensor_schema( - UNIT_VOLT_AMPS_REACTIVE_HOURS, ICON_EMPTY, 2, DEVICE_CLASS_ENERGY + UNIT_VOLT_AMPS_REACTIVE_HOURS, + ICON_EMPTY, + 2, + DEVICE_CLASS_ENERGY, + STATE_CLASS_NONE, ), cv.Optional(CONF_EXPORT_REACTIVE_ENERGY): sensor.sensor_schema( - UNIT_VOLT_AMPS_REACTIVE_HOURS, ICON_EMPTY, 2, DEVICE_CLASS_ENERGY + UNIT_VOLT_AMPS_REACTIVE_HOURS, + ICON_EMPTY, + 2, + DEVICE_CLASS_ENERGY, + STATE_CLASS_NONE, ), } ) diff --git a/esphome/components/sds011/sensor.py b/esphome/components/sds011/sensor.py index 5655533b21..af482839a9 100644 --- a/esphome/components/sds011/sensor.py +++ b/esphome/components/sds011/sensor.py @@ -8,6 +8,7 @@ from esphome.const import ( CONF_RX_ONLY, CONF_UPDATE_INTERVAL, DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_MICROGRAMS_PER_CUBIC_METER, ICON_CHEMICAL_WEAPON, ) @@ -42,12 +43,14 @@ CONFIG_SCHEMA = cv.All( ICON_CHEMICAL_WEAPON, 1, DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_PM_10_0): sensor.sensor_schema( UNIT_MICROGRAMS_PER_CUBIC_METER, ICON_CHEMICAL_WEAPON, 1, DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_RX_ONLY, default=False): cv.boolean, cv.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_minutes, diff --git a/esphome/components/senseair/sensor.py b/esphome/components/senseair/sensor.py index f37a2dd5ff..2d40e12a09 100644 --- a/esphome/components/senseair/sensor.py +++ b/esphome/components/senseair/sensor.py @@ -8,6 +8,7 @@ from esphome.const import ( CONF_ID, DEVICE_CLASS_EMPTY, ICON_MOLECULE_CO2, + STATE_CLASS_MEASUREMENT, UNIT_PARTS_PER_MILLION, ) @@ -38,7 +39,11 @@ CONFIG_SCHEMA = ( { cv.GenerateID(): cv.declare_id(SenseAirComponent), cv.Required(CONF_CO2): sensor.sensor_schema( - UNIT_PARTS_PER_MILLION, ICON_MOLECULE_CO2, 0, DEVICE_CLASS_EMPTY + UNIT_PARTS_PER_MILLION, + ICON_MOLECULE_CO2, + 0, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), } ) diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py index 9c0b0bedd1..89bde9476a 100644 --- a/esphome/components/sensor/__init__.py +++ b/esphome/components/sensor/__init__.py @@ -22,6 +22,7 @@ from esphome.const import ( CONF_ON_VALUE_RANGE, CONF_SEND_EVERY, CONF_SEND_FIRST_AT, + CONF_STATE_CLASS, CONF_TO, CONF_TRIGGER_ID, CONF_UNIT_OF_MEASUREMENT, @@ -46,6 +47,7 @@ from esphome.const import ( DEVICE_CLASS_PRESSURE, DEVICE_CLASS_TIMESTAMP, DEVICE_CLASS_VOLTAGE, + STATE_CLASS_NONE, ) from esphome.core import CORE, coroutine_with_priority from esphome.util import Registry @@ -69,6 +71,14 @@ DEVICE_CLASSES = [ DEVICE_CLASS_VOLTAGE, ] +sensor_ns = cg.esphome_ns.namespace("sensor") +StateClasses = sensor_ns.enum("StateClass") +STATE_CLASSES = { + "": StateClasses.STATE_CLASS_NONE, + "measurement": StateClasses.STATE_CLASS_MEASUREMENT, +} +validate_state_class = cv.enum(STATE_CLASSES, lower=True, space="_") + IS_PLATFORM_COMPONENT = True @@ -157,6 +167,7 @@ SENSOR_SCHEMA = cv.MQTT_COMPONENT_SCHEMA.extend( cv.Optional(CONF_ICON): icon, cv.Optional(CONF_ACCURACY_DECIMALS): accuracy_decimals, cv.Optional(CONF_DEVICE_CLASS): device_class, + cv.Optional(CONF_STATE_CLASS): validate_state_class, cv.Optional(CONF_FORCE_UPDATE, default=False): cv.boolean, cv.Optional(CONF_EXPIRE_AFTER): cv.All( cv.requires_component("mqtt"), @@ -190,6 +201,7 @@ def sensor_schema( icon_: str, accuracy_decimals_: int, device_class_: Optional[str] = DEVICE_CLASS_EMPTY, + state_class_: Optional[str] = STATE_CLASS_NONE, ) -> cv.Schema: schema = SENSOR_SCHEMA if unit_of_measurement_ != UNIT_EMPTY: @@ -214,6 +226,10 @@ def sensor_schema( schema = schema.extend( {cv.Optional(CONF_DEVICE_CLASS, default=device_class_): device_class} ) + if state_class_ != STATE_CLASS_NONE: + schema = schema.extend( + {cv.Optional(CONF_STATE_CLASS, default=state_class_): validate_state_class} + ) return schema @@ -455,6 +471,8 @@ async def setup_sensor_core_(var, config): cg.add(var.set_internal(config[CONF_INTERNAL])) if CONF_DEVICE_CLASS in config: cg.add(var.set_device_class(config[CONF_DEVICE_CLASS])) + if CONF_STATE_CLASS in config: + cg.add(var.set_state_class(config[CONF_STATE_CLASS])) if CONF_UNIT_OF_MEASUREMENT in config: cg.add(var.set_unit_of_measurement(config[CONF_UNIT_OF_MEASUREMENT])) if CONF_ICON in config: diff --git a/esphome/components/sensor/sensor.cpp b/esphome/components/sensor/sensor.cpp index 069a5c5923..d7be618c2a 100644 --- a/esphome/components/sensor/sensor.cpp +++ b/esphome/components/sensor/sensor.cpp @@ -6,6 +6,16 @@ namespace sensor { static const char *TAG = "sensor"; +const char *state_class_to_string(StateClass state_class) { + switch (state_class) { + case STATE_CLASS_MEASUREMENT: + return "measurement"; + case STATE_CLASS_NONE: + default: + return ""; + } +} + void Sensor::publish_state(float state) { this->raw_state = state; this->raw_callback_.call(state); @@ -47,6 +57,14 @@ std::string Sensor::get_device_class() { return this->device_class(); } std::string Sensor::device_class() { return ""; } +void Sensor::set_state_class(StateClass state_class) { this->state_class = state_class; } +void Sensor::set_state_class(const std::string &state_class) { + if (str_equals_case_insensitive(state_class, "measurement")) { + this->state_class = STATE_CLASS_MEASUREMENT; + } else { + ESP_LOGW(TAG, "'%s' - Unrecognized state class %s", this->get_name().c_str(), state_class.c_str()); + } +} std::string Sensor::get_unit_of_measurement() { if (this->unit_of_measurement_.has_value()) return *this->unit_of_measurement_; diff --git a/esphome/components/sensor/sensor.h b/esphome/components/sensor/sensor.h index 6bb6c876ab..fe528603c4 100644 --- a/esphome/components/sensor/sensor.h +++ b/esphome/components/sensor/sensor.h @@ -13,6 +13,7 @@ namespace sensor { if (!obj->get_device_class().empty()) { \ ESP_LOGCONFIG(TAG, "%s Device Class: '%s'", prefix, obj->get_device_class().c_str()); \ } \ + ESP_LOGCONFIG(TAG, "%s State Class: '%s'", prefix, state_class_to_string(obj->state_class)); \ ESP_LOGCONFIG(TAG, "%s Unit of Measurement: '%s'", prefix, obj->get_unit_of_measurement().c_str()); \ ESP_LOGCONFIG(TAG, "%s Accuracy Decimals: %d", prefix, obj->get_accuracy_decimals()); \ if (!obj->get_icon().empty()) { \ @@ -26,6 +27,16 @@ namespace sensor { } \ } +/** + * Sensor state classes + */ +enum StateClass : uint8_t { + STATE_CLASS_NONE = 0, + STATE_CLASS_MEASUREMENT = 1, +}; + +const char *state_class_to_string(StateClass state_class); + /** Base-class for all sensors. * * A sensor has unit of measurement and can use publish_state to send out a new value with the specified accuracy. @@ -139,6 +150,13 @@ class Sensor : public Nameable { /// Return whether this sensor has gotten a full state (that passed through all filters) yet. bool has_state() const; + // The state class of this sensor state + StateClass state_class{STATE_CLASS_NONE}; + + /// Manually set the Home Assistant state class (see sensor::state_class) + void set_state_class(StateClass state_class); + void set_state_class(const std::string &state_class); + /** Override this to set the Home Assistant device class for this sensor. * * Return "" to disable this feature. diff --git a/esphome/components/sgp30/sensor.py b/esphome/components/sgp30/sensor.py index 7046605f3b..f393627eda 100644 --- a/esphome/components/sgp30/sensor.py +++ b/esphome/components/sgp30/sensor.py @@ -5,6 +5,7 @@ from esphome.const import ( CONF_ID, DEVICE_CLASS_EMPTY, ICON_RADIATOR, + STATE_CLASS_MEASUREMENT, UNIT_PARTS_PER_MILLION, UNIT_PARTS_PER_BILLION, ICON_MOLECULE_CO2, @@ -30,10 +31,18 @@ CONFIG_SCHEMA = ( { cv.GenerateID(): cv.declare_id(SGP30Component), cv.Required(CONF_ECO2): sensor.sensor_schema( - UNIT_PARTS_PER_MILLION, ICON_MOLECULE_CO2, 0, DEVICE_CLASS_EMPTY + UNIT_PARTS_PER_MILLION, + ICON_MOLECULE_CO2, + 0, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Required(CONF_TVOC): sensor.sensor_schema( - UNIT_PARTS_PER_BILLION, ICON_RADIATOR, 0, DEVICE_CLASS_EMPTY + UNIT_PARTS_PER_BILLION, + ICON_RADIATOR, + 0, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_BASELINE): cv.Schema( { diff --git a/esphome/components/sgp40/sensor.py b/esphome/components/sgp40/sensor.py index a308d7bb79..36e039d2b5 100644 --- a/esphome/components/sgp40/sensor.py +++ b/esphome/components/sgp40/sensor.py @@ -1,7 +1,13 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import i2c, sensor -from esphome.const import CONF_ID, DEVICE_CLASS_EMPTY, ICON_RADIATOR, UNIT_EMPTY +from esphome.const import ( + CONF_ID, + DEVICE_CLASS_EMPTY, + ICON_RADIATOR, + STATE_CLASS_MEASUREMENT, + UNIT_EMPTY, +) DEPENDENCIES = ["i2c"] @@ -19,7 +25,9 @@ CONF_STORE_BASELINE = "store_baseline" CONF_VOC_BASELINE = "voc_baseline" CONFIG_SCHEMA = ( - sensor.sensor_schema(UNIT_EMPTY, ICON_RADIATOR, 0, DEVICE_CLASS_EMPTY) + sensor.sensor_schema( + UNIT_EMPTY, ICON_RADIATOR, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_MEASUREMENT + ) .extend( { cv.GenerateID(): cv.declare_id(SGP40Component), diff --git a/esphome/components/sht3xd/sensor.py b/esphome/components/sht3xd/sensor.py index cac53e47e3..2a4bb6594e 100644 --- a/esphome/components/sht3xd/sensor.py +++ b/esphome/components/sht3xd/sensor.py @@ -8,6 +8,7 @@ from esphome.const import ( DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_TEMPERATURE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, UNIT_PERCENT, ) @@ -24,10 +25,18 @@ CONFIG_SCHEMA = ( { cv.GenerateID(): cv.declare_id(SHT3XDComponent), cv.Required(CONF_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_EMPTY, + 1, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ), cv.Required(CONF_HUMIDITY): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 1, DEVICE_CLASS_HUMIDITY + UNIT_PERCENT, + ICON_EMPTY, + 1, + DEVICE_CLASS_HUMIDITY, + STATE_CLASS_MEASUREMENT, ), } ) diff --git a/esphome/components/sht4x/sensor.py b/esphome/components/sht4x/sensor.py index fdc4029e41..a746ecde07 100644 --- a/esphome/components/sht4x/sensor.py +++ b/esphome/components/sht4x/sensor.py @@ -5,6 +5,7 @@ from esphome.const import ( CONF_ID, CONF_TEMPERATURE, CONF_HUMIDITY, + STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, UNIT_PERCENT, ICON_THERMOMETER, @@ -50,10 +51,18 @@ CONFIG_SCHEMA = ( { cv.GenerateID(): cv.declare_id(SHT4XComponent), cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_THERMOMETER, 2, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_THERMOMETER, + 2, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( - UNIT_PERCENT, ICON_WATER_PERCENT, 2, DEVICE_CLASS_HUMIDITY + UNIT_PERCENT, + ICON_WATER_PERCENT, + 2, + DEVICE_CLASS_HUMIDITY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_PRECISION, default="High"): cv.enum(PRECISION_OPTIONS), cv.Optional(CONF_HEATER_POWER, default="High"): cv.enum( diff --git a/esphome/components/shtcx/sensor.py b/esphome/components/shtcx/sensor.py index 7156029488..af9379218c 100644 --- a/esphome/components/shtcx/sensor.py +++ b/esphome/components/shtcx/sensor.py @@ -8,6 +8,7 @@ from esphome.const import ( DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_TEMPERATURE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, UNIT_PERCENT, ) @@ -24,10 +25,18 @@ CONFIG_SCHEMA = ( { cv.GenerateID(): cv.declare_id(SHTCXComponent), cv.Required(CONF_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_EMPTY, + 1, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ), cv.Required(CONF_HUMIDITY): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 1, DEVICE_CLASS_HUMIDITY + UNIT_PERCENT, + ICON_EMPTY, + 1, + DEVICE_CLASS_HUMIDITY, + STATE_CLASS_MEASUREMENT, ), } ) diff --git a/esphome/components/sm300d2/sensor.py b/esphome/components/sm300d2/sensor.py index 7618136bd9..3d522b3bd5 100644 --- a/esphome/components/sm300d2/sensor.py +++ b/esphome/components/sm300d2/sensor.py @@ -13,6 +13,7 @@ from esphome.const import ( DEVICE_CLASS_EMPTY, DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_HUMIDITY, + STATE_CLASS_MEASUREMENT, UNIT_PARTS_PER_MILLION, UNIT_MICROGRAMS_PER_CUBIC_METER, UNIT_CELSIUS, @@ -34,28 +35,53 @@ CONFIG_SCHEMA = cv.All( { cv.GenerateID(): cv.declare_id(SM300D2Sensor), cv.Optional(CONF_CO2): sensor.sensor_schema( - UNIT_PARTS_PER_MILLION, ICON_MOLECULE_CO2, 0, DEVICE_CLASS_EMPTY + UNIT_PARTS_PER_MILLION, + ICON_MOLECULE_CO2, + 0, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_FORMALDEHYDE): sensor.sensor_schema( - UNIT_MICROGRAMS_PER_CUBIC_METER, ICON_FLASK, 0, DEVICE_CLASS_EMPTY + UNIT_MICROGRAMS_PER_CUBIC_METER, + ICON_FLASK, + 0, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_TVOC): sensor.sensor_schema( UNIT_MICROGRAMS_PER_CUBIC_METER, ICON_CHEMICAL_WEAPON, 0, DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_PM_2_5): sensor.sensor_schema( - UNIT_MICROGRAMS_PER_CUBIC_METER, ICON_GRAIN, 0, DEVICE_CLASS_EMPTY + UNIT_MICROGRAMS_PER_CUBIC_METER, + ICON_GRAIN, + 0, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_PM_10_0): sensor.sensor_schema( - UNIT_MICROGRAMS_PER_CUBIC_METER, ICON_GRAIN, 0, DEVICE_CLASS_EMPTY + UNIT_MICROGRAMS_PER_CUBIC_METER, + ICON_GRAIN, + 0, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 0, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_EMPTY, + 0, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 0, DEVICE_CLASS_HUMIDITY + UNIT_PERCENT, + ICON_EMPTY, + 0, + DEVICE_CLASS_HUMIDITY, + STATE_CLASS_MEASUREMENT, ), } ) diff --git a/esphome/components/sps30/sensor.py b/esphome/components/sps30/sensor.py index 32c55b969c..219f68c5c8 100644 --- a/esphome/components/sps30/sensor.py +++ b/esphome/components/sps30/sensor.py @@ -14,6 +14,7 @@ from esphome.const import ( CONF_PMC_10_0, CONF_PM_SIZE, DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_MICROGRAMS_PER_CUBIC_METER, UNIT_COUNTS_PER_CUBIC_METER, UNIT_MICROMETER, @@ -36,42 +37,70 @@ CONFIG_SCHEMA = ( ICON_CHEMICAL_WEAPON, 2, DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_PM_2_5): sensor.sensor_schema( UNIT_MICROGRAMS_PER_CUBIC_METER, ICON_CHEMICAL_WEAPON, 2, DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_PM_4_0): sensor.sensor_schema( UNIT_MICROGRAMS_PER_CUBIC_METER, ICON_CHEMICAL_WEAPON, 2, DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_PM_10_0): sensor.sensor_schema( UNIT_MICROGRAMS_PER_CUBIC_METER, ICON_CHEMICAL_WEAPON, 2, DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_PMC_0_5): sensor.sensor_schema( - UNIT_COUNTS_PER_CUBIC_METER, ICON_COUNTER, 2, DEVICE_CLASS_EMPTY + UNIT_COUNTS_PER_CUBIC_METER, + ICON_COUNTER, + 2, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_PMC_1_0): sensor.sensor_schema( - UNIT_COUNTS_PER_CUBIC_METER, ICON_COUNTER, 2, DEVICE_CLASS_EMPTY + UNIT_COUNTS_PER_CUBIC_METER, + ICON_COUNTER, + 2, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_PMC_2_5): sensor.sensor_schema( - UNIT_COUNTS_PER_CUBIC_METER, ICON_COUNTER, 2, DEVICE_CLASS_EMPTY + UNIT_COUNTS_PER_CUBIC_METER, + ICON_COUNTER, + 2, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_PMC_4_0): sensor.sensor_schema( - UNIT_COUNTS_PER_CUBIC_METER, ICON_COUNTER, 2, DEVICE_CLASS_EMPTY + UNIT_COUNTS_PER_CUBIC_METER, + ICON_COUNTER, + 2, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_PMC_10_0): sensor.sensor_schema( - UNIT_COUNTS_PER_CUBIC_METER, ICON_COUNTER, 2, DEVICE_CLASS_EMPTY + UNIT_COUNTS_PER_CUBIC_METER, + ICON_COUNTER, + 2, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_PM_SIZE): sensor.sensor_schema( - UNIT_MICROMETER, ICON_RULER, 0, DEVICE_CLASS_EMPTY + UNIT_MICROMETER, + ICON_RULER, + 0, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), } ) diff --git a/esphome/components/sts3x/sensor.py b/esphome/components/sts3x/sensor.py index 9fb798e7f1..9de077c20a 100644 --- a/esphome/components/sts3x/sensor.py +++ b/esphome/components/sts3x/sensor.py @@ -1,7 +1,13 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import i2c, sensor -from esphome.const import CONF_ID, DEVICE_CLASS_TEMPERATURE, ICON_EMPTY, UNIT_CELSIUS +from esphome.const import ( + CONF_ID, + DEVICE_CLASS_TEMPERATURE, + ICON_EMPTY, + STATE_CLASS_MEASUREMENT, + UNIT_CELSIUS, +) DEPENDENCIES = ["i2c"] @@ -12,7 +18,9 @@ STS3XComponent = sts3x_ns.class_( ) CONFIG_SCHEMA = ( - sensor.sensor_schema(UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE) + sensor.sensor_schema( + UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE, STATE_CLASS_MEASUREMENT + ) .extend( { cv.GenerateID(): cv.declare_id(STS3XComponent), diff --git a/esphome/components/sun/sensor/__init__.py b/esphome/components/sun/sensor/__init__.py index 3e72a2a04e..644490ffc6 100644 --- a/esphome/components/sun/sensor/__init__.py +++ b/esphome/components/sun/sensor/__init__.py @@ -3,6 +3,7 @@ import esphome.config_validation as cv from esphome.components import sensor from esphome.const import ( DEVICE_CLASS_EMPTY, + STATE_CLASS_NONE, UNIT_DEGREES, ICON_WEATHER_SUNSET, CONF_ID, @@ -20,7 +21,9 @@ TYPES = { } CONFIG_SCHEMA = ( - sensor.sensor_schema(UNIT_DEGREES, ICON_WEATHER_SUNSET, 1, DEVICE_CLASS_EMPTY) + sensor.sensor_schema( + UNIT_DEGREES, ICON_WEATHER_SUNSET, 1, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE + ) .extend( { cv.GenerateID(): cv.declare_id(SunSensor), diff --git a/esphome/components/tcs34725/sensor.py b/esphome/components/tcs34725/sensor.py index 2b02f7b296..d0fa0c1732 100644 --- a/esphome/components/tcs34725/sensor.py +++ b/esphome/components/tcs34725/sensor.py @@ -11,6 +11,7 @@ from esphome.const import ( DEVICE_CLASS_ILLUMINANCE, ICON_EMPTY, ICON_LIGHTBULB, + STATE_CLASS_MEASUREMENT, UNIT_PERCENT, ICON_THERMOMETER, UNIT_KELVIN, @@ -48,13 +49,13 @@ TCS34725_GAINS = { } color_channel_schema = sensor.sensor_schema( - UNIT_PERCENT, ICON_LIGHTBULB, 1, DEVICE_CLASS_EMPTY + UNIT_PERCENT, ICON_LIGHTBULB, 1, DEVICE_CLASS_EMPTY, STATE_CLASS_MEASUREMENT ) color_temperature_schema = sensor.sensor_schema( - UNIT_KELVIN, ICON_THERMOMETER, 1, DEVICE_CLASS_EMPTY + UNIT_KELVIN, ICON_THERMOMETER, 1, DEVICE_CLASS_EMPTY, STATE_CLASS_MEASUREMENT ) illuminance_schema = sensor.sensor_schema( - UNIT_LUX, ICON_EMPTY, 1, DEVICE_CLASS_ILLUMINANCE + UNIT_LUX, ICON_EMPTY, 1, DEVICE_CLASS_ILLUMINANCE, STATE_CLASS_MEASUREMENT ) CONFIG_SCHEMA = ( diff --git a/esphome/components/template/sensor/__init__.py b/esphome/components/template/sensor/__init__.py index f4d2a1831f..47027583bf 100644 --- a/esphome/components/template/sensor/__init__.py +++ b/esphome/components/template/sensor/__init__.py @@ -7,8 +7,9 @@ from esphome.const import ( CONF_LAMBDA, CONF_STATE, DEVICE_CLASS_EMPTY, - UNIT_EMPTY, ICON_EMPTY, + STATE_CLASS_NONE, + UNIT_EMPTY, ) from .. import template_ns @@ -17,7 +18,13 @@ TemplateSensor = template_ns.class_( ) CONFIG_SCHEMA = ( - sensor.sensor_schema(UNIT_EMPTY, ICON_EMPTY, 1, DEVICE_CLASS_EMPTY) + sensor.sensor_schema( + UNIT_EMPTY, + ICON_EMPTY, + 1, + DEVICE_CLASS_EMPTY, + STATE_CLASS_NONE, + ) .extend( { cv.GenerateID(): cv.declare_id(TemplateSensor), diff --git a/esphome/components/tmp102/sensor.py b/esphome/components/tmp102/sensor.py index 6a0d3cd73e..b54d5646ba 100644 --- a/esphome/components/tmp102/sensor.py +++ b/esphome/components/tmp102/sensor.py @@ -10,7 +10,13 @@ https://www.sparkfun.com/datasheets/Sensors/Temperature/tmp102.pdf import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import i2c, sensor -from esphome.const import CONF_ID, DEVICE_CLASS_TEMPERATURE, ICON_EMPTY, UNIT_CELSIUS +from esphome.const import ( + CONF_ID, + DEVICE_CLASS_TEMPERATURE, + ICON_EMPTY, + STATE_CLASS_MEASUREMENT, + UNIT_CELSIUS, +) CODEOWNERS = ["@timsavage"] DEPENDENCIES = ["i2c"] @@ -21,7 +27,9 @@ TMP102Component = tmp102_ns.class_( ) CONFIG_SCHEMA = ( - sensor.sensor_schema(UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE) + sensor.sensor_schema( + UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE, STATE_CLASS_MEASUREMENT + ) .extend( { cv.GenerateID(): cv.declare_id(TMP102Component), diff --git a/esphome/components/tmp117/sensor.py b/esphome/components/tmp117/sensor.py index 81a9569ca5..a5fc027b20 100644 --- a/esphome/components/tmp117/sensor.py +++ b/esphome/components/tmp117/sensor.py @@ -6,6 +6,7 @@ from esphome.const import ( CONF_UPDATE_INTERVAL, DEVICE_CLASS_TEMPERATURE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ) @@ -17,7 +18,9 @@ TMP117Component = tmp117_ns.class_( ) CONFIG_SCHEMA = cv.All( - sensor.sensor_schema(UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE) + sensor.sensor_schema( + UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE, STATE_CLASS_MEASUREMENT + ) .extend( { cv.GenerateID(): cv.declare_id(TMP117Component), diff --git a/esphome/components/tof10120/sensor.py b/esphome/components/tof10120/sensor.py index 5ff8c23cc6..2110cbfcf8 100644 --- a/esphome/components/tof10120/sensor.py +++ b/esphome/components/tof10120/sensor.py @@ -1,7 +1,13 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import i2c, sensor -from esphome.const import CONF_ID, UNIT_METER, ICON_ARROW_EXPAND_VERTICAL +from esphome.const import ( + CONF_ID, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, + UNIT_METER, + ICON_ARROW_EXPAND_VERTICAL, +) CODEOWNERS = ["@wstrzalka"] DEPENDENCIES = ["i2c"] @@ -12,7 +18,13 @@ TOF10120Sensor = tof10120_ns.class_( ) CONFIG_SCHEMA = ( - sensor.sensor_schema(UNIT_METER, ICON_ARROW_EXPAND_VERTICAL, 3) + sensor.sensor_schema( + UNIT_METER, + ICON_ARROW_EXPAND_VERTICAL, + 3, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, + ) .extend({cv.GenerateID(): cv.declare_id(TOF10120Sensor)}) .extend(cv.polling_component_schema("60s")) .extend(i2c.i2c_device_schema(0x52)) diff --git a/esphome/components/tsl2561/sensor.py b/esphome/components/tsl2561/sensor.py index a49c776447..c05079f668 100644 --- a/esphome/components/tsl2561/sensor.py +++ b/esphome/components/tsl2561/sensor.py @@ -7,6 +7,7 @@ from esphome.const import ( CONF_INTEGRATION_TIME, DEVICE_CLASS_ILLUMINANCE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_LUX, ) @@ -39,7 +40,9 @@ TSL2561Sensor = tsl2561_ns.class_( ) CONFIG_SCHEMA = ( - sensor.sensor_schema(UNIT_LUX, ICON_EMPTY, 1, DEVICE_CLASS_ILLUMINANCE) + sensor.sensor_schema( + UNIT_LUX, ICON_EMPTY, 1, DEVICE_CLASS_ILLUMINANCE, STATE_CLASS_MEASUREMENT + ) .extend( { cv.GenerateID(): cv.declare_id(TSL2561Sensor), diff --git a/esphome/components/tx20/sensor.py b/esphome/components/tx20/sensor.py index 5b275505fd..57c3165d16 100644 --- a/esphome/components/tx20/sensor.py +++ b/esphome/components/tx20/sensor.py @@ -8,6 +8,8 @@ from esphome.const import ( CONF_PIN, CONF_WIND_DIRECTION_DEGREES, DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, + STATE_CLASS_NONE, UNIT_KILOMETER_PER_HOUR, ICON_WEATHER_WINDY, ICON_SIGN_DIRECTION, @@ -21,10 +23,14 @@ CONFIG_SCHEMA = cv.Schema( { cv.GenerateID(): cv.declare_id(Tx20Component), cv.Optional(CONF_WIND_SPEED): sensor.sensor_schema( - UNIT_KILOMETER_PER_HOUR, ICON_WEATHER_WINDY, 1, DEVICE_CLASS_EMPTY + UNIT_KILOMETER_PER_HOUR, + ICON_WEATHER_WINDY, + 1, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_WIND_DIRECTION_DEGREES): sensor.sensor_schema( - UNIT_DEGREES, ICON_SIGN_DIRECTION, 1, DEVICE_CLASS_EMPTY + UNIT_DEGREES, ICON_SIGN_DIRECTION, 1, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE ), cv.Required(CONF_PIN): cv.All( pins.internal_gpio_input_pin_schema, pins.validate_has_interrupt diff --git a/esphome/components/ultrasonic/sensor.py b/esphome/components/ultrasonic/sensor.py index 43492a7a2e..77b08b3324 100644 --- a/esphome/components/ultrasonic/sensor.py +++ b/esphome/components/ultrasonic/sensor.py @@ -8,6 +8,7 @@ from esphome.const import ( CONF_TRIGGER_PIN, CONF_TIMEOUT, DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_METER, ICON_ARROW_EXPAND_VERTICAL, ) @@ -20,7 +21,13 @@ UltrasonicSensorComponent = ultrasonic_ns.class_( ) CONFIG_SCHEMA = ( - sensor.sensor_schema(UNIT_METER, ICON_ARROW_EXPAND_VERTICAL, 2, DEVICE_CLASS_EMPTY) + sensor.sensor_schema( + UNIT_METER, + ICON_ARROW_EXPAND_VERTICAL, + 2, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, + ) .extend( { cv.GenerateID(): cv.declare_id(UltrasonicSensorComponent), diff --git a/esphome/components/uptime/sensor.py b/esphome/components/uptime/sensor.py index 86bd58e739..eaaee5a2d5 100644 --- a/esphome/components/uptime/sensor.py +++ b/esphome/components/uptime/sensor.py @@ -1,13 +1,21 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import sensor -from esphome.const import CONF_ID, DEVICE_CLASS_EMPTY, UNIT_SECOND, ICON_TIMER +from esphome.const import ( + CONF_ID, + DEVICE_CLASS_EMPTY, + STATE_CLASS_NONE, + UNIT_SECOND, + ICON_TIMER, +) uptime_ns = cg.esphome_ns.namespace("uptime") UptimeSensor = uptime_ns.class_("UptimeSensor", sensor.Sensor, cg.PollingComponent) CONFIG_SCHEMA = ( - sensor.sensor_schema(UNIT_SECOND, ICON_TIMER, 0, DEVICE_CLASS_EMPTY) + sensor.sensor_schema( + UNIT_SECOND, ICON_TIMER, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE + ) .extend( { cv.GenerateID(): cv.declare_id(UptimeSensor), diff --git a/esphome/components/vl53l0x/sensor.py b/esphome/components/vl53l0x/sensor.py index 775532dc9e..8a9667a1bd 100644 --- a/esphome/components/vl53l0x/sensor.py +++ b/esphome/components/vl53l0x/sensor.py @@ -4,6 +4,7 @@ from esphome.components import i2c, sensor from esphome.const import ( CONF_ID, DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_METER, ICON_ARROW_EXPAND_VERTICAL, CONF_ADDRESS, @@ -40,7 +41,13 @@ def check_timeout(value): CONFIG_SCHEMA = cv.All( - sensor.sensor_schema(UNIT_METER, ICON_ARROW_EXPAND_VERTICAL, 2, DEVICE_CLASS_EMPTY) + sensor.sensor_schema( + UNIT_METER, + ICON_ARROW_EXPAND_VERTICAL, + 2, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, + ) .extend( { cv.GenerateID(): cv.declare_id(VL53L0XSensor), diff --git a/esphome/components/wifi_signal/sensor.py b/esphome/components/wifi_signal/sensor.py index be7f32b0d4..f1807966a2 100644 --- a/esphome/components/wifi_signal/sensor.py +++ b/esphome/components/wifi_signal/sensor.py @@ -5,6 +5,7 @@ from esphome.const import ( CONF_ID, DEVICE_CLASS_SIGNAL_STRENGTH, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_DECIBEL_MILLIWATT, ) @@ -16,7 +17,11 @@ WiFiSignalSensor = wifi_signal_ns.class_( CONFIG_SCHEMA = ( sensor.sensor_schema( - UNIT_DECIBEL_MILLIWATT, ICON_EMPTY, 0, DEVICE_CLASS_SIGNAL_STRENGTH + UNIT_DECIBEL_MILLIWATT, + ICON_EMPTY, + 0, + DEVICE_CLASS_SIGNAL_STRENGTH, + STATE_CLASS_MEASUREMENT, ) .extend( { diff --git a/esphome/components/xiaomi_cgd1/sensor.py b/esphome/components/xiaomi_cgd1/sensor.py index e8a27660fd..e7f18a6be9 100644 --- a/esphome/components/xiaomi_cgd1/sensor.py +++ b/esphome/components/xiaomi_cgd1/sensor.py @@ -11,6 +11,7 @@ from esphome.const import ( DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_TEMPERATURE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, UNIT_PERCENT, CONF_BINDKEY, @@ -31,13 +32,25 @@ CONFIG_SCHEMA = ( cv.Required(CONF_BINDKEY): cv.bind_key, cv.Required(CONF_MAC_ADDRESS): cv.mac_address, cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_EMPTY, + 1, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 1, DEVICE_CLASS_HUMIDITY + UNIT_PERCENT, + ICON_EMPTY, + 1, + DEVICE_CLASS_HUMIDITY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 0, DEVICE_CLASS_BATTERY + UNIT_PERCENT, + ICON_EMPTY, + 0, + DEVICE_CLASS_BATTERY, + STATE_CLASS_MEASUREMENT, ), } ) diff --git a/esphome/components/xiaomi_cgdk2/sensor.py b/esphome/components/xiaomi_cgdk2/sensor.py index 50509b7af7..6b2c144911 100644 --- a/esphome/components/xiaomi_cgdk2/sensor.py +++ b/esphome/components/xiaomi_cgdk2/sensor.py @@ -10,6 +10,7 @@ from esphome.const import ( DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_TEMPERATURE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, UNIT_PERCENT, CONF_ID, @@ -31,13 +32,25 @@ CONFIG_SCHEMA = ( cv.Required(CONF_BINDKEY): cv.bind_key, cv.Required(CONF_MAC_ADDRESS): cv.mac_address, cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_EMPTY, + 1, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 1, DEVICE_CLASS_HUMIDITY + UNIT_PERCENT, + ICON_EMPTY, + 1, + DEVICE_CLASS_HUMIDITY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 0, DEVICE_CLASS_BATTERY + UNIT_PERCENT, + ICON_EMPTY, + 0, + DEVICE_CLASS_BATTERY, + STATE_CLASS_MEASUREMENT, ), } ) diff --git a/esphome/components/xiaomi_cgg1/sensor.py b/esphome/components/xiaomi_cgg1/sensor.py index 978393d2d4..f26a7ae54e 100644 --- a/esphome/components/xiaomi_cgg1/sensor.py +++ b/esphome/components/xiaomi_cgg1/sensor.py @@ -12,6 +12,7 @@ from esphome.const import ( DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_TEMPERATURE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, UNIT_PERCENT, ) @@ -31,13 +32,25 @@ CONFIG_SCHEMA = ( cv.Optional(CONF_BINDKEY): cv.bind_key, cv.Required(CONF_MAC_ADDRESS): cv.mac_address, cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_EMPTY, + 1, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 1, DEVICE_CLASS_HUMIDITY + UNIT_PERCENT, + ICON_EMPTY, + 1, + DEVICE_CLASS_HUMIDITY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 0, DEVICE_CLASS_BATTERY + UNIT_PERCENT, + ICON_EMPTY, + 0, + DEVICE_CLASS_BATTERY, + STATE_CLASS_MEASUREMENT, ), } ) diff --git a/esphome/components/xiaomi_gcls002/sensor.py b/esphome/components/xiaomi_gcls002/sensor.py index 8789378824..a5c702aa9d 100644 --- a/esphome/components/xiaomi_gcls002/sensor.py +++ b/esphome/components/xiaomi_gcls002/sensor.py @@ -9,6 +9,7 @@ from esphome.const import ( DEVICE_CLASS_TEMPERATURE, ICON_EMPTY, ICON_WATER_PERCENT, + STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, UNIT_PERCENT, CONF_ID, @@ -34,16 +35,32 @@ CONFIG_SCHEMA = ( cv.GenerateID(): cv.declare_id(XiaomiGCLS002), cv.Required(CONF_MAC_ADDRESS): cv.mac_address, cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_EMPTY, + 1, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_MOISTURE): sensor.sensor_schema( - UNIT_PERCENT, ICON_WATER_PERCENT, 0, DEVICE_CLASS_EMPTY + UNIT_PERCENT, + ICON_WATER_PERCENT, + 0, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_ILLUMINANCE): sensor.sensor_schema( - UNIT_LUX, ICON_EMPTY, 0, DEVICE_CLASS_ILLUMINANCE + UNIT_LUX, + ICON_EMPTY, + 0, + DEVICE_CLASS_ILLUMINANCE, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_CONDUCTIVITY): sensor.sensor_schema( - UNIT_MICROSIEMENS_PER_CENTIMETER, ICON_FLOWER, 0, DEVICE_CLASS_EMPTY + UNIT_MICROSIEMENS_PER_CENTIMETER, + ICON_FLOWER, + 0, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), } ) diff --git a/esphome/components/xiaomi_hhccjcy01/sensor.py b/esphome/components/xiaomi_hhccjcy01/sensor.py index 13f6e5685c..03289a6219 100644 --- a/esphome/components/xiaomi_hhccjcy01/sensor.py +++ b/esphome/components/xiaomi_hhccjcy01/sensor.py @@ -9,6 +9,7 @@ from esphome.const import ( DEVICE_CLASS_TEMPERATURE, ICON_EMPTY, ICON_WATER_PERCENT, + STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, UNIT_PERCENT, CONF_ID, @@ -36,19 +37,39 @@ CONFIG_SCHEMA = ( cv.GenerateID(): cv.declare_id(XiaomiHHCCJCY01), cv.Required(CONF_MAC_ADDRESS): cv.mac_address, cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_EMPTY, + 1, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_MOISTURE): sensor.sensor_schema( - UNIT_PERCENT, ICON_WATER_PERCENT, 0, DEVICE_CLASS_EMPTY + UNIT_PERCENT, + ICON_WATER_PERCENT, + 0, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_ILLUMINANCE): sensor.sensor_schema( - UNIT_LUX, ICON_EMPTY, 0, DEVICE_CLASS_ILLUMINANCE + UNIT_LUX, + ICON_EMPTY, + 0, + DEVICE_CLASS_ILLUMINANCE, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_CONDUCTIVITY): sensor.sensor_schema( - UNIT_MICROSIEMENS_PER_CENTIMETER, ICON_FLOWER, 0, DEVICE_CLASS_EMPTY + UNIT_MICROSIEMENS_PER_CENTIMETER, + ICON_FLOWER, + 0, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 0, DEVICE_CLASS_BATTERY + UNIT_PERCENT, + ICON_EMPTY, + 0, + DEVICE_CLASS_BATTERY, + STATE_CLASS_MEASUREMENT, ), } ) diff --git a/esphome/components/xiaomi_hhccpot002/sensor.py b/esphome/components/xiaomi_hhccpot002/sensor.py index d2493f77c6..8393de5e5a 100644 --- a/esphome/components/xiaomi_hhccpot002/sensor.py +++ b/esphome/components/xiaomi_hhccpot002/sensor.py @@ -4,6 +4,7 @@ from esphome.components import sensor, esp32_ble_tracker from esphome.const import ( CONF_MAC_ADDRESS, DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_PERCENT, ICON_WATER_PERCENT, CONF_ID, @@ -27,10 +28,18 @@ CONFIG_SCHEMA = ( cv.GenerateID(): cv.declare_id(XiaomiHHCCPOT002), cv.Required(CONF_MAC_ADDRESS): cv.mac_address, cv.Optional(CONF_MOISTURE): sensor.sensor_schema( - UNIT_PERCENT, ICON_WATER_PERCENT, 0, DEVICE_CLASS_EMPTY + UNIT_PERCENT, + ICON_WATER_PERCENT, + 0, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_CONDUCTIVITY): sensor.sensor_schema( - UNIT_MICROSIEMENS_PER_CENTIMETER, ICON_FLOWER, 0, DEVICE_CLASS_EMPTY + UNIT_MICROSIEMENS_PER_CENTIMETER, + ICON_FLOWER, + 0, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), } ) diff --git a/esphome/components/xiaomi_jqjcy01ym/sensor.py b/esphome/components/xiaomi_jqjcy01ym/sensor.py index e2c2bce40e..70036eb5d9 100644 --- a/esphome/components/xiaomi_jqjcy01ym/sensor.py +++ b/esphome/components/xiaomi_jqjcy01ym/sensor.py @@ -11,6 +11,7 @@ from esphome.const import ( DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_TEMPERATURE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, UNIT_PERCENT, CONF_HUMIDITY, @@ -33,19 +34,32 @@ CONFIG_SCHEMA = ( cv.GenerateID(): cv.declare_id(XiaomiJQJCY01YM), cv.Required(CONF_MAC_ADDRESS): cv.mac_address, cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_EMPTY, + 1, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 0, DEVICE_CLASS_HUMIDITY + UNIT_PERCENT, + ICON_EMPTY, + 0, + DEVICE_CLASS_HUMIDITY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_FORMALDEHYDE): sensor.sensor_schema( UNIT_MILLIGRAMS_PER_CUBIC_METER, ICON_FLASK_OUTLINE, 2, DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 0, DEVICE_CLASS_BATTERY + UNIT_PERCENT, + ICON_EMPTY, + 0, + DEVICE_CLASS_BATTERY, + STATE_CLASS_MEASUREMENT, ), } ) diff --git a/esphome/components/xiaomi_lywsd02/sensor.py b/esphome/components/xiaomi_lywsd02/sensor.py index 5ea633dfa3..ca55f28176 100644 --- a/esphome/components/xiaomi_lywsd02/sensor.py +++ b/esphome/components/xiaomi_lywsd02/sensor.py @@ -7,6 +7,7 @@ from esphome.const import ( CONF_MAC_ADDRESS, CONF_TEMPERATURE, DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ICON_EMPTY, UNIT_PERCENT, @@ -29,13 +30,25 @@ CONFIG_SCHEMA = ( cv.GenerateID(): cv.declare_id(XiaomiLYWSD02), cv.Required(CONF_MAC_ADDRESS): cv.mac_address, cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_EMPTY, + 1, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 1, DEVICE_CLASS_HUMIDITY + UNIT_PERCENT, + ICON_EMPTY, + 1, + DEVICE_CLASS_HUMIDITY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 0, DEVICE_CLASS_BATTERY + UNIT_PERCENT, + ICON_EMPTY, + 0, + DEVICE_CLASS_BATTERY, + STATE_CLASS_MEASUREMENT, ), } ) diff --git a/esphome/components/xiaomi_lywsd03mmc/sensor.py b/esphome/components/xiaomi_lywsd03mmc/sensor.py index 24bd8d78c6..05b3798955 100644 --- a/esphome/components/xiaomi_lywsd03mmc/sensor.py +++ b/esphome/components/xiaomi_lywsd03mmc/sensor.py @@ -6,6 +6,7 @@ from esphome.const import ( CONF_HUMIDITY, CONF_MAC_ADDRESS, CONF_TEMPERATURE, + STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ICON_EMPTY, UNIT_PERCENT, @@ -33,13 +34,25 @@ CONFIG_SCHEMA = ( cv.Required(CONF_BINDKEY): cv.bind_key, cv.Required(CONF_MAC_ADDRESS): cv.mac_address, cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_EMPTY, + 1, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 0, DEVICE_CLASS_HUMIDITY + UNIT_PERCENT, + ICON_EMPTY, + 0, + DEVICE_CLASS_HUMIDITY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 0, DEVICE_CLASS_BATTERY + UNIT_PERCENT, + ICON_EMPTY, + 0, + DEVICE_CLASS_BATTERY, + STATE_CLASS_MEASUREMENT, ), } ) diff --git a/esphome/components/xiaomi_lywsdcgq/sensor.py b/esphome/components/xiaomi_lywsdcgq/sensor.py index b36a03e455..82bb4c83fb 100644 --- a/esphome/components/xiaomi_lywsdcgq/sensor.py +++ b/esphome/components/xiaomi_lywsdcgq/sensor.py @@ -6,6 +6,7 @@ from esphome.const import ( CONF_HUMIDITY, CONF_MAC_ADDRESS, CONF_TEMPERATURE, + STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ICON_EMPTY, UNIT_PERCENT, @@ -29,13 +30,25 @@ CONFIG_SCHEMA = ( cv.GenerateID(): cv.declare_id(XiaomiLYWSDCGQ), cv.Required(CONF_MAC_ADDRESS): cv.mac_address, cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_EMPTY, + 1, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 1, DEVICE_CLASS_HUMIDITY + UNIT_PERCENT, + ICON_EMPTY, + 1, + DEVICE_CLASS_HUMIDITY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 0, DEVICE_CLASS_BATTERY + UNIT_PERCENT, + ICON_EMPTY, + 0, + DEVICE_CLASS_BATTERY, + STATE_CLASS_MEASUREMENT, ), } ) diff --git a/esphome/components/xiaomi_mhoc401/sensor.py b/esphome/components/xiaomi_mhoc401/sensor.py index 94c594621e..5180bdbb89 100644 --- a/esphome/components/xiaomi_mhoc401/sensor.py +++ b/esphome/components/xiaomi_mhoc401/sensor.py @@ -6,6 +6,7 @@ from esphome.const import ( CONF_HUMIDITY, CONF_MAC_ADDRESS, CONF_TEMPERATURE, + STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, ICON_EMPTY, UNIT_PERCENT, @@ -32,13 +33,25 @@ CONFIG_SCHEMA = ( cv.Required(CONF_BINDKEY): cv.bind_key, cv.Required(CONF_MAC_ADDRESS): cv.mac_address, cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_EMPTY, + 1, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 0, DEVICE_CLASS_HUMIDITY + UNIT_PERCENT, + ICON_EMPTY, + 0, + DEVICE_CLASS_HUMIDITY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 0, DEVICE_CLASS_BATTERY + UNIT_PERCENT, + ICON_EMPTY, + 0, + DEVICE_CLASS_BATTERY, + STATE_CLASS_MEASUREMENT, ), } ) diff --git a/esphome/components/xiaomi_miscale/sensor.py b/esphome/components/xiaomi_miscale/sensor.py index 4423dc13cd..9fe76c0645 100644 --- a/esphome/components/xiaomi_miscale/sensor.py +++ b/esphome/components/xiaomi_miscale/sensor.py @@ -5,6 +5,7 @@ from esphome.const import ( CONF_MAC_ADDRESS, CONF_ID, CONF_WEIGHT, + STATE_CLASS_MEASUREMENT, UNIT_KILOGRAM, ICON_SCALE_BATHROOM, DEVICE_CLASS_EMPTY, @@ -23,7 +24,11 @@ CONFIG_SCHEMA = ( cv.GenerateID(): cv.declare_id(XiaomiMiscale), cv.Required(CONF_MAC_ADDRESS): cv.mac_address, cv.Optional(CONF_WEIGHT): sensor.sensor_schema( - UNIT_KILOGRAM, ICON_SCALE_BATHROOM, 2, DEVICE_CLASS_EMPTY + UNIT_KILOGRAM, + ICON_SCALE_BATHROOM, + 2, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), } ) diff --git a/esphome/components/xiaomi_miscale2/sensor.py b/esphome/components/xiaomi_miscale2/sensor.py index f20ef38c87..9944098407 100644 --- a/esphome/components/xiaomi_miscale2/sensor.py +++ b/esphome/components/xiaomi_miscale2/sensor.py @@ -5,6 +5,7 @@ from esphome.const import ( CONF_MAC_ADDRESS, CONF_ID, CONF_WEIGHT, + STATE_CLASS_MEASUREMENT, UNIT_KILOGRAM, ICON_SCALE_BATHROOM, UNIT_OHM, @@ -26,10 +27,14 @@ CONFIG_SCHEMA = ( cv.GenerateID(): cv.declare_id(XiaomiMiscale2), cv.Required(CONF_MAC_ADDRESS): cv.mac_address, cv.Optional(CONF_WEIGHT): sensor.sensor_schema( - UNIT_KILOGRAM, ICON_SCALE_BATHROOM, 2, DEVICE_CLASS_EMPTY + UNIT_KILOGRAM, + ICON_SCALE_BATHROOM, + 2, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_IMPEDANCE): sensor.sensor_schema( - UNIT_OHM, ICON_OMEGA, 0, DEVICE_CLASS_EMPTY + UNIT_OHM, ICON_OMEGA, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_MEASUREMENT ), } ) diff --git a/esphome/components/xiaomi_mjyd02yla/binary_sensor.py b/esphome/components/xiaomi_mjyd02yla/binary_sensor.py index a1c26b62a8..90b971c08a 100644 --- a/esphome/components/xiaomi_mjyd02yla/binary_sensor.py +++ b/esphome/components/xiaomi_mjyd02yla/binary_sensor.py @@ -12,6 +12,8 @@ from esphome.const import ( DEVICE_CLASS_EMPTY, DEVICE_CLASS_ILLUMINANCE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, + STATE_CLASS_NONE, UNIT_PERCENT, CONF_IDLE_TIME, CONF_ILLUMINANCE, @@ -41,13 +43,21 @@ CONFIG_SCHEMA = cv.All( CONF_DEVICE_CLASS, default="motion" ): binary_sensor.device_class, cv.Optional(CONF_IDLE_TIME): sensor.sensor_schema( - UNIT_MINUTE, ICON_TIMELAPSE, 0, DEVICE_CLASS_EMPTY + UNIT_MINUTE, ICON_TIMELAPSE, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE ), cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 0, DEVICE_CLASS_BATTERY + UNIT_PERCENT, + ICON_EMPTY, + 0, + DEVICE_CLASS_BATTERY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_ILLUMINANCE): sensor.sensor_schema( - UNIT_LUX, ICON_EMPTY, 0, DEVICE_CLASS_ILLUMINANCE + UNIT_LUX, + ICON_EMPTY, + 0, + DEVICE_CLASS_ILLUMINANCE, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_LIGHT): binary_sensor.BINARY_SENSOR_SCHEMA.extend( { diff --git a/esphome/components/xiaomi_wx08zm/binary_sensor.py b/esphome/components/xiaomi_wx08zm/binary_sensor.py index d538d4fbd7..90d4702da4 100644 --- a/esphome/components/xiaomi_wx08zm/binary_sensor.py +++ b/esphome/components/xiaomi_wx08zm/binary_sensor.py @@ -8,6 +8,7 @@ from esphome.const import ( DEVICE_CLASS_BATTERY, DEVICE_CLASS_EMPTY, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_PERCENT, ICON_BUG, CONF_ID, @@ -31,10 +32,14 @@ CONFIG_SCHEMA = cv.All( cv.GenerateID(): cv.declare_id(XiaomiWX08ZM), cv.Required(CONF_MAC_ADDRESS): cv.mac_address, cv.Optional(CONF_TABLET): sensor.sensor_schema( - UNIT_PERCENT, ICON_BUG, 0, DEVICE_CLASS_EMPTY + UNIT_PERCENT, ICON_BUG, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_MEASUREMENT ), cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 0, DEVICE_CLASS_BATTERY + UNIT_PERCENT, + ICON_EMPTY, + 0, + DEVICE_CLASS_BATTERY, + STATE_CLASS_MEASUREMENT, ), } ) diff --git a/esphome/components/zyaura/sensor.py b/esphome/components/zyaura/sensor.py index ebd43af630..5f9a5e3add 100644 --- a/esphome/components/zyaura/sensor.py +++ b/esphome/components/zyaura/sensor.py @@ -13,6 +13,7 @@ from esphome.const import ( DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_TEMPERATURE, ICON_EMPTY, + STATE_CLASS_MEASUREMENT, UNIT_PARTS_PER_MILLION, UNIT_CELSIUS, UNIT_PERCENT, @@ -33,13 +34,21 @@ CONFIG_SCHEMA = cv.Schema( pins.internal_gpio_input_pin_schema, pins.validate_has_interrupt ), cv.Optional(CONF_CO2): sensor.sensor_schema( - UNIT_PARTS_PER_MILLION, ICON_MOLECULE_CO2, 0, DEVICE_CLASS_EMPTY + UNIT_PARTS_PER_MILLION, + ICON_MOLECULE_CO2, + 0, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( - UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE + UNIT_CELSIUS, + ICON_EMPTY, + 1, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( - UNIT_PERCENT, ICON_EMPTY, 1, DEVICE_CLASS_HUMIDITY + UNIT_PERCENT, ICON_EMPTY, 1, DEVICE_CLASS_HUMIDITY, STATE_CLASS_MEASUREMENT ), } ).extend(cv.polling_component_schema("60s")) diff --git a/esphome/const.py b/esphome/const.py index 2316cee7dc..18ef10bb01 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -538,6 +538,7 @@ CONF_SPIKE_REJECTION = "spike_rejection" CONF_SSID = "ssid" CONF_SSL_FINGERPRINTS = "ssl_fingerprints" CONF_STATE = "state" +CONF_STATE_CLASS = "state_class" CONF_STATE_TOPIC = "state_topic" CONF_STATIC_IP = "static_ip" CONF_STATUS = "status" @@ -768,3 +769,9 @@ DEVICE_CLASS_POWER_FACTOR = "power_factor" DEVICE_CLASS_PRESSURE = "pressure" DEVICE_CLASS_TIMESTAMP = "timestamp" DEVICE_CLASS_VOLTAGE = "voltage" + +# state classes +STATE_CLASS_NONE = "" + +# The state represents a measurement in present time +STATE_CLASS_MEASUREMENT = "measurement" diff --git a/tests/test1.yaml b/tests/test1.yaml index e9e89defd3..378d4192d3 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -261,7 +261,6 @@ mcp23s17: cs_pin: GPIO12 deviceaddress: 1 - sensor: - platform: ble_client ble_client_id: ble_foo @@ -794,6 +793,7 @@ sensor: update_interval: 15s - platform: template name: 'Template Sensor' + state_class: measurement id: template_sensor lambda: |- if (id(ultrasonic_sensor1).state > 1) { From 7bc51582f08817c3e4a41e191131d63f2fd503d1 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Wed, 2 Jun 2021 21:13:42 -0700 Subject: [PATCH 087/104] make crc16 function accessible (#1857) --- esphome/components/modbus/modbus.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/components/modbus/modbus.h b/esphome/components/modbus/modbus.h index 91fc55b998..876c46b688 100644 --- a/esphome/components/modbus/modbus.h +++ b/esphome/components/modbus/modbus.h @@ -36,6 +36,8 @@ class Modbus : public uart::UARTDevice, public Component { std::vector devices_; }; +uint16_t crc16(const uint8_t *data, uint8_t len); + class ModbusDevice { public: void set_parent(Modbus *parent) { parent_ = parent; } From ebadaa966016dd9cfbc7fbd3046883ade9be0214 Mon Sep 17 00:00:00 2001 From: Lumpusz Date: Fri, 4 Jun 2021 12:04:54 +0200 Subject: [PATCH 088/104] Add preset, custom_preset and custom_fan_mode support to climate (#1471) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/api/api.proto | 24 ++- esphome/components/api/api_connection.cpp | 33 +++- esphome/components/api/api_pb2.cpp | 158 ++++++++++++++++- esphome/components/api/api_pb2.h | 104 +++++++----- esphome/components/climate/__init__.py | 35 +++- esphome/components/climate/automation.h | 6 + esphome/components/climate/climate.cpp | 159 ++++++++++++++++-- esphome/components/climate/climate.h | 39 ++++- esphome/components/climate/climate_mode.cpp | 23 +++ esphome/components/climate/climate_mode.h | 27 ++- esphome/components/climate/climate_traits.cpp | 65 +++++++ esphome/components/climate/climate_traits.h | 25 +++ .../climate_ir_lg/climate_ir_lg.cpp | 2 +- esphome/components/coolix/coolix.cpp | 2 +- esphome/components/daikin/daikin.cpp | 2 +- .../fujitsu_general/fujitsu_general.cpp | 2 +- .../hitachi_ac344/hitachi_ac344.cpp | 4 +- esphome/components/midea_ac/climate.py | 35 +++- esphome/components/midea_ac/midea_climate.cpp | 88 +++++++++- esphome/components/midea_ac/midea_climate.h | 14 ++ esphome/components/midea_ac/midea_frame.cpp | 72 ++++++++ esphome/components/midea_ac/midea_frame.h | 32 +++- esphome/components/mqtt/mqtt_climate.cpp | 7 +- esphome/components/tcl112/tcl112.cpp | 2 +- .../thermostat/thermostat_climate.cpp | 2 +- esphome/components/whirlpool/whirlpool.cpp | 2 +- esphome/const.py | 8 + tests/test1.yaml | 17 -- tests/test3.yaml | 37 ++++ tests/test4.yaml | 1 + 30 files changed, 931 insertions(+), 96 deletions(-) diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index 43e23f640b..f543c2356f 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -672,11 +672,12 @@ message CameraImageRequest { // ==================== CLIMATE ==================== enum ClimateMode { CLIMATE_MODE_OFF = 0; - CLIMATE_MODE_AUTO = 1; + CLIMATE_MODE_HEAT_COOL = 1; CLIMATE_MODE_COOL = 2; CLIMATE_MODE_HEAT = 3; CLIMATE_MODE_FAN_ONLY = 4; CLIMATE_MODE_DRY = 5; + CLIMATE_MODE_AUTO = 6; } enum ClimateFanMode { CLIMATE_FAN_ON = 0; @@ -704,6 +705,15 @@ enum ClimateAction { CLIMATE_ACTION_DRYING = 5; CLIMATE_ACTION_FAN = 6; } +enum ClimatePreset { + CLIMATE_PRESET_ECO = 0; + CLIMATE_PRESET_AWAY = 1; + CLIMATE_PRESET_BOOST = 2; + CLIMATE_PRESET_COMFORT = 3; + CLIMATE_PRESET_HOME = 4; + CLIMATE_PRESET_SLEEP = 5; + CLIMATE_PRESET_ACTIVITY = 6; +} message ListEntitiesClimateResponse { option (id) = 46; option (source) = SOURCE_SERVER; @@ -724,6 +734,9 @@ message ListEntitiesClimateResponse { bool supports_action = 12; repeated ClimateFanMode supported_fan_modes = 13; repeated ClimateSwingMode supported_swing_modes = 14; + repeated string supported_custom_fan_modes = 15; + repeated ClimatePreset supported_presets = 16; + repeated string supported_custom_presets = 17; } message ClimateStateResponse { option (id) = 47; @@ -741,6 +754,9 @@ message ClimateStateResponse { ClimateAction action = 8; ClimateFanMode fan_mode = 9; ClimateSwingMode swing_mode = 10; + string custom_fan_mode = 11; + ClimatePreset preset = 12; + string custom_preset = 13; } message ClimateCommandRequest { option (id) = 48; @@ -763,4 +779,10 @@ message ClimateCommandRequest { ClimateFanMode fan_mode = 13; bool has_swing_mode = 14; ClimateSwingMode swing_mode = 15; + bool has_custom_fan_mode = 16; + string custom_fan_mode = 17; + bool has_preset = 18; + ClimatePreset preset = 19; + bool has_custom_preset = 20; + string custom_preset = 21; } diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index b5fc9b245c..eca95de3c2 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -477,8 +477,14 @@ bool APIConnection::send_climate_state(climate::Climate *climate) { } if (traits.get_supports_away()) resp.away = climate->away; - if (traits.get_supports_fan_modes()) - resp.fan_mode = static_cast(climate->fan_mode); + if (traits.get_supports_fan_modes() && climate->fan_mode.has_value()) + resp.fan_mode = static_cast(climate->fan_mode.value()); + if (!traits.get_supported_custom_fan_modes().empty() && climate->custom_fan_mode.has_value()) + resp.custom_fan_mode = climate->custom_fan_mode.value(); + if (traits.get_supports_presets() && climate->preset.has_value()) + resp.preset = static_cast(climate->preset.value()); + if (!traits.get_supported_custom_presets().empty() && climate->custom_preset.has_value()) + resp.custom_preset = climate->custom_preset.value(); if (traits.get_supports_swing_modes()) resp.swing_mode = static_cast(climate->swing_mode); return this->send_climate_state_response(resp); @@ -492,8 +498,9 @@ bool APIConnection::send_climate_info(climate::Climate *climate) { msg.unique_id = get_default_unique_id("climate", climate); msg.supports_current_temperature = traits.get_supports_current_temperature(); msg.supports_two_point_target_temperature = traits.get_supports_two_point_target_temperature(); - for (auto mode : {climate::CLIMATE_MODE_AUTO, climate::CLIMATE_MODE_OFF, climate::CLIMATE_MODE_COOL, - climate::CLIMATE_MODE_HEAT, climate::CLIMATE_MODE_DRY, climate::CLIMATE_MODE_FAN_ONLY}) { + for (auto mode : + {climate::CLIMATE_MODE_AUTO, climate::CLIMATE_MODE_OFF, climate::CLIMATE_MODE_COOL, climate::CLIMATE_MODE_HEAT, + climate::CLIMATE_MODE_DRY, climate::CLIMATE_MODE_FAN_ONLY, climate::CLIMATE_MODE_HEAT_COOL}) { if (traits.supports_mode(mode)) msg.supported_modes.push_back(static_cast(mode)); } @@ -508,6 +515,18 @@ bool APIConnection::send_climate_info(climate::Climate *climate) { if (traits.supports_fan_mode(fan_mode)) msg.supported_fan_modes.push_back(static_cast(fan_mode)); } + for (auto const &custom_fan_mode : traits.get_supported_custom_fan_modes()) { + msg.supported_custom_fan_modes.push_back(custom_fan_mode); + } + for (auto preset : {climate::CLIMATE_PRESET_ECO, climate::CLIMATE_PRESET_AWAY, climate::CLIMATE_PRESET_BOOST, + climate::CLIMATE_PRESET_COMFORT, climate::CLIMATE_PRESET_HOME, climate::CLIMATE_PRESET_SLEEP, + climate::CLIMATE_PRESET_ACTIVITY}) { + if (traits.supports_preset(preset)) + msg.supported_presets.push_back(static_cast(preset)); + } + for (auto const &custom_preset : traits.get_supported_custom_presets()) { + msg.supported_custom_presets.push_back(custom_preset); + } for (auto swing_mode : {climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_BOTH, climate::CLIMATE_SWING_VERTICAL, climate::CLIMATE_SWING_HORIZONTAL}) { if (traits.supports_swing_mode(swing_mode)) @@ -533,6 +552,12 @@ void APIConnection::climate_command(const ClimateCommandRequest &msg) { call.set_away(msg.away); if (msg.has_fan_mode) call.set_fan_mode(static_cast(msg.fan_mode)); + if (msg.has_custom_fan_mode) + call.set_fan_mode(msg.custom_fan_mode); + if (msg.has_preset) + call.set_preset(static_cast(msg.preset)); + if (msg.has_custom_preset) + call.set_preset(msg.custom_preset); if (msg.has_swing_mode) call.set_swing_mode(static_cast(msg.swing_mode)); call.perform(); diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 38efbc2ec4..76cdc44e1e 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -118,8 +118,8 @@ template<> const char *proto_enum_to_string(enums::ClimateMo switch (value) { case enums::CLIMATE_MODE_OFF: return "CLIMATE_MODE_OFF"; - case enums::CLIMATE_MODE_AUTO: - return "CLIMATE_MODE_AUTO"; + case enums::CLIMATE_MODE_HEAT_COOL: + return "CLIMATE_MODE_HEAT_COOL"; case enums::CLIMATE_MODE_COOL: return "CLIMATE_MODE_COOL"; case enums::CLIMATE_MODE_HEAT: @@ -128,6 +128,8 @@ template<> const char *proto_enum_to_string(enums::ClimateMo return "CLIMATE_MODE_FAN_ONLY"; case enums::CLIMATE_MODE_DRY: return "CLIMATE_MODE_DRY"; + case enums::CLIMATE_MODE_AUTO: + return "CLIMATE_MODE_AUTO"; default: return "UNKNOWN"; } @@ -188,6 +190,26 @@ template<> const char *proto_enum_to_string(enums::Climate return "UNKNOWN"; } } +template<> const char *proto_enum_to_string(enums::ClimatePreset value) { + switch (value) { + case enums::CLIMATE_PRESET_ECO: + return "CLIMATE_PRESET_ECO"; + case enums::CLIMATE_PRESET_AWAY: + return "CLIMATE_PRESET_AWAY"; + case enums::CLIMATE_PRESET_BOOST: + return "CLIMATE_PRESET_BOOST"; + case enums::CLIMATE_PRESET_COMFORT: + return "CLIMATE_PRESET_COMFORT"; + case enums::CLIMATE_PRESET_HOME: + return "CLIMATE_PRESET_HOME"; + case enums::CLIMATE_PRESET_SLEEP: + return "CLIMATE_PRESET_SLEEP"; + case enums::CLIMATE_PRESET_ACTIVITY: + return "CLIMATE_PRESET_ACTIVITY"; + default: + return "UNKNOWN"; + } +} bool HelloRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) { switch (field_id) { case 1: { @@ -2647,6 +2669,10 @@ bool ListEntitiesClimateResponse::decode_varint(uint32_t field_id, ProtoVarInt v this->supported_swing_modes.push_back(value.as_enum()); return true; } + case 16: { + this->supported_presets.push_back(value.as_enum()); + return true; + } default: return false; } @@ -2665,6 +2691,14 @@ bool ListEntitiesClimateResponse::decode_length(uint32_t field_id, ProtoLengthDe this->unique_id = value.as_string(); return true; } + case 15: { + this->supported_custom_fan_modes.push_back(value.as_string()); + return true; + } + case 17: { + this->supported_custom_presets.push_back(value.as_string()); + return true; + } default: return false; } @@ -2712,6 +2746,15 @@ void ListEntitiesClimateResponse::encode(ProtoWriteBuffer buffer) const { for (auto &it : this->supported_swing_modes) { buffer.encode_enum(14, it, true); } + for (auto &it : this->supported_custom_fan_modes) { + buffer.encode_string(15, it, true); + } + for (auto &it : this->supported_presets) { + buffer.encode_enum(16, it, true); + } + for (auto &it : this->supported_custom_presets) { + buffer.encode_string(17, it, true); + } } void ListEntitiesClimateResponse::dump_to(std::string &out) const { char buffer[64]; @@ -2781,6 +2824,24 @@ void ListEntitiesClimateResponse::dump_to(std::string &out) const { out.append(proto_enum_to_string(it)); out.append("\n"); } + + for (const auto &it : this->supported_custom_fan_modes) { + out.append(" supported_custom_fan_modes: "); + out.append("'").append(it).append("'"); + out.append("\n"); + } + + for (const auto &it : this->supported_presets) { + out.append(" supported_presets: "); + out.append(proto_enum_to_string(it)); + out.append("\n"); + } + + for (const auto &it : this->supported_custom_presets) { + out.append(" supported_custom_presets: "); + out.append("'").append(it).append("'"); + out.append("\n"); + } out.append("}"); } bool ClimateStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { @@ -2805,6 +2866,24 @@ bool ClimateStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { this->swing_mode = value.as_enum(); return true; } + case 12: { + this->preset = value.as_enum(); + return true; + } + default: + return false; + } +} +bool ClimateStateResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) { + switch (field_id) { + case 11: { + this->custom_fan_mode = value.as_string(); + return true; + } + case 13: { + this->custom_preset = value.as_string(); + return true; + } default: return false; } @@ -2846,6 +2925,9 @@ void ClimateStateResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_enum(8, this->action); buffer.encode_enum(9, this->fan_mode); buffer.encode_enum(10, this->swing_mode); + buffer.encode_string(11, this->custom_fan_mode); + buffer.encode_enum(12, this->preset); + buffer.encode_string(13, this->custom_preset); } void ClimateStateResponse::dump_to(std::string &out) const { char buffer[64]; @@ -2894,6 +2976,18 @@ void ClimateStateResponse::dump_to(std::string &out) const { out.append(" swing_mode: "); out.append(proto_enum_to_string(this->swing_mode)); out.append("\n"); + + out.append(" custom_fan_mode: "); + out.append("'").append(this->custom_fan_mode).append("'"); + out.append("\n"); + + out.append(" preset: "); + out.append(proto_enum_to_string(this->preset)); + out.append("\n"); + + out.append(" custom_preset: "); + out.append("'").append(this->custom_preset).append("'"); + out.append("\n"); out.append("}"); } bool ClimateCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { @@ -2942,6 +3036,36 @@ bool ClimateCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) this->swing_mode = value.as_enum(); return true; } + case 16: { + this->has_custom_fan_mode = value.as_bool(); + return true; + } + case 18: { + this->has_preset = value.as_bool(); + return true; + } + case 19: { + this->preset = value.as_enum(); + return true; + } + case 20: { + this->has_custom_preset = value.as_bool(); + return true; + } + default: + return false; + } +} +bool ClimateCommandRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) { + switch (field_id) { + case 17: { + this->custom_fan_mode = value.as_string(); + return true; + } + case 21: { + this->custom_preset = value.as_string(); + return true; + } default: return false; } @@ -2984,6 +3108,12 @@ void ClimateCommandRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_enum(13, this->fan_mode); buffer.encode_bool(14, this->has_swing_mode); buffer.encode_enum(15, this->swing_mode); + buffer.encode_bool(16, this->has_custom_fan_mode); + buffer.encode_string(17, this->custom_fan_mode); + buffer.encode_bool(18, this->has_preset); + buffer.encode_enum(19, this->preset); + buffer.encode_bool(20, this->has_custom_preset); + buffer.encode_string(21, this->custom_preset); } void ClimateCommandRequest::dump_to(std::string &out) const { char buffer[64]; @@ -3051,6 +3181,30 @@ void ClimateCommandRequest::dump_to(std::string &out) const { out.append(" swing_mode: "); out.append(proto_enum_to_string(this->swing_mode)); out.append("\n"); + + out.append(" has_custom_fan_mode: "); + out.append(YESNO(this->has_custom_fan_mode)); + out.append("\n"); + + out.append(" custom_fan_mode: "); + out.append("'").append(this->custom_fan_mode).append("'"); + out.append("\n"); + + out.append(" has_preset: "); + out.append(YESNO(this->has_preset)); + out.append("\n"); + + out.append(" preset: "); + out.append(proto_enum_to_string(this->preset)); + out.append("\n"); + + out.append(" has_custom_preset: "); + out.append(YESNO(this->has_custom_preset)); + out.append("\n"); + + out.append(" custom_preset: "); + out.append("'").append(this->custom_preset).append("'"); + out.append("\n"); out.append("}"); } diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index e49136b442..365ea0025d 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -57,11 +57,12 @@ enum ServiceArgType : uint32_t { }; enum ClimateMode : uint32_t { CLIMATE_MODE_OFF = 0, - CLIMATE_MODE_AUTO = 1, + CLIMATE_MODE_HEAT_COOL = 1, CLIMATE_MODE_COOL = 2, CLIMATE_MODE_HEAT = 3, CLIMATE_MODE_FAN_ONLY = 4, CLIMATE_MODE_DRY = 5, + CLIMATE_MODE_AUTO = 6, }; enum ClimateFanMode : uint32_t { CLIMATE_FAN_ON = 0, @@ -88,6 +89,15 @@ enum ClimateAction : uint32_t { CLIMATE_ACTION_DRYING = 5, CLIMATE_ACTION_FAN = 6, }; +enum ClimatePreset : uint32_t { + CLIMATE_PRESET_ECO = 0, + CLIMATE_PRESET_AWAY = 1, + CLIMATE_PRESET_BOOST = 2, + CLIMATE_PRESET_COMFORT = 3, + CLIMATE_PRESET_HOME = 4, + CLIMATE_PRESET_SLEEP = 5, + CLIMATE_PRESET_ACTIVITY = 6, +}; } // namespace enums @@ -687,20 +697,23 @@ class CameraImageRequest : public ProtoMessage { }; class ListEntitiesClimateResponse : public ProtoMessage { public: - std::string object_id{}; - uint32_t key{0}; - std::string name{}; - std::string unique_id{}; - bool supports_current_temperature{false}; - bool supports_two_point_target_temperature{false}; - std::vector supported_modes{}; - float visual_min_temperature{0.0f}; - float visual_max_temperature{0.0f}; - float visual_temperature_step{0.0f}; - bool supports_away{false}; - bool supports_action{false}; - std::vector supported_fan_modes{}; - std::vector supported_swing_modes{}; + std::string object_id{}; // NOLINT + uint32_t key{0}; // NOLINT + std::string name{}; // NOLINT + std::string unique_id{}; // NOLINT + bool supports_current_temperature{false}; // NOLINT + bool supports_two_point_target_temperature{false}; // NOLINT + std::vector supported_modes{}; // NOLINT + float visual_min_temperature{0.0f}; // NOLINT + float visual_max_temperature{0.0f}; // NOLINT + float visual_temperature_step{0.0f}; // NOLINT + bool supports_away{false}; // NOLINT + bool supports_action{false}; // NOLINT + std::vector supported_fan_modes{}; // NOLINT + std::vector supported_swing_modes{}; // NOLINT + std::vector supported_custom_fan_modes{}; // NOLINT + std::vector supported_presets{}; // NOLINT + std::vector supported_custom_presets{}; // NOLINT void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; @@ -711,45 +724,56 @@ class ListEntitiesClimateResponse : public ProtoMessage { }; class ClimateStateResponse : public ProtoMessage { public: - uint32_t key{0}; - enums::ClimateMode mode{}; - float current_temperature{0.0f}; - float target_temperature{0.0f}; - float target_temperature_low{0.0f}; - float target_temperature_high{0.0f}; - bool away{false}; - enums::ClimateAction action{}; - enums::ClimateFanMode fan_mode{}; - enums::ClimateSwingMode swing_mode{}; + uint32_t key{0}; // NOLINT + enums::ClimateMode mode{}; // NOLINT + float current_temperature{0.0f}; // NOLINT + float target_temperature{0.0f}; // NOLINT + float target_temperature_low{0.0f}; // NOLINT + float target_temperature_high{0.0f}; // NOLINT + bool away{false}; // NOLINT + enums::ClimateAction action{}; // NOLINT + enums::ClimateFanMode fan_mode{}; // NOLINT + enums::ClimateSwingMode swing_mode{}; // NOLINT + std::string custom_fan_mode{}; // NOLINT + enums::ClimatePreset preset{}; // NOLINT + std::string custom_preset{}; // NOLINT void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; protected: bool decode_32bit(uint32_t field_id, Proto32Bit value) override; + bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; class ClimateCommandRequest : public ProtoMessage { public: - uint32_t key{0}; - bool has_mode{false}; - enums::ClimateMode mode{}; - bool has_target_temperature{false}; - float target_temperature{0.0f}; - bool has_target_temperature_low{false}; - float target_temperature_low{0.0f}; - bool has_target_temperature_high{false}; - float target_temperature_high{0.0f}; - bool has_away{false}; - bool away{false}; - bool has_fan_mode{false}; - enums::ClimateFanMode fan_mode{}; - bool has_swing_mode{false}; - enums::ClimateSwingMode swing_mode{}; + uint32_t key{0}; // NOLINT + bool has_mode{false}; // NOLINT + enums::ClimateMode mode{}; // NOLINT + bool has_target_temperature{false}; // NOLINT + float target_temperature{0.0f}; // NOLINT + bool has_target_temperature_low{false}; // NOLINT + float target_temperature_low{0.0f}; // NOLINT + bool has_target_temperature_high{false}; // NOLINT + float target_temperature_high{0.0f}; // NOLINT + bool has_away{false}; // NOLINT + bool away{false}; // NOLINT + bool has_fan_mode{false}; // NOLINT + enums::ClimateFanMode fan_mode{}; // NOLINT + bool has_swing_mode{false}; // NOLINT + enums::ClimateSwingMode swing_mode{}; // NOLINT + bool has_custom_fan_mode{false}; // NOLINT + std::string custom_fan_mode{}; // NOLINT + bool has_preset{false}; // NOLINT + enums::ClimatePreset preset{}; // NOLINT + bool has_custom_preset{false}; // NOLINT + std::string custom_preset{}; // NOLINT void encode(ProtoWriteBuffer buffer) const override; void dump_to(std::string &out) const override; protected: bool decode_32bit(uint32_t field_id, Proto32Bit value) override; + bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; diff --git a/esphome/components/climate/__init__.py b/esphome/components/climate/__init__.py index fb163c96ae..5a4492216e 100644 --- a/esphome/components/climate/__init__.py +++ b/esphome/components/climate/__init__.py @@ -4,11 +4,14 @@ from esphome import automation from esphome.components import mqtt from esphome.const import ( CONF_AWAY, + CONF_CUSTOM_FAN_MODE, + CONF_CUSTOM_PRESET, CONF_ID, CONF_INTERNAL, CONF_MAX_TEMPERATURE, CONF_MIN_TEMPERATURE, CONF_MODE, + CONF_PRESET, CONF_TARGET_TEMPERATURE, CONF_TARGET_TEMPERATURE_HIGH, CONF_TARGET_TEMPERATURE_LOW, @@ -33,11 +36,12 @@ ClimateTraits = climate_ns.class_("ClimateTraits") ClimateMode = climate_ns.enum("ClimateMode") CLIMATE_MODES = { "OFF": ClimateMode.CLIMATE_MODE_OFF, - "AUTO": ClimateMode.CLIMATE_MODE_AUTO, + "HEAT_COOL": ClimateMode.CLIMATE_HEAT_COOL, "COOL": ClimateMode.CLIMATE_MODE_COOL, "HEAT": ClimateMode.CLIMATE_MODE_HEAT, "DRY": ClimateMode.CLIMATE_MODE_DRY, "FAN_ONLY": ClimateMode.CLIMATE_MODE_FAN_ONLY, + "AUTO": ClimateMode.CLIMATE_MODE_AUTO, } validate_climate_mode = cv.enum(CLIMATE_MODES, upper=True) @@ -56,6 +60,19 @@ CLIMATE_FAN_MODES = { validate_climate_fan_mode = cv.enum(CLIMATE_FAN_MODES, upper=True) +ClimatePreset = climate_ns.enum("ClimatePreset") +CLIMATE_PRESETS = { + "ECO": ClimatePreset.CLIMATE_PRESET_ECO, + "AWAY": ClimatePreset.CLIMATE_PRESET_AWAY, + "BOOST": ClimatePreset.CLIMATE_PRESET_BOOST, + "COMFORT": ClimatePreset.CLIMATE_PRESET_COMFORT, + "HOME": ClimatePreset.CLIMATE_PRESET_HOME, + "SLEEP": ClimatePreset.CLIMATE_PRESET_SLEEP, + "ACTIVITY": ClimatePreset.CLIMATE_PRESET_ACTIVITY, +} + +validate_climate_preset = cv.enum(CLIMATE_PRESETS, upper=True) + ClimateSwingMode = climate_ns.enum("ClimateSwingMode") CLIMATE_SWING_MODES = { "OFF": ClimateSwingMode.CLIMATE_SWING_OFF, @@ -117,7 +134,12 @@ CLIMATE_CONTROL_ACTION_SCHEMA = cv.Schema( cv.Optional(CONF_TARGET_TEMPERATURE_LOW): cv.templatable(cv.temperature), cv.Optional(CONF_TARGET_TEMPERATURE_HIGH): cv.templatable(cv.temperature), cv.Optional(CONF_AWAY): cv.templatable(cv.boolean), - cv.Optional(CONF_FAN_MODE): cv.templatable(validate_climate_fan_mode), + cv.Exclusive(CONF_FAN_MODE, "fan_mode"): cv.templatable( + validate_climate_fan_mode + ), + cv.Exclusive(CONF_CUSTOM_FAN_MODE, "fan_mode"): cv.string_strict, + cv.Exclusive(CONF_PRESET, "preset"): cv.templatable(validate_climate_preset), + cv.Exclusive(CONF_CUSTOM_PRESET, "preset"): cv.string_strict, cv.Optional(CONF_SWING_MODE): cv.templatable(validate_climate_swing_mode), } ) @@ -151,6 +173,15 @@ async def climate_control_to_code(config, action_id, template_arg, args): if CONF_FAN_MODE in config: template_ = await cg.templatable(config[CONF_FAN_MODE], args, ClimateFanMode) cg.add(var.set_fan_mode(template_)) + if CONF_CUSTOM_FAN_MODE in config: + template_ = await cg.templatable(config[CONF_CUSTOM_FAN_MODE], args, str) + cg.add(var.set_custom_fan_mode(template_)) + if CONF_PRESET in config: + template_ = await cg.templatable(config[CONF_PRESET], args, ClimatePreset) + cg.add(var.set_preset(template_)) + if CONF_CUSTOM_PRESET in config: + template_ = await cg.templatable(config[CONF_CUSTOM_PRESET], args, str) + cg.add(var.set_custom_preset(template_)) if CONF_SWING_MODE in config: template_ = await cg.templatable( config[CONF_SWING_MODE], args, ClimateSwingMode diff --git a/esphome/components/climate/automation.h b/esphome/components/climate/automation.h index 0cd52b1036..b0b71cb7d7 100644 --- a/esphome/components/climate/automation.h +++ b/esphome/components/climate/automation.h @@ -16,6 +16,9 @@ template class ControlAction : public Action { TEMPLATABLE_VALUE(float, target_temperature_high) TEMPLATABLE_VALUE(bool, away) TEMPLATABLE_VALUE(ClimateFanMode, fan_mode) + TEMPLATABLE_VALUE(std::string, custom_fan_mode) + TEMPLATABLE_VALUE(ClimatePreset, preset) + TEMPLATABLE_VALUE(std::string, custom_preset) TEMPLATABLE_VALUE(ClimateSwingMode, swing_mode) void play(Ts... x) override { @@ -26,6 +29,9 @@ template class ControlAction : public Action { call.set_target_temperature_high(this->target_temperature_high_.optional_value(x...)); call.set_away(this->away_.optional_value(x...)); call.set_fan_mode(this->fan_mode_.optional_value(x...)); + call.set_fan_mode(this->custom_fan_mode_.optional_value(x...)); + call.set_preset(this->preset_.optional_value(x...)); + call.set_preset(this->custom_preset_.optional_value(x...)); call.set_swing_mode(this->swing_mode_.optional_value(x...)); call.perform(); } diff --git a/esphome/components/climate/climate.cpp b/esphome/components/climate/climate.cpp index 443290ed6d..c047d96cdb 100644 --- a/esphome/components/climate/climate.cpp +++ b/esphome/components/climate/climate.cpp @@ -1,5 +1,4 @@ #include "climate.h" -#include "esphome/core/log.h" namespace esphome { namespace climate { @@ -13,10 +12,24 @@ void ClimateCall::perform() { const char *mode_s = climate_mode_to_string(*this->mode_); ESP_LOGD(TAG, " Mode: %s", mode_s); } + if (this->custom_fan_mode_.has_value()) { + this->fan_mode_.reset(); + ESP_LOGD(TAG, " Custom Fan: %s", this->custom_fan_mode_.value().c_str()); + } if (this->fan_mode_.has_value()) { + this->custom_fan_mode_.reset(); const char *fan_mode_s = climate_fan_mode_to_string(*this->fan_mode_); ESP_LOGD(TAG, " Fan: %s", fan_mode_s); } + if (this->custom_preset_.has_value()) { + this->preset_.reset(); + ESP_LOGD(TAG, " Custom Preset: %s", this->custom_preset_.value().c_str()); + } + if (this->preset_.has_value()) { + this->custom_preset_.reset(); + const char *preset_s = climate_preset_to_string(*this->preset_); + ESP_LOGD(TAG, " Preset: %s", preset_s); + } if (this->swing_mode_.has_value()) { const char *swing_mode_s = climate_swing_mode_to_string(*this->swing_mode_); ESP_LOGD(TAG, " Swing: %s", swing_mode_s); @@ -44,13 +57,32 @@ void ClimateCall::validate_() { this->mode_.reset(); } } - if (this->fan_mode_.has_value()) { + if (this->custom_fan_mode_.has_value()) { + auto custom_fan_mode = *this->custom_fan_mode_; + if (!traits.supports_custom_fan_mode(custom_fan_mode)) { + ESP_LOGW(TAG, " Fan Mode %s is not supported by this device!", custom_fan_mode.c_str()); + this->custom_fan_mode_.reset(); + } + } else if (this->fan_mode_.has_value()) { auto fan_mode = *this->fan_mode_; if (!traits.supports_fan_mode(fan_mode)) { ESP_LOGW(TAG, " Fan Mode %s is not supported by this device!", climate_fan_mode_to_string(fan_mode)); this->fan_mode_.reset(); } } + if (this->custom_preset_.has_value()) { + auto custom_preset = *this->custom_preset_; + if (!traits.supports_custom_preset(custom_preset)) { + ESP_LOGW(TAG, " Preset %s is not supported by this device!", custom_preset.c_str()); + this->custom_preset_.reset(); + } + } else if (this->preset_.has_value()) { + auto preset = *this->preset_; + if (!traits.supports_preset(preset)) { + ESP_LOGW(TAG, " Preset %s is not supported by this device!", climate_preset_to_string(preset)); + this->preset_.reset(); + } + } if (this->swing_mode_.has_value()) { auto swing_mode = *this->swing_mode_; if (!traits.supports_swing_mode(swing_mode)) { @@ -117,6 +149,8 @@ ClimateCall &ClimateCall::set_mode(const std::string &mode) { this->set_mode(CLIMATE_MODE_FAN_ONLY); } else if (str_equals_case_insensitive(mode, "DRY")) { this->set_mode(CLIMATE_MODE_DRY); + } else if (str_equals_case_insensitive(mode, "HEAT_COOL")) { + this->set_mode(CLIMATE_MODE_HEAT_COOL); } else { ESP_LOGW(TAG, "'%s' - Unrecognized mode %s", this->parent_->get_name().c_str(), mode.c_str()); } @@ -124,6 +158,7 @@ ClimateCall &ClimateCall::set_mode(const std::string &mode) { } ClimateCall &ClimateCall::set_fan_mode(ClimateFanMode fan_mode) { this->fan_mode_ = fan_mode; + this->custom_fan_mode_.reset(); return *this; } ClimateCall &ClimateCall::set_fan_mode(const std::string &fan_mode) { @@ -146,11 +181,59 @@ ClimateCall &ClimateCall::set_fan_mode(const std::string &fan_mode) { } else if (str_equals_case_insensitive(fan_mode, "DIFFUSE")) { this->set_fan_mode(CLIMATE_FAN_DIFFUSE); } else { - ESP_LOGW(TAG, "'%s' - Unrecognized fan mode %s", this->parent_->get_name().c_str(), fan_mode.c_str()); + auto custom_fan_modes = this->parent_->get_traits().get_supported_custom_fan_modes(); + if (std::find(custom_fan_modes.begin(), custom_fan_modes.end(), fan_mode) != custom_fan_modes.end()) { + this->custom_fan_mode_ = fan_mode; + this->fan_mode_.reset(); + } else { + ESP_LOGW(TAG, "'%s' - Unrecognized fan mode %s", this->parent_->get_name().c_str(), fan_mode.c_str()); + } + } + return *this; +} +ClimateCall &ClimateCall::set_fan_mode(optional fan_mode) { + if (fan_mode.has_value()) { + this->set_fan_mode(fan_mode.value()); + } + return *this; +} +ClimateCall &ClimateCall::set_preset(ClimatePreset preset) { + this->preset_ = preset; + this->custom_preset_.reset(); + return *this; +} +ClimateCall &ClimateCall::set_preset(const std::string &preset) { + if (str_equals_case_insensitive(preset, "ECO")) { + this->set_preset(CLIMATE_PRESET_ECO); + } else if (str_equals_case_insensitive(preset, "AWAY")) { + this->set_preset(CLIMATE_PRESET_AWAY); + } else if (str_equals_case_insensitive(preset, "BOOST")) { + this->set_preset(CLIMATE_PRESET_BOOST); + } else if (str_equals_case_insensitive(preset, "COMFORT")) { + this->set_preset(CLIMATE_PRESET_COMFORT); + } else if (str_equals_case_insensitive(preset, "HOME")) { + this->set_preset(CLIMATE_PRESET_HOME); + } else if (str_equals_case_insensitive(preset, "SLEEP")) { + this->set_preset(CLIMATE_PRESET_SLEEP); + } else if (str_equals_case_insensitive(preset, "ACTIVITY")) { + this->set_preset(CLIMATE_PRESET_ACTIVITY); + } else { + auto custom_presets = this->parent_->get_traits().get_supported_custom_presets(); + if (std::find(custom_presets.begin(), custom_presets.end(), preset) != custom_presets.end()) { + this->custom_preset_ = preset; + this->preset_.reset(); + } else { + ESP_LOGW(TAG, "'%s' - Unrecognized preset %s", this->parent_->get_name().c_str(), preset.c_str()); + } + } + return *this; +} +ClimateCall &ClimateCall::set_preset(optional preset) { + if (preset.has_value()) { + this->set_preset(preset.value()); } return *this; } - ClimateCall &ClimateCall::set_swing_mode(ClimateSwingMode swing_mode) { this->swing_mode_ = swing_mode; return *this; @@ -188,6 +271,9 @@ const optional &ClimateCall::get_target_temperature_low() const { return const optional &ClimateCall::get_target_temperature_high() const { return this->target_temperature_high_; } const optional &ClimateCall::get_away() const { return this->away_; } const optional &ClimateCall::get_fan_mode() const { return this->fan_mode_; } +const optional &ClimateCall::get_custom_fan_mode() const { return this->custom_fan_mode_; } +const optional &ClimateCall::get_preset() const { return this->preset_; } +const optional &ClimateCall::get_custom_preset() const { return this->custom_preset_; } const optional &ClimateCall::get_swing_mode() const { return this->swing_mode_; } ClimateCall &ClimateCall::set_away(bool away) { this->away_ = away; @@ -215,6 +301,12 @@ ClimateCall &ClimateCall::set_mode(optional mode) { } ClimateCall &ClimateCall::set_fan_mode(optional fan_mode) { this->fan_mode_ = fan_mode; + this->custom_fan_mode_.reset(); + return *this; +} +ClimateCall &ClimateCall::set_preset(optional preset) { + this->preset_ = preset; + this->custom_preset_.reset(); return *this; } ClimateCall &ClimateCall::set_swing_mode(optional swing_mode) { @@ -249,8 +341,31 @@ void Climate::save_state_() { if (traits.get_supports_away()) { state.away = this->away; } - if (traits.get_supports_fan_modes()) { - state.fan_mode = this->fan_mode; + if (traits.get_supports_fan_modes() && fan_mode.has_value()) { + state.uses_custom_fan_mode = false; + state.fan_mode = this->fan_mode.value(); + } + if (!traits.get_supported_custom_fan_modes().empty() && custom_fan_mode.has_value()) { + state.uses_custom_fan_mode = true; + auto &custom_fan_modes = traits.get_supported_custom_fan_modes(); + auto it = std::find(custom_fan_modes.begin(), custom_fan_modes.end(), this->custom_fan_mode.value()); + // only set custom fan mode if value exists, otherwise leave it as is + if (it != custom_fan_modes.cend()) { + state.custom_fan_mode = std::distance(custom_fan_modes.begin(), it); + } + } + if (traits.get_supports_presets() && preset.has_value()) { + state.uses_custom_preset = false; + state.preset = this->preset.value(); + } + if (!traits.get_supported_custom_presets().empty() && custom_preset.has_value()) { + state.uses_custom_preset = true; + auto custom_presets = traits.get_supported_custom_presets(); + auto it = std::find(custom_presets.begin(), custom_presets.end(), this->custom_preset.value()); + // only set custom preset if value exists, otherwise leave it as is + if (it != custom_presets.cend()) { + state.custom_preset = std::distance(custom_presets.begin(), it); + } } if (traits.get_supports_swing_modes()) { state.swing_mode = this->swing_mode; @@ -266,8 +381,17 @@ void Climate::publish_state() { if (traits.get_supports_action()) { ESP_LOGD(TAG, " Action: %s", climate_action_to_string(this->action)); } - if (traits.get_supports_fan_modes()) { - ESP_LOGD(TAG, " Fan Mode: %s", climate_fan_mode_to_string(this->fan_mode)); + if (traits.get_supports_fan_modes() && this->fan_mode.has_value()) { + ESP_LOGD(TAG, " Fan Mode: %s", climate_fan_mode_to_string(this->fan_mode.value())); + } + if (!traits.get_supported_custom_fan_modes().empty() && this->custom_fan_mode.has_value()) { + ESP_LOGD(TAG, " Custom Fan Mode: %s", this->custom_fan_mode.value().c_str()); + } + if (traits.get_supports_presets() && this->preset.has_value()) { + ESP_LOGD(TAG, " Preset: %s", climate_preset_to_string(this->preset.value())); + } + if (!traits.get_supported_custom_presets().empty() && this->custom_preset.has_value()) { + ESP_LOGD(TAG, " Custom Preset: %s", this->custom_preset.value().c_str()); } if (traits.get_supports_swing_modes()) { ESP_LOGD(TAG, " Swing Mode: %s", climate_swing_mode_to_string(this->swing_mode)); @@ -332,9 +456,12 @@ ClimateCall ClimateDeviceRestoreState::to_call(Climate *climate) { if (traits.get_supports_away()) { call.set_away(this->away); } - if (traits.get_supports_fan_modes()) { + if (traits.get_supports_fan_modes() || !traits.get_supported_custom_fan_modes().empty()) { call.set_fan_mode(this->fan_mode); } + if (traits.get_supports_presets() || !traits.get_supported_custom_presets().empty()) { + call.set_preset(this->preset); + } if (traits.get_supports_swing_modes()) { call.set_swing_mode(this->swing_mode); } @@ -352,9 +479,21 @@ void ClimateDeviceRestoreState::apply(Climate *climate) { if (traits.get_supports_away()) { climate->away = this->away; } - if (traits.get_supports_fan_modes()) { + if (traits.get_supports_fan_modes() && !this->uses_custom_fan_mode) { climate->fan_mode = this->fan_mode; } + if (!traits.get_supported_custom_fan_modes().empty() && this->uses_custom_fan_mode) { + climate->custom_fan_mode = traits.get_supported_custom_fan_modes()[this->custom_fan_mode]; + } + if (traits.get_supports_presets() && !this->uses_custom_preset) { + climate->preset = this->preset; + } + if (!traits.get_supported_custom_presets().empty() && this->uses_custom_preset) { + climate->custom_preset = traits.get_supported_custom_presets()[this->custom_preset]; + } + if (!traits.get_supported_custom_presets().empty() && uses_custom_preset) { + climate->custom_preset = traits.get_supported_custom_presets()[this->preset]; + } if (traits.get_supports_swing_modes()) { climate->swing_mode = this->swing_mode; } diff --git a/esphome/components/climate/climate.h b/esphome/components/climate/climate.h index 786afe097a..cd69469692 100644 --- a/esphome/components/climate/climate.h +++ b/esphome/components/climate/climate.h @@ -3,6 +3,7 @@ #include "esphome/core/component.h" #include "esphome/core/helpers.h" #include "esphome/core/preferences.h" +#include "esphome/core/log.h" #include "climate_mode.h" #include "climate_traits.h" @@ -70,12 +71,22 @@ class ClimateCall { ClimateCall &set_fan_mode(optional fan_mode); /// Set the fan mode of the climate device based on a string. ClimateCall &set_fan_mode(const std::string &fan_mode); + /// Set the fan mode of the climate device based on a string. + ClimateCall &set_fan_mode(optional fan_mode); /// Set the swing mode of the climate device. ClimateCall &set_swing_mode(ClimateSwingMode swing_mode); /// Set the swing mode of the climate device. ClimateCall &set_swing_mode(optional swing_mode); /// Set the swing mode of the climate device based on a string. ClimateCall &set_swing_mode(const std::string &swing_mode); + /// Set the preset of the climate device. + ClimateCall &set_preset(ClimatePreset preset); + /// Set the preset of the climate device. + ClimateCall &set_preset(optional preset); + /// Set the preset of the climate device based on a string. + ClimateCall &set_preset(const std::string &preset); + /// Set the preset of the climate device based on a string. + ClimateCall &set_preset(optional preset); void perform(); @@ -86,6 +97,9 @@ class ClimateCall { const optional &get_away() const; const optional &get_fan_mode() const; const optional &get_swing_mode() const; + const optional &get_custom_fan_mode() const; + const optional &get_preset() const; + const optional &get_custom_preset() const; protected: void validate_(); @@ -98,13 +112,25 @@ class ClimateCall { optional away_; optional fan_mode_; optional swing_mode_; + optional custom_fan_mode_; + optional preset_; + optional custom_preset_; }; /// Struct used to save the state of the climate device in restore memory. struct ClimateDeviceRestoreState { ClimateMode mode; bool away; - ClimateFanMode fan_mode; + bool uses_custom_fan_mode{false}; + union { + ClimateFanMode fan_mode; + uint8_t custom_fan_mode; + }; + bool uses_custom_preset{false}; + union { + ClimatePreset preset; + uint8_t custom_preset; + }; ClimateSwingMode swing_mode; union { float target_temperature; @@ -168,11 +194,20 @@ class Climate : public Nameable { bool away{false}; /// The active fan mode of the climate device. - ClimateFanMode fan_mode; + optional fan_mode; /// The active swing mode of the climate device. ClimateSwingMode swing_mode; + /// The active custom fan mode of the climate device. + optional custom_fan_mode; + + /// The active preset of the climate device. + optional preset; + + /// The active custom preset mode of the climate device. + optional custom_preset; + /** Add a callback for the climate device state, each time the state of the climate device is updated * (using publish_state), this callback will be called. * diff --git a/esphome/components/climate/climate_mode.cpp b/esphome/components/climate/climate_mode.cpp index ddcc4af4d9..4540208a3f 100644 --- a/esphome/components/climate/climate_mode.cpp +++ b/esphome/components/climate/climate_mode.cpp @@ -17,6 +17,8 @@ const char *climate_mode_to_string(ClimateMode mode) { return "FAN_ONLY"; case CLIMATE_MODE_DRY: return "DRY"; + case CLIMATE_MODE_HEAT_COOL: + return "HEAT_COOL"; default: return "UNKNOWN"; } @@ -80,5 +82,26 @@ const char *climate_swing_mode_to_string(ClimateSwingMode swing_mode) { } } +const char *climate_preset_to_string(ClimatePreset preset) { + switch (preset) { + case climate::CLIMATE_PRESET_ECO: + return "ECO"; + case climate::CLIMATE_PRESET_AWAY: + return "AWAY"; + case climate::CLIMATE_PRESET_BOOST: + return "BOOST"; + case climate::CLIMATE_PRESET_COMFORT: + return "COMFORT"; + case climate::CLIMATE_PRESET_HOME: + return "HOME"; + case climate::CLIMATE_PRESET_SLEEP: + return "SLEEP"; + case climate::CLIMATE_PRESET_ACTIVITY: + return "ACTIVITY"; + default: + return "UNKNOWN"; + } +} + } // namespace climate } // namespace esphome diff --git a/esphome/components/climate/climate_mode.h b/esphome/components/climate/climate_mode.h index 8037ea2196..e129fca91d 100644 --- a/esphome/components/climate/climate_mode.h +++ b/esphome/components/climate/climate_mode.h @@ -10,7 +10,7 @@ enum ClimateMode : uint8_t { /// The climate device is off (not in auto, heat or cool mode) CLIMATE_MODE_OFF = 0, /// The climate device is set to automatically change the heating/cooling cycle - CLIMATE_MODE_AUTO = 1, + CLIMATE_MODE_HEAT_COOL = 1, /// The climate device is manually set to cool mode (not in auto mode!) CLIMATE_MODE_COOL = 2, /// The climate device is manually set to heat mode (not in auto mode!) @@ -19,6 +19,8 @@ enum ClimateMode : uint8_t { CLIMATE_MODE_FAN_ONLY = 4, /// The climate device is manually set to dry mode CLIMATE_MODE_DRY = 5, + /// The climate device is manually set to heat-cool mode + CLIMATE_MODE_AUTO = 6 }; /// Enum for the current action of the climate device. Values match those of ClimateMode. @@ -61,7 +63,7 @@ enum ClimateFanMode : uint8_t { /// Enum for all modes a climate swing can be in enum ClimateSwingMode : uint8_t { - /// The sing mode is set to Off + /// The swing mode is set to Off CLIMATE_SWING_OFF = 0, /// The fan mode is set to Both CLIMATE_SWING_BOTH = 1, @@ -71,6 +73,24 @@ enum ClimateSwingMode : uint8_t { CLIMATE_SWING_HORIZONTAL = 3, }; +/// Enum for all modes a climate swing can be in +enum ClimatePreset : uint8_t { + /// Preset is set to ECO + CLIMATE_PRESET_ECO = 0, + /// Preset is set to AWAY + CLIMATE_PRESET_AWAY = 1, + /// Preset is set to BOOST + CLIMATE_PRESET_BOOST = 2, + /// Preset is set to COMFORT + CLIMATE_PRESET_COMFORT = 3, + /// Preset is set to HOME + CLIMATE_PRESET_HOME = 4, + /// Preset is set to SLEEP + CLIMATE_PRESET_SLEEP = 5, + /// Preset is set to ACTIVITY + CLIMATE_PRESET_ACTIVITY = 6, +}; + /// Convert the given ClimateMode to a human-readable string. const char *climate_mode_to_string(ClimateMode mode); @@ -83,5 +103,8 @@ const char *climate_fan_mode_to_string(ClimateFanMode mode); /// Convert the given ClimateSwingMode to a human-readable string. const char *climate_swing_mode_to_string(ClimateSwingMode mode); +/// Convert the given ClimateSwingMode to a human-readable string. +const char *climate_preset_to_string(ClimatePreset preset); + } // namespace climate } // namespace esphome diff --git a/esphome/components/climate/climate_traits.cpp b/esphome/components/climate/climate_traits.cpp index 6e941bddf0..eda4722fcb 100644 --- a/esphome/components/climate/climate_traits.cpp +++ b/esphome/components/climate/climate_traits.cpp @@ -119,6 +119,71 @@ bool ClimateTraits::get_supports_fan_modes() const { this->supports_fan_mode_low_ || this->supports_fan_mode_medium_ || this->supports_fan_mode_high_ || this->supports_fan_mode_middle_ || this->supports_fan_mode_focus_ || this->supports_fan_mode_diffuse_; } +void ClimateTraits::set_supported_custom_fan_modes(std::vector &supported_custom_fan_modes) { + this->supported_custom_fan_modes_ = supported_custom_fan_modes; +} +const std::vector ClimateTraits::get_supported_custom_fan_modes() const { + return this->supported_custom_fan_modes_; +} +bool ClimateTraits::supports_custom_fan_mode(std::string &custom_fan_mode) const { + return std::count(this->supported_custom_fan_modes_.begin(), this->supported_custom_fan_modes_.end(), + custom_fan_mode); +} +bool ClimateTraits::supports_preset(ClimatePreset preset) const { + switch (preset) { + case climate::CLIMATE_PRESET_ECO: + return this->supports_preset_eco_; + case climate::CLIMATE_PRESET_AWAY: + return this->supports_preset_away_; + case climate::CLIMATE_PRESET_BOOST: + return this->supports_preset_boost_; + case climate::CLIMATE_PRESET_COMFORT: + return this->supports_preset_comfort_; + case climate::CLIMATE_PRESET_HOME: + return this->supports_preset_home_; + case climate::CLIMATE_PRESET_SLEEP: + return this->supports_preset_sleep_; + case climate::CLIMATE_PRESET_ACTIVITY: + return this->supports_preset_activity_; + default: + return false; + } +} +void ClimateTraits::set_supports_preset_eco(bool supports_preset_eco) { + this->supports_preset_eco_ = supports_preset_eco; +} +void ClimateTraits::set_supports_preset_away(bool supports_preset_away) { + this->supports_preset_away_ = supports_preset_away; +} +void ClimateTraits::set_supports_preset_boost(bool supports_preset_boost) { + this->supports_preset_boost_ = supports_preset_boost; +} +void ClimateTraits::set_supports_preset_comfort(bool supports_preset_comfort) { + this->supports_preset_comfort_ = supports_preset_comfort; +} +void ClimateTraits::set_supports_preset_home(bool supports_preset_home) { + this->supports_preset_home_ = supports_preset_home; +} +void ClimateTraits::set_supports_preset_sleep(bool supports_preset_sleep) { + this->supports_preset_sleep_ = supports_preset_sleep; +} +void ClimateTraits::set_supports_preset_activity(bool supports_preset_activity) { + this->supports_preset_activity_ = supports_preset_activity; +} +bool ClimateTraits::get_supports_presets() const { + return this->supports_preset_eco_ || this->supports_preset_away_ || this->supports_preset_boost_ || + this->supports_preset_comfort_ || this->supports_preset_home_ || this->supports_preset_sleep_ || + this->supports_preset_activity_; +} +void ClimateTraits::set_supported_custom_presets(std::vector &supported_custom_presets) { + this->supported_custom_presets_ = supported_custom_presets; +} +const std::vector ClimateTraits::get_supported_custom_presets() const { + return this->supported_custom_presets_; +} +bool ClimateTraits::supports_custom_preset(std::string &custom_preset) const { + return std::count(this->supported_custom_presets_.begin(), this->supported_custom_presets_.end(), custom_preset); +} void ClimateTraits::set_supports_swing_mode_off(bool supports_swing_mode_off) { this->supports_swing_mode_off_ = supports_swing_mode_off; } diff --git a/esphome/components/climate/climate_traits.h b/esphome/components/climate/climate_traits.h index 347a7bc1f2..f0a48ca308 100644 --- a/esphome/components/climate/climate_traits.h +++ b/esphome/components/climate/climate_traits.h @@ -1,5 +1,6 @@ #pragma once +#include "esphome/core/helpers.h" #include "climate_mode.h" namespace esphome { @@ -65,6 +66,21 @@ class ClimateTraits { void set_supports_fan_mode_diffuse(bool supports_fan_mode_diffuse); bool supports_fan_mode(ClimateFanMode fan_mode) const; bool get_supports_fan_modes() const; + void set_supported_custom_fan_modes(std::vector &supported_custom_fan_modes); + const std::vector get_supported_custom_fan_modes() const; + bool supports_custom_fan_mode(std::string &custom_fan_mode) const; + bool supports_preset(ClimatePreset preset) const; + void set_supports_preset_eco(bool supports_preset_eco); + void set_supports_preset_away(bool supports_preset_away); + void set_supports_preset_boost(bool supports_preset_boost); + void set_supports_preset_comfort(bool supports_preset_comfort); + void set_supports_preset_home(bool supports_preset_home); + void set_supports_preset_sleep(bool supports_preset_sleep); + void set_supports_preset_activity(bool supports_preset_activity); + bool get_supports_presets() const; + void set_supported_custom_presets(std::vector &supported_custom_presets); + const std::vector get_supported_custom_presets() const; + bool supports_custom_preset(std::string &custom_preset) const; void set_supports_swing_mode_off(bool supports_swing_mode_off); void set_supports_swing_mode_both(bool supports_swing_mode_both); void set_supports_swing_mode_vertical(bool supports_swing_mode_vertical); @@ -103,6 +119,15 @@ class ClimateTraits { bool supports_swing_mode_both_{false}; bool supports_swing_mode_vertical_{false}; bool supports_swing_mode_horizontal_{false}; + bool supports_preset_eco_{false}; + bool supports_preset_away_{false}; + bool supports_preset_boost_{false}; + bool supports_preset_comfort_{false}; + bool supports_preset_home_{false}; + bool supports_preset_sleep_{false}; + bool supports_preset_activity_{false}; + std::vector supported_custom_fan_modes_; + std::vector supported_custom_presets_; float visual_min_temperature_{10}; float visual_max_temperature_{30}; diff --git a/esphome/components/climate_ir_lg/climate_ir_lg.cpp b/esphome/components/climate_ir_lg/climate_ir_lg.cpp index ee73d30796..983d33c0b1 100644 --- a/esphome/components/climate_ir_lg/climate_ir_lg.cpp +++ b/esphome/components/climate_ir_lg/climate_ir_lg.cpp @@ -72,7 +72,7 @@ void LgIrClimate::transmit_state() { remote_state |= FAN_AUTO; } else if (this->mode == climate::CLIMATE_MODE_COOL || this->mode == climate::CLIMATE_MODE_DRY || this->mode == climate::CLIMATE_MODE_HEAT) { - switch (this->fan_mode) { + switch (this->fan_mode.value()) { case climate::CLIMATE_FAN_HIGH: remote_state |= FAN_MAX; break; diff --git a/esphome/components/coolix/coolix.cpp b/esphome/components/coolix/coolix.cpp index 441f43b424..e50521a348 100644 --- a/esphome/components/coolix/coolix.cpp +++ b/esphome/components/coolix/coolix.cpp @@ -93,7 +93,7 @@ void CoolixClimate::transmit_state() { this->fan_mode = climate::CLIMATE_FAN_AUTO; remote_state |= COOLIX_FAN_MODE_AUTO_DRY; } else { - switch (this->fan_mode) { + switch (this->fan_mode.value()) { case climate::CLIMATE_FAN_HIGH: remote_state |= COOLIX_FAN_MAX; break; diff --git a/esphome/components/daikin/daikin.cpp b/esphome/components/daikin/daikin.cpp index 0701344a8b..e0ffd46387 100644 --- a/esphome/components/daikin/daikin.cpp +++ b/esphome/components/daikin/daikin.cpp @@ -94,7 +94,7 @@ uint8_t DaikinClimate::operation_mode_() { uint16_t DaikinClimate::fan_speed_() { uint16_t fan_speed; - switch (this->fan_mode) { + switch (this->fan_mode.value()) { case climate::CLIMATE_FAN_LOW: fan_speed = DAIKIN_FAN_1 << 8; break; diff --git a/esphome/components/fujitsu_general/fujitsu_general.cpp b/esphome/components/fujitsu_general/fujitsu_general.cpp index 2676609d9b..8671f38e8e 100644 --- a/esphome/components/fujitsu_general/fujitsu_general.cpp +++ b/esphome/components/fujitsu_general/fujitsu_general.cpp @@ -140,7 +140,7 @@ void FujitsuGeneralClimate::transmit_state() { } // Set fan - switch (this->fan_mode) { + switch (this->fan_mode.value()) { case climate::CLIMATE_FAN_HIGH: SET_NIBBLE(remote_state, FUJITSU_GENERAL_FAN_NIBBLE, FUJITSU_GENERAL_FAN_HIGH); break; diff --git a/esphome/components/hitachi_ac344/hitachi_ac344.cpp b/esphome/components/hitachi_ac344/hitachi_ac344.cpp index 8d56c7f51c..b2798b608a 100644 --- a/esphome/components/hitachi_ac344/hitachi_ac344.cpp +++ b/esphome/components/hitachi_ac344/hitachi_ac344.cpp @@ -164,11 +164,13 @@ void HitachiClimate::transmit_state() { case climate::CLIMATE_MODE_OFF: set_power_(false); break; + default: + ESP_LOGW(TAG, "Unsupported mode: %s", climate_mode_to_string(this->mode)); } set_temp_(static_cast(this->target_temperature)); - switch (this->fan_mode) { + switch (this->fan_mode.value()) { case climate::CLIMATE_FAN_LOW: set_fan_(HITACHI_AC344_FAN_LOW); break; diff --git a/esphome/components/midea_ac/climate.py b/esphome/components/midea_ac/climate.py index 7bf77d7c6b..00aa979515 100644 --- a/esphome/components/midea_ac/climate.py +++ b/esphome/components/midea_ac/climate.py @@ -2,7 +2,12 @@ from esphome.components import climate, sensor import esphome.config_validation as cv import esphome.codegen as cg from esphome.const import ( + CONF_CUSTOM_FAN_MODES, + CONF_CUSTOM_PRESETS, CONF_ID, + CONF_PRESET_BOOST, + CONF_PRESET_ECO, + CONF_PRESET_SLEEP, STATE_CLASS_MEASUREMENT, UNIT_CELSIUS, UNIT_PERCENT, @@ -18,7 +23,6 @@ from esphome.components.midea_dongle import CONF_MIDEA_DONGLE_ID, MideaDongle AUTO_LOAD = ["climate", "sensor", "midea_dongle"] CODEOWNERS = ["@dudanov"] - CONF_BEEPER = "beeper" CONF_SWING_HORIZONTAL = "swing_horizontal" CONF_SWING_BOTH = "swing_both" @@ -28,14 +32,36 @@ CONF_HUMIDITY_SETPOINT = "humidity_setpoint" midea_ac_ns = cg.esphome_ns.namespace("midea_ac") MideaAC = midea_ac_ns.class_("MideaAC", climate.Climate, cg.Component) +CLIMATE_CUSTOM_FAN_MODES = { + "SILENT": "silent", + "TURBO": "turbo", +} + +validate_climate_custom_fan_mode = cv.enum(CLIMATE_CUSTOM_FAN_MODES, upper=True) + +CLIMATE_CUSTOM_PRESETS = { + "FREEZE_PROTECTION": "freeze protection", +} + +validate_climate_custom_preset = cv.enum(CLIMATE_CUSTOM_PRESETS, upper=True) + CONFIG_SCHEMA = cv.All( climate.CLIMATE_SCHEMA.extend( { cv.GenerateID(): cv.declare_id(MideaAC), cv.GenerateID(CONF_MIDEA_DONGLE_ID): cv.use_id(MideaDongle), cv.Optional(CONF_BEEPER, default=False): cv.boolean, + cv.Optional(CONF_CUSTOM_FAN_MODES): cv.ensure_list( + validate_climate_custom_fan_mode + ), + cv.Optional(CONF_CUSTOM_PRESETS): cv.ensure_list( + validate_climate_custom_preset + ), cv.Optional(CONF_SWING_HORIZONTAL, default=False): cv.boolean, cv.Optional(CONF_SWING_BOTH, default=False): cv.boolean, + cv.Optional(CONF_PRESET_ECO, default=False): cv.boolean, + cv.Optional(CONF_PRESET_SLEEP, default=False): cv.boolean, + cv.Optional(CONF_PRESET_BOOST, default=False): cv.boolean, cv.Optional(CONF_OUTDOOR_TEMPERATURE): sensor.sensor_schema( UNIT_CELSIUS, ICON_THERMOMETER, @@ -65,8 +91,15 @@ async def to_code(config): paren = await cg.get_variable(config[CONF_MIDEA_DONGLE_ID]) cg.add(var.set_midea_dongle_parent(paren)) cg.add(var.set_beeper_feedback(config[CONF_BEEPER])) + if CONF_CUSTOM_FAN_MODES in config: + cg.add(var.set_custom_fan_modes(config[CONF_CUSTOM_FAN_MODES])) + if CONF_CUSTOM_PRESETS in config: + cg.add(var.set_custom_presets(config[CONF_CUSTOM_PRESETS])) cg.add(var.set_swing_horizontal(config[CONF_SWING_HORIZONTAL])) cg.add(var.set_swing_both(config[CONF_SWING_BOTH])) + cg.add(var.set_preset_eco(config[CONF_PRESET_ECO])) + cg.add(var.set_preset_sleep(config[CONF_PRESET_SLEEP])) + cg.add(var.set_preset_boost(config[CONF_PRESET_BOOST])) if CONF_OUTDOOR_TEMPERATURE in config: sens = await sensor.new_sensor(config[CONF_OUTDOOR_TEMPERATURE]) cg.add(var.set_outdoor_temperature_sensor(sens)) diff --git a/esphome/components/midea_ac/midea_climate.cpp b/esphome/components/midea_ac/midea_climate.cpp index 8a74251696..f98cf74ac1 100644 --- a/esphome/components/midea_ac/midea_climate.cpp +++ b/esphome/components/midea_ac/midea_climate.cpp @@ -40,8 +40,24 @@ void MideaAC::on_frame(const midea_dongle::Frame &frame) { set_property(this->mode, p.get_mode(), need_publish); set_property(this->target_temperature, p.get_target_temp(), need_publish); set_property(this->current_temperature, p.get_indoor_temp(), need_publish); - set_property(this->fan_mode, p.get_fan_mode(), need_publish); + if (p.is_custom_fan_mode()) { + this->fan_mode.reset(); + optional mode = p.get_custom_fan_mode(); + set_property(this->custom_fan_mode, mode, need_publish); + } else { + this->custom_fan_mode.reset(); + optional mode = p.get_fan_mode(); + set_property(this->fan_mode, mode, need_publish); + } set_property(this->swing_mode, p.get_swing_mode(), need_publish); + if (p.is_custom_preset()) { + this->preset.reset(); + optional preset = p.get_custom_preset(); + set_property(this->custom_preset, preset, need_publish); + } else { + this->custom_preset.reset(); + set_property(this->preset, p.get_preset(), need_publish); + } if (need_publish) this->publish_state(); set_sensor(this->outdoor_sensor_, p.get_outdoor_temp()); @@ -61,6 +77,48 @@ void MideaAC::on_update() { } } +bool MideaAC::allow_preset(climate::ClimatePreset preset) const { + switch (preset) { + case climate::CLIMATE_PRESET_ECO: + if (this->mode == climate::CLIMATE_MODE_COOL) { + return true; + } else { + ESP_LOGD(TAG, "ECO preset is only available in COOL mode"); + } + break; + case climate::CLIMATE_PRESET_SLEEP: + if (this->mode == climate::CLIMATE_MODE_FAN_ONLY || this->mode == climate::CLIMATE_MODE_DRY) { + ESP_LOGD(TAG, "SLEEP preset is not available in FAN_ONLY or DRY mode"); + } else { + return true; + } + break; + case climate::CLIMATE_PRESET_BOOST: + if (this->mode == climate::CLIMATE_MODE_HEAT || this->mode == climate::CLIMATE_MODE_COOL) { + return true; + } else { + ESP_LOGD(TAG, "BOOST preset is only available in HEAT or COOL mode"); + } + break; + case climate::CLIMATE_PRESET_HOME: + return true; + default: + break; + } + return false; +} + +bool MideaAC::allow_custom_preset(const std::string &custom_preset) const { + if (custom_preset == MIDEA_FREEZE_PROTECTION_PRESET) { + if (this->mode == climate::CLIMATE_MODE_HEAT) { + return true; + } else { + ESP_LOGD(TAG, "%s is only available in HEAT mode", MIDEA_FREEZE_PROTECTION_PRESET.c_str()); + } + } + return false; +} + void MideaAC::control(const climate::ClimateCall &call) { if (call.get_mode().has_value() && call.get_mode().value() != this->mode) { this->cmd_frame_.set_mode(call.get_mode().value()); @@ -70,14 +128,34 @@ void MideaAC::control(const climate::ClimateCall &call) { this->cmd_frame_.set_target_temp(call.get_target_temperature().value()); this->ctrl_request_ = true; } - if (call.get_fan_mode().has_value() && call.get_fan_mode().value() != this->fan_mode) { + if (call.get_fan_mode().has_value() && + (!this->fan_mode.has_value() || this->fan_mode.value() != call.get_fan_mode().value())) { + this->custom_fan_mode.reset(); this->cmd_frame_.set_fan_mode(call.get_fan_mode().value()); this->ctrl_request_ = true; } + if (call.get_custom_fan_mode().has_value() && + (!this->custom_fan_mode.has_value() || this->custom_fan_mode.value() != call.get_custom_fan_mode().value())) { + this->fan_mode.reset(); + this->cmd_frame_.set_custom_fan_mode(call.get_custom_fan_mode().value()); + this->ctrl_request_ = true; + } if (call.get_swing_mode().has_value() && call.get_swing_mode().value() != this->swing_mode) { this->cmd_frame_.set_swing_mode(call.get_swing_mode().value()); this->ctrl_request_ = true; } + if (call.get_preset().has_value() && this->allow_preset(call.get_preset().value()) && + (!this->preset.has_value() || this->preset.value() != call.get_preset().value())) { + this->custom_preset.reset(); + this->cmd_frame_.set_preset(call.get_preset().value()); + this->ctrl_request_ = true; + } + if (call.get_custom_preset().has_value() && this->allow_custom_preset(call.get_custom_preset().value()) && + (!this->custom_preset.has_value() || this->custom_preset.value() != call.get_custom_preset().value())) { + this->preset.reset(); + this->cmd_frame_.set_custom_preset(call.get_custom_preset().value()); + this->ctrl_request_ = true; + } if (this->ctrl_request_) { this->cmd_frame_.set_beeper_feedback(this->beeper_feedback_); this->cmd_frame_.finalize(); @@ -98,10 +176,16 @@ climate::ClimateTraits MideaAC::traits() { traits.set_supports_fan_mode_low(true); traits.set_supports_fan_mode_medium(true); traits.set_supports_fan_mode_high(true); + traits.set_supported_custom_fan_modes(this->traits_custom_fan_modes_); traits.set_supports_swing_mode_off(true); traits.set_supports_swing_mode_vertical(true); traits.set_supports_swing_mode_horizontal(this->traits_swing_horizontal_); traits.set_supports_swing_mode_both(this->traits_swing_both_); + traits.set_supports_preset_home(true); + traits.set_supports_preset_eco(this->traits_preset_eco_); + traits.set_supports_preset_sleep(this->traits_preset_sleep_); + traits.set_supports_preset_boost(this->traits_preset_boost_); + traits.set_supported_custom_presets(this->traits_custom_presets_); traits.set_supports_current_temperature(true); return traits; } diff --git a/esphome/components/midea_ac/midea_climate.h b/esphome/components/midea_ac/midea_climate.h index f08350b252..0a63312961 100644 --- a/esphome/components/midea_ac/midea_climate.h +++ b/esphome/components/midea_ac/midea_climate.h @@ -22,6 +22,15 @@ class MideaAC : public midea_dongle::MideaAppliance, public climate::Climate, pu void set_beeper_feedback(bool state) { this->beeper_feedback_ = state; } void set_swing_horizontal(bool state) { this->traits_swing_horizontal_ = state; } void set_swing_both(bool state) { this->traits_swing_both_ = state; } + void set_preset_eco(bool state) { this->traits_preset_eco_ = state; } + void set_preset_sleep(bool state) { this->traits_preset_sleep_ = state; } + void set_preset_boost(bool state) { this->traits_preset_boost_ = state; } + bool allow_preset(climate::ClimatePreset preset) const; + void set_custom_fan_modes(std::vector custom_fan_modes) { + this->traits_custom_fan_modes_ = custom_fan_modes; + } + void set_custom_presets(std::vector custom_presets) { this->traits_custom_presets_ = custom_presets; } + bool allow_custom_preset(const std::string &custom_preset) const; protected: /// Override control to change settings of the climate device. @@ -41,6 +50,11 @@ class MideaAC : public midea_dongle::MideaAppliance, public climate::Climate, pu bool beeper_feedback_{false}; bool traits_swing_horizontal_{false}; bool traits_swing_both_{false}; + bool traits_preset_eco_{false}; + bool traits_preset_sleep_{false}; + bool traits_preset_boost_{false}; + std::vector traits_custom_fan_modes_{{}}; + std::vector traits_custom_presets_{{}}; }; } // namespace midea_ac diff --git a/esphome/components/midea_ac/midea_frame.cpp b/esphome/components/midea_ac/midea_frame.cpp index 2d9be1bdc5..e90155bad3 100644 --- a/esphome/components/midea_ac/midea_frame.cpp +++ b/esphome/components/midea_ac/midea_frame.cpp @@ -3,6 +3,11 @@ namespace esphome { namespace midea_ac { +static const char *TAG = "midea_ac"; +const std::string MIDEA_SILENT_FAN_MODE = "silent"; +const std::string MIDEA_TURBO_FAN_MODE = "turbo"; +const std::string MIDEA_FREEZE_PROTECTION_PRESET = "freeze protection"; + const uint8_t QueryFrame::INIT[] = {0xAA, 0x22, 0xAC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x41, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x68}; @@ -80,6 +85,54 @@ void PropertiesFrame::set_mode(climate::ClimateMode mode) { this->pbuf_[12] |= m << 5; } +optional PropertiesFrame::get_preset() const { + if (this->get_eco_mode()) { + return climate::CLIMATE_PRESET_ECO; + } else if (this->get_sleep_mode()) { + return climate::CLIMATE_PRESET_SLEEP; + } else if (this->get_turbo_mode()) { + return climate::CLIMATE_PRESET_BOOST; + } else { + return climate::CLIMATE_PRESET_HOME; + } +} + +void PropertiesFrame::set_preset(climate::ClimatePreset preset) { + switch (preset) { + case climate::CLIMATE_PRESET_ECO: + this->set_eco_mode(true); + break; + case climate::CLIMATE_PRESET_SLEEP: + this->set_sleep_mode(true); + break; + case climate::CLIMATE_PRESET_BOOST: + this->set_turbo_mode(true); + break; + default: + break; + } +} + +bool PropertiesFrame::is_custom_preset() const { return this->get_freeze_protection_mode(); } + +const std::string &PropertiesFrame::get_custom_preset() const { return midea_ac::MIDEA_FREEZE_PROTECTION_PRESET; }; + +void PropertiesFrame::set_custom_preset(const std::string &preset) { + if (preset == MIDEA_FREEZE_PROTECTION_PRESET) { + this->set_freeze_protection_mode(true); + } +} + +bool PropertiesFrame::is_custom_fan_mode() const { + switch (this->pbuf_[13]) { + case MIDEA_FAN_SILENT: + case MIDEA_FAN_TURBO: + return true; + default: + return false; + } +} + climate::ClimateFanMode PropertiesFrame::get_fan_mode() const { switch (this->pbuf_[13]) { case MIDEA_FAN_LOW: @@ -112,6 +165,25 @@ void PropertiesFrame::set_fan_mode(climate::ClimateFanMode mode) { this->pbuf_[13] = m; } +const std::string &PropertiesFrame::get_custom_fan_mode() const { + switch (this->pbuf_[13]) { + case MIDEA_FAN_SILENT: + return MIDEA_SILENT_FAN_MODE; + default: + return MIDEA_TURBO_FAN_MODE; + } +} + +void PropertiesFrame::set_custom_fan_mode(const std::string &mode) { + uint8_t m; + if (mode == MIDEA_SILENT_FAN_MODE) { + m = MIDEA_FAN_SILENT; + } else { + m = MIDEA_FAN_TURBO; + } + this->pbuf_[13] = m; +} + climate::ClimateSwingMode PropertiesFrame::get_swing_mode() const { switch (this->pbuf_[17] & 0x0F) { case MIDEA_SWING_VERTICAL: diff --git a/esphome/components/midea_ac/midea_frame.h b/esphome/components/midea_ac/midea_frame.h index e07a5bf946..a84161b4af 100644 --- a/esphome/components/midea_ac/midea_frame.h +++ b/esphome/components/midea_ac/midea_frame.h @@ -5,6 +5,10 @@ namespace esphome { namespace midea_ac { +extern const std::string MIDEA_SILENT_FAN_MODE; +extern const std::string MIDEA_TURBO_FAN_MODE; +extern const std::string MIDEA_FREEZE_PROTECTION_PRESET; + /// Enum for all modes a Midea device can be in. enum MideaMode : uint8_t { /// The Midea device is set to automatically change the heating/cooling cycle @@ -23,12 +27,16 @@ enum MideaMode : uint8_t { enum MideaFanMode : uint8_t { /// The fan mode is set to Auto MIDEA_FAN_AUTO = 102, + /// The fan mode is set to Silent + MIDEA_FAN_SILENT = 20, /// The fan mode is set to Low MIDEA_FAN_LOW = 40, /// The fan mode is set to Medium MIDEA_FAN_MEDIUM = 60, /// The fan mode is set to High MIDEA_FAN_HIGH = 80, + /// The fan mode is set to Turbo + MIDEA_FAN_TURBO = 100, }; /// Enum for all modes a Midea swing can be in @@ -65,9 +73,13 @@ class PropertiesFrame : public midea_dongle::BaseFrame { void set_mode(climate::ClimateMode mode); /* FAN SPEED */ + bool is_custom_fan_mode() const; climate::ClimateFanMode get_fan_mode() const; void set_fan_mode(climate::ClimateFanMode mode); + const std::string &get_custom_fan_mode() const; + void set_custom_fan_mode(const std::string &mode); + /* SWING MODE */ climate::ClimateSwingMode get_swing_mode() const; void set_swing_mode(climate::ClimateSwingMode mode); @@ -82,16 +94,28 @@ class PropertiesFrame : public midea_dongle::BaseFrame { float get_humidity_setpoint() const; /* ECO MODE */ - bool get_eco_mode() const { return this->pbuf_[19]; } - void set_eco_mode(bool state) { this->set_bytemask_(19, 0xFF, state); } + bool get_eco_mode() const { return this->pbuf_[19] & 0x10; } + void set_eco_mode(bool state) { this->set_bytemask_(19, 0x80, state); } /* SLEEP MODE */ bool get_sleep_mode() const { return this->pbuf_[20] & 0x01; } void set_sleep_mode(bool state) { this->set_bytemask_(20, 0x01, state); } /* TURBO MODE */ - bool get_turbo_mode() const { return this->pbuf_[20] & 0x02; } - void set_turbo_mode(bool state) { this->set_bytemask_(20, 0x02, state); } + bool get_turbo_mode() const { return this->pbuf_[18] & 0x20; } + void set_turbo_mode(bool state) { this->set_bytemask_(18, 0x20, state); } + + /* FREEZE PROTECTION */ + bool get_freeze_protection_mode() const { return this->pbuf_[31] & 0x80; } + void set_freeze_protection_mode(bool state) { this->set_bytemask_(31, 0x80, state); } + + /* PRESET */ + optional get_preset() const; + void set_preset(climate::ClimatePreset preset); + + bool is_custom_preset() const; + const std::string &get_custom_preset() const; + void set_custom_preset(const std::string &preset); /* POWER USAGE */ float get_power_usage() const; diff --git a/esphome/components/mqtt/mqtt_climate.cpp b/esphome/components/mqtt/mqtt_climate.cpp index 2a95ed2f64..47923dc924 100644 --- a/esphome/components/mqtt/mqtt_climate.cpp +++ b/esphome/components/mqtt/mqtt_climate.cpp @@ -35,6 +35,8 @@ void MQTTClimateComponent::send_discovery(JsonObject &root, mqtt::SendDiscoveryC modes.add("fan_only"); if (traits.supports_mode(CLIMATE_MODE_DRY)) modes.add("dry"); + if (traits.supports_mode(CLIMATE_MODE_HEAT_COOL)) + modes.add("heat_cool"); if (traits.get_supports_two_point_target_temperature()) { // temperature_low_command_topic @@ -231,6 +233,9 @@ bool MQTTClimateComponent::publish_state_() { case CLIMATE_MODE_DRY: mode_s = "dry"; break; + case CLIMATE_MODE_HEAT_COOL: + mode_s = "heat_cool"; + break; } bool success = true; if (!this->publish(this->get_mode_state_topic(), mode_s)) @@ -287,7 +292,7 @@ bool MQTTClimateComponent::publish_state_() { if (traits.get_supports_fan_modes()) { const char *payload = ""; - switch (this->device_->fan_mode) { + switch (this->device_->fan_mode.value()) { case CLIMATE_FAN_ON: payload = "on"; break; diff --git a/esphome/components/tcl112/tcl112.cpp b/esphome/components/tcl112/tcl112.cpp index 3e7eb7ec9a..91cec27094 100644 --- a/esphome/components/tcl112/tcl112.cpp +++ b/esphome/components/tcl112/tcl112.cpp @@ -88,7 +88,7 @@ void Tcl112Climate::transmit_state() { // Set fan uint8_t selected_fan; - switch (this->fan_mode) { + switch (this->fan_mode.value()) { case climate::CLIMATE_FAN_HIGH: selected_fan = TCL112_FAN_HIGH; break; diff --git a/esphome/components/thermostat/thermostat_climate.cpp b/esphome/components/thermostat/thermostat_climate.cpp index 64a7c1b05d..3bab0e85fd 100644 --- a/esphome/components/thermostat/thermostat_climate.cpp +++ b/esphome/components/thermostat/thermostat_climate.cpp @@ -33,7 +33,7 @@ float ThermostatClimate::hysteresis() { return this->hysteresis_; } void ThermostatClimate::refresh() { this->switch_to_mode_(this->mode); this->switch_to_action_(compute_action_()); - this->switch_to_fan_mode_(this->fan_mode); + this->switch_to_fan_mode_(this->fan_mode.value()); this->switch_to_swing_mode_(this->swing_mode); this->publish_state(); } diff --git a/esphome/components/whirlpool/whirlpool.cpp b/esphome/components/whirlpool/whirlpool.cpp index eba08d5bbe..e7c93246f2 100644 --- a/esphome/components/whirlpool/whirlpool.cpp +++ b/esphome/components/whirlpool/whirlpool.cpp @@ -81,7 +81,7 @@ void WhirlpoolClimate::transmit_state() { remote_state[3] |= (uint8_t)(temp - this->temperature_min_()) << 4; // Fan speed - switch (this->fan_mode) { + switch (this->fan_mode.value()) { case climate::CLIMATE_FAN_HIGH: remote_state[2] |= WHIRLPOOL_FAN_HIGH; break; diff --git a/esphome/const.py b/esphome/const.py index 18ef10bb01..907a49e2ad 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -145,6 +145,10 @@ CONF_CSS_URL = "css_url" CONF_CURRENT = "current" CONF_CURRENT_OPERATION = "current_operation" CONF_CURRENT_RESISTOR = "current_resistor" +CONF_CUSTOM_FAN_MODE = "custom_fan_mode" +CONF_CUSTOM_FAN_MODES = "custom_fan_modes" +CONF_CUSTOM_PRESET = "custom_preset" +CONF_CUSTOM_PRESETS = "custom_presets" CONF_DALLAS_ID = "dallas_id" CONF_DATA = "data" CONF_DATA_PIN = "data_pin" @@ -449,6 +453,10 @@ CONF_POWER_FACTOR = "power_factor" CONF_POWER_ON_VALUE = "power_on_value" CONF_POWER_SAVE_MODE = "power_save_mode" CONF_POWER_SUPPLY = "power_supply" +CONF_PRESET = "preset" +CONF_PRESET_BOOST = "preset_boost" +CONF_PRESET_ECO = "preset_eco" +CONF_PRESET_SLEEP = "preset_sleep" CONF_PRESSURE = "pressure" CONF_PRIORITY = "priority" CONF_PROTOCOL = "protocol" diff --git a/tests/test1.yaml b/tests/test1.yaml index 378d4192d3..29df5857d3 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -1525,23 +1525,6 @@ climate: name: Toshiba Climate - platform: hitachi_ac344 name: Hitachi Climate - - platform: midea_ac - visual: - min_temperature: 18 °C - max_temperature: 25 °C - temperature_step: 0.1 °C - name: 'Electrolux EACS' - beeper: true - outdoor_temperature: - name: 'Temp' - power_usage: - name: 'Power' - humidity_setpoint: - name: 'Hum' - -midea_dongle: - uart_id: uart0 - strength_icon: true switch: - platform: gpio diff --git a/tests/test3.yaml b/tests/test3.yaml index 8f6b33bd5d..af5398b604 100644 --- a/tests/test3.yaml +++ b/tests/test3.yaml @@ -658,6 +658,17 @@ script: - id: my_script then: - lambda: 'ESP_LOGD("main", "Hello World!");' + - id: climate_custom + then: + - climate.control: + id: midea_ac_unit + custom_preset: FREEZE_PROTECTION + custom_fan_mode: SILENT + - id: climate_preset + then: + - climate.control: + id: midea_ac_unit + preset: SLEEP sm2135: data_pin: GPIO12 @@ -819,6 +830,32 @@ climate: kp: 0.0 ki: 0.0 kd: 0.0 + - platform: midea_ac + id: midea_ac_unit + visual: + min_temperature: 18 °C + max_temperature: 25 °C + temperature_step: 0.1 °C + name: "Electrolux EACS" + beeper: true + custom_fan_modes: + - SILENT + - TURBO + preset_eco: true + preset_sleep: true + preset_boost: true + custom_presets: + - FREEZE_PROTECTION + outdoor_temperature: + name: "Temp" + power_usage: + name: "Power" + humidity_setpoint: + name: "Hum" + +midea_dongle: + uart_id: uart1 + strength_icon: true cover: - platform: endstop diff --git a/tests/test4.yaml b/tests/test4.yaml index 9e09f20449..7868fd4968 100644 --- a/tests/test4.yaml +++ b/tests/test4.yaml @@ -166,6 +166,7 @@ display: it.rectangle(3, 3, it.get_width()-6, it.get_height()-6, red); rotation: 0° update_interval: 16ms + - platform: waveshare_epaper cs_pin: GPIO23 dc_pin: GPIO23 From 80ad784a4ef1f57b0b4dca480d6babcbea1c2212 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Sat, 5 Jun 2021 10:52:16 +0200 Subject: [PATCH 089/104] Avoid unnecessary waits to stabilize the VOC algorithm (#1834) --- esphome/components/sgp40/sgp40.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/esphome/components/sgp40/sgp40.cpp b/esphome/components/sgp40/sgp40.cpp index 3e9f2b96cf..cfd9766aa9 100644 --- a/esphome/components/sgp40/sgp40.cpp +++ b/esphome/components/sgp40/sgp40.cpp @@ -220,7 +220,8 @@ void SGP40Component::update() { uint32_t voc_index = this->measure_voc_index_(); - if (this->samples_read_++ < this->samples_to_stabalize_) { + if (this->samples_read_ < this->samples_to_stabalize_) { + this->samples_read_++; ESP_LOGD(TAG, "Sensor has not collected enough samples yet. (%d/%d) VOC index is: %u", this->samples_read_, this->samples_to_stabalize_, voc_index); return; From 18a8c727fab159134814225cc9dab532abcb30b6 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Sat, 5 Jun 2021 10:56:54 +0200 Subject: [PATCH 090/104] Fix SCD30 configuration on ESP32 (#1830) --- esphome/components/scd30/scd30.cpp | 37 ++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/esphome/components/scd30/scd30.cpp b/esphome/components/scd30/scd30.cpp index 443deda3cc..e658397e35 100644 --- a/esphome/components/scd30/scd30.cpp +++ b/esphome/components/scd30/scd30.cpp @@ -43,14 +43,6 @@ void SCD30Component::setup() { ESP_LOGD(TAG, "SCD30 Firmware v%0d.%02d", (uint16_t(raw_firmware_version[0]) >> 8), uint16_t(raw_firmware_version[0] & 0xFF)); - /// Sensor initialization - if (!this->write_command_(SCD30_CMD_START_CONTINUOUS_MEASUREMENTS, this->ambient_pressure_compensation_)) { - ESP_LOGE(TAG, "Sensor SCD30 error starting continuous measurements."); - this->error_code_ = MEASUREMENT_INIT_FAILED; - this->mark_failed(); - return; - } - if (this->temperature_offset_ != 0) { if (!this->write_command_(SCD30_CMD_TEMPERATURE_OFFSET, (uint16_t)(temperature_offset_ * 100.0))) { ESP_LOGE(TAG, "Sensor SCD30 error setting temperature offset."); @@ -59,15 +51,31 @@ void SCD30Component::setup() { return; } } +#ifdef ARDUINO_ARCH_ESP32 + // According ESP32 clock stretching is typically 30ms and up to 150ms "due to + // internal calibration processes". The I2C peripheral only supports 13ms (at + // least when running at 80MHz). + // In practise it seems that clock stretching occures during this calibration + // calls. It also seems that delays in between calls makes them + // disappear/shorter. Hence work around with delays for ESP32. + // + // By experimentation a delay of 20ms as already sufficient. Let's go + // safe and use 30ms delays. + delay(30); +#endif + // The start measurement command disables the altitude compensation, if any, so we only set it if it's turned on if (this->altitude_compensation_ != 0xFFFF) { if (!this->write_command_(SCD30_CMD_ALTITUDE_COMPENSATION, altitude_compensation_)) { - ESP_LOGE(TAG, "Sensor SCD30 error starting continuous measurements."); + ESP_LOGE(TAG, "Sensor SCD30 error setting altitude compensation."); this->error_code_ = MEASUREMENT_INIT_FAILED; this->mark_failed(); return; } } +#ifdef ARDUINO_ARCH_ESP32 + delay(30); +#endif if (!this->write_command_(SCD30_CMD_AUTOMATIC_SELF_CALIBRATION, enable_asc_ ? 1 : 0)) { ESP_LOGE(TAG, "Sensor SCD30 error setting automatic self calibration."); @@ -75,6 +83,17 @@ void SCD30Component::setup() { this->mark_failed(); return; } +#ifdef ARDUINO_ARCH_ESP32 + delay(30); +#endif + + /// Sensor initialization + if (!this->write_command_(SCD30_CMD_START_CONTINUOUS_MEASUREMENTS, this->ambient_pressure_compensation_)) { + ESP_LOGE(TAG, "Sensor SCD30 error starting continuous measurements."); + this->error_code_ = MEASUREMENT_INIT_FAILED; + this->mark_failed(); + return; + } } void SCD30Component::dump_config() { From 0277218319a5443f3d3368bf52603d985f5f2a53 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Mon, 7 Jun 2021 21:02:31 +0200 Subject: [PATCH 091/104] Bump Docker base version to 3.1.0 (#1864) Bump Docker base version to 3.1.0 which includes Arduino SDK 1.0.6 for ESP32. --- .github/workflows/ci-docker.yml | 2 +- .github/workflows/release-dev.yml | 2 +- .github/workflows/release.yml | 2 +- docker/Dockerfile | 2 +- docker/Dockerfile.dev | 2 +- docker/Dockerfile.lint | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci-docker.yml b/.github/workflows/ci-docker.yml index 7da8a3f8f1..edbb2cf003 100644 --- a/.github/workflows/ci-docker.yml +++ b/.github/workflows/ci-docker.yml @@ -26,7 +26,7 @@ jobs: - uses: actions/checkout@v2 - name: Set up env variables run: | - base_version="3.0.0" + base_version="3.1.0" if [[ "${{ matrix.build_type }}" == "hassio" ]]; then build_from="esphome/esphome-hassio-base-${{ matrix.arch }}:${base_version}" diff --git a/.github/workflows/release-dev.yml b/.github/workflows/release-dev.yml index f0dc4bd0c0..1a88a362f8 100644 --- a/.github/workflows/release-dev.yml +++ b/.github/workflows/release-dev.yml @@ -174,7 +174,7 @@ jobs: echo "TAG=${TAG}" >> $GITHUB_ENV - name: Set up env variables run: | - base_version="3.0.0" + base_version="3.1.0" if [[ "${{ matrix.build_type }}" == "hassio" ]]; then build_from="esphome/esphome-hassio-base-${{ matrix.arch }}:${base_version}" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1eca3be269..fff89040ba 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -194,7 +194,7 @@ jobs: echo "TAG=${TAG}" >> $GITHUB_ENV - name: Set up env variables run: | - base_version="3.0.0" + base_version="3.1.0" if [[ "${{ matrix.build_type }}" == "hassio" ]]; then build_from="esphome/esphome-hassio-base-${{ matrix.arch }}:${base_version}" diff --git a/docker/Dockerfile b/docker/Dockerfile index 7364299ba7..927c62cf42 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,4 +1,4 @@ -ARG BUILD_FROM=esphome/esphome-base-amd64:3.0.0 +ARG BUILD_FROM=esphome/esphome-base-amd64:3.1.0 FROM ${BUILD_FROM} # First install requirements to leverage caching when requirements don't change diff --git a/docker/Dockerfile.dev b/docker/Dockerfile.dev index 52495fc8ae..e09eeb6837 100644 --- a/docker/Dockerfile.dev +++ b/docker/Dockerfile.dev @@ -1,4 +1,4 @@ -FROM esphome/esphome-base-amd64:3.0.0 +FROM esphome/esphome-base-amd64:3.1.0 COPY . . diff --git a/docker/Dockerfile.lint b/docker/Dockerfile.lint index 5488e68c91..4a88667245 100644 --- a/docker/Dockerfile.lint +++ b/docker/Dockerfile.lint @@ -1,4 +1,4 @@ -FROM esphome/esphome-lint-base:3.0.0 +FROM esphome/esphome-lint-base:3.1.0 COPY requirements.txt requirements_test.txt docker/platformio_install_deps.py platformio.ini / RUN \ From 33625e2dd3b7fc85dd6fe2b45ba4d898a560bfec Mon Sep 17 00:00:00 2001 From: Oxan van Leeuwen Date: Tue, 8 Jun 2021 01:14:12 +0200 Subject: [PATCH 092/104] CLI user experience improvements (#1805) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- .github/workflows/release-dev.yml | 2 +- .github/workflows/release.yml | 2 +- .vscode/tasks.json | 2 +- docker/Dockerfile | 2 +- docker/rootfs/etc/services.d/esphome/run | 2 +- esphome/__main__.py | 236 ++++++++++++++++------- esphome/dashboard/dashboard.py | 24 +-- script/test | 8 +- 9 files changed, 187 insertions(+), 93 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d2230b3da7..68e308d2bb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -126,7 +126,7 @@ jobs: run: | echo "::add-matcher::.github/workflows/matchers/gcc.json" echo "::add-matcher::.github/workflows/matchers/python.json" - - run: esphome tests/${{ matrix.test }}.yaml compile + - run: esphome compile tests/${{ matrix.test }}.yaml pytest: runs-on: ubuntu-latest diff --git a/.github/workflows/release-dev.yml b/.github/workflows/release-dev.yml index 1a88a362f8..51606ecad0 100644 --- a/.github/workflows/release-dev.yml +++ b/.github/workflows/release-dev.yml @@ -123,7 +123,7 @@ jobs: run: | echo "::add-matcher::.github/workflows/matchers/gcc.json" echo "::add-matcher::.github/workflows/matchers/python.json" - - run: esphome tests/${{ matrix.test }}.yaml compile + - run: esphome compile tests/${{ matrix.test }}.yaml pytest: runs-on: ubuntu-latest diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fff89040ba..2891959d35 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -121,7 +121,7 @@ jobs: run: | echo "::add-matcher::.github/workflows/matchers/gcc.json" echo "::add-matcher::.github/workflows/matchers/python.json" - - run: esphome tests/${{ matrix.test }}.yaml compile + - run: esphome compile tests/${{ matrix.test }}.yaml pytest: runs-on: ubuntu-latest diff --git a/.vscode/tasks.json b/.vscode/tasks.json index e11600b093..cc83d8bcdf 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -4,7 +4,7 @@ { "label": "run", "type": "shell", - "command": "python3 -m esphome config dashboard", + "command": "python3 -m esphome dashboard config", "problemMatcher": [] } ] diff --git a/docker/Dockerfile b/docker/Dockerfile index 927c62cf42..ef547fc0f1 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -27,4 +27,4 @@ WORKDIR /config # in every docker command twice ENTRYPOINT ["esphome"] # When no arguments given, start the dashboard in the workdir -CMD ["/config", "dashboard"] +CMD ["dashboard", "/config"] diff --git a/docker/rootfs/etc/services.d/esphome/run b/docker/rootfs/etc/services.d/esphome/run index 6257bec6a3..f806c50929 100755 --- a/docker/rootfs/etc/services.d/esphome/run +++ b/docker/rootfs/etc/services.d/esphome/run @@ -23,4 +23,4 @@ if bashio::config.has_value 'relative_url'; then fi bashio::log.info "Starting ESPHome dashboard..." -exec esphome /config/esphome dashboard --socket /var/run/esphome.sock --hassio +exec esphome dashboard /config/esphome --socket /var/run/esphome.sock --hassio diff --git a/esphome/__main__.py b/esphome/__main__.py index b78962c2c0..9af08a8f21 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -268,7 +268,7 @@ def clean_mqtt(config, args): def command_wizard(args): from esphome import wizard - return wizard.wizard(args.configuration[0]) + return wizard.wizard(args.configuration) def command_config(args, config): @@ -284,7 +284,7 @@ def command_vscode(args): logging.disable(logging.INFO) logging.disable(logging.WARNING) - CORE.config_path = args.configuration[0] + CORE.config_path = args.configuration vscode.read_config(args) @@ -304,7 +304,7 @@ def command_compile(args, config): def command_upload(args, config): port = choose_upload_log_host( - default=args.upload_port, + default=args.device, check_default=None, show_ota=True, show_mqtt=False, @@ -319,7 +319,7 @@ def command_upload(args, config): def command_logs(args, config): port = choose_upload_log_host( - default=args.serial_port, + default=args.device, check_default=None, show_ota=False, show_mqtt=True, @@ -337,7 +337,7 @@ def command_run(args, config): return exit_code _LOGGER.info("Successfully compiled program.") port = choose_upload_log_host( - default=args.upload_port, + default=args.device, check_default=None, show_ota=True, show_mqtt=False, @@ -350,7 +350,7 @@ def command_run(args, config): if args.no_logs: return 0 port = choose_upload_log_host( - default=args.upload_port, + default=args.device, check_default=port, show_ota=False, show_mqtt=True, @@ -394,7 +394,7 @@ def command_update_all(args): import click success = {} - files = list_yaml_files(args.configuration[0]) + files = list_yaml_files(args.configuration) twidth = 60 def print_bar(middle_text): @@ -408,7 +408,7 @@ def command_update_all(args): print("-" * twidth) print() rc = run_external_process( - "esphome", "--dashboard", f, "run", "--no-logs", "--upload-port", "OTA" + "esphome", "--dashboard", "run", f, "--no-logs", "--device", "OTA" ) if rc == 0: print_bar("[{}] {}".format(color(Fore.BOLD_GREEN, "SUCCESS"), f)) @@ -453,15 +453,17 @@ POST_CONFIG_ACTIONS = { def parse_args(argv): - parser = argparse.ArgumentParser(description=f"ESPHome v{const.__version__}") - parser.add_argument( - "-v", "--verbose", help="Enable verbose esphome logs.", action="store_true" + options_parser = argparse.ArgumentParser(add_help=False) + options_parser.add_argument( + "-v", "--verbose", help="Enable verbose ESPHome logs.", action="store_true" ) - parser.add_argument( - "-q", "--quiet", help="Disable all esphome logs.", action="store_true" + options_parser.add_argument( + "-q", "--quiet", help="Disable all ESPHome logs.", action="store_true" ) - parser.add_argument("--dashboard", help=argparse.SUPPRESS, action="store_true") - parser.add_argument( + options_parser.add_argument( + "--dashboard", help=argparse.SUPPRESS, action="store_true" + ) + options_parser.add_argument( "-s", "--substitution", nargs=2, @@ -469,17 +471,87 @@ def parse_args(argv): help="Add a substitution", metavar=("key", "value"), ) - parser.add_argument( - "configuration", help="Your YAML configuration file.", nargs="*" + + # Keep backward compatibility with the old command line format of + # esphome . + # + # Unfortunately this can't be done by adding another configuration argument to the + # main config parser, as argparse is greedy when parsing arguments, so in regular + # usage it'll eat the command as the configuration argument and error out out + # because it can't parse the configuration as a command. + # + # Instead, construct an ad-hoc parser for the old format that doesn't actually + # process the arguments, but parses them enough to let us figure out if the old + # format is used. In that case, swap the command and configuration in the arguments + # and continue on with the normal parser (after raising a deprecation warning). + # + # Disable argparse's built-in help option and add it manually to prevent this + # parser from printing the help messagefor the old format when invoked with -h. + compat_parser = argparse.ArgumentParser(parents=[options_parser], add_help=False) + compat_parser.add_argument("-h", "--help") + compat_parser.add_argument("configuration", nargs="*") + compat_parser.add_argument( + "command", + choices=[ + "config", + "compile", + "upload", + "logs", + "run", + "clean-mqtt", + "wizard", + "mqtt-fingerprint", + "version", + "clean", + "dashboard", + ], ) - subparsers = parser.add_subparsers(help="Commands", dest="command") + # on Python 3.9+ we can simply set exit_on_error=False in the constructor + def _raise(x): + raise argparse.ArgumentError(None, x) + + compat_parser.error = _raise + + try: + result, unparsed = compat_parser.parse_known_args(argv[1:]) + last_option = len(argv) - len(unparsed) - 1 - len(result.configuration) + argv = argv[0:last_option] + [result.command] + result.configuration + unparsed + deprecated_argv_suggestion = argv + except argparse.ArgumentError: + # This is not an old-style command line, so we don't have to do anything. + deprecated_argv_suggestion = None + + # And continue on with regular parsing + parser = argparse.ArgumentParser( + description=f"ESPHome v{const.__version__}", parents=[options_parser] + ) + parser.set_defaults(deprecated_argv_suggestion=deprecated_argv_suggestion) + + mqtt_options = argparse.ArgumentParser(add_help=False) + mqtt_options.add_argument("--topic", help="Manually set the MQTT topic.") + mqtt_options.add_argument("--username", help="Manually set the MQTT username.") + mqtt_options.add_argument("--password", help="Manually set the MQTT password.") + mqtt_options.add_argument("--client-id", help="Manually set the MQTT client id.") + + subparsers = parser.add_subparsers( + help="Command to run:", dest="command", metavar="command" + ) subparsers.required = True - subparsers.add_parser("config", help="Validate the configuration and spit it out.") + + parser_config = subparsers.add_parser( + "config", help="Validate the configuration and spit it out." + ) + parser_config.add_argument( + "configuration", help="Your YAML configuration file(s).", nargs="+" + ) parser_compile = subparsers.add_parser( "compile", help="Read the configuration and compile a program." ) + parser_compile.add_argument( + "configuration", help="Your YAML configuration file(s).", nargs="+" + ) parser_compile.add_argument( "--only-generate", help="Only generate source code, do not compile.", @@ -487,106 +559,124 @@ def parse_args(argv): ) parser_upload = subparsers.add_parser( - "upload", help="Validate the configuration " "and upload the latest binary." + "upload", help="Validate the configuration and upload the latest binary." ) parser_upload.add_argument( - "--upload-port", - help="Manually specify the upload port to use. " - "For example /dev/cu.SLAB_USBtoUART.", + "configuration", help="Your YAML configuration file(s).", nargs="+" + ) + parser_upload.add_argument( + "--device", + help="Manually specify the serial port/address to use, for example /dev/ttyUSB0.", ) parser_logs = subparsers.add_parser( - "logs", help="Validate the configuration " "and show all MQTT logs." + "logs", + help="Validate the configuration and show all logs.", + parents=[mqtt_options], ) - parser_logs.add_argument("--topic", help="Manually set the topic to subscribe to.") - parser_logs.add_argument("--username", help="Manually set the username.") - parser_logs.add_argument("--password", help="Manually set the password.") - 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.", + "configuration", help="Your YAML configuration file.", nargs=1 + ) + parser_logs.add_argument( + "--device", + help="Manually specify the serial port/address to use, for example /dev/ttyUSB0.", ) parser_run = subparsers.add_parser( "run", - help="Validate the configuration, create a binary, " - "upload it, and start MQTT logs.", + help="Validate the configuration, create a binary, upload it, and start logs.", + parents=[mqtt_options], ) parser_run.add_argument( - "--upload-port", - help="Manually specify the upload port/ip to use. " - "For example /dev/cu.SLAB_USBtoUART.", + "configuration", help="Your YAML configuration file(s).", nargs="+" ) parser_run.add_argument( - "--no-logs", help="Disable starting MQTT logs.", action="store_true" + "--device", + help="Manually specify the serial port/address to use, for example /dev/ttyUSB0.", ) parser_run.add_argument( - "--topic", help="Manually set the topic to subscribe to for logs." + "--no-logs", help="Disable starting logs.", action="store_true" ) - 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_clean = subparsers.add_parser( - "clean-mqtt", help="Helper to clear an MQTT topic from " "retain messages." + "clean-mqtt", + help="Helper to clear retained messages from an MQTT topic.", + parents=[mqtt_options], + ) + parser_clean.add_argument( + "configuration", help="Your YAML configuration file(s).", nargs="+" ) - parser_clean.add_argument("--topic", help="Manually set the topic to subscribe to.") - parser_clean.add_argument("--username", help="Manually set the username.") - parser_clean.add_argument("--password", help="Manually set the password.") - parser_clean.add_argument("--client-id", help="Manually set the client id.") - subparsers.add_parser( + parser_wizard = subparsers.add_parser( "wizard", - help="A helpful setup wizard that will guide " - "you through setting up esphome.", + help="A helpful setup wizard that will guide you through setting up ESPHome.", + ) + parser_wizard.add_argument( + "configuration", + help="Your YAML configuration file.", ) - subparsers.add_parser( + parser_fingerprint = subparsers.add_parser( "mqtt-fingerprint", help="Get the SSL fingerprint from a MQTT broker." ) + parser_fingerprint.add_argument( + "configuration", help="Your YAML configuration file(s).", nargs="+" + ) - subparsers.add_parser("version", help="Print the esphome version and exit.") + subparsers.add_parser("version", help="Print the ESPHome version and exit.") - subparsers.add_parser("clean", help="Delete all temporary build files.") + parser_clean = subparsers.add_parser( + "clean", help="Delete all temporary build files." + ) + parser_clean.add_argument( + "configuration", help="Your YAML configuration file(s).", nargs="+" + ) - dashboard = subparsers.add_parser( + parser_dashboard = subparsers.add_parser( "dashboard", help="Create a simple web server for a dashboard." ) - dashboard.add_argument( + parser_dashboard.add_argument( + "configuration", + help="Your YAML configuration file directory.", + ) + parser_dashboard.add_argument( "--port", help="The HTTP port to open connections on. Defaults to 6052.", type=int, default=6052, ) - dashboard.add_argument( + parser_dashboard.add_argument( "--username", - help="The optional username to require " "for authentication.", + help="The optional username to require for authentication.", type=str, default="", ) - dashboard.add_argument( + parser_dashboard.add_argument( "--password", - help="The optional password to require " "for authentication.", + help="The optional password to require for authentication.", type=str, default="", ) - dashboard.add_argument( + parser_dashboard.add_argument( "--open-ui", help="Open the dashboard UI in a browser.", action="store_true" ) - dashboard.add_argument("--hassio", help=argparse.SUPPRESS, action="store_true") - dashboard.add_argument( + parser_dashboard.add_argument( + "--hassio", help=argparse.SUPPRESS, action="store_true" + ) + parser_dashboard.add_argument( "--socket", help="Make the dashboard serve under a unix socket", type=str ) - vscode = subparsers.add_parser("vscode", help=argparse.SUPPRESS) - vscode.add_argument("--ace", action="store_true") + parser_vscode = subparsers.add_parser("vscode") + parser_vscode.add_argument( + "configuration", help="Your YAML configuration file.", nargs=1 + ) + parser_vscode.add_argument("--ace", action="store_true") - subparsers.add_parser("update-all", help=argparse.SUPPRESS) + parser_update = subparsers.add_parser("update-all") + parser_update.add_argument( + "configuration", help="Your YAML configuration file directory.", nargs=1 + ) return parser.parse_args(argv[1:]) @@ -596,9 +686,13 @@ def run_esphome(argv): CORE.dashboard = args.dashboard setup_log(args.verbose, args.quiet) - if args.command != "version" and not args.configuration: - _LOGGER.error("Missing configuration parameter, see esphome --help.") - return 1 + if args.deprecated_argv_suggestion is not None: + _LOGGER.warning( + "Calling ESPHome with the configuration before the command is deprecated " + "and will be removed in the future. " + ) + _LOGGER.warning("Please instead use:") + _LOGGER.warning(" esphome %s", " ".join(args.deprecated_argv_suggestion[1:])) if sys.version_info < (3, 7, 0): _LOGGER.error( diff --git a/esphome/dashboard/dashboard.py b/esphome/dashboard/dashboard.py index f0e9604141..4b40237768 100644 --- a/esphome/dashboard/dashboard.py +++ b/esphome/dashboard/dashboard.py @@ -62,7 +62,7 @@ class DashboardSettings: self.using_password = bool(password) if self.using_password: self.password_hash = password_hash(password) - self.config_dir = args.configuration[0] + self.config_dir = args.configuration @property def relative_url(self): @@ -274,9 +274,9 @@ class EsphomeLogsHandler(EsphomeCommandWebSocket): return [ "esphome", "--dashboard", - config_file, "logs", - "--serial-port", + config_file, + "--device", json_message["port"], ] @@ -287,9 +287,9 @@ class EsphomeUploadHandler(EsphomeCommandWebSocket): return [ "esphome", "--dashboard", - config_file, "run", - "--upload-port", + config_file, + "--device", json_message["port"], ] @@ -297,40 +297,40 @@ class EsphomeUploadHandler(EsphomeCommandWebSocket): class EsphomeCompileHandler(EsphomeCommandWebSocket): def build_command(self, json_message): config_file = settings.rel_path(json_message["configuration"]) - return ["esphome", "--dashboard", config_file, "compile"] + return ["esphome", "--dashboard", "compile", config_file] class EsphomeValidateHandler(EsphomeCommandWebSocket): def build_command(self, json_message): config_file = settings.rel_path(json_message["configuration"]) - return ["esphome", "--dashboard", config_file, "config"] + return ["esphome", "--dashboard", "config", config_file] class EsphomeCleanMqttHandler(EsphomeCommandWebSocket): def build_command(self, json_message): config_file = settings.rel_path(json_message["configuration"]) - return ["esphome", "--dashboard", config_file, "clean-mqtt"] + return ["esphome", "--dashboard", "clean-mqtt", config_file] class EsphomeCleanHandler(EsphomeCommandWebSocket): def build_command(self, json_message): config_file = settings.rel_path(json_message["configuration"]) - return ["esphome", "--dashboard", config_file, "clean"] + return ["esphome", "--dashboard", "clean", config_file] class EsphomeVscodeHandler(EsphomeCommandWebSocket): def build_command(self, json_message): - return ["esphome", "--dashboard", "-q", "dummy", "vscode"] + return ["esphome", "--dashboard", "-q", "vscode", "dummy"] class EsphomeAceEditorHandler(EsphomeCommandWebSocket): def build_command(self, json_message): - return ["esphome", "--dashboard", "-q", settings.config_dir, "vscode", "--ace"] + return ["esphome", "--dashboard", "-q", "vscode", settings.config_dir, "--ace"] class EsphomeUpdateAllHandler(EsphomeCommandWebSocket): def build_command(self, json_message): - return ["esphome", "--dashboard", settings.config_dir, "update-all"] + return ["esphome", "--dashboard", "update-all", settings.config_dir] class SerialPortRequestHandler(BaseHandler): diff --git a/script/test b/script/test index a6d99c8f62..0327e08ca8 100755 --- a/script/test +++ b/script/test @@ -6,7 +6,7 @@ cd "$(dirname "$0")/.." set -x -esphome tests/test1.yaml compile -esphome tests/test2.yaml compile -esphome tests/test3.yaml compile -esphome tests/test4.yaml compile +esphome compile tests/test1.yaml +esphome compile tests/test2.yaml +esphome compile tests/test3.yaml +esphome compile tests/test4.yaml From a70a205ace089c30c0ffcf38b9793d7181595b04 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 8 Jun 2021 11:56:21 +1200 Subject: [PATCH 093/104] Improv - BLE WiFi provisioning (#1807) Co-authored-by: Paulus Schoutsen --- .github/workflows/ci.yml | 1 + .github/workflows/release-dev.yml | 1 + .github/workflows/release.yml | 1 + CODEOWNERS | 3 + .../captive_portal/captive_portal.cpp | 25 +- .../captive_portal/captive_portal.h | 8 - esphome/components/esp32_ble/__init__.py | 44 +++ esphome/components/esp32_ble/ble.cpp | 178 +++++++++++ esphome/components/esp32_ble/ble.h | 62 ++++ esphome/components/esp32_ble/ble_2901.cpp | 18 ++ esphome/components/esp32_ble/ble_2901.h | 19 ++ esphome/components/esp32_ble/ble_2902.cpp | 18 ++ esphome/components/esp32_ble/ble_2902.h | 18 ++ .../components/esp32_ble/ble_advertising.cpp | 97 ++++++ .../components/esp32_ble/ble_advertising.h | 37 +++ .../esp32_ble/ble_characteristic.cpp | 280 ++++++++++++++++++ .../components/esp32_ble/ble_characteristic.h | 85 ++++++ .../components/esp32_ble/ble_descriptor.cpp | 82 +++++ esphome/components/esp32_ble/ble_descriptor.h | 40 +++ esphome/components/esp32_ble/ble_server.cpp | 158 ++++++++++ esphome/components/esp32_ble/ble_server.h | 84 ++++++ esphome/components/esp32_ble/ble_service.cpp | 129 ++++++++ esphome/components/esp32_ble/ble_service.h | 61 ++++ esphome/components/esp32_ble/ble_uuid.cpp | 184 ++++++++++++ esphome/components/esp32_ble/ble_uuid.h | 45 +++ esphome/components/esp32_ble/queue.h | 114 +++++++ esphome/components/esp32_improv/__init__.py | 69 +++++ .../esp32_improv/esp32_improv_component.cpp | 275 +++++++++++++++++ .../esp32_improv/esp32_improv_component.h | 74 +++++ esphome/components/improv/__init__.py | 1 + esphome/components/improv/improv.cpp | 66 +++++ esphome/components/improv/improv.h | 53 ++++ esphome/components/wifi/wifi_component.cpp | 60 +++- esphome/components/wifi/wifi_component.h | 10 + esphome/core/component.cpp | 2 + esphome/core/component.h | 2 + esphome/core/helpers.h | 10 +- script/test | 1 + tests/README.md | 13 +- tests/test5.yaml | 36 +++ 40 files changed, 2422 insertions(+), 42 deletions(-) create mode 100644 esphome/components/esp32_ble/__init__.py create mode 100644 esphome/components/esp32_ble/ble.cpp create mode 100644 esphome/components/esp32_ble/ble.h create mode 100644 esphome/components/esp32_ble/ble_2901.cpp create mode 100644 esphome/components/esp32_ble/ble_2901.h create mode 100644 esphome/components/esp32_ble/ble_2902.cpp create mode 100644 esphome/components/esp32_ble/ble_2902.h create mode 100644 esphome/components/esp32_ble/ble_advertising.cpp create mode 100644 esphome/components/esp32_ble/ble_advertising.h create mode 100644 esphome/components/esp32_ble/ble_characteristic.cpp create mode 100644 esphome/components/esp32_ble/ble_characteristic.h create mode 100644 esphome/components/esp32_ble/ble_descriptor.cpp create mode 100644 esphome/components/esp32_ble/ble_descriptor.h create mode 100644 esphome/components/esp32_ble/ble_server.cpp create mode 100644 esphome/components/esp32_ble/ble_server.h create mode 100644 esphome/components/esp32_ble/ble_service.cpp create mode 100644 esphome/components/esp32_ble/ble_service.h create mode 100644 esphome/components/esp32_ble/ble_uuid.cpp create mode 100644 esphome/components/esp32_ble/ble_uuid.h create mode 100644 esphome/components/esp32_ble/queue.h create mode 100644 esphome/components/esp32_improv/__init__.py create mode 100644 esphome/components/esp32_improv/esp32_improv_component.cpp create mode 100644 esphome/components/esp32_improv/esp32_improv_component.h create mode 100644 esphome/components/improv/__init__.py create mode 100644 esphome/components/improv/improv.cpp create mode 100644 esphome/components/improv/improv.h create mode 100644 tests/test5.yaml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 68e308d2bb..56e94cb32c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -97,6 +97,7 @@ jobs: - test2 - test3 - test4 + - test5 steps: - uses: actions/checkout@v2 - name: Set up Python diff --git a/.github/workflows/release-dev.yml b/.github/workflows/release-dev.yml index 51606ecad0..9361ab4b73 100644 --- a/.github/workflows/release-dev.yml +++ b/.github/workflows/release-dev.yml @@ -94,6 +94,7 @@ jobs: - test2 - test3 - test4 + - test5 steps: - uses: actions/checkout@v2 - name: Set up Python diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2891959d35..39cc7c37ce 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -93,6 +93,7 @@ jobs: - test2 - test3 - test4 + - test5 steps: - uses: actions/checkout@v2 - name: Set up Python diff --git a/CODEOWNERS b/CODEOWNERS index 576af1459e..3f1abae5df 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -35,6 +35,8 @@ esphome/components/debug/* @OttoWinter esphome/components/dfplayer/* @glmnet esphome/components/dht/* @OttoWinter esphome/components/ds1307/* @badbadc0ffee +esphome/components/esp32_ble/* @jesserockz +esphome/components/esp32_improv/* @jesserockz esphome/components/exposure_notifications/* @OttoWinter esphome/components/ezo/* @ssieb esphome/components/fastled_base/* @OttoWinter @@ -44,6 +46,7 @@ esphome/components/gpio/* @esphome/core esphome/components/gps/* @coogle esphome/components/homeassistant/* @OttoWinter esphome/components/i2c/* @esphome/core +esphome/components/improv/* @jesserockz esphome/components/inkbird_ibsth1_mini/* @fkirill esphome/components/inkplate6/* @jesserockz esphome/components/integration/* @OttoWinter diff --git a/esphome/components/captive_portal/captive_portal.cpp b/esphome/components/captive_portal/captive_portal.cpp index 83f85d354c..0e0e08fdea 100644 --- a/esphome/components/captive_portal/captive_portal.cpp +++ b/esphome/components/captive_portal/captive_portal.cpp @@ -64,32 +64,11 @@ void CaptivePortal::handle_wifisave(AsyncWebServerRequest *request) { ESP_LOGI(TAG, "Captive Portal Requested WiFi Settings Change:"); ESP_LOGI(TAG, " SSID='%s'", ssid.c_str()); ESP_LOGI(TAG, " Password=" LOG_SECRET("'%s'"), psk.c_str()); - this->override_sta_(ssid, psk); + wifi::global_wifi_component->save_wifi_sta(ssid, psk); request->redirect("/?save=true"); } -void CaptivePortal::override_sta_(const std::string &ssid, const std::string &password) { - CaptivePortalSettings save{}; - strcpy(save.ssid, ssid.c_str()); - strcpy(save.password, password.c_str()); - this->pref_.save(&save); - wifi::WiFiAP sta{}; - sta.set_ssid(ssid); - sta.set_password(password); - wifi::global_wifi_component->set_sta(sta); -} - -void CaptivePortal::setup() { - // Hash with compilation time - // This ensures the AP override is not applied for OTA - uint32_t hash = fnv1_hash(App.get_compilation_time()); - this->pref_ = global_preferences.make_preference(hash, true); - - CaptivePortalSettings save{}; - if (this->pref_.load(&save)) { - this->override_sta_(save.ssid, save.password); - } -} +void CaptivePortal::setup() {} void CaptivePortal::start() { this->base_->init(); if (!this->initialized_) { diff --git a/esphome/components/captive_portal/captive_portal.h b/esphome/components/captive_portal/captive_portal.h index 3af47546cf..afd4ff9dc5 100644 --- a/esphome/components/captive_portal/captive_portal.h +++ b/esphome/components/captive_portal/captive_portal.h @@ -10,11 +10,6 @@ namespace esphome { namespace captive_portal { -struct CaptivePortalSettings { - char ssid[33]; - char password[65]; -} PACKED; // NOLINT - class CaptivePortal : public AsyncWebHandler, public Component { public: CaptivePortal(web_server_base::WebServerBase *base); @@ -67,12 +62,9 @@ class CaptivePortal : public AsyncWebHandler, public Component { void handleRequest(AsyncWebServerRequest *req) override; protected: - void override_sta_(const std::string &ssid, const std::string &password); - web_server_base::WebServerBase *base_; bool initialized_{false}; bool active_{false}; - ESPPreferenceObject pref_; DNSServer *dns_server_{nullptr}; }; diff --git a/esphome/components/esp32_ble/__init__.py b/esphome/components/esp32_ble/__init__.py new file mode 100644 index 0000000000..6437216f69 --- /dev/null +++ b/esphome/components/esp32_ble/__init__.py @@ -0,0 +1,44 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.const import CONF_ID, CONF_MODEL, ESP_PLATFORM_ESP32 + +ESP_PLATFORMS = [ESP_PLATFORM_ESP32] +CODEOWNERS = ["@jesserockz"] + +CONF_MANUFACTURER = "manufacturer" +CONF_SERVER = "server" + +esp32_ble_ns = cg.esphome_ns.namespace("esp32_ble") +ESP32BLE = esp32_ble_ns.class_("ESP32BLE", cg.Component) +BLEServer = esp32_ble_ns.class_("BLEServer", cg.Component) + +BLEServiceComponent = esp32_ble_ns.class_("BLEServiceComponent") + + +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(): cv.declare_id(ESP32BLE), + cv.Optional(CONF_SERVER): cv.Schema( + { + cv.GenerateID(): cv.declare_id(BLEServer), + cv.Optional(CONF_MANUFACTURER, default="ESPHome"): cv.string, + cv.Optional(CONF_MODEL): cv.string, + } + ), + } +).extend(cv.COMPONENT_SCHEMA) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + + if CONF_SERVER in config: + conf = config[CONF_SERVER] + server = cg.new_Pvariable(conf[CONF_ID]) + await cg.register_component(server, conf) + cg.add(server.set_manufacturer(conf[CONF_MANUFACTURER])) + if CONF_MODEL in conf: + cg.add(server.set_model(conf[CONF_MODEL])) + cg.add_define("USE_ESP32_BLE_SERVER") + cg.add(var.set_server(server)) diff --git a/esphome/components/esp32_ble/ble.cpp b/esphome/components/esp32_ble/ble.cpp new file mode 100644 index 0000000000..9ce9eaec7e --- /dev/null +++ b/esphome/components/esp32_ble/ble.cpp @@ -0,0 +1,178 @@ +#include "ble.h" +#include "esphome/core/application.h" +#include "esphome/core/log.h" + +#ifdef ARDUINO_ARCH_ESP32 + +#include +#include +#include +#include +#include +#include + +namespace esphome { +namespace esp32_ble { + +static const char *TAG = "esp32_ble"; + +void ESP32BLE::setup() { + global_ble = this; + ESP_LOGCONFIG(TAG, "Setting up BLE..."); + + xTaskCreatePinnedToCore(ESP32BLE::ble_core_task_, + "ble_task", // name + 10000, // stack size + nullptr, // input params + 1, // priority + nullptr, // handle, not needed + 0 // core + ); +} + +void ESP32BLE::mark_failed() { + Component::mark_failed(); + if (this->server_ != nullptr) { + this->server_->mark_failed(); + } +} + +bool ESP32BLE::can_proceed() { return this->ready_; } + +void ESP32BLE::ble_core_task_(void *params) { + if (!ble_setup_()) { + ESP_LOGE(TAG, "BLE could not be set up"); + global_ble->mark_failed(); + return; + } + + global_ble->ready_ = true; + ESP_LOGD(TAG, "BLE Setup complete"); + + while (true) { + vTaskDelay(1000 / portTICK_PERIOD_MS); + } +} + +bool ESP32BLE::ble_setup_() { + esp_err_t err = nvs_flash_init(); + if (err != ESP_OK) { + ESP_LOGE(TAG, "nvs_flash_init failed: %d", err); + return false; + } + + if (!btStart()) { + ESP_LOGE(TAG, "btStart failed: %d", esp_bt_controller_get_status()); + return false; + } + + esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT); + + err = esp_bluedroid_init(); + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_bluedroid_init failed: %d", err); + return false; + } + err = esp_bluedroid_enable(); + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_bluedroid_enable failed: %d", err); + return false; + } + err = esp_ble_gap_register_callback(ESP32BLE::gap_event_handler); + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_ble_gap_register_callback failed: %d", err); + return false; + } + + if (global_ble->has_server()) { + err = esp_ble_gatts_register_callback(ESP32BLE::gatts_event_handler); + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_ble_gatts_register_callback failed: %d", err); + return false; + } + } + + if (global_ble->has_client()) { + err = esp_ble_gattc_register_callback(ESP32BLE::gattc_event_handler); + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_ble_gattc_register_callback failed: %d", err); + return false; + } + } + + err = esp_ble_gap_set_device_name(App.get_name().c_str()); + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_ble_gap_set_device_name failed: %d", err); + return false; + } + + esp_ble_io_cap_t iocap = ESP_IO_CAP_NONE; + err = esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t)); + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_ble_gap_set_security_param failed: %d", err); + return false; + } + + // BLE takes some time to be fully set up, 200ms should be more than enough + delay(200); // NOLINT + + return true; +} + +void ESP32BLE::loop() { + BLEEvent *ble_event = this->ble_events_.pop(); + while (ble_event != nullptr) { + switch (ble_event->type_) { + case ble_event->GATTS: + this->real_gatts_event_handler_(ble_event->event_.gatts.gatts_event, ble_event->event_.gatts.gatts_if, + &ble_event->event_.gatts.gatts_param); + break; + case ble_event->GAP: + this->real_gap_event_handler_(ble_event->event_.gap.gap_event, &ble_event->event_.gap.gap_param); + break; + default: + break; + } + delete ble_event; + ble_event = this->ble_events_.pop(); + } +} + +void ESP32BLE::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) { + global_ble->real_gap_event_handler_(event, param); +} + +void ESP32BLE::real_gap_event_handler_(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) { + ESP_LOGV(TAG, "(BLE) gap_event_handler - %d", event); + switch (event) { + default: + break; + } +} + +void ESP32BLE::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, + esp_ble_gatts_cb_param_t *param) { + global_ble->real_gatts_event_handler_(event, gatts_if, param); +} + +void ESP32BLE::real_gatts_event_handler_(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, + esp_ble_gatts_cb_param_t *param) { + ESP_LOGV(TAG, "(BLE) gatts_event [esp_gatt_if: %d] - %d", gatts_if, event); + this->server_->gatts_event_handler(event, gatts_if, param); +} + +void ESP32BLE::real_gattc_event_handler_(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, + esp_ble_gattc_cb_param_t *param) { + // this->client_->gattc_event_handler(event, gattc_if, param); +} + +float ESP32BLE::get_setup_priority() const { return setup_priority::BLUETOOTH; } + +void ESP32BLE::dump_config() { ESP_LOGCONFIG(TAG, "ESP32 BLE:"); } + +ESP32BLE *global_ble = nullptr; + +} // namespace esp32_ble +} // namespace esphome + +#endif diff --git a/esphome/components/esp32_ble/ble.h b/esphome/components/esp32_ble/ble.h new file mode 100644 index 0000000000..8eaa7068fd --- /dev/null +++ b/esphome/components/esp32_ble/ble.h @@ -0,0 +1,62 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/helpers.h" +#include "ble_server.h" +#include "queue.h" + +#ifdef ARDUINO_ARCH_ESP32 + +#include +#include +#include + +namespace esphome { +namespace esp32_ble { + +typedef struct { + void *peer_device; + bool connected; + uint16_t mtu; +} conn_status_t; + +class ESP32BLE : public Component { + public: + void setup() override; + void loop() override; + void dump_config() override; + float get_setup_priority() const override; + void mark_failed() override; + bool can_proceed() override; + + bool has_server() { return this->server_ != nullptr; } + bool has_client() { return false; } + + bool is_ready() { return this->ready_; } + + void set_server(BLEServer *server) { this->server_ = server; } + + protected: + static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param); + static void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param); + static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param); + + void real_gatts_event_handler_(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param); + void real_gattc_event_handler_(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param); + void real_gap_event_handler_(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param); + + static void ble_core_task_(void *params); + static bool ble_setup_(); + + bool ready_{false}; + + BLEServer *server_{nullptr}; + Queue ble_events_; +}; + +extern ESP32BLE *global_ble; + +} // namespace esp32_ble +} // namespace esphome + +#endif diff --git a/esphome/components/esp32_ble/ble_2901.cpp b/esphome/components/esp32_ble/ble_2901.cpp new file mode 100644 index 0000000000..d62c67c4cf --- /dev/null +++ b/esphome/components/esp32_ble/ble_2901.cpp @@ -0,0 +1,18 @@ +#include "ble_2901.h" +#include "ble_uuid.h" + +#ifdef ARDUINO_ARCH_ESP32 + +namespace esphome { +namespace esp32_ble { + +BLE2901::BLE2901(const std::string value) : BLE2901((uint8_t *) value.data(), value.length()) {} +BLE2901::BLE2901(uint8_t *data, size_t length) : BLEDescriptor(ESPBTUUID::from_uint16(0x2901)) { + this->set_value(data, length); + this->permissions_ = ESP_GATT_PERM_READ; +} + +} // namespace esp32_ble +} // namespace esphome + +#endif diff --git a/esphome/components/esp32_ble/ble_2901.h b/esphome/components/esp32_ble/ble_2901.h new file mode 100644 index 0000000000..6f72f38fd0 --- /dev/null +++ b/esphome/components/esp32_ble/ble_2901.h @@ -0,0 +1,19 @@ +#pragma once + +#include "ble_descriptor.h" + +#ifdef ARDUINO_ARCH_ESP32 + +namespace esphome { +namespace esp32_ble { + +class BLE2901 : public BLEDescriptor { + public: + BLE2901(const std::string value); + BLE2901(uint8_t *data, size_t length); +}; + +} // namespace esp32_ble +} // namespace esphome + +#endif diff --git a/esphome/components/esp32_ble/ble_2902.cpp b/esphome/components/esp32_ble/ble_2902.cpp new file mode 100644 index 0000000000..164c8f40ff --- /dev/null +++ b/esphome/components/esp32_ble/ble_2902.cpp @@ -0,0 +1,18 @@ +#include "ble_2902.h" +#include "ble_uuid.h" + +#ifdef ARDUINO_ARCH_ESP32 + +namespace esphome { +namespace esp32_ble { + +BLE2902::BLE2902() : BLEDescriptor(ESPBTUUID::from_uint16(0x2902)) { + this->value_.attr_len = 2; + uint8_t data[2] = {0, 0}; + memcpy(this->value_.attr_value, data, 2); +} + +} // namespace esp32_ble +} // namespace esphome + +#endif diff --git a/esphome/components/esp32_ble/ble_2902.h b/esphome/components/esp32_ble/ble_2902.h new file mode 100644 index 0000000000..356a0bb107 --- /dev/null +++ b/esphome/components/esp32_ble/ble_2902.h @@ -0,0 +1,18 @@ +#pragma once + +#include "ble_descriptor.h" + +#ifdef ARDUINO_ARCH_ESP32 + +namespace esphome { +namespace esp32_ble { + +class BLE2902 : public BLEDescriptor { + public: + BLE2902(); +}; + +} // namespace esp32_ble +} // namespace esphome + +#endif diff --git a/esphome/components/esp32_ble/ble_advertising.cpp b/esphome/components/esp32_ble/ble_advertising.cpp new file mode 100644 index 0000000000..6162bf3a40 --- /dev/null +++ b/esphome/components/esp32_ble/ble_advertising.cpp @@ -0,0 +1,97 @@ +#include "ble_advertising.h" + +#ifdef ARDUINO_ARCH_ESP32 + +#include "ble_uuid.h" + +namespace esphome { +namespace esp32_ble { + +BLEAdvertising::BLEAdvertising() { + this->advertising_data_.set_scan_rsp = false; + this->advertising_data_.include_name = true; + this->advertising_data_.include_txpower = true; + this->advertising_data_.min_interval = 0x20; + this->advertising_data_.max_interval = 0x40; + this->advertising_data_.appearance = 0x00; + this->advertising_data_.manufacturer_len = 0; + this->advertising_data_.p_manufacturer_data = nullptr; + this->advertising_data_.service_data_len = 0; + this->advertising_data_.p_service_data = nullptr; + this->advertising_data_.service_uuid_len = 0; + this->advertising_data_.p_service_uuid = nullptr; + this->advertising_data_.flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT); + + this->advertising_params_.adv_int_min = 0x20; + this->advertising_params_.adv_int_max = 0x40; + this->advertising_params_.adv_type = ADV_TYPE_IND; + this->advertising_params_.own_addr_type = BLE_ADDR_TYPE_PUBLIC; + this->advertising_params_.channel_map = ADV_CHNL_ALL; + this->advertising_params_.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY; + this->advertising_params_.peer_addr_type = BLE_ADDR_TYPE_PUBLIC; +} + +void BLEAdvertising::add_service_uuid(ESPBTUUID uuid) { this->advertising_uuids_.push_back(uuid); } + +void BLEAdvertising::start() { + int num_services = this->advertising_uuids_.size(); + if (num_services == 0) { + this->advertising_data_.service_uuid_len = 0; + } else { + this->advertising_data_.service_uuid_len = 16 * num_services; + this->advertising_data_.p_service_uuid = new uint8_t[this->advertising_data_.service_uuid_len]; + uint8_t *p = this->advertising_data_.p_service_uuid; + for (int i = 0; i < num_services; i++) { + ESPBTUUID uuid = this->advertising_uuids_[i]; + memcpy(p, uuid.as_128bit().get_uuid().uuid.uuid128, 16); + p += 16; + } + } + + esp_err_t err; + + this->advertising_data_.set_scan_rsp = false; + this->advertising_data_.include_name = !this->scan_response_; + this->advertising_data_.include_txpower = !this->scan_response_; + err = esp_ble_gap_config_adv_data(&this->advertising_data_); + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_ble_gap_config_adv_data failed (Advertising): %d", err); + return; + } + + memcpy(&this->scan_response_data_, &this->advertising_data_, sizeof(esp_ble_adv_data_t)); + this->scan_response_data_.set_scan_rsp = true; + this->scan_response_data_.include_name = true; + this->scan_response_data_.include_txpower = true; + this->scan_response_data_.appearance = 0; + this->scan_response_data_.flag = 0; + err = esp_ble_gap_config_adv_data(&this->scan_response_data_); + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_ble_gap_config_adv_data failed (Scan response): %d", err); + return; + } + + if (this->advertising_data_.service_uuid_len > 0) { + delete[] this->advertising_data_.p_service_uuid; + this->advertising_data_.p_service_uuid = nullptr; + } + + err = esp_ble_gap_start_advertising(&this->advertising_params_); + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_ble_gap_start_advertising failed: %d", err); + return; + } +} + +void BLEAdvertising::stop() { + esp_err_t err = esp_ble_gap_stop_advertising(); + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_ble_gap_stop_advertising failed: %d", err); + return; + } +} + +} // namespace esp32_ble +} // namespace esphome + +#endif diff --git a/esphome/components/esp32_ble/ble_advertising.h b/esphome/components/esp32_ble/ble_advertising.h new file mode 100644 index 0000000000..405edbf482 --- /dev/null +++ b/esphome/components/esp32_ble/ble_advertising.h @@ -0,0 +1,37 @@ +#pragma once + +#include + +#ifdef ARDUINO_ARCH_ESP32 + +#include +#include + +namespace esphome { +namespace esp32_ble { + +class ESPBTUUID; + +class BLEAdvertising { + public: + BLEAdvertising(); + + void add_service_uuid(ESPBTUUID uuid); + void set_scan_response(bool scan_response) { this->scan_response_ = scan_response; } + void set_min_preferred_interval(uint16_t interval) { this->advertising_data_.min_interval = interval; } + + void start(); + void stop(); + + protected: + bool scan_response_; + esp_ble_adv_data_t advertising_data_; + esp_ble_adv_data_t scan_response_data_; + esp_ble_adv_params_t advertising_params_; + std::vector advertising_uuids_; +}; + +} // namespace esp32_ble +} // namespace esphome + +#endif diff --git a/esphome/components/esp32_ble/ble_characteristic.cpp b/esphome/components/esp32_ble/ble_characteristic.cpp new file mode 100644 index 0000000000..cee15ce6a8 --- /dev/null +++ b/esphome/components/esp32_ble/ble_characteristic.cpp @@ -0,0 +1,280 @@ +#include "ble_characteristic.h" +#include "ble_server.h" +#include "ble_service.h" + +#include "esphome/core/log.h" + +#ifdef ARDUINO_ARCH_ESP32 + +namespace esphome { +namespace esp32_ble { + +static const char *TAG = "esp32_ble.characteristic"; + +BLECharacteristic::BLECharacteristic(const ESPBTUUID uuid, uint32_t properties) : uuid_(uuid) { + this->set_value_lock_ = xSemaphoreCreateBinary(); + this->create_lock_ = xSemaphoreCreateBinary(); + + xSemaphoreGive(this->set_value_lock_); + xSemaphoreGive(this->create_lock_); + this->properties_ = (esp_gatt_char_prop_t) 0; + + this->set_broadcast_property((properties & PROPERTY_BROADCAST) != 0); + this->set_indicate_property((properties & PROPERTY_INDICATE) != 0); + this->set_notify_property((properties & PROPERTY_NOTIFY) != 0); + this->set_read_property((properties & PROPERTY_READ) != 0); + this->set_write_property((properties & PROPERTY_WRITE) != 0); + this->set_write_no_response_property((properties & PROPERTY_WRITE_NR) != 0); +} + +void BLECharacteristic::set_value(std::vector value) { + xSemaphoreTake(this->set_value_lock_, 0L); + this->value_ = value; + xSemaphoreGive(this->set_value_lock_); +} +void BLECharacteristic::set_value(std::string value) { + this->set_value(std::vector(value.begin(), value.end())); +} +void BLECharacteristic::set_value(uint8_t *data, size_t length) { + this->set_value(std::vector(data, data + length)); +} +void BLECharacteristic::set_value(uint8_t &data) { + uint8_t temp[1]; + temp[0] = data; + this->set_value(temp, 1); +} +void BLECharacteristic::set_value(uint16_t &data) { + uint8_t temp[2]; + temp[0] = data; + temp[1] = data >> 8; + this->set_value(temp, 2); +} +void BLECharacteristic::set_value(uint32_t &data) { + uint8_t temp[4]; + temp[0] = data; + temp[1] = data >> 8; + temp[2] = data >> 16; + temp[3] = data >> 24; + this->set_value(temp, 4); +} +void BLECharacteristic::set_value(int &data) { + uint8_t temp[4]; + temp[0] = data; + temp[1] = data >> 8; + temp[2] = data >> 16; + temp[3] = data >> 24; + this->set_value(temp, 4); +} +void BLECharacteristic::set_value(float &data) { + float temp = data; + this->set_value((uint8_t *) &temp, 4); +} +void BLECharacteristic::set_value(double &data) { + double temp = data; + this->set_value((uint8_t *) &temp, 8); +} +void BLECharacteristic::set_value(bool &data) { + uint8_t temp[1]; + temp[0] = data; + this->set_value(temp, 1); +} + +void BLECharacteristic::notify(bool notification) { + if (!notification) { + ESP_LOGW(TAG, "notification=false is not yet supported"); + // TODO: Handle when notification=false + } + if (this->service_->get_server()->get_connected_client_count() == 0) + return; + + for (auto &client : this->service_->get_server()->get_clients()) { + size_t length = this->value_.size(); + esp_err_t err = esp_ble_gatts_send_indicate(this->service_->get_server()->get_gatts_if(), client.first, + this->handle_, length, this->value_.data(), false); + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_ble_gatts_send_indicate failed %d", err); + return; + } + } +} + +void BLECharacteristic::add_descriptor(BLEDescriptor *descriptor) { this->descriptors_.push_back(descriptor); } + +bool BLECharacteristic::do_create(BLEService *service) { + this->service_ = service; + esp_attr_control_t control; + control.auto_rsp = ESP_GATT_RSP_BY_APP; + + xSemaphoreTake(this->create_lock_, SEMAPHORE_MAX_DELAY); + ESP_LOGV(TAG, "Creating characteristic - %s", this->uuid_.to_string().c_str()); + + esp_bt_uuid_t uuid = this->uuid_.get_uuid(); + esp_err_t err = esp_ble_gatts_add_char(service->get_handle(), &uuid, static_cast(this->permissions_), + this->properties_, nullptr, &control); + + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_ble_gatts_add_char failed: %d", err); + return false; + } + + xSemaphoreWait(this->create_lock_, SEMAPHORE_MAX_DELAY); + + for (auto *descriptor : this->descriptors_) { + descriptor->do_create(this); + } + return true; +} + +void BLECharacteristic::set_broadcast_property(bool value) { + if (value) + this->properties_ = (esp_gatt_char_prop_t)(this->properties_ | ESP_GATT_CHAR_PROP_BIT_BROADCAST); + else + this->properties_ = (esp_gatt_char_prop_t)(this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_BROADCAST); +} +void BLECharacteristic::set_indicate_property(bool value) { + if (value) + this->properties_ = (esp_gatt_char_prop_t)(this->properties_ | ESP_GATT_CHAR_PROP_BIT_INDICATE); + else + this->properties_ = (esp_gatt_char_prop_t)(this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_INDICATE); +} +void BLECharacteristic::set_notify_property(bool value) { + if (value) + this->properties_ = (esp_gatt_char_prop_t)(this->properties_ | ESP_GATT_CHAR_PROP_BIT_NOTIFY); + else + this->properties_ = (esp_gatt_char_prop_t)(this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_NOTIFY); +} +void BLECharacteristic::set_read_property(bool value) { + if (value) + this->properties_ = (esp_gatt_char_prop_t)(this->properties_ | ESP_GATT_CHAR_PROP_BIT_READ); + else + this->properties_ = (esp_gatt_char_prop_t)(this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_READ); +} +void BLECharacteristic::set_write_property(bool value) { + if (value) + this->properties_ = (esp_gatt_char_prop_t)(this->properties_ | ESP_GATT_CHAR_PROP_BIT_WRITE); + else + this->properties_ = (esp_gatt_char_prop_t)(this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_WRITE); +} +void BLECharacteristic::set_write_no_response_property(bool value) { + if (value) + this->properties_ = (esp_gatt_char_prop_t)(this->properties_ | ESP_GATT_CHAR_PROP_BIT_WRITE_NR); + else + this->properties_ = (esp_gatt_char_prop_t)(this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_WRITE_NR); +} + +void BLECharacteristic::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, + esp_ble_gatts_cb_param_t *param) { + switch (event) { + case ESP_GATTS_ADD_CHAR_EVT: { + if (this->uuid_ == ESPBTUUID::from_uuid(param->add_char.char_uuid)) { + this->handle_ = param->add_char.attr_handle; + xSemaphoreGive(this->create_lock_); + } + break; + } + case ESP_GATTS_READ_EVT: { + if (param->read.handle != this->handle_) + break; // Not this characteristic + + if (!param->read.need_rsp) + break; // For some reason you can request a read but not want a response + + uint16_t max_offset = 22; + + esp_gatt_rsp_t response; + if (param->read.is_long) { + if (this->value_.size() - this->value_read_offset_ < max_offset) { + // Last message in the chain + response.attr_value.len = this->value_.size() - this->value_read_offset_; + response.attr_value.offset = this->value_read_offset_; + memcpy(response.attr_value.value, this->value_.data() + response.attr_value.offset, response.attr_value.len); + this->value_read_offset_ = 0; + } else { + response.attr_value.len = max_offset; + response.attr_value.offset = this->value_read_offset_; + memcpy(response.attr_value.value, this->value_.data() + response.attr_value.offset, response.attr_value.len); + this->value_read_offset_ += max_offset; + } + } else { + response.attr_value.offset = 0; + if (this->value_.size() + 1 > max_offset) { + response.attr_value.len = max_offset; + this->value_read_offset_ = max_offset; + } else { + response.attr_value.len = this->value_.size(); + } + memcpy(response.attr_value.value, this->value_.data(), response.attr_value.len); + } + + response.attr_value.handle = this->handle_; + response.attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE; + + esp_err_t err = + esp_ble_gatts_send_response(gatts_if, param->read.conn_id, param->read.trans_id, ESP_GATT_OK, &response); + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_ble_gatts_send_response failed: %d", err); + } + break; + } + case ESP_GATTS_WRITE_EVT: { + if (this->handle_ != param->write.handle) + return; + + if (param->write.is_prep) { + this->value_.insert(this->value_.end(), param->write.value, param->write.value + param->write.len); + this->write_event_ = true; + } else { + this->set_value(param->write.value, param->write.len); + } + + if (param->write.need_rsp) { + esp_gatt_rsp_t response; + + response.attr_value.len = param->write.len; + response.attr_value.handle = this->handle_; + response.attr_value.offset = param->write.offset; + response.attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE; + memcpy(response.attr_value.value, param->write.value, param->write.len); + + esp_err_t err = + esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, &response); + + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_ble_gatts_send_response failed: %d", err); + } + } + + if (!param->write.is_prep) { + this->on_write_(this->value_); + } + + break; + } + + case ESP_GATTS_EXEC_WRITE_EVT: { + if (!this->write_event_) + break; + this->write_event_ = false; + if (param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC) { + this->on_write_(this->value_); + } + esp_err_t err = + esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, nullptr); + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_ble_gatts_send_response failed: %d", err); + } + break; + } + default: + break; + } + + for (auto *descriptor : this->descriptors_) { + descriptor->gatts_event_handler(event, gatts_if, param); + } +} + +} // namespace esp32_ble +} // namespace esphome + +#endif diff --git a/esphome/components/esp32_ble/ble_characteristic.h b/esphome/components/esp32_ble/ble_characteristic.h new file mode 100644 index 0000000000..b181b98e8c --- /dev/null +++ b/esphome/components/esp32_ble/ble_characteristic.h @@ -0,0 +1,85 @@ +#pragma once + +#include + +#include "ble_uuid.h" +#include "ble_descriptor.h" + +#ifdef ARDUINO_ARCH_ESP32 + +#include +#include +#include +#include +#include + +namespace esphome { +namespace esp32_ble { + +class BLEService; + +class BLECharacteristic { + public: + BLECharacteristic(const ESPBTUUID uuid, uint32_t properties); + + void set_value(uint8_t *data, size_t length); + void set_value(std::vector value); + void set_value(std::string value); + void set_value(uint8_t &data); + void set_value(uint16_t &data); + void set_value(uint32_t &data); + void set_value(int &data); + void set_value(float &data); + void set_value(double &data); + void set_value(bool &data); + + void set_broadcast_property(bool value); + void set_indicate_property(bool value); + void set_notify_property(bool value); + void set_read_property(bool value); + void set_write_property(bool value); + void set_write_no_response_property(bool value); + + void notify(bool notification = true); + + bool do_create(BLEService *service); + void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param); + + void on_write(const std::function &)> &func) { this->on_write_ = func; } + + void add_descriptor(BLEDescriptor *descriptor); + + BLEService *get_service() { return this->service_; } + ESPBTUUID get_uuid() { return this->uuid_; } + std::vector &get_value() { return this->value_; } + + static const uint32_t PROPERTY_READ = 1 << 0; + static const uint32_t PROPERTY_WRITE = 1 << 1; + static const uint32_t PROPERTY_NOTIFY = 1 << 2; + static const uint32_t PROPERTY_BROADCAST = 1 << 3; + static const uint32_t PROPERTY_INDICATE = 1 << 4; + static const uint32_t PROPERTY_WRITE_NR = 1 << 5; + + protected: + bool write_event_{false}; + BLEService *service_; + ESPBTUUID uuid_; + esp_gatt_char_prop_t properties_; + uint16_t handle_{0xFFFF}; + + uint16_t value_read_offset_{0}; + std::vector value_; + SemaphoreHandle_t set_value_lock_; + SemaphoreHandle_t create_lock_; + + std::vector descriptors_; + + std::function &)> on_write_; + + esp_gatt_perm_t permissions_ = ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE; +}; + +} // namespace esp32_ble +} // namespace esphome + +#endif diff --git a/esphome/components/esp32_ble/ble_descriptor.cpp b/esphome/components/esp32_ble/ble_descriptor.cpp new file mode 100644 index 0000000000..a6cf4c707e --- /dev/null +++ b/esphome/components/esp32_ble/ble_descriptor.cpp @@ -0,0 +1,82 @@ +#include "ble_descriptor.h" +#include "ble_characteristic.h" +#include "ble_service.h" + +#include "esphome/core/log.h" + +#ifdef ARDUINO_ARCH_ESP32 + +namespace esphome { +namespace esp32_ble { + +static const char *TAG = "esp32_ble.descriptor"; + +BLEDescriptor::BLEDescriptor(ESPBTUUID uuid, uint16_t max_len) { + this->uuid_ = uuid; + this->value_.attr_len = 0; + this->value_.attr_max_len = max_len; + this->value_.attr_value = (uint8_t *) malloc(max_len); + + this->create_lock_ = xSemaphoreCreateBinary(); + xSemaphoreGive(this->create_lock_); +} + +BLEDescriptor::~BLEDescriptor() { free(this->value_.attr_value); } + +bool BLEDescriptor::do_create(BLECharacteristic *characteristic) { + this->characteristic_ = characteristic; + esp_attr_control_t control; + control.auto_rsp = ESP_GATT_AUTO_RSP; + + xSemaphoreTake(this->create_lock_, SEMAPHORE_MAX_DELAY); + ESP_LOGV(TAG, "Creating descriptor - %s", this->uuid_.to_string().c_str()); + esp_bt_uuid_t uuid = this->uuid_.get_uuid(); + esp_err_t err = esp_ble_gatts_add_char_descr(this->characteristic_->get_service()->get_handle(), &uuid, + this->permissions_, &this->value_, &control); + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_ble_gatts_add_char_descr failed: %d", err); + return false; + } + xSemaphoreWait(this->create_lock_, SEMAPHORE_MAX_DELAY); + + return true; +} + +void BLEDescriptor::set_value(const std::string value) { this->set_value((uint8_t *) value.data(), value.length()); } +void BLEDescriptor::set_value(uint8_t *data, size_t length) { + if (length > this->value_.attr_max_len) { + ESP_LOGE(TAG, "Size %d too large, must be no bigger than %d", length, this->value_.attr_max_len); + return; + } + this->value_.attr_len = length; + memcpy(this->value_.attr_value, data, length); +} + +void BLEDescriptor::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, + esp_ble_gatts_cb_param_t *param) { + switch (event) { + case ESP_GATTS_ADD_CHAR_DESCR_EVT: { + if (this->characteristic_ != nullptr && this->uuid_ == ESPBTUUID::from_uuid(param->add_char_descr.descr_uuid) && + this->characteristic_->get_service()->get_handle() == param->add_char_descr.service_handle && + this->characteristic_ == this->characteristic_->get_service()->get_last_created_characteristic()) { + this->handle_ = param->add_char_descr.attr_handle; + xSemaphoreGive(this->create_lock_); + } + break; + } + case ESP_GATTS_WRITE_EVT: { + if (this->handle_ == param->write.handle) { + this->value_.attr_len = param->write.len; + memcpy(this->value_.attr_value, param->write.value, param->write.len); + } + break; + } + default: + break; + } +} + +} // namespace esp32_ble +} // namespace esphome + +#endif diff --git a/esphome/components/esp32_ble/ble_descriptor.h b/esphome/components/esp32_ble/ble_descriptor.h new file mode 100644 index 0000000000..a0f92dc929 --- /dev/null +++ b/esphome/components/esp32_ble/ble_descriptor.h @@ -0,0 +1,40 @@ +#pragma once + +#include "ble_uuid.h" + +#ifdef ARDUINO_ARCH_ESP32 + +#include +#include + +namespace esphome { +namespace esp32_ble { + +class BLECharacteristic; + +class BLEDescriptor { + public: + BLEDescriptor(ESPBTUUID uuid, uint16_t max_len = 100); + virtual ~BLEDescriptor(); + bool do_create(BLECharacteristic *characteristic); + + void set_value(const std::string value); + void set_value(uint8_t *data, size_t length); + + void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param); + + protected: + BLECharacteristic *characteristic_{nullptr}; + ESPBTUUID uuid_; + uint16_t handle_{0xFFFF}; + SemaphoreHandle_t create_lock_; + + esp_attr_value_t value_; + + esp_gatt_perm_t permissions_ = ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE; +}; + +} // namespace esp32_ble +} // namespace esphome + +#endif diff --git a/esphome/components/esp32_ble/ble_server.cpp b/esphome/components/esp32_ble/ble_server.cpp new file mode 100644 index 0000000000..0b0105cd4d --- /dev/null +++ b/esphome/components/esp32_ble/ble_server.cpp @@ -0,0 +1,158 @@ +#include "ble_server.h" +#include "ble.h" +#include "esphome/core/log.h" +#include "esphome/core/application.h" +#include "esphome/core/version.h" + +#ifdef ARDUINO_ARCH_ESP32 + +#include +#include +#include +#include +#include +#include + +namespace esphome { +namespace esp32_ble { + +static const char *TAG = "esp32_ble.server"; + +static const uint16_t DEVICE_INFORMATION_SERVICE_UUID = 0x180A; +static const uint16_t MODEL_UUID = 0x2A24; +static const uint16_t VERSION_UUID = 0x2A26; +static const uint16_t MANUFACTURER_UUID = 0x2A29; + +void BLEServer::setup() { + if (this->is_failed()) { + ESP_LOGE(TAG, "BLE Server was marked failed by ESP32BLE"); + return; + } + + ESP_LOGD(TAG, "Setting up BLE Server..."); + + global_ble_server = this; + this->register_lock_ = xSemaphoreCreateBinary(); + xSemaphoreGive(this->register_lock_); + this->advertising_ = new BLEAdvertising(); + + this->setup_server_(); + + for (auto *component : this->service_components_) { + component->setup_service(); + } + + ESP_LOGD(TAG, "BLE Server set up complete..."); +} + +void BLEServer::setup_server_() { + xSemaphoreTake(this->register_lock_, SEMAPHORE_MAX_DELAY); + esp_err_t err = esp_ble_gatts_app_register(0); + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_ble_gatts_app_register failed: %d", err); + this->mark_failed(); + return; + } + xSemaphoreWait(this->register_lock_, SEMAPHORE_MAX_DELAY); + + this->device_information_service = this->create_service(DEVICE_INFORMATION_SERVICE_UUID); + + this->create_device_characteristics_(); + + this->advertising_->set_scan_response(true); + this->advertising_->set_min_preferred_interval(0x06); + this->advertising_->start(); + + this->device_information_service->start(); +} + +bool BLEServer::create_device_characteristics_() { + if (this->model_.has_value()) { + BLECharacteristic *model = + this->device_information_service->create_characteristic(MODEL_UUID, BLECharacteristic::PROPERTY_READ); + model->set_value(this->model_.value()); + } else { +#ifdef ARDUINO_BOARD + BLECharacteristic *model = + this->device_information_service->create_characteristic(MODEL_UUID, BLECharacteristic::PROPERTY_READ); + model->set_value(ARDUINO_BOARD); +#endif + } + + BLECharacteristic *version = + this->device_information_service->create_characteristic(VERSION_UUID, BLECharacteristic::PROPERTY_READ); + version->set_value("ESPHome " ESPHOME_VERSION); + + BLECharacteristic *manufacturer = + this->device_information_service->create_characteristic(MANUFACTURER_UUID, BLECharacteristic::PROPERTY_READ); + manufacturer->set_value(this->manufacturer_); + + return true; +} + +BLEService *BLEServer::create_service(const uint8_t *uuid, bool advertise) { + return this->create_service(ESPBTUUID::from_raw(uuid), advertise); +} +BLEService *BLEServer::create_service(uint16_t uuid, bool advertise) { + return this->create_service(ESPBTUUID::from_uint16(uuid), advertise); +} +BLEService *BLEServer::create_service(const std::string uuid, bool advertise) { + return this->create_service(ESPBTUUID::from_raw(uuid), advertise); +} +BLEService *BLEServer::create_service(ESPBTUUID uuid, bool advertise, uint16_t num_handles, uint8_t inst_id) { + ESP_LOGV(TAG, "Creating service - %s", uuid.to_string().c_str()); + BLEService *service = new BLEService(uuid, num_handles, inst_id); + this->services_.push_back(service); + if (advertise) { + this->advertising_->add_service_uuid(uuid); + } + service->do_create(this); + return service; +} + +void BLEServer::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, + esp_ble_gatts_cb_param_t *param) { + switch (event) { + case ESP_GATTS_CONNECT_EVT: { + ESP_LOGD(TAG, "BLE Client connected"); + this->add_client_(param->connect.conn_id, (void *) this); + this->connected_clients_++; + for (auto *component : this->service_components_) { + component->on_client_connect(); + } + break; + } + case ESP_GATTS_DISCONNECT_EVT: { + ESP_LOGD(TAG, "BLE Client disconnected"); + if (this->remove_client_(param->disconnect.conn_id)) + this->connected_clients_--; + this->advertising_->start(); + for (auto *component : this->service_components_) { + component->on_client_disconnect(); + } + break; + } + case ESP_GATTS_REG_EVT: { + this->gatts_if_ = gatts_if; + xSemaphoreGive(this->register_lock_); + break; + } + default: + break; + } + + for (auto *service : this->services_) { + service->gatts_event_handler(event, gatts_if, param); + } +} + +float BLEServer::get_setup_priority() const { return setup_priority::BLUETOOTH - 10; } + +void BLEServer::dump_config() { ESP_LOGCONFIG(TAG, "ESP32 BLE Server:"); } + +BLEServer *global_ble_server = nullptr; + +} // namespace esp32_ble +} // namespace esphome + +#endif diff --git a/esphome/components/esp32_ble/ble_server.h b/esphome/components/esp32_ble/ble_server.h new file mode 100644 index 0000000000..b6e3f203ed --- /dev/null +++ b/esphome/components/esp32_ble/ble_server.h @@ -0,0 +1,84 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/helpers.h" +#include "esphome/core/preferences.h" +#include "ble_service.h" +#include "ble_characteristic.h" +#include "ble_uuid.h" +#include "ble_advertising.h" +#include + +#include "queue.h" + +#ifdef ARDUINO_ARCH_ESP32 + +#include +#include + +namespace esphome { +namespace esp32_ble { + +class BLEServiceComponent { + public: + virtual void setup_service(); + virtual void on_client_connect(){}; + virtual void on_client_disconnect(){}; +}; + +class BLEServer : public Component { + public: + void setup() override; + void dump_config() override; + float get_setup_priority() const override; + + void teardown(); + + void set_manufacturer(const std::string manufacturer) { this->manufacturer_ = manufacturer; } + void set_model(const std::string model) { this->model_ = model; } + + BLEService *create_service(const uint8_t *uuid, bool advertise = false); + BLEService *create_service(uint16_t uuid, bool advertise = false); + BLEService *create_service(const std::string uuid, bool advertise = false); + BLEService *create_service(ESPBTUUID uuid, bool advertise = false, uint16_t num_handles = 15, uint8_t inst_id = 0); + + esp_gatt_if_t get_gatts_if() { return this->gatts_if_; } + uint32_t get_connected_client_count() { return this->connected_clients_; } + std::map get_clients() { return this->clients_; } + BLEAdvertising *get_advertising() { return this->advertising_; } + + void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param); + + void register_service_component(BLEServiceComponent *component) { this->service_components_.push_back(component); } + + protected: + bool create_device_characteristics_(); + void setup_server_(); + + void add_client_(uint16_t conn_id, void *client) { + this->clients_.insert(std::pair(conn_id, client)); + } + bool remove_client_(uint16_t conn_id) { return this->clients_.erase(conn_id) > 0; } + + std::string manufacturer_; + optional model_; + esp_gatt_if_t gatts_if_{0}; + BLEAdvertising *advertising_; + + uint32_t connected_clients_{0}; + std::map clients_; + + std::vector services_; + BLEService *device_information_service; + + std::vector service_components_; + + SemaphoreHandle_t register_lock_; +}; + +extern BLEServer *global_ble_server; + +} // namespace esp32_ble +} // namespace esphome + +#endif diff --git a/esphome/components/esp32_ble/ble_service.cpp b/esphome/components/esp32_ble/ble_service.cpp new file mode 100644 index 0000000000..9f837175ed --- /dev/null +++ b/esphome/components/esp32_ble/ble_service.cpp @@ -0,0 +1,129 @@ +#include "ble_service.h" +#include "ble_server.h" +#include "esphome/core/log.h" + +#ifdef ARDUINO_ARCH_ESP32 + +namespace esphome { +namespace esp32_ble { + +static const char *TAG = "esp32_ble.service"; + +BLEService::BLEService(ESPBTUUID uuid, uint16_t num_handles, uint8_t inst_id) + : uuid_(uuid), num_handles_(num_handles), inst_id_(inst_id) { + this->create_lock_ = xSemaphoreCreateBinary(); + this->start_lock_ = xSemaphoreCreateBinary(); + this->stop_lock_ = xSemaphoreCreateBinary(); + + xSemaphoreGive(this->create_lock_); + xSemaphoreGive(this->start_lock_); + xSemaphoreGive(this->stop_lock_); +} + +BLEService::~BLEService() { + for (auto &chr : this->characteristics_) + delete chr; +} + +BLECharacteristic *BLEService::get_characteristic(ESPBTUUID uuid) { + for (auto *chr : this->characteristics_) + if (chr->get_uuid() == uuid) + return chr; + return nullptr; +} + +BLECharacteristic *BLEService::get_characteristic(uint16_t uuid) { + return this->get_characteristic(ESPBTUUID::from_uint16(uuid)); +} +BLECharacteristic *BLEService::create_characteristic(uint16_t uuid, esp_gatt_char_prop_t properties) { + return create_characteristic(ESPBTUUID::from_uint16(uuid), properties); +} +BLECharacteristic *BLEService::create_characteristic(const std::string uuid, esp_gatt_char_prop_t properties) { + return create_characteristic(ESPBTUUID::from_raw(uuid), properties); +} +BLECharacteristic *BLEService::create_characteristic(ESPBTUUID uuid, esp_gatt_char_prop_t properties) { + BLECharacteristic *characteristic = new BLECharacteristic(uuid, properties); + this->characteristics_.push_back(characteristic); + return characteristic; +} + +bool BLEService::do_create(BLEServer *server) { + this->server_ = server; + + xSemaphoreTake(this->create_lock_, SEMAPHORE_MAX_DELAY); + esp_gatt_srvc_id_t srvc_id; + srvc_id.is_primary = true; + srvc_id.id.inst_id = this->inst_id_; + srvc_id.id.uuid = this->uuid_.get_uuid(); + + esp_err_t err = esp_ble_gatts_create_service(server->get_gatts_if(), &srvc_id, this->num_handles_); + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_ble_gatts_create_service failed: %d", err); + return false; + } + xSemaphoreWait(this->create_lock_, SEMAPHORE_MAX_DELAY); + + return true; +} + +void BLEService::start() { + for (auto *characteristic : this->characteristics_) { + this->last_created_characteristic_ = characteristic; + characteristic->do_create(this); + } + + xSemaphoreTake(this->start_lock_, SEMAPHORE_MAX_DELAY); + esp_err_t err = esp_ble_gatts_start_service(this->handle_); + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_ble_gatts_start_service failed: %d", err); + return; + } + xSemaphoreWait(this->start_lock_, SEMAPHORE_MAX_DELAY); +} + +void BLEService::stop() { + xSemaphoreTake(this->stop_lock_, SEMAPHORE_MAX_DELAY); + esp_err_t err = esp_ble_gatts_stop_service(this->handle_); + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_ble_gatts_stop_service failed: %d", err); + return; + } + xSemaphoreWait(this->stop_lock_, SEMAPHORE_MAX_DELAY); +} + +void BLEService::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, + esp_ble_gatts_cb_param_t *param) { + switch (event) { + case ESP_GATTS_CREATE_EVT: { + if (this->uuid_ == ESPBTUUID::from_uuid(param->create.service_id.id.uuid) && + this->inst_id_ == param->create.service_id.id.inst_id) { + this->handle_ = param->create.service_handle; + xSemaphoreGive(this->create_lock_); + } + break; + } + case ESP_GATTS_START_EVT: { + if (param->start.service_handle == this->handle_) { + xSemaphoreGive(this->start_lock_); + } + break; + } + case ESP_GATTS_STOP_EVT: { + if (param->start.service_handle == this->handle_) { + xSemaphoreGive(this->stop_lock_); + } + break; + } + default: + break; + } + + for (auto *characteristic : this->characteristics_) { + characteristic->gatts_event_handler(event, gatts_if, param); + } +} + +} // namespace esp32_ble +} // namespace esphome + +#endif diff --git a/esphome/components/esp32_ble/ble_service.h b/esphome/components/esp32_ble/ble_service.h new file mode 100644 index 0000000000..c87415be13 --- /dev/null +++ b/esphome/components/esp32_ble/ble_service.h @@ -0,0 +1,61 @@ +#pragma once + +#include "ble_uuid.h" +#include "ble_characteristic.h" + +#ifdef ARDUINO_ARCH_ESP32 + +#include +#include +#include +#include +#include + +namespace esphome { +namespace esp32_ble { + +class BLEServer; + +class BLEService { + public: + BLEService(ESPBTUUID uuid, uint16_t num_handles, uint8_t inst_id); + ~BLEService(); + BLECharacteristic *get_characteristic(ESPBTUUID uuid); + BLECharacteristic *get_characteristic(uint16_t uuid); + + BLECharacteristic *create_characteristic(const std::string uuid, esp_gatt_char_prop_t properties); + BLECharacteristic *create_characteristic(uint16_t uuid, esp_gatt_char_prop_t properties); + BLECharacteristic *create_characteristic(ESPBTUUID uuid, esp_gatt_char_prop_t properties); + + ESPBTUUID get_uuid() { return this->uuid_; } + BLECharacteristic *get_last_created_characteristic() { return this->last_created_characteristic_; } + uint16_t get_handle() { return this->handle_; } + + BLEServer *get_server() { return this->server_; } + + bool do_create(BLEServer *server); + void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param); + + void start(); + void stop(); + + protected: + bool errored_{false}; + + std::vector characteristics_; + BLECharacteristic *last_created_characteristic_{nullptr}; + BLEServer *server_; + ESPBTUUID uuid_; + uint16_t num_handles_; + uint16_t handle_{0xFFFF}; + uint8_t inst_id_; + + SemaphoreHandle_t create_lock_; + SemaphoreHandle_t start_lock_; + SemaphoreHandle_t stop_lock_; +}; + +} // namespace esp32_ble +} // namespace esphome + +#endif diff --git a/esphome/components/esp32_ble/ble_uuid.cpp b/esphome/components/esp32_ble/ble_uuid.cpp new file mode 100644 index 0000000000..63633e2c43 --- /dev/null +++ b/esphome/components/esp32_ble/ble_uuid.cpp @@ -0,0 +1,184 @@ +#include "ble_uuid.h" + +#ifdef ARDUINO_ARCH_ESP32 + +namespace esphome { +namespace esp32_ble { + +ESPBTUUID::ESPBTUUID() : uuid_() {} +ESPBTUUID ESPBTUUID::from_uint16(uint16_t uuid) { + ESPBTUUID ret; + ret.uuid_.len = ESP_UUID_LEN_16; + ret.uuid_.uuid.uuid16 = uuid; + return ret; +} +ESPBTUUID ESPBTUUID::from_uint32(uint32_t uuid) { + ESPBTUUID ret; + ret.uuid_.len = ESP_UUID_LEN_32; + ret.uuid_.uuid.uuid32 = uuid; + return ret; +} +ESPBTUUID ESPBTUUID::from_raw(const uint8_t *data) { + ESPBTUUID ret; + ret.uuid_.len = ESP_UUID_LEN_128; + for (size_t i = 0; i < ESP_UUID_LEN_128; i++) + ret.uuid_.uuid.uuid128[i] = data[i]; + return ret; +} +ESPBTUUID ESPBTUUID::from_raw(const std::string data) { + ESPBTUUID ret; + if (data.length() == 4) { + ret.uuid_.len = ESP_UUID_LEN_16; + ret.uuid_.uuid.uuid16 = 0; + for (int i = 0; i < data.length();) { + uint8_t MSB = data.c_str()[i]; + uint8_t LSB = data.c_str()[i + 1]; + + if (MSB > '9') + MSB -= 7; + if (LSB > '9') + LSB -= 7; + ret.uuid_.uuid.uuid16 += (((MSB & 0x0F) << 4) | (LSB & 0x0F)) << (2 - i) * 4; + i += 2; + } + } else if (data.length() == 8) { + ret.uuid_.len = ESP_UUID_LEN_32; + ret.uuid_.uuid.uuid32 = 0; + for (int i = 0; i < data.length();) { + uint8_t MSB = data.c_str()[i]; + uint8_t LSB = data.c_str()[i + 1]; + + if (MSB > '9') + MSB -= 7; + if (LSB > '9') + LSB -= 7; + ret.uuid_.uuid.uuid32 += (((MSB & 0x0F) << 4) | (LSB & 0x0F)) << (6 - i) * 4; + i += 2; + } + } else if (data.length() == 16) { // how we can have 16 byte length string reprezenting 128 bit uuid??? needs to be + // investigated (lack of time) + ret.uuid_.len = ESP_UUID_LEN_128; + memcpy(ret.uuid_.uuid.uuid128, (uint8_t *) data.data(), 16); + } else if (data.length() == 36) { + // If the length of the string is 36 bytes then we will assume it is a long hex string in + // UUID format. + ret.uuid_.len = ESP_UUID_LEN_128; + int n = 0; + for (int i = 0; i < data.length();) { + if (data.c_str()[i] == '-') + i++; + uint8_t MSB = data.c_str()[i]; + uint8_t LSB = data.c_str()[i + 1]; + + if (MSB > '9') + MSB -= 7; + if (LSB > '9') + LSB -= 7; + ret.uuid_.uuid.uuid128[15 - n++] = ((MSB & 0x0F) << 4) | (LSB & 0x0F); + i += 2; + } + } else { + ESP_LOGE(TAG, "ERROR: UUID value not 2, 4, 16 or 36 bytes - %s", data.c_str()); + } + return ret; +} +ESPBTUUID ESPBTUUID::from_uuid(esp_bt_uuid_t uuid) { + ESPBTUUID ret; + ret.uuid_.len = uuid.len; + ret.uuid_.uuid.uuid16 = uuid.uuid.uuid16; + ret.uuid_.uuid.uuid32 = uuid.uuid.uuid32; + for (size_t i = 0; i < ESP_UUID_LEN_128; i++) + ret.uuid_.uuid.uuid128[i] = uuid.uuid.uuid128[i]; + return ret; +} +ESPBTUUID ESPBTUUID::as_128bit() const { + if (this->uuid_.len == ESP_UUID_LEN_128) { + return *this; + } + uint8_t data[] = {0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint32_t uuid32; + if (this->uuid_.len == ESP_UUID_LEN_32) { + uuid32 = this->uuid_.uuid.uuid32; + } else { + uuid32 = this->uuid_.uuid.uuid16; + } + for (uint8_t i = 0; i < this->uuid_.len; i++) { + data[12 + i] = ((uuid32 >> i * 8) & 0xFF); + } + return ESPBTUUID::from_raw(data); +} +bool ESPBTUUID::contains(uint8_t data1, uint8_t data2) const { + if (this->uuid_.len == ESP_UUID_LEN_16) { + return (this->uuid_.uuid.uuid16 >> 8) == data2 && (this->uuid_.uuid.uuid16 & 0xFF) == data1; + } else if (this->uuid_.len == ESP_UUID_LEN_32) { + for (uint8_t i = 0; i < 3; i++) { + bool a = ((this->uuid_.uuid.uuid32 >> i * 8) & 0xFF) == data1; + bool b = ((this->uuid_.uuid.uuid32 >> (i + 1) * 8) & 0xFF) == data2; + if (a && b) + return true; + } + } else { + for (uint8_t i = 0; i < 15; i++) { + if (this->uuid_.uuid.uuid128[i] == data1 && this->uuid_.uuid.uuid128[i + 1] == data2) + return true; + } + } + return false; +} +bool ESPBTUUID::operator==(const ESPBTUUID &uuid) const { + if (this->uuid_.len == uuid.uuid_.len) { + switch (this->uuid_.len) { + case ESP_UUID_LEN_16: + if (uuid.uuid_.uuid.uuid16 == this->uuid_.uuid.uuid16) { + return true; + } + break; + case ESP_UUID_LEN_32: + if (uuid.uuid_.uuid.uuid32 == this->uuid_.uuid.uuid32) { + return true; + } + break; + case ESP_UUID_LEN_128: + for (int i = 0; i < ESP_UUID_LEN_128; i++) { + if (uuid.uuid_.uuid.uuid128[i] != this->uuid_.uuid.uuid128[i]) { + return false; + } + } + return true; + break; + } + } else { + return this->as_128bit() == uuid.as_128bit(); + } + return false; +} +esp_bt_uuid_t ESPBTUUID::get_uuid() { return this->uuid_; } +std::string ESPBTUUID::to_string() { + char sbuf[64]; + switch (this->uuid_.len) { + case ESP_UUID_LEN_16: + sprintf(sbuf, "0x%02X%02X", this->uuid_.uuid.uuid16 >> 8, this->uuid_.uuid.uuid16 & 0xff); + break; + case ESP_UUID_LEN_32: + sprintf(sbuf, "0x%02X%02X%02X%02X", this->uuid_.uuid.uuid32 >> 24, (this->uuid_.uuid.uuid32 >> 16 & 0xff), + (this->uuid_.uuid.uuid32 >> 8 & 0xff), this->uuid_.uuid.uuid32 & 0xff); + break; + default: + case ESP_UUID_LEN_128: + char *bpos = sbuf; + for (int8_t i = 15; i >= 0; i--) { + sprintf(bpos, "%02X", this->uuid_.uuid.uuid128[i]); + bpos += 2; + if (i == 6 || i == 8 || i == 10 || i == 12) + sprintf(bpos++, "-"); + } + sbuf[47] = '\0'; + break; + } + return sbuf; +} + +} // namespace esp32_ble +} // namespace esphome + +#endif diff --git a/esphome/components/esp32_ble/ble_uuid.h b/esphome/components/esp32_ble/ble_uuid.h new file mode 100644 index 0000000000..96e9b126d4 --- /dev/null +++ b/esphome/components/esp32_ble/ble_uuid.h @@ -0,0 +1,45 @@ +#pragma once + +#include "esphome/core/helpers.h" + +#ifdef ARDUINO_ARCH_ESP32 + +#include +#include + +namespace esphome { +namespace esp32_ble { + +class ESPBTUUID { + public: + ESPBTUUID(); + + static ESPBTUUID from_uint16(uint16_t uuid); + + static ESPBTUUID from_uint32(uint32_t uuid); + + static ESPBTUUID from_raw(const uint8_t *data); + + static ESPBTUUID from_raw(const std::string data); + + static ESPBTUUID from_uuid(esp_bt_uuid_t uuid); + + ESPBTUUID as_128bit() const; + + bool contains(uint8_t data1, uint8_t data2) const; + + bool operator==(const ESPBTUUID &uuid) const; + bool operator!=(const ESPBTUUID &uuid) const { return !(*this == uuid); } + + esp_bt_uuid_t get_uuid(); + + std::string to_string(); + + protected: + esp_bt_uuid_t uuid_; +}; + +} // namespace esp32_ble +} // namespace esphome + +#endif diff --git a/esphome/components/esp32_ble/queue.h b/esphome/components/esp32_ble/queue.h new file mode 100644 index 0000000000..f5c861a917 --- /dev/null +++ b/esphome/components/esp32_ble/queue.h @@ -0,0 +1,114 @@ +#pragma once +#include "esphome/core/component.h" +#include "esphome/core/helpers.h" + +#include +#include + +#ifdef ARDUINO_ARCH_ESP32 + +#include +#include +#include + +/* + * BLE events come in from a separate Task (thread) in the ESP32 stack. Rather + * than trying to deal wth various locking strategies, all incoming GAP and GATT + * events will simply be placed on a semaphore guarded queue. The next time the + * component runs loop(), these events are popped off the queue and handed at + * this safer time. + */ + +namespace esphome { +namespace esp32_ble { + +template class Queue { + public: + Queue() { m = xSemaphoreCreateMutex(); } + + void push(T *element) { + if (element == nullptr) + return; + if (xSemaphoreTake(m, 5L / portTICK_PERIOD_MS)) { + q.push(element); + xSemaphoreGive(m); + } + } + + T *pop() { + T *element = nullptr; + + if (xSemaphoreTake(m, 5L / portTICK_PERIOD_MS)) { + if (!q.empty()) { + element = q.front(); + q.pop(); + } + xSemaphoreGive(m); + } + return element; + } + + protected: + std::queue q; + SemaphoreHandle_t m; +}; + +// Received GAP and GATTC events are only queued, and get processed in the main loop(). +// This class stores each event in a single type. +class BLEEvent { + public: + BLEEvent(esp_gap_ble_cb_event_t e, esp_ble_gap_cb_param_t *p) { + this->event_.gap.gap_event = e; + memcpy(&this->event_.gap.gap_param, p, sizeof(esp_ble_gap_cb_param_t)); + this->type_ = GAP; + }; + + BLEEvent(esp_gattc_cb_event_t e, esp_gatt_if_t i, esp_ble_gattc_cb_param_t *p) { + this->event_.gattc.gattc_event = e; + this->event_.gattc.gattc_if = i; + memcpy(&this->event_.gattc.gattc_param, p, sizeof(esp_ble_gattc_cb_param_t)); + // Need to also make a copy of notify event data. + if (e == ESP_GATTC_NOTIFY_EVT) { + memcpy(this->event_.gattc.notify_data, p->notify.value, p->notify.value_len); + this->event_.gattc.gattc_param.notify.value = this->event_.gattc.notify_data; + } + this->type_ = GATTC; + }; + + BLEEvent(esp_gatts_cb_event_t e, esp_gatt_if_t i, esp_ble_gatts_cb_param_t *p) { + this->event_.gatts.gatts_event = e; + this->event_.gatts.gatts_if = i; + memcpy(&this->event_.gatts.gatts_param, p, sizeof(esp_ble_gatts_cb_param_t)); + this->type_ = GATTS; + }; + + union { + struct gap_event { + esp_gap_ble_cb_event_t gap_event; + esp_ble_gap_cb_param_t gap_param; + } gap; + + struct gattc_event { + esp_gattc_cb_event_t gattc_event; + esp_gatt_if_t gattc_if; + esp_ble_gattc_cb_param_t gattc_param; + uint8_t notify_data[64]; + } gattc; + + struct gatts_event { + esp_gatts_cb_event_t gatts_event; + esp_gatt_if_t gatts_if; + esp_ble_gatts_cb_param_t gatts_param; + } gatts; + } event_; + enum ble_event_t : uint8_t { + GAP, + GATTC, + GATTS, + } type_; +}; + +} // namespace esp32_ble +} // namespace esphome + +#endif diff --git a/esphome/components/esp32_improv/__init__.py b/esphome/components/esp32_improv/__init__.py new file mode 100644 index 0000000000..8b91e9151d --- /dev/null +++ b/esphome/components/esp32_improv/__init__.py @@ -0,0 +1,69 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import binary_sensor, output, esp32_ble +from esphome.const import CONF_ID, ESP_PLATFORM_ESP32 + + +AUTO_LOAD = ["binary_sensor", "output", "improv"] +CODEOWNERS = ["@jesserockz"] +DEPENDENCIES = ["esp32_ble", "wifi"] +ESP_PLATFORMS = [ESP_PLATFORM_ESP32] + +CONF_AUTHORIZED_DURATION = "authorized_duration" +CONF_AUTHORIZER = "authorizer" +CONF_BLE_SERVER_ID = "ble_server_id" +CONF_IDENTIFY_DURATION = "identify_duration" +CONF_STATUS_INDICATOR = "status_indicator" +CONF_WIFI_TIMEOUT = "wifi_timeout" + +esp32_improv_ns = cg.esphome_ns.namespace("esp32_improv") +ESP32ImprovComponent = esp32_improv_ns.class_( + "ESP32ImprovComponent", cg.Component, esp32_ble.BLEServiceComponent +) + + +def validate_none_(value): + if value in ("none", "None"): + return None + if cv.boolean(value) is False: + return None + raise cv.Invalid("Must be none") + + +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(): cv.declare_id(ESP32ImprovComponent), + cv.GenerateID(CONF_BLE_SERVER_ID): cv.use_id(esp32_ble.BLEServer), + cv.Required(CONF_AUTHORIZER): cv.Any( + validate_none_, cv.use_id(binary_sensor.BinarySensor) + ), + cv.Optional(CONF_STATUS_INDICATOR): cv.use_id(output.BinaryOutput), + cv.Optional( + CONF_IDENTIFY_DURATION, default="10s" + ): cv.positive_time_period_milliseconds, + cv.Optional( + CONF_AUTHORIZED_DURATION, default="1min" + ): cv.positive_time_period_milliseconds, + } +).extend(cv.COMPONENT_SCHEMA) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + + ble_server = await cg.get_variable(config[CONF_BLE_SERVER_ID]) + cg.add(ble_server.register_service_component(var)) + + cg.add_define("USE_IMPROV") + + cg.add(var.set_identify_duration(config[CONF_IDENTIFY_DURATION])) + cg.add(var.set_authorized_duration(config[CONF_AUTHORIZED_DURATION])) + + if CONF_AUTHORIZER in config and config[CONF_AUTHORIZER] is not None: + activator = await cg.get_variable(config[CONF_AUTHORIZER]) + cg.add(var.set_authorizer(activator)) + + if CONF_STATUS_INDICATOR in config: + status_indicator = await cg.get_variable(config[CONF_STATUS_INDICATOR]) + cg.add(var.set_status_indicator(status_indicator)) diff --git a/esphome/components/esp32_improv/esp32_improv_component.cpp b/esphome/components/esp32_improv/esp32_improv_component.cpp new file mode 100644 index 0000000000..3fc5e6acf2 --- /dev/null +++ b/esphome/components/esp32_improv/esp32_improv_component.cpp @@ -0,0 +1,275 @@ +#include "esp32_improv_component.h" +#include "esphome/core/log.h" +#include "esphome/core/application.h" +#include "esphome/components/esp32_ble/ble_2902.h" + +#ifdef ARDUINO_ARCH_ESP32 + +namespace esphome { +namespace esp32_improv { + +static const char *TAG = "esp32_improv.component"; + +ESP32ImprovComponent::ESP32ImprovComponent() { global_improv_component = this; } + +void ESP32ImprovComponent::setup_service() { + this->service_ = esp32_ble::global_ble_server->create_service(improv::SERVICE_UUID, true); + + this->status_ = this->service_->create_characteristic( + improv::STATUS_UUID, esp32_ble::BLECharacteristic::PROPERTY_READ | esp32_ble::BLECharacteristic::PROPERTY_NOTIFY); + esp32_ble::BLEDescriptor *status_descriptor = new esp32_ble::BLE2902(); + this->status_->add_descriptor(status_descriptor); + + this->error_ = this->service_->create_characteristic( + improv::ERROR_UUID, esp32_ble::BLECharacteristic::PROPERTY_READ | esp32_ble::BLECharacteristic::PROPERTY_NOTIFY); + esp32_ble::BLEDescriptor *error_descriptor = new esp32_ble::BLE2902(); + this->error_->add_descriptor(error_descriptor); + + this->rpc_ = + this->service_->create_characteristic(improv::RPC_COMMAND_UUID, esp32_ble::BLECharacteristic::PROPERTY_WRITE); + this->rpc_->on_write([this](std::vector &data) { + if (data.size() > 0) { + this->incoming_data_.insert(this->incoming_data_.end(), data.begin(), data.end()); + } + }); + esp32_ble::BLEDescriptor *rpc_descriptor = new esp32_ble::BLE2902(); + this->rpc_->add_descriptor(rpc_descriptor); + + this->rpc_response_ = + this->service_->create_characteristic(improv::RPC_RESULT_UUID, esp32_ble::BLECharacteristic::PROPERTY_READ | + esp32_ble::BLECharacteristic::PROPERTY_NOTIFY); + esp32_ble::BLEDescriptor *rpc_response_descriptor = new esp32_ble::BLE2902(); + this->rpc_response_->add_descriptor(rpc_response_descriptor); + + this->capabilities_ = + this->service_->create_characteristic(improv::CAPABILITIES_UUID, esp32_ble::BLECharacteristic::PROPERTY_READ); + esp32_ble::BLEDescriptor *capabilities_descriptor = new esp32_ble::BLE2902(); + this->capabilities_->add_descriptor(capabilities_descriptor); + uint8_t capabilities = 0x00; + if (this->status_indicator_ != nullptr) + capabilities |= improv::CAPABILITY_IDENTIFY; + this->capabilities_->set_value(capabilities); + this->setup_complete_ = true; +} + +void ESP32ImprovComponent::loop() { + if (this->incoming_data_.size() > 0) + this->process_incoming_data_(); + uint32_t now = millis(); + + switch (this->state_) { + case improv::STATE_STOPPED: + if (this->status_indicator_ != nullptr) + this->status_indicator_->turn_off(); + + if (this->should_start_ && this->setup_complete_) { + ESP_LOGD(TAG, "Starting Improv service..."); + + this->service_->start(); + this->service_->get_server()->get_advertising()->start(); + + this->set_state_(improv::STATE_AWAITING_AUTHORIZATION); + this->set_error_(improv::ERROR_NONE); + this->should_start_ = false; + ESP_LOGD(TAG, "Service started!"); + } + break; + case improv::STATE_AWAITING_AUTHORIZATION: { + if (this->authorizer_ == nullptr || this->authorizer_->state) { + this->set_state_(improv::STATE_AUTHORIZED); + this->authorized_start_ = now; + } else { + if (this->status_indicator_ != nullptr) { + if (!this->check_identify_()) + this->status_indicator_->turn_on(); + } + } + break; + } + case improv::STATE_AUTHORIZED: { + if (this->authorizer_ != nullptr) { + if (now - this->authorized_start_ > this->authorized_duration_) { + ESP_LOGD(TAG, "Authorization timeout"); + this->set_state_(improv::STATE_AWAITING_AUTHORIZATION); + return; + } + } + if (this->status_indicator_ != nullptr) { + if (!this->check_identify_()) { + if ((now % 1000) < 500) { + this->status_indicator_->turn_on(); + } else { + this->status_indicator_->turn_off(); + } + } + } + break; + } + case improv::STATE_PROVISIONING: { + if (this->status_indicator_ != nullptr) { + if ((now % 200) < 100) { + this->status_indicator_->turn_on(); + } else { + this->status_indicator_->turn_off(); + } + } + if (wifi::global_wifi_component->is_connected()) { + wifi::global_wifi_component->save_wifi_sta(this->connecting_sta_.get_ssid(), + this->connecting_sta_.get_password()); + this->connecting_sta_ = {}; + this->cancel_timeout("wifi-connect-timeout"); + this->set_state_(improv::STATE_PROVISIONED); + + std::string url = "https://my.home-assistant.io/redirect/config_flow_start?domain=esphome"; + std::vector data = improv::build_rpc_response(improv::WIFI_SETTINGS, {url}); + this->send_response(data); + } + break; + } + case improv::STATE_PROVISIONED: { + this->incoming_data_.clear(); + if (this->status_indicator_ != nullptr) + this->status_indicator_->turn_on(); + break; + } + } +} + +bool ESP32ImprovComponent::check_identify_() { + uint32_t now = millis(); + + bool identify = this->identify_start_ != 0 && now - this->identify_start_ <= this->identify_duration_; + + if (identify) { + uint32_t time = now % 1000; + if (time < 600 && time % 200 < 100) { + this->status_indicator_->turn_on(); + } else { + this->status_indicator_->turn_off(); + } + } + return identify; +} + +void ESP32ImprovComponent::set_state_(improv::State state) { + ESP_LOGV(TAG, "Setting state: %d", state); + this->state_ = state; + if (this->status_->get_value().size() == 0 || this->status_->get_value()[0] != state) { + uint8_t data[1]{state}; + this->status_->set_value(data, 1); + if (state != improv::STATE_STOPPED) + this->status_->notify(); + } +} + +void ESP32ImprovComponent::set_error_(improv::Error error) { + if (error != improv::ERROR_NONE) + ESP_LOGE(TAG, "Error: %d", error); + if (this->error_->get_value().size() == 0 || this->error_->get_value()[0] != error) { + uint8_t data[1]{error}; + this->error_->set_value(data, 1); + if (this->state_ != improv::STATE_STOPPED) + this->error_->notify(); + } +} + +void ESP32ImprovComponent::send_response(std::vector &response) { + this->rpc_response_->set_value(response); + if (this->state_ != improv::STATE_STOPPED) + this->rpc_response_->notify(); +} + +void ESP32ImprovComponent::start() { + if (this->state_ != improv::STATE_STOPPED) + return; + + ESP_LOGD(TAG, "Setting Improv to start"); + this->should_start_ = true; +} + +void ESP32ImprovComponent::end() { + this->set_state_(improv::STATE_STOPPED); + this->service_->stop(); +} + +float ESP32ImprovComponent::get_setup_priority() const { + // Before WiFi + return setup_priority::AFTER_BLUETOOTH; +} + +void ESP32ImprovComponent::dump_config() { + ESP_LOGCONFIG(TAG, "ESP32 Improv:"); + LOG_BINARY_SENSOR(" ", "Authorizer", this->authorizer_); + ESP_LOGCONFIG(TAG, " Status Indicator: '%s'", YESNO(this->status_indicator_ != nullptr)); +} + +void ESP32ImprovComponent::process_incoming_data_() { + uint8_t length = this->incoming_data_[1]; + + ESP_LOGD(TAG, "Processing bytes - %s", hexencode(this->incoming_data_).c_str()); + if (this->incoming_data_.size() - 3 == length) { + this->set_error_(improv::ERROR_NONE); + improv::ImprovCommand command = improv::parse_improv_data(this->incoming_data_); + switch (command.command) { + case improv::BAD_CHECKSUM: + ESP_LOGW(TAG, "Error decoding Improv payload"); + this->set_error_(improv::ERROR_INVALID_RPC); + this->incoming_data_.clear(); + break; + case improv::WIFI_SETTINGS: { + if (this->state_ != improv::STATE_AUTHORIZED) { + ESP_LOGW(TAG, "Settings received, but not authorized"); + this->set_error_(improv::ERROR_NOT_AUTHORIZED); + this->incoming_data_.clear(); + return; + } + wifi::WiFiAP sta{}; + sta.set_ssid(command.ssid); + sta.set_password(command.password); + this->connecting_sta_ = sta; + + wifi::global_wifi_component->set_sta(sta); + wifi::global_wifi_component->start_scanning(); + this->set_state_(improv::STATE_PROVISIONING); + ESP_LOGD(TAG, "Received Improv wifi settings ssid=%s, password=" LOG_SECRET("%s"), command.ssid.c_str(), + command.password.c_str()); + + auto f = std::bind(&ESP32ImprovComponent::on_wifi_connect_timeout_, this); + this->set_timeout("wifi-connect-timeout", 30000, f); + this->incoming_data_.clear(); + break; + } + case improv::IDENTIFY: + this->incoming_data_.clear(); + this->identify_start_ = millis(); + break; + default: + ESP_LOGW(TAG, "Unknown Improv payload"); + this->set_error_(improv::ERROR_UNKNOWN_RPC); + this->incoming_data_.clear(); + } + } else if (this->incoming_data_.size() - 2 > length) { + ESP_LOGV(TAG, "Too much data came in, or malformed resetting buffer..."); + this->incoming_data_.clear(); + } else { + ESP_LOGV(TAG, "Waiting for split data packets..."); + } +} + +void ESP32ImprovComponent::on_wifi_connect_timeout_() { + this->set_error_(improv::ERROR_UNABLE_TO_CONNECT); + this->set_state_(improv::STATE_AUTHORIZED); + if (this->authorizer_ != nullptr) + this->authorized_start_ = millis(); + ESP_LOGW(TAG, "Timed out trying to connect to given WiFi network"); + wifi::global_wifi_component->clear_sta(); +} + +void ESP32ImprovComponent::on_client_disconnect() { this->set_error_(improv::ERROR_NONE); }; + +ESP32ImprovComponent *global_improv_component = nullptr; + +} // namespace esp32_improv +} // namespace esphome + +#endif diff --git a/esphome/components/esp32_improv/esp32_improv_component.h b/esphome/components/esp32_improv/esp32_improv_component.h new file mode 100644 index 0000000000..820951f18d --- /dev/null +++ b/esphome/components/esp32_improv/esp32_improv_component.h @@ -0,0 +1,74 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/helpers.h" +#include "esphome/core/preferences.h" +#include "esphome/components/binary_sensor/binary_sensor.h" +#include "esphome/components/esp32_ble/ble_server.h" +#include "esphome/components/esp32_ble/ble_characteristic.h" +#include "esphome/components/output/binary_output.h" +#include "esphome/components/wifi/wifi_component.h" +#include "esphome/components/improv/improv.h" + +#ifdef ARDUINO_ARCH_ESP32 + +namespace esphome { +namespace esp32_improv { + +class ESP32ImprovComponent : public Component, public esp32_ble::BLEServiceComponent { + public: + ESP32ImprovComponent(); + void dump_config() override; + void loop() override; + void setup_service() override; + void on_client_disconnect() override; + + float get_setup_priority() const override; + void start(); + void end(); + bool is_active() const { return this->state_ == improv::STATE_AUTHORIZED; } + + void set_authorizer(binary_sensor::BinarySensor *authorizer) { this->authorizer_ = authorizer; } + void set_status_indicator(output::BinaryOutput *status_indicator) { this->status_indicator_ = status_indicator; } + void set_identify_duration(uint32_t identify_duration) { this->identify_duration_ = identify_duration; } + void set_authorized_duration(uint32_t authorized_duration) { this->authorized_duration_ = authorized_duration; } + + protected: + bool should_start_{false}; + bool setup_complete_{false}; + + uint32_t identify_start_{0}; + uint32_t identify_duration_; + uint32_t authorized_start_{0}; + uint32_t authorized_duration_; + + std::vector incoming_data_; + wifi::WiFiAP connecting_sta_; + + esp32_ble::BLEService *service_; + esp32_ble::BLECharacteristic *status_; + esp32_ble::BLECharacteristic *error_; + esp32_ble::BLECharacteristic *rpc_; + esp32_ble::BLECharacteristic *rpc_response_; + esp32_ble::BLECharacteristic *capabilities_; + + binary_sensor::BinarySensor *authorizer_{nullptr}; + output::BinaryOutput *status_indicator_{nullptr}; + + improv::State state_{improv::STATE_STOPPED}; + improv::Error error_state_{improv::ERROR_NONE}; + + void set_state_(improv::State state); + void set_error_(improv::Error error); + void send_response(std::vector &response); + void process_incoming_data_(); + void on_wifi_connect_timeout_(); + bool check_identify_(); +}; + +extern ESP32ImprovComponent *global_improv_component; + +} // namespace esp32_improv +} // namespace esphome + +#endif diff --git a/esphome/components/improv/__init__.py b/esphome/components/improv/__init__.py new file mode 100644 index 0000000000..b1de57df8f --- /dev/null +++ b/esphome/components/improv/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@jesserockz"] diff --git a/esphome/components/improv/improv.cpp b/esphome/components/improv/improv.cpp new file mode 100644 index 0000000000..6bda79a2c1 --- /dev/null +++ b/esphome/components/improv/improv.cpp @@ -0,0 +1,66 @@ +#include "improv.h" + +namespace improv { + +ImprovCommand parse_improv_data(std::vector &data) { return parse_improv_data(data.data(), data.size()); } + +ImprovCommand parse_improv_data(const uint8_t *data, size_t length) { + Command command = (Command) data[0]; + uint8_t data_length = data[1]; + + if (data_length != length - 3) { + return {.command = UNKNOWN}; + } + + uint8_t checksum = data[length - 1]; + + uint32_t calculated_checksum = 0; + for (uint8_t i = 0; i < length - 1; i++) { + calculated_checksum += data[i]; + } + + if ((uint8_t) calculated_checksum != checksum) { + return {.command = BAD_CHECKSUM}; + } + + if (command == WIFI_SETTINGS) { + uint8_t ssid_length = data[2]; + uint8_t ssid_start = 3; + size_t ssid_end = ssid_start + ssid_length; + + uint8_t pass_length = data[ssid_end]; + size_t pass_start = ssid_end + 1; + size_t pass_end = pass_start + pass_length; + + std::string ssid(data + ssid_start, data + ssid_end); + std::string password(data + pass_start, data + pass_end); + return {.command = command, .ssid = ssid, .password = password}; + } + + return { + .command = command, + }; +} + +std::vector build_rpc_response(Command command, std::vector datum) { + std::vector out; + uint32_t length = 0; + out.push_back(command); + for (auto str : datum) { + uint8_t len = str.length(); + length += len; + out.push_back(len); + out.insert(out.end(), str.begin(), str.end()); + } + out.insert(out.begin() + 1, length); + + uint32_t calculated_checksum = 0; + + for (uint8_t byte : out) { + calculated_checksum += byte; + } + out.push_back(calculated_checksum); + return out; +} + +} // namespace improv diff --git a/esphome/components/improv/improv.h b/esphome/components/improv/improv.h new file mode 100644 index 0000000000..c13c68c90e --- /dev/null +++ b/esphome/components/improv/improv.h @@ -0,0 +1,53 @@ +#pragma once + +#include +#include +#include + +namespace improv { + +static const char *SERVICE_UUID = "00467768-6228-2272-4663-277478268000"; +static const char *STATUS_UUID = "00467768-6228-2272-4663-277478268001"; +static const char *ERROR_UUID = "00467768-6228-2272-4663-277478268002"; +static const char *RPC_COMMAND_UUID = "00467768-6228-2272-4663-277478268003"; +static const char *RPC_RESULT_UUID = "00467768-6228-2272-4663-277478268004"; +static const char *CAPABILITIES_UUID = "00467768-6228-2272-4663-277478268005"; + +enum Error : uint8_t { + ERROR_NONE = 0x00, + ERROR_INVALID_RPC = 0x01, + ERROR_UNKNOWN_RPC = 0x02, + ERROR_UNABLE_TO_CONNECT = 0x03, + ERROR_NOT_AUTHORIZED = 0x04, + ERROR_UNKNOWN = 0xFF, +}; + +enum State : uint8_t { + STATE_STOPPED = 0x00, + STATE_AWAITING_AUTHORIZATION = 0x01, + STATE_AUTHORIZED = 0x02, + STATE_PROVISIONING = 0x03, + STATE_PROVISIONED = 0x04, +}; + +enum Command : uint8_t { + UNKNOWN = 0x00, + WIFI_SETTINGS = 0x01, + IDENTIFY = 0x02, + BAD_CHECKSUM = 0xFF, +}; + +static const uint8_t CAPABILITY_IDENTIFY = 0x01; + +struct ImprovCommand { + Command command; + std::string ssid; + std::string password; +}; + +ImprovCommand parse_improv_data(std::vector &data); +ImprovCommand parse_improv_data(const uint8_t *data, size_t length); + +std::vector build_rpc_response(Command command, std::vector datum); + +} // namespace improv diff --git a/esphome/components/wifi/wifi_component.cpp b/esphome/components/wifi/wifi_component.cpp index 0a6607852d..da1f6f85a7 100644 --- a/esphome/components/wifi/wifi_component.cpp +++ b/esphome/components/wifi/wifi_component.cpp @@ -22,6 +22,10 @@ #include "esphome/components/captive_portal/captive_portal.h" #endif +#ifdef USE_IMPROV +#include "esphome/components/esp32_improv/esp32_improv_component.h" +#endif + namespace esphome { namespace wifi { @@ -34,6 +38,19 @@ void WiFiComponent::setup() { this->last_connected_ = millis(); this->wifi_pre_setup_(); + uint32_t hash = fnv1_hash(App.get_compilation_time()); + this->pref_ = global_preferences.make_preference(hash, true); + + SavedWifiSettings save{}; + if (this->pref_.load(&save)) { + ESP_LOGD(TAG, "Loaded saved wifi settings: %s", save.ssid); + + WiFiAP sta{}; + sta.set_ssid(save.ssid); + sta.set_password(save.password); + this->set_sta(sta); + } + if (this->has_sta()) { this->wifi_sta_pre_setup_(); if (this->output_power_.has_value() && !this->wifi_apply_output_power_(*this->output_power_)) { @@ -60,7 +77,10 @@ void WiFiComponent::setup() { captive_portal::global_captive_portal->start(); #endif } - +#ifdef USE_IMPROV + if (esp32_improv::global_improv_component != nullptr) + esp32_improv::global_improv_component->start(); +#endif this->wifi_apply_hostname_(); #if defined(ARDUINO_ARCH_ESP32) && defined(USE_MDNS) network_setup_mdns(); @@ -122,6 +142,14 @@ void WiFiComponent::loop() { } } +#ifdef USE_IMPROV + if (esp32_improv::global_improv_component != nullptr) { + if (!this->is_connected()) { + esp32_improv::global_improv_component->start(); + } + } +#endif + if (!this->has_ap() && this->reboot_timeout_ != 0) { if (now - this->last_connected_ > this->reboot_timeout_) { ESP_LOGE(TAG, "Can't connect to WiFi, rebooting..."); @@ -186,9 +214,21 @@ float WiFiComponent::get_loop_priority() const { void WiFiComponent::set_ap(const WiFiAP &ap) { this->ap_ = ap; } void WiFiComponent::add_sta(const WiFiAP &ap) { this->sta_.push_back(ap); } void WiFiComponent::set_sta(const WiFiAP &ap) { - this->sta_.clear(); + this->clear_sta(); this->add_sta(ap); } +void WiFiComponent::clear_sta() { this->sta_.clear(); } +void WiFiComponent::save_wifi_sta(const std::string &ssid, const std::string &password) { + SavedWifiSettings save{}; + strcpy(save.ssid, ssid.c_str()); + strcpy(save.password, password.c_str()); + this->pref_.save(&save); + + WiFiAP sta{}; + sta.set_ssid(ssid); + sta.set_password(password); + this->set_sta(sta); +} void WiFiComponent::start_connecting(const WiFiAP &ap, bool two) { ESP_LOGI(TAG, "WiFi Connecting to '%s'...", ap.get_ssid().c_str()); @@ -466,6 +506,12 @@ void WiFiComponent::check_connecting_finished() { ESP_LOGD(TAG, "Disabling AP..."); this->wifi_mode_({}, false); } +#ifdef USE_IMPROV + if (this->is_esp32_improv_active_()) { + esp32_improv::global_improv_component->end(); + } +#endif + #if defined(ARDUINO_ARCH_ESP8266) && defined(USE_MDNS) network_setup_mdns(this->wifi_sta_ip_(), 0); #endif @@ -517,7 +563,8 @@ void WiFiComponent::retry_connect() { } delay(10); - if (!this->is_captive_portal_active_() && (this->num_retried_ > 5 || this->error_from_callback_)) { + if (!this->is_captive_portal_active_() && !this->is_esp32_improv_active_() && + (this->num_retried_ > 5 || this->error_from_callback_)) { // If retry failed for more than 5 times, let's restart STA ESP_LOGW(TAG, "Restarting WiFi adapter..."); this->wifi_mode_(false, {}); @@ -563,6 +610,13 @@ bool WiFiComponent::is_captive_portal_active_() { return false; #endif } +bool WiFiComponent::is_esp32_improv_active_() { +#ifdef USE_IMPROV + return esp32_improv::global_improv_component != nullptr && esp32_improv::global_improv_component->is_active(); +#else + return false; +#endif +} void WiFiAP::set_ssid(const std::string &ssid) { this->ssid_ = ssid; } void WiFiAP::set_bssid(bssid_t bssid) { this->bssid_ = bssid; } diff --git a/esphome/components/wifi/wifi_component.h b/esphome/components/wifi/wifi_component.h index ee8fd208b2..753455ddb1 100644 --- a/esphome/components/wifi/wifi_component.h +++ b/esphome/components/wifi/wifi_component.h @@ -27,6 +27,11 @@ extern "C" { namespace esphome { namespace wifi { +struct SavedWifiSettings { + char ssid[33]; + char password[65]; +} PACKED; // NOLINT + enum WiFiComponentState { /** Nothing has been initialized yet. Internal AP, if configured, is disabled at this point. */ WIFI_COMPONENT_STATE_OFF = 0, @@ -156,6 +161,7 @@ class WiFiComponent : public Component { void set_sta(const WiFiAP &ap); void add_sta(const WiFiAP &ap); + void clear_sta(); /** Setup an Access Point that should be created if no connection to a station can be made. * @@ -185,6 +191,7 @@ class WiFiComponent : public Component { void set_power_save_mode(WiFiPowerSaveMode power_save); void set_output_power(float output_power) { output_power_ = output_power; } + void save_wifi_sta(const std::string &ssid, const std::string &password); // ========== INTERNAL METHODS ========== // (In most use cases you won't need these) /// Setup WiFi interface. @@ -253,6 +260,7 @@ class WiFiComponent : public Component { bool wifi_disconnect_(); bool is_captive_portal_active_(); + bool is_esp32_improv_active_(); #ifdef ARDUINO_ARCH_ESP8266 static void wifi_event_callback(System_Event_t *event); @@ -288,6 +296,8 @@ class WiFiComponent : public Component { bool scan_done_{false}; bool ap_setup_{false}; optional output_power_; + ESPPreferenceObject pref_; + bool has_saved_wifi_settings_{false}; }; extern WiFiComponent *global_wifi_component; diff --git a/esphome/core/component.cpp b/esphome/core/component.cpp index d2e9607e28..c571e5e23f 100644 --- a/esphome/core/component.cpp +++ b/esphome/core/component.cpp @@ -15,6 +15,8 @@ const float IO = 900.0f; const float HARDWARE = 800.0f; const float DATA = 600.0f; const float PROCESSOR = 400.0; +const float BLUETOOTH = 350.0f; +const float AFTER_BLUETOOTH = 300.0f; const float WIFI = 250.0f; const float AFTER_WIFI = 200.0f; const float AFTER_CONNECTION = 100.0f; diff --git a/esphome/core/component.h b/esphome/core/component.h index e3f9a51f25..ad3619386b 100644 --- a/esphome/core/component.h +++ b/esphome/core/component.h @@ -26,6 +26,8 @@ extern const float DATA; extern const float HARDWARE_LATE; /// For components that use data from sensors like displays extern const float PROCESSOR; +extern const float BLUETOOTH; +extern const float AFTER_BLUETOOTH; extern const float WIFI; /// For components that should be initialized after WiFi is connected. extern const float AFTER_WIFI; diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index 5f9ab1fdd1..d4ee109126 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -21,8 +21,14 @@ #define ALWAYS_INLINE __attribute__((always_inline)) #define PACKED __attribute__((packed)) +#define xSemaphoreWait(semaphore, wait_time) \ + xSemaphoreTake(semaphore, wait_time); \ + xSemaphoreGive(semaphore); + namespace esphome { +static const uint32_t SEMAPHORE_MAX_DELAY = 4294967295UL; + /// The characters that are allowed in a hostname. extern const char *HOSTNAME_CHARACTER_ALLOWLIST; @@ -318,8 +324,6 @@ template class Parented { uint32_t fnv1_hash(const std::string &str); -} // namespace esphome - template T *new_buffer(size_t length) { T *buffer; #ifdef ARDUINO_ARCH_ESP32 @@ -333,4 +337,6 @@ template T *new_buffer(size_t length) { #endif return buffer; +} + } // namespace esphome diff --git a/script/test b/script/test index 0327e08ca8..9f5dca65fa 100755 --- a/script/test +++ b/script/test @@ -10,3 +10,4 @@ esphome compile tests/test1.yaml esphome compile tests/test2.yaml esphome compile tests/test3.yaml esphome compile tests/test4.yaml +esphome compile tests/test5.yaml diff --git a/tests/README.md b/tests/README.md index c8962dedc1..546025526f 100644 --- a/tests/README.md +++ b/tests/README.md @@ -17,9 +17,10 @@ be tested on the same device. Current test_.yaml file contents. -| Test name | Platform | Network | -|-|-|-| -| test1.yaml | ESP32 | wifi | -| test2.yaml | ESP32 | ethernet | -| test3.yaml | ESP8266 | wifi | -| test4.yaml | ESP32 | ethernet | +| Test name | Platform | Network | BLE | +|-|-|-|-| +| test1.yaml | ESP32 | wifi | None +| test2.yaml | ESP32 | ethernet | esp32_ble_tracker +| test3.yaml | ESP8266 | wifi | N/A +| test4.yaml | ESP32 | ethernet | None +| test5.yaml | ESP32 | wifi | ble_server diff --git a/tests/test5.yaml b/tests/test5.yaml new file mode 100644 index 0000000000..993c421bdd --- /dev/null +++ b/tests/test5.yaml @@ -0,0 +1,36 @@ +esphome: + name: test5 + platform: ESP32 + board: nodemcu-32s + build_path: build/test5 + +wifi: + networks: + - ssid: 'MySSID' + password: 'password1' + +api: + +ota: + +logger: + +binary_sensor: + - platform: gpio + pin: GPIO0 + id: io0_button + +output: + - platform: gpio + pin: GPIO2 + id: built_in_led + +esp32_ble: + server: + manufacturer: "ESPHome" + model: "Test5" + +esp32_improv: + authorizer: io0_button + authorized_duration: 1min + status_indicator: built_in_led From 01e2a51132850e03c0965a1e18e878897179e68f Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Tue, 8 Jun 2021 21:28:19 +0200 Subject: [PATCH 094/104] Implement versioning for esphome/esphome-lint docker images (#1877) --- .github/workflows/ci.yml | 4 ++-- .github/workflows/docker-lint-build.yml | 5 +++++ .github/workflows/release-dev.yml | 4 ++-- .github/workflows/release.yml | 4 ++-- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 56e94cb32c..5075609526 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest # cpp lint job runs with esphome-lint docker image so that clang-format-* # doesn't have to be installed - container: esphome/esphome-lint:latest + container: esphome/esphome-lint:1.0 steps: - uses: actions/checkout@v2 # Set up the pio project so that the cpp checks know how files are compiled @@ -32,7 +32,7 @@ jobs: runs-on: ubuntu-latest # cpp lint job runs with esphome-lint docker image so that clang-format-* # doesn't have to be installed - container: esphome/esphome-lint:latest + container: esphome/esphome-lint:1.0 # Split clang-tidy check into 4 jobs. Each one will check 1/4th of the .cpp files strategy: fail-fast: false diff --git a/.github/workflows/docker-lint-build.yml b/.github/workflows/docker-lint-build.yml index f148d98d65..4e75a4c162 100644 --- a/.github/workflows/docker-lint-build.yml +++ b/.github/workflows/docker-lint-build.yml @@ -17,6 +17,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 + - name: Set TAG + run: | + echo "TAG=1.0" >> $GITHUB_ENV - name: Pull for cache run: | docker pull "esphome/esphome-lint:latest" || true @@ -26,6 +29,7 @@ jobs: --cache-from "esphome/esphome-lint:latest" \ --file "docker/Dockerfile.lint" \ --tag "esphome/esphome-lint:latest" \ + --tag "esphome/esphome-lint:${TAG}" \ . - name: Log in to docker hub env: @@ -33,4 +37,5 @@ jobs: DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} run: docker login -u "${DOCKER_USER}" -p "${DOCKER_PASSWORD}" - run: | + docker push "esphome/esphome-lint:${TAG}" docker push "esphome/esphome-lint:latest" diff --git a/.github/workflows/release-dev.yml b/.github/workflows/release-dev.yml index 9361ab4b73..917e273aea 100644 --- a/.github/workflows/release-dev.yml +++ b/.github/workflows/release-dev.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest # cpp lint job runs with esphome-lint docker image so that clang-format-* # doesn't have to be installed - container: esphome/esphome-lint:latest + container: esphome/esphome-lint:1.0 steps: - uses: actions/checkout@v2 # Set up the pio project so that the cpp checks know how files are compiled @@ -29,7 +29,7 @@ jobs: runs-on: ubuntu-latest # cpp lint job runs with esphome-lint docker image so that clang-format-* # doesn't have to be installed - container: esphome/esphome-lint:latest + container: esphome/esphome-lint:1.0 # Split clang-tidy check into 4 jobs. Each one will check 1/4th of the .cpp files strategy: fail-fast: false diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 39cc7c37ce..806e23d7e4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest # cpp lint job runs with esphome-lint docker image so that clang-format-* # doesn't have to be installed - container: esphome/esphome-lint:latest + container: esphome/esphome-lint:1.0 steps: - uses: actions/checkout@v2 # Set up the pio project so that the cpp checks know how files are compiled @@ -28,7 +28,7 @@ jobs: runs-on: ubuntu-latest # cpp lint job runs with esphome-lint docker image so that clang-format-* # doesn't have to be installed - container: esphome/esphome-lint:latest + container: esphome/esphome-lint:1.0 # Split clang-tidy check into 4 jobs. Each one will check 1/4th of the .cpp files strategy: fail-fast: false From 4711f36a1f4593aa4a8dd5f0cdedc0c6e7d350a3 Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Tue, 8 Jun 2021 22:03:04 +0200 Subject: [PATCH 095/104] Bump base image to 3.4.0 (#1879) --- .github/workflows/ci-docker.yml | 2 +- .github/workflows/ci.yml | 4 ++-- .github/workflows/docker-lint-build.yml | 3 ++- .github/workflows/release-dev.yml | 6 +++--- .github/workflows/release.yml | 6 +++--- docker/Dockerfile | 6 +++--- docker/Dockerfile.dev | 2 +- docker/Dockerfile.hassio | 4 ++-- docker/Dockerfile.lint | 6 +++--- requirements_optional.txt | 2 ++ requirements_test.txt | 2 -- script/setup | 2 +- 12 files changed, 23 insertions(+), 22 deletions(-) create mode 100644 requirements_optional.txt diff --git a/.github/workflows/ci-docker.yml b/.github/workflows/ci-docker.yml index edbb2cf003..b5f8b7b0e0 100644 --- a/.github/workflows/ci-docker.yml +++ b/.github/workflows/ci-docker.yml @@ -26,7 +26,7 @@ jobs: - uses: actions/checkout@v2 - name: Set up env variables run: | - base_version="3.1.0" + base_version="3.4.0" if [[ "${{ matrix.build_type }}" == "hassio" ]]; then build_from="esphome/esphome-hassio-base-${{ matrix.arch }}:${base_version}" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5075609526..a27cbe67b0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest # cpp lint job runs with esphome-lint docker image so that clang-format-* # doesn't have to be installed - container: esphome/esphome-lint:1.0 + container: esphome/esphome-lint:1.1 steps: - uses: actions/checkout@v2 # Set up the pio project so that the cpp checks know how files are compiled @@ -32,7 +32,7 @@ jobs: runs-on: ubuntu-latest # cpp lint job runs with esphome-lint docker image so that clang-format-* # doesn't have to be installed - container: esphome/esphome-lint:1.0 + container: esphome/esphome-lint:1.1 # Split clang-tidy check into 4 jobs. Each one will check 1/4th of the .cpp files strategy: fail-fast: false diff --git a/.github/workflows/docker-lint-build.yml b/.github/workflows/docker-lint-build.yml index 4e75a4c162..d254ac332a 100644 --- a/.github/workflows/docker-lint-build.yml +++ b/.github/workflows/docker-lint-build.yml @@ -7,6 +7,7 @@ on: paths: - 'docker/Dockerfile.lint' - 'requirements.txt' + - 'requirements_optional.txt' - 'requirements_test.txt' - 'platformio.ini' - '.github/workflows/docker-lint-build.yml' @@ -19,7 +20,7 @@ jobs: - uses: actions/checkout@v2 - name: Set TAG run: | - echo "TAG=1.0" >> $GITHUB_ENV + echo "TAG=1.1" >> $GITHUB_ENV - name: Pull for cache run: | docker pull "esphome/esphome-lint:latest" || true diff --git a/.github/workflows/release-dev.yml b/.github/workflows/release-dev.yml index 917e273aea..f8b90d524f 100644 --- a/.github/workflows/release-dev.yml +++ b/.github/workflows/release-dev.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest # cpp lint job runs with esphome-lint docker image so that clang-format-* # doesn't have to be installed - container: esphome/esphome-lint:1.0 + container: esphome/esphome-lint:1.1 steps: - uses: actions/checkout@v2 # Set up the pio project so that the cpp checks know how files are compiled @@ -29,7 +29,7 @@ jobs: runs-on: ubuntu-latest # cpp lint job runs with esphome-lint docker image so that clang-format-* # doesn't have to be installed - container: esphome/esphome-lint:1.0 + container: esphome/esphome-lint:1.1 # Split clang-tidy check into 4 jobs. Each one will check 1/4th of the .cpp files strategy: fail-fast: false @@ -175,7 +175,7 @@ jobs: echo "TAG=${TAG}" >> $GITHUB_ENV - name: Set up env variables run: | - base_version="3.1.0" + base_version="3.4.0" if [[ "${{ matrix.build_type }}" == "hassio" ]]; then build_from="esphome/esphome-hassio-base-${{ matrix.arch }}:${base_version}" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 806e23d7e4..9523a2164c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest # cpp lint job runs with esphome-lint docker image so that clang-format-* # doesn't have to be installed - container: esphome/esphome-lint:1.0 + container: esphome/esphome-lint:1.1 steps: - uses: actions/checkout@v2 # Set up the pio project so that the cpp checks know how files are compiled @@ -28,7 +28,7 @@ jobs: runs-on: ubuntu-latest # cpp lint job runs with esphome-lint docker image so that clang-format-* # doesn't have to be installed - container: esphome/esphome-lint:1.0 + container: esphome/esphome-lint:1.1 # Split clang-tidy check into 4 jobs. Each one will check 1/4th of the .cpp files strategy: fail-fast: false @@ -195,7 +195,7 @@ jobs: echo "TAG=${TAG}" >> $GITHUB_ENV - name: Set up env variables run: | - base_version="3.1.0" + base_version="3.4.0" if [[ "${{ matrix.build_type }}" == "hassio" ]]; then build_from="esphome/esphome-hassio-base-${{ matrix.arch }}:${base_version}" diff --git a/docker/Dockerfile b/docker/Dockerfile index ef547fc0f1..0d126a2944 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,10 +1,10 @@ -ARG BUILD_FROM=esphome/esphome-base-amd64:3.1.0 +ARG BUILD_FROM=esphome/esphome-base-amd64:3.4.0 FROM ${BUILD_FROM} # First install requirements to leverage caching when requirements don't change -COPY requirements.txt docker/platformio_install_deps.py platformio.ini / +COPY requirements.txt requirements_optional.txt docker/platformio_install_deps.py platformio.ini / RUN \ - pip3 install --no-cache-dir -r /requirements.txt \ + pip3 install --no-cache-dir -r /requirements.txt -r /requirements_optional.txt \ && /platformio_install_deps.py /platformio.ini # Then copy esphome and install diff --git a/docker/Dockerfile.dev b/docker/Dockerfile.dev index e09eeb6837..ebcf14d1bc 100644 --- a/docker/Dockerfile.dev +++ b/docker/Dockerfile.dev @@ -1,4 +1,4 @@ -FROM esphome/esphome-base-amd64:3.1.0 +FROM esphome/esphome-base-amd64:3.4.0 COPY . . diff --git a/docker/Dockerfile.hassio b/docker/Dockerfile.hassio index b6ff037c35..5dd9339b18 100644 --- a/docker/Dockerfile.hassio +++ b/docker/Dockerfile.hassio @@ -2,9 +2,9 @@ ARG BUILD_FROM FROM ${BUILD_FROM} # First install requirements to leverage caching when requirements don't change -COPY requirements.txt docker/platformio_install_deps.py platformio.ini / +COPY requirements.txt requirements_optional.txt docker/platformio_install_deps.py platformio.ini / RUN \ - pip3 install --no-cache-dir -r /requirements.txt \ + pip3 install --no-cache-dir -r /requirements.txt -r /requirements_optional.txt \ && /platformio_install_deps.py /platformio.ini # Copy root filesystem diff --git a/docker/Dockerfile.lint b/docker/Dockerfile.lint index 4a88667245..60d63152a0 100644 --- a/docker/Dockerfile.lint +++ b/docker/Dockerfile.lint @@ -1,8 +1,8 @@ -FROM esphome/esphome-lint-base:3.1.0 +FROM esphome/esphome-lint-base:3.4.0 -COPY requirements.txt requirements_test.txt docker/platformio_install_deps.py platformio.ini / +COPY requirements.txt requirements_optional.txt requirements_test.txt docker/platformio_install_deps.py platformio.ini / RUN \ - pip3 install --no-cache-dir -r /requirements.txt -r /requirements_test.txt \ + pip3 install --no-cache-dir -r /requirements.txt -r /requirements_optional.txt -r /requirements_test.txt \ && /platformio_install_deps.py /platformio.ini VOLUME ["/esphome"] diff --git a/requirements_optional.txt b/requirements_optional.txt new file mode 100644 index 0000000000..2c73430109 --- /dev/null +++ b/requirements_optional.txt @@ -0,0 +1,2 @@ +pillow>4.0.0 +cryptography>=2.0.0,<4 diff --git a/requirements_test.txt b/requirements_test.txt index b5cf617fee..15593a8e12 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -1,8 +1,6 @@ pylint==2.8.2 flake8==3.9.2 black==21.5b1 -pillow>4.0.0 -cryptography>=2.0.0,<4 pexpect==4.8.0 pre-commit diff --git a/script/setup b/script/setup index 199b46891d..6d095af46c 100755 --- a/script/setup +++ b/script/setup @@ -4,7 +4,7 @@ set -e cd "$(dirname "$0")/.." -pip3 install -r requirements.txt -r requirements_test.txt +pip3 install -r requirements.txt -r requirements_optional.txt -r requirements_test.txt pip3 install -e . pre-commit install From 13fe9e83fa31b23b7693001700c953889e418e98 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Tue, 8 Jun 2021 22:16:17 +0200 Subject: [PATCH 096/104] Use Clang 11 (#1846) --- .clang-tidy | 40 +++++++++++++++++++ esphome/components/mqtt/mqtt_client.cpp | 17 ++++---- .../sensor/mqtt_subscribe_sensor.cpp | 23 ++++++----- .../mqtt_subscribe_text_sensor.cpp | 6 +-- esphome/core/helpers.h | 2 +- script/clang-format | 6 +-- script/clang-tidy | 12 +++--- 7 files changed, 74 insertions(+), 32 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 5e486e6a0c..ceb51884a5 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -4,14 +4,37 @@ Checks: >- -abseil-*, -android-*, -boost-*, + -bugprone-branch-clone, -bugprone-macro-parentheses, + -bugprone-narrowing-conversions, + -bugprone-reserved-identifier, + -bugprone-signed-char-misuse, + -bugprone-suspicious-include, + -bugprone-too-small-loop-variable, + -bugprone-unhandled-self-assignment, + -cert-dcl37-c, -cert-dcl50-cpp, + -cert-dcl51-cpp, -cert-err58-cpp, + -cert-oop54-cpp, + -cert-oop57-cpp, + -cert-str34-c, -clang-analyzer-core.CallAndMessage, + -clang-analyzer-deadcode.DeadStores, + -clang-analyzer-optin.*, -clang-analyzer-osx.*, -clang-analyzer-security.*, + -clang-diagnostic-fortify-source, + -clang-diagnostic-shadow-field, + -cppcoreguidelines-avoid-c-arrays, -cppcoreguidelines-avoid-goto, + -cppcoreguidelines-avoid-magic-numbers, + -cppcoreguidelines-avoid-non-const-global-variables, -cppcoreguidelines-c-copy-assignment-signature, + -cppcoreguidelines-init-variables, + -cppcoreguidelines-macro-usage, + -cppcoreguidelines-narrowing-conversions, + -cppcoreguidelines-non-private-member-variables-in-classes, -cppcoreguidelines-owning-memory, -cppcoreguidelines-pro-bounds-array-to-pointer-decay, -cppcoreguidelines-pro-bounds-constant-array-index, @@ -37,10 +60,16 @@ Checks: >- -google-runtime-int, -google-runtime-references, -hicpp-*, + -llvm-else-after-return, -llvm-header-guard, -llvm-include-order, + -llvm-qualified-auto, + -llvmlibc-*, + -misc-non-private-member-variables-in-classes, + -misc-no-recursion, -misc-unconventional-assign-operator, -misc-unused-parameters, + -modernize-avoid-c-arrays, -modernize-deprecated-headers, -modernize-pass-by-value, -modernize-pass-by-value, @@ -48,14 +77,25 @@ Checks: >- -modernize-use-auto, -modernize-use-default-member-init, -modernize-use-equals-default, + -modernize-use-trailing-return-type, -mpi-*, -objc-*, -performance-unnecessary-value-param, -readability-braces-around-statements, + -readability-const-return-type, + -readability-convert-member-functions-to-static, -readability-else-after-return, -readability-implicit-bool-conversion, + -readability-isolate-declaration, + -readability-magic-numbers, + -readability-make-member-function-const, -readability-named-parameter, + -readability-qualified-auto, + -readability-redundant-access-specifiers, -readability-redundant-member-init, + -readability-redundant-string-init, + -readability-uppercase-literal-suffix, + -readability-use-anyofallof, -warnings-as-errors, -zircon-* WarningsAsErrors: '*' diff --git a/esphome/components/mqtt/mqtt_client.cpp b/esphome/components/mqtt/mqtt_client.cpp index b8743fc142..3330956b52 100644 --- a/esphome/components/mqtt/mqtt_client.cpp +++ b/esphome/components/mqtt/mqtt_client.cpp @@ -565,15 +565,16 @@ MQTTMessageTrigger::MQTTMessageTrigger(const std::string &topic) : topic_(topic) void MQTTMessageTrigger::set_qos(uint8_t qos) { this->qos_ = qos; } void MQTTMessageTrigger::set_payload(const std::string &payload) { this->payload_ = payload; } void MQTTMessageTrigger::setup() { - global_mqtt_client->subscribe(this->topic_, - [this](const std::string &topic, const std::string &payload) { - if (this->payload_.has_value() && payload != *this->payload_) { - return; - } + global_mqtt_client->subscribe( + this->topic_, + [this](const std::string &topic, const std::string &payload) { + if (this->payload_.has_value() && payload != *this->payload_) { + return; + } - this->trigger(payload); - }, - this->qos_); + this->trigger(payload); + }, + this->qos_); } void MQTTMessageTrigger::dump_config() { ESP_LOGCONFIG(TAG, "MQTT Message Trigger:"); diff --git a/esphome/components/mqtt_subscribe/sensor/mqtt_subscribe_sensor.cpp b/esphome/components/mqtt_subscribe/sensor/mqtt_subscribe_sensor.cpp index 50977e98ca..f6ecb0df36 100644 --- a/esphome/components/mqtt_subscribe/sensor/mqtt_subscribe_sensor.cpp +++ b/esphome/components/mqtt_subscribe/sensor/mqtt_subscribe_sensor.cpp @@ -7,18 +7,19 @@ namespace mqtt_subscribe { static const char *TAG = "mqtt_subscribe.sensor"; void MQTTSubscribeSensor::setup() { - mqtt::global_mqtt_client->subscribe(this->topic_, - [this](const std::string &topic, std::string payload) { - auto val = parse_float(payload); - if (!val.has_value()) { - ESP_LOGW(TAG, "Can't convert '%s' to number!", payload.c_str()); - this->publish_state(NAN); - return; - } + mqtt::global_mqtt_client->subscribe( + this->topic_, + [this](const std::string &topic, std::string payload) { + auto val = parse_float(payload); + if (!val.has_value()) { + ESP_LOGW(TAG, "Can't convert '%s' to number!", payload.c_str()); + this->publish_state(NAN); + return; + } - this->publish_state(*val); - }, - this->qos_); + this->publish_state(*val); + }, + this->qos_); } float MQTTSubscribeSensor::get_setup_priority() const { return setup_priority::AFTER_CONNECTION; } diff --git a/esphome/components/mqtt_subscribe/text_sensor/mqtt_subscribe_text_sensor.cpp b/esphome/components/mqtt_subscribe/text_sensor/mqtt_subscribe_text_sensor.cpp index fdab5cf6d7..e7373c4b95 100644 --- a/esphome/components/mqtt_subscribe/text_sensor/mqtt_subscribe_text_sensor.cpp +++ b/esphome/components/mqtt_subscribe/text_sensor/mqtt_subscribe_text_sensor.cpp @@ -7,9 +7,9 @@ namespace mqtt_subscribe { static const char *TAG = "mqtt_subscribe.text_sensor"; void MQTTSubscribeTextSensor::setup() { - this->parent_->subscribe(this->topic_, - [this](const std::string &topic, std::string payload) { this->publish_state(payload); }, - this->qos_); + this->parent_->subscribe( + this->topic_, [this](const std::string &topic, std::string payload) { this->publish_state(payload); }, + this->qos_); } float MQTTSubscribeTextSensor::get_setup_priority() const { return setup_priority::AFTER_CONNECTION; } void MQTTSubscribeTextSensor::set_qos(uint8_t qos) { this->qos_ = qos; } diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index d4ee109126..499ca8f832 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -95,7 +95,7 @@ float clamp(float val, float min, float max); float lerp(float completion, float start, float end); /// std::make_unique -template std::unique_ptr make_unique(Args &&... args) { +template std::unique_ptr make_unique(Args &&...args) { return std::unique_ptr(new T(std::forward(args)...)); } diff --git a/script/clang-format b/script/clang-format index e9c3692bb8..bb2b722e1c 100755 --- a/script/clang-format +++ b/script/clang-format @@ -31,7 +31,7 @@ def run_format(args, queue, lock): """Takes filenames out of queue and runs clang-tidy on them.""" while True: path = queue.get() - invocation = ['clang-format-7'] + invocation = ['clang-format-11'] if args.inplace: invocation.append('-i') invocation.append(path) @@ -69,12 +69,12 @@ def main(): args = parser.parse_args() try: - get_output('clang-format-7', '-version') + get_output('clang-format-11', '-version') except: print(""" Oops. It looks like clang-format is not installed. - Please check you can run "clang-format-7 -version" in your terminal and install + Please check you can run "clang-format-11 -version" in your terminal and install clang-format (v7) if necessary. Note you can also upload your code as a pull request on GitHub and see the CI check diff --git a/script/clang-tidy b/script/clang-tidy index 0bd1ef51fa..0bf17f9076 100755 --- a/script/clang-tidy +++ b/script/clang-tidy @@ -30,7 +30,7 @@ else: def run_tidy(args, tmpdir, queue, lock, failed_files): while True: path = queue.get() - invocation = ['clang-tidy-7', '-header-filter=^{}/.*'.format(re.escape(basepath))] + invocation = ['clang-tidy-11', '-header-filter=^{}/.*'.format(re.escape(basepath))] if tmpdir is not None: invocation.append('-export-fixes') # Get a temporary file. We immediately close the handle so clang-tidy can @@ -90,13 +90,13 @@ def main(): args = parser.parse_args() try: - get_output('clang-tidy-7', '-version') + get_output('clang-tidy-11', '-version') except: print(""" - Oops. It looks like clang-tidy is not installed. + Oops. It looks like clang-tidy-11 is not installed. - Please check you can run "clang-tidy-7 -version" in your terminal and install - clang-tidy (v7) if necessary. + Please check you can run "clang-tidy-11 -version" in your terminal and install + clang-tidy (v11) if necessary. Note you can also upload your code as a pull request on GitHub and see the CI check output to apply clang-tidy. @@ -163,7 +163,7 @@ def main(): if args.fix and failed_files: print('Applying fixes ...') try: - subprocess.call(['clang-apply-replacements-7', tmpdir]) + subprocess.call(['clang-apply-replacements-11', tmpdir]) except: print('Error applying fixes.\n', file=sys.stderr) raise From 7c678659d43a3f9cd8fcb34966e551113fb94a4c Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Tue, 8 Jun 2021 22:23:23 +0200 Subject: [PATCH 097/104] Remove explain changes section from PR template (#1876) --- .github/PULL_REQUEST_TEMPLATE.md | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 0d77eee7aa..aa90ef365f 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,25 +1,22 @@ # What does this implement/fix? -Quick description +Quick description and explanation of changes ## Types of changes - [ ] Bugfix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) -- [ ] Configuration change (this will require users to update their yaml configuration files to keep working) +- [ ] Other **Related issue or feature (if applicable):** fixes **Pull request in [esphome-docs](https://github.com/esphome/esphome-docs) with documentation (if applicable):** esphome/esphome-docs# - -# Test Environment + +## Test Environment - [ ] ESP32 - [ ] ESP8266 -- [ ] Windows -- [ ] Mac OS -- [ ] Linux ## Example entry for `config.yaml`: