mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	Merge remote-tracking branch 'refs/remotes/origin/gsm' into gsm
This commit is contained in:
		
							
								
								
									
										2
									
								
								.github/workflows/ci-docker.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/ci-docker.yml
									
									
									
									
										vendored
									
									
								
							| @@ -46,7 +46,7 @@ jobs: | ||||
|         with: | ||||
|           python-version: "3.9" | ||||
|       - name: Set up Docker Buildx | ||||
|         uses: docker/setup-buildx-action@v3.5.0 | ||||
|         uses: docker/setup-buildx-action@v3.6.1 | ||||
|       - name: Set up QEMU | ||||
|         uses: docker/setup-qemu-action@v3.2.0 | ||||
|  | ||||
|   | ||||
							
								
								
									
										4
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							| @@ -90,7 +90,7 @@ jobs: | ||||
|           python-version: "3.9" | ||||
|  | ||||
|       - name: Set up Docker Buildx | ||||
|         uses: docker/setup-buildx-action@v3.5.0 | ||||
|         uses: docker/setup-buildx-action@v3.6.1 | ||||
|       - name: Set up QEMU | ||||
|         if: matrix.platform != 'linux/amd64' | ||||
|         uses: docker/setup-qemu-action@v3.2.0 | ||||
| @@ -184,7 +184,7 @@ jobs: | ||||
|           merge-multiple: true | ||||
|  | ||||
|       - name: Set up Docker Buildx | ||||
|         uses: docker/setup-buildx-action@v3.5.0 | ||||
|         uses: docker/setup-buildx-action@v3.6.1 | ||||
|  | ||||
|       - name: Log in to docker hub | ||||
|         if: matrix.registry == 'dockerhub' | ||||
|   | ||||
| @@ -428,6 +428,7 @@ esphome/components/veml7700/* @latonita | ||||
| esphome/components/version/* @esphome/core | ||||
| esphome/components/voice_assistant/* @jesserockz | ||||
| esphome/components/wake_on_lan/* @clydebarrow @willwill2will54 | ||||
| esphome/components/watchdog/* @oarcher | ||||
| esphome/components/waveshare_epaper/* @clydebarrow | ||||
| esphome/components/web_server_base/* @OttoWinter | ||||
| esphome/components/web_server_idf/* @dentra | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| # PYTHON_ARGCOMPLETE_OK | ||||
| import argparse | ||||
| from datetime import datetime | ||||
| import functools | ||||
| import logging | ||||
| import os | ||||
| import re | ||||
| import sys | ||||
| import time | ||||
| from datetime import datetime | ||||
|  | ||||
| import argcomplete | ||||
|  | ||||
| @@ -39,14 +39,14 @@ from esphome.const import ( | ||||
| ) | ||||
| from esphome.core import CORE, EsphomeError, coroutine | ||||
| from esphome.helpers import indent, is_ip_address | ||||
| from esphome.log import Fore, color, setup_log | ||||
| from esphome.util import ( | ||||
|     get_serial_ports, | ||||
|     list_yaml_files, | ||||
|     run_external_command, | ||||
|     run_external_process, | ||||
|     safe_print, | ||||
|     list_yaml_files, | ||||
|     get_serial_ports, | ||||
| ) | ||||
| from esphome.log import color, setup_log, Fore | ||||
|  | ||||
| _LOGGER = logging.getLogger(__name__) | ||||
|  | ||||
| @@ -116,6 +116,7 @@ def get_port_type(port): | ||||
|  | ||||
| def run_miniterm(config, port): | ||||
|     import serial | ||||
|  | ||||
|     from esphome import platformio_api | ||||
|  | ||||
|     if CONF_LOGGER not in config: | ||||
| @@ -596,9 +597,10 @@ def command_update_all(args): | ||||
|  | ||||
|  | ||||
| def command_idedata(args, config): | ||||
|     from esphome import platformio_api | ||||
|     import json | ||||
|  | ||||
|     from esphome import platformio_api | ||||
|  | ||||
|     logging.disable(logging.INFO) | ||||
|     logging.disable(logging.WARNING) | ||||
|  | ||||
| @@ -747,7 +749,14 @@ def parse_args(argv): | ||||
|     ) | ||||
|  | ||||
|     parser = argparse.ArgumentParser( | ||||
|         description=f"ESPHome v{const.__version__}", parents=[options_parser] | ||||
|         description=f"ESPHome {const.__version__}", parents=[options_parser] | ||||
|     ) | ||||
|  | ||||
|     parser.add_argument( | ||||
|         "--version", | ||||
|         action="version", | ||||
|         version=f"Version: {const.__version__}", | ||||
|         help="Print the ESPHome version and exit.", | ||||
|     ) | ||||
|  | ||||
|     mqtt_options = argparse.ArgumentParser(add_help=False) | ||||
| @@ -948,67 +957,6 @@ def parse_args(argv): | ||||
|     # a deprecation warning). | ||||
|     arguments = argv[1:] | ||||
|  | ||||
|     # On Python 3.9+ we can simply set exit_on_error=False in the constructor | ||||
|     def _raise(x): | ||||
|         raise argparse.ArgumentError(None, x) | ||||
|  | ||||
|     # First, try new-style parsing, but don't exit in case of failure | ||||
|     try: | ||||
|         # duplicate parser so that we can use the original one to raise errors later on | ||||
|         current_parser = argparse.ArgumentParser(add_help=False, parents=[parser]) | ||||
|         current_parser.set_defaults(deprecated_argv_suggestion=None) | ||||
|         current_parser.error = _raise | ||||
|         return current_parser.parse_args(arguments) | ||||
|     except argparse.ArgumentError: | ||||
|         pass | ||||
|  | ||||
|     # Second, try compat parsing and rearrange the command-line if it succeeds | ||||
|     # 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", action="store_true") | ||||
|     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", | ||||
|             "vscode", | ||||
|             "update-all", | ||||
|         ], | ||||
|     ) | ||||
|  | ||||
|     try: | ||||
|         compat_parser.error = _raise | ||||
|         result, unparsed = compat_parser.parse_known_args(argv[1:]) | ||||
|         last_option = len(arguments) - len(unparsed) - 1 - len(result.configuration) | ||||
|         unparsed = [ | ||||
|             "--device" if arg in ("--upload-port", "--serial-port") else arg | ||||
|             for arg in unparsed | ||||
|         ] | ||||
|         arguments = ( | ||||
|             arguments[0:last_option] | ||||
|             + [result.command] | ||||
|             + result.configuration | ||||
|             + unparsed | ||||
|         ) | ||||
|         deprecated_argv_suggestion = arguments | ||||
|     except argparse.ArgumentError: | ||||
|         # old-style parsing failed, don't suggest any argument | ||||
|         deprecated_argv_suggestion = None | ||||
|  | ||||
|     # Finally, run the new-style parser again with the possibly swapped arguments, | ||||
|     # and let it error out if the command is unparsable. | ||||
|     parser.set_defaults(deprecated_argv_suggestion=deprecated_argv_suggestion) | ||||
|     argcomplete.autocomplete(parser) | ||||
|     return parser.parse_args(arguments) | ||||
|  | ||||
| @@ -1023,13 +971,6 @@ def run_esphome(argv): | ||||
|         # Show timestamp for dashboard access logs | ||||
|         args.command == "dashboard", | ||||
|     ) | ||||
|     if args.deprecated_argv_suggestion is not None and args.command != "vscode": | ||||
|         _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)) | ||||
|  | ||||
|     if sys.version_info < (3, 8, 0): | ||||
|         _LOGGER.error( | ||||
|   | ||||
| @@ -7,10 +7,10 @@ from esphome.const import ( | ||||
|     CONF_ELSE, | ||||
|     CONF_ID, | ||||
|     CONF_THEN, | ||||
|     CONF_TIME, | ||||
|     CONF_TIMEOUT, | ||||
|     CONF_TRIGGER_ID, | ||||
|     CONF_TYPE_ID, | ||||
|     CONF_TIME, | ||||
|     CONF_UPDATE_INTERVAL, | ||||
| ) | ||||
| from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor | ||||
|   | ||||
| @@ -8,55 +8,78 @@ | ||||
| # want to break suddenly due to a rename (this file will get backports for features). | ||||
|  | ||||
| # pylint: disable=unused-import | ||||
| from esphome.cpp_generator import (  # noqa | ||||
| from esphome.cpp_generator import (  # noqa: F401 | ||||
|     ArrayInitializer, | ||||
|     Expression, | ||||
|     LineComment, | ||||
|     MockObj, | ||||
|     MockObjClass, | ||||
|     Pvariable, | ||||
|     RawExpression, | ||||
|     RawStatement, | ||||
|     TemplateArguments, | ||||
|     StructInitializer, | ||||
|     ArrayInitializer, | ||||
|     safe_exp, | ||||
|     Statement, | ||||
|     LineComment, | ||||
|     progmem_array, | ||||
|     static_const_array, | ||||
|     statement, | ||||
|     variable, | ||||
|     with_local_variable, | ||||
|     new_variable, | ||||
|     Pvariable, | ||||
|     new_Pvariable, | ||||
|     StructInitializer, | ||||
|     TemplateArguments, | ||||
|     add, | ||||
|     add_global, | ||||
|     add_library, | ||||
|     add_build_flag, | ||||
|     add_define, | ||||
|     add_global, | ||||
|     add_library, | ||||
|     add_platformio_option, | ||||
|     get_variable, | ||||
|     get_variable_with_full_id, | ||||
|     process_lambda, | ||||
|     is_template, | ||||
|     new_Pvariable, | ||||
|     new_variable, | ||||
|     process_lambda, | ||||
|     progmem_array, | ||||
|     safe_exp, | ||||
|     statement, | ||||
|     static_const_array, | ||||
|     templatable, | ||||
|     MockObj, | ||||
|     MockObjClass, | ||||
|     variable, | ||||
|     with_local_variable, | ||||
| ) | ||||
| from esphome.cpp_helpers import (  # noqa | ||||
|     gpio_pin_expression, | ||||
|     register_component, | ||||
| from esphome.cpp_helpers import (  # noqa: F401 | ||||
|     build_registry_entry, | ||||
|     build_registry_list, | ||||
|     extract_registry_entry_config, | ||||
|     register_parented, | ||||
|     gpio_pin_expression, | ||||
|     past_safe_mode, | ||||
|     register_component, | ||||
|     register_parented, | ||||
| ) | ||||
| from esphome.cpp_types import (  # noqa | ||||
|     global_ns, | ||||
|     void, | ||||
|     nullptr, | ||||
|     float_, | ||||
|     double, | ||||
| from esphome.cpp_types import (  # noqa: F401 | ||||
|     NAN, | ||||
|     App, | ||||
|     Application, | ||||
|     Component, | ||||
|     ComponentPtr, | ||||
|     Controller, | ||||
|     EntityBase, | ||||
|     EntityCategory, | ||||
|     ESPTime, | ||||
|     GPIOPin, | ||||
|     InternalGPIOPin, | ||||
|     JsonObject, | ||||
|     JsonObjectConst, | ||||
|     Parented, | ||||
|     PollingComponent, | ||||
|     arduino_json_ns, | ||||
|     bool_, | ||||
|     const_char_ptr, | ||||
|     double, | ||||
|     esphome_ns, | ||||
|     float_, | ||||
|     global_ns, | ||||
|     gpio_Flags, | ||||
|     int16, | ||||
|     int32, | ||||
|     int64, | ||||
|     int_, | ||||
|     nullptr, | ||||
|     optional, | ||||
|     size_t, | ||||
|     std_ns, | ||||
|     std_shared_ptr, | ||||
|     std_string, | ||||
| @@ -66,28 +89,5 @@ from esphome.cpp_types import (  # noqa | ||||
|     uint16, | ||||
|     uint32, | ||||
|     uint64, | ||||
|     int16, | ||||
|     int32, | ||||
|     int64, | ||||
|     size_t, | ||||
|     const_char_ptr, | ||||
|     NAN, | ||||
|     esphome_ns, | ||||
|     App, | ||||
|     EntityBase, | ||||
|     Component, | ||||
|     ComponentPtr, | ||||
|     PollingComponent, | ||||
|     Application, | ||||
|     optional, | ||||
|     arduino_json_ns, | ||||
|     JsonObject, | ||||
|     JsonObjectConst, | ||||
|     Controller, | ||||
|     GPIOPin, | ||||
|     InternalGPIOPin, | ||||
|     gpio_Flags, | ||||
|     EntityCategory, | ||||
|     Parented, | ||||
|     ESPTime, | ||||
|     void, | ||||
| ) | ||||
|   | ||||
| @@ -1,7 +1,8 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome import automation | ||||
| from esphome.automation import maybe_simple_id | ||||
| from esphome.components import esp32_ble_tracker, esp32_ble_client | ||||
| import esphome.codegen as cg | ||||
| from esphome.components import esp32_ble_client, esp32_ble_tracker | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import ( | ||||
|     CONF_CHARACTERISTIC_UUID, | ||||
|     CONF_ID, | ||||
| @@ -13,7 +14,6 @@ from esphome.const import ( | ||||
|     CONF_TRIGGER_ID, | ||||
|     CONF_VALUE, | ||||
| ) | ||||
| from esphome import automation | ||||
|  | ||||
| AUTO_LOAD = ["esp32_ble_client"] | ||||
| CODEOWNERS = ["@buxtronix", "@clydebarrow"] | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.components import ble_client, esp32_ble_tracker, output | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import CONF_CHARACTERISTIC_UUID, CONF_ID, CONF_SERVICE_UUID | ||||
|  | ||||
| from .. import ble_client_ns | ||||
|   | ||||
| @@ -1,17 +1,18 @@ | ||||
| from esphome import automation | ||||
| import esphome.codegen as cg | ||||
| from esphome.components import ble_client, esp32_ble_tracker, sensor | ||||
| import esphome.config_validation as cv | ||||
| from esphome.components import sensor, ble_client, esp32_ble_tracker | ||||
| from esphome.const import ( | ||||
|     CONF_CHARACTERISTIC_UUID, | ||||
|     CONF_LAMBDA, | ||||
|     CONF_SERVICE_UUID, | ||||
|     CONF_TRIGGER_ID, | ||||
|     CONF_TYPE, | ||||
|     CONF_SERVICE_UUID, | ||||
|     DEVICE_CLASS_SIGNAL_STRENGTH, | ||||
|     STATE_CLASS_MEASUREMENT, | ||||
|     UNIT_DECIBEL_MILLIWATT, | ||||
| ) | ||||
| from esphome import automation | ||||
|  | ||||
| from .. import ble_client_ns | ||||
|  | ||||
| DEPENDENCIES = ["ble_client"] | ||||
|   | ||||
| @@ -1,7 +1,8 @@ | ||||
| import esphome.codegen as cg | ||||
| from esphome.components import ble_client, switch | ||||
| import esphome.config_validation as cv | ||||
| from esphome.components import switch, ble_client | ||||
| from esphome.const import ICON_BLUETOOTH | ||||
|  | ||||
| from .. import ble_client_ns | ||||
|  | ||||
| BLEClientSwitch = ble_client_ns.class_( | ||||
|   | ||||
| @@ -1,13 +1,14 @@ | ||||
| from esphome import automation | ||||
| import esphome.codegen as cg | ||||
| from esphome.components import ble_client, esp32_ble_tracker, text_sensor | ||||
| import esphome.config_validation as cv | ||||
| from esphome.components import text_sensor, ble_client, esp32_ble_tracker | ||||
| from esphome.const import ( | ||||
|     CONF_CHARACTERISTIC_UUID, | ||||
|     CONF_ID, | ||||
|     CONF_TRIGGER_ID, | ||||
|     CONF_SERVICE_UUID, | ||||
|     CONF_TRIGGER_ID, | ||||
| ) | ||||
| from esphome import automation | ||||
|  | ||||
| from .. import ble_client_ns | ||||
|  | ||||
| DEPENDENCIES = ["ble_client"] | ||||
|   | ||||
| @@ -1,13 +1,13 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.components import binary_sensor, esp32_ble_tracker | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import ( | ||||
|     CONF_MAC_ADDRESS, | ||||
|     CONF_SERVICE_UUID, | ||||
|     CONF_IBEACON_MAJOR, | ||||
|     CONF_IBEACON_MINOR, | ||||
|     CONF_IBEACON_UUID, | ||||
|     CONF_MAC_ADDRESS, | ||||
|     CONF_MIN_RSSI, | ||||
|     CONF_SERVICE_UUID, | ||||
|     CONF_TIMEOUT, | ||||
| ) | ||||
|  | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| import esphome.codegen as cg | ||||
| from esphome.components import esp32_ble_tracker, sensor | ||||
| import esphome.config_validation as cv | ||||
| from esphome.components import sensor, esp32_ble_tracker | ||||
| from esphome.const import ( | ||||
|     CONF_IBEACON_MAJOR, | ||||
|     CONF_IBEACON_MINOR, | ||||
|     CONF_IBEACON_UUID, | ||||
|     CONF_SERVICE_UUID, | ||||
|     CONF_MAC_ADDRESS, | ||||
|     CONF_SERVICE_UUID, | ||||
|     DEVICE_CLASS_SIGNAL_STRENGTH, | ||||
|     STATE_CLASS_MEASUREMENT, | ||||
|     UNIT_DECIBEL_MILLIWATT, | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import esphome.codegen as cg | ||||
| from esphome.components import esp32_ble_tracker, text_sensor | ||||
| import esphome.config_validation as cv | ||||
| from esphome.components import text_sensor, esp32_ble_tracker | ||||
|  | ||||
| DEPENDENCIES = ["esp32_ble_tracker"] | ||||
|  | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| from esphome.components import esp32_ble_tracker, esp32_ble_client | ||||
| import esphome.config_validation as cv | ||||
| import esphome.codegen as cg | ||||
| from esphome.const import CONF_ACTIVE, CONF_ID | ||||
| from esphome.components import esp32_ble_client, esp32_ble_tracker | ||||
| from esphome.components.esp32 import add_idf_sdkconfig_option | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import CONF_ACTIVE, CONF_ID | ||||
|  | ||||
| AUTO_LOAD = ["esp32_ble_client", "esp32_ble_tracker"] | ||||
| DEPENDENCIES = ["api", "esp32"] | ||||
|   | ||||
| @@ -1,11 +1,12 @@ | ||||
| from dataclasses import dataclass | ||||
| from typing import Union, Optional | ||||
| from pathlib import Path | ||||
| import logging | ||||
| import os | ||||
| import esphome.final_validate as fv | ||||
| from pathlib import Path | ||||
| from typing import Optional, Union | ||||
|  | ||||
| from esphome.helpers import copy_file_if_changed, write_file_if_changed, mkdir_p | ||||
| from esphome import git | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import ( | ||||
|     CONF_ADVANCED, | ||||
|     CONF_BOARD, | ||||
| @@ -15,6 +16,7 @@ from esphome.const import ( | ||||
|     CONF_IGNORE_EFUSE_MAC_CRC, | ||||
|     CONF_NAME, | ||||
|     CONF_PATH, | ||||
|     CONF_PLATFORM_VERSION, | ||||
|     CONF_PLATFORMIO_OPTIONS, | ||||
|     CONF_REF, | ||||
|     CONF_REFRESH, | ||||
| @@ -32,13 +34,12 @@ from esphome.const import ( | ||||
|     TYPE_GIT, | ||||
|     TYPE_LOCAL, | ||||
|     __version__, | ||||
|     CONF_PLATFORM_VERSION, | ||||
| ) | ||||
| from esphome.core import CORE, HexInt, TimePeriod | ||||
| import esphome.config_validation as cv | ||||
| import esphome.codegen as cg | ||||
| from esphome import git | ||||
| import esphome.final_validate as fv | ||||
| from esphome.helpers import copy_file_if_changed, mkdir_p, write_file_if_changed | ||||
|  | ||||
| from .boards import BOARDS | ||||
| from .const import (  # noqa | ||||
|     KEY_BOARD, | ||||
|     KEY_COMPONENTS, | ||||
| @@ -54,12 +55,10 @@ from .const import (  # noqa | ||||
|     VARIANT_FRIENDLY, | ||||
|     VARIANTS, | ||||
| ) | ||||
| from .boards import BOARDS | ||||
|  | ||||
| # force import gpio to register pin schema | ||||
| from .gpio import esp32_pin_to_code  # noqa | ||||
|  | ||||
|  | ||||
| _LOGGER = logging.getLogger(__name__) | ||||
| CODEOWNERS = ["@esphome/core"] | ||||
| AUTO_LOAD = ["preferences"] | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| from .const import VARIANT_ESP32, VARIANT_ESP32S2, VARIANT_ESP32C3, VARIANT_ESP32S3 | ||||
| from .const import VARIANT_ESP32, VARIANT_ESP32C3, VARIANT_ESP32S2, VARIANT_ESP32S3 | ||||
|  | ||||
| ESP32_BASE_PINS = { | ||||
|     "TX": 1, | ||||
|   | ||||
| @@ -1,22 +1,22 @@ | ||||
| from dataclasses import dataclass | ||||
| from typing import Any | ||||
| import logging | ||||
| from typing import Any | ||||
|  | ||||
| from esphome import pins | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import ( | ||||
|     CONF_ID, | ||||
|     CONF_IGNORE_PIN_VALIDATION_ERROR, | ||||
|     CONF_IGNORE_STRAPPING_WARNING, | ||||
|     CONF_INVERTED, | ||||
|     CONF_MODE, | ||||
|     CONF_NUMBER, | ||||
|     CONF_OPEN_DRAIN, | ||||
|     CONF_OUTPUT, | ||||
|     CONF_IGNORE_PIN_VALIDATION_ERROR, | ||||
|     CONF_IGNORE_STRAPPING_WARNING, | ||||
|     PLATFORM_ESP32, | ||||
| ) | ||||
| from esphome import pins | ||||
| from esphome.core import CORE | ||||
| import esphome.config_validation as cv | ||||
| import esphome.codegen as cg | ||||
|  | ||||
| from . import boards | ||||
| from .const import ( | ||||
| @@ -24,22 +24,21 @@ from .const import ( | ||||
|     KEY_ESP32, | ||||
|     KEY_VARIANT, | ||||
|     VARIANT_ESP32, | ||||
|     VARIANT_ESP32C3, | ||||
|     VARIANT_ESP32S2, | ||||
|     VARIANT_ESP32S3, | ||||
|     VARIANT_ESP32C2, | ||||
|     VARIANT_ESP32C3, | ||||
|     VARIANT_ESP32C6, | ||||
|     VARIANT_ESP32H2, | ||||
|     VARIANT_ESP32S2, | ||||
|     VARIANT_ESP32S3, | ||||
|     esp32_ns, | ||||
| ) | ||||
|  | ||||
| from .gpio_esp32 import esp32_validate_gpio_pin, esp32_validate_supports | ||||
| from .gpio_esp32_s2 import esp32_s2_validate_gpio_pin, esp32_s2_validate_supports | ||||
| from .gpio_esp32_c3 import esp32_c3_validate_gpio_pin, esp32_c3_validate_supports | ||||
| from .gpio_esp32_s3 import esp32_s3_validate_gpio_pin, esp32_s3_validate_supports | ||||
| from .gpio_esp32_c2 import esp32_c2_validate_gpio_pin, esp32_c2_validate_supports | ||||
| from .gpio_esp32_c3 import esp32_c3_validate_gpio_pin, esp32_c3_validate_supports | ||||
| from .gpio_esp32_c6 import esp32_c6_validate_gpio_pin, esp32_c6_validate_supports | ||||
| from .gpio_esp32_h2 import esp32_h2_validate_gpio_pin, esp32_h2_validate_supports | ||||
| from .gpio_esp32_s2 import esp32_s2_validate_gpio_pin, esp32_s2_validate_supports | ||||
| from .gpio_esp32_s3 import esp32_s3_validate_gpio_pin, esp32_s3_validate_supports | ||||
|  | ||||
| ESP32InternalGPIOPin = esp32_ns.class_("ESP32InternalGPIOPin", cg.InternalGPIOPin) | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| import logging | ||||
|  | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import ( | ||||
|     CONF_INPUT, | ||||
|     CONF_MODE, | ||||
| @@ -8,10 +9,8 @@ from esphome.const import ( | ||||
|     CONF_PULLDOWN, | ||||
|     CONF_PULLUP, | ||||
| ) | ||||
| import esphome.config_validation as cv | ||||
| from esphome.pins import check_strapping_pin | ||||
|  | ||||
|  | ||||
| _ESP_SDIO_PINS = { | ||||
|     6: "Flash Clock", | ||||
|     7: "Flash Data 0", | ||||
|   | ||||
| @@ -1,10 +1,9 @@ | ||||
| import logging | ||||
|  | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER | ||||
| from esphome.pins import check_strapping_pin | ||||
|  | ||||
| import esphome.config_validation as cv | ||||
|  | ||||
| _ESP32C2_STRAPPING_PINS = {8, 9} | ||||
|  | ||||
| _LOGGER = logging.getLogger(__name__) | ||||
|   | ||||
| @@ -1,11 +1,7 @@ | ||||
| import logging | ||||
|  | ||||
| from esphome.const import ( | ||||
|     CONF_INPUT, | ||||
|     CONF_MODE, | ||||
|     CONF_NUMBER, | ||||
| ) | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER | ||||
| from esphome.pins import check_strapping_pin | ||||
|  | ||||
| _ESP32C3_SPI_PSRAM_PINS = { | ||||
|   | ||||
| @@ -1,8 +1,7 @@ | ||||
| import logging | ||||
|  | ||||
| from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER | ||||
|  | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER | ||||
| from esphome.pins import check_strapping_pin | ||||
|  | ||||
| _ESP32C6_SPI_PSRAM_PINS = { | ||||
|   | ||||
| @@ -1,8 +1,7 @@ | ||||
| import logging | ||||
|  | ||||
| from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER | ||||
|  | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER | ||||
|  | ||||
| _ESP32H2_SPI_FLASH_PINS = {6, 7, 15, 16, 17, 18, 19, 20, 21} | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| import logging | ||||
|  | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import ( | ||||
|     CONF_INPUT, | ||||
|     CONF_MODE, | ||||
| @@ -8,8 +9,6 @@ from esphome.const import ( | ||||
|     CONF_PULLDOWN, | ||||
|     CONF_PULLUP, | ||||
| ) | ||||
|  | ||||
| import esphome.config_validation as cv | ||||
| from esphome.pins import check_strapping_pin | ||||
|  | ||||
| _ESP32S2_SPI_PSRAM_PINS = { | ||||
|   | ||||
| @@ -1,12 +1,7 @@ | ||||
| import logging | ||||
|  | ||||
| from esphome.const import ( | ||||
|     CONF_INPUT, | ||||
|     CONF_MODE, | ||||
|     CONF_NUMBER, | ||||
| ) | ||||
|  | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER | ||||
| from esphome.pins import check_strapping_pin | ||||
|  | ||||
| _ESP_32S3_SPI_PSRAM_PINS = { | ||||
|   | ||||
| @@ -1,9 +1,9 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome import automation | ||||
| import esphome.codegen as cg | ||||
| from esphome.components.esp32 import add_idf_sdkconfig_option, const, get_esp32_variant | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import CONF_ENABLE_ON_BOOT, CONF_ID | ||||
| from esphome.core import CORE | ||||
| from esphome.components.esp32 import add_idf_sdkconfig_option, get_esp32_variant, const | ||||
|  | ||||
| DEPENDENCIES = ["esp32"] | ||||
| CODEOWNERS = ["@jesserockz", "@Rapsssito"] | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.components.esp32_ble import CONF_BLE_ID | ||||
| from esphome.const import CONF_ID, CONF_TYPE, CONF_UUID, CONF_TX_POWER | ||||
| from esphome.core import CORE, TimePeriod | ||||
| from esphome.components.esp32 import add_idf_sdkconfig_option | ||||
| from esphome.components import esp32_ble | ||||
| from esphome.components.esp32 import add_idf_sdkconfig_option | ||||
| from esphome.components.esp32_ble import CONF_BLE_ID | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import CONF_ID, CONF_TX_POWER, CONF_TYPE, CONF_UUID | ||||
| from esphome.core import CORE, TimePeriod | ||||
|  | ||||
| AUTO_LOAD = ["esp32_ble"] | ||||
| DEPENDENCIES = ["esp32"] | ||||
|   | ||||
| @@ -1,5 +1,4 @@ | ||||
| import esphome.codegen as cg | ||||
|  | ||||
| from esphome.components import esp32_ble_tracker | ||||
|  | ||||
| AUTO_LOAD = ["esp32_ble_tracker"] | ||||
|   | ||||
| @@ -1,9 +1,9 @@ | ||||
| import esphome.codegen as cg | ||||
| from esphome.components import esp32_ble | ||||
| from esphome.components.esp32 import add_idf_sdkconfig_option | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import CONF_ID, CONF_MODEL | ||||
| from esphome.components import esp32_ble | ||||
| from esphome.core import CORE | ||||
| from esphome.components.esp32 import add_idf_sdkconfig_option | ||||
|  | ||||
| AUTO_LOAD = ["esp32_ble"] | ||||
| CODEOWNERS = ["@jesserockz", "@clydebarrow", "@Rapsssito"] | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| import re | ||||
|  | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome import automation | ||||
| import esphome.codegen as cg | ||||
| from esphome.components import esp32_ble | ||||
| from esphome.components.esp32 import add_idf_sdkconfig_option | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import ( | ||||
|     CONF_ACTIVE, | ||||
|     CONF_DURATION, | ||||
|   | ||||
| @@ -1,6 +1,4 @@ | ||||
| from esphome import pins | ||||
| import esphome.config_validation as cv | ||||
| import esphome.final_validate as fv | ||||
| import esphome.codegen as cg | ||||
| from esphome.components.esp32 import add_idf_sdkconfig_option, get_esp32_variant | ||||
| from esphome.components.esp32.const import ( | ||||
| @@ -8,31 +6,33 @@ from esphome.components.esp32.const import ( | ||||
|     VARIANT_ESP32S2, | ||||
|     VARIANT_ESP32S3, | ||||
| ) | ||||
| from esphome.components.network import IPAddress | ||||
| from esphome.components.spi import CONF_INTERFACE_INDEX, get_spi_interface | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import ( | ||||
|     CONF_DOMAIN, | ||||
|     CONF_ID, | ||||
|     CONF_VALUE, | ||||
|     CONF_MANUAL_IP, | ||||
|     CONF_STATIC_IP, | ||||
|     CONF_TYPE, | ||||
|     CONF_USE_ADDRESS, | ||||
|     CONF_GATEWAY, | ||||
|     CONF_SUBNET, | ||||
|     CONF_ADDRESS, | ||||
|     CONF_CLK_PIN, | ||||
|     CONF_CS_PIN, | ||||
|     CONF_DNS1, | ||||
|     CONF_DNS2, | ||||
|     CONF_CLK_PIN, | ||||
|     CONF_DOMAIN, | ||||
|     CONF_GATEWAY, | ||||
|     CONF_ID, | ||||
|     CONF_INTERRUPT_PIN, | ||||
|     CONF_MANUAL_IP, | ||||
|     CONF_MISO_PIN, | ||||
|     CONF_MOSI_PIN, | ||||
|     CONF_CS_PIN, | ||||
|     CONF_INTERRUPT_PIN, | ||||
|     CONF_PAGE_ID, | ||||
|     CONF_RESET_PIN, | ||||
|     CONF_SPI, | ||||
|     CONF_PAGE_ID, | ||||
|     CONF_ADDRESS, | ||||
|     CONF_STATIC_IP, | ||||
|     CONF_SUBNET, | ||||
|     CONF_TYPE, | ||||
|     CONF_USE_ADDRESS, | ||||
|     CONF_VALUE, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.components.network import IPAddress | ||||
| from esphome.components.spi import get_spi_interface, CONF_INTERFACE_INDEX | ||||
| import esphome.final_validate as fv | ||||
|  | ||||
| CONFLICTS_WITH = ["wifi"] | ||||
| DEPENDENCIES = ["esp32"] | ||||
|   | ||||
| @@ -1,9 +1,9 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.components import text_sensor | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import ( | ||||
|     CONF_IP_ADDRESS, | ||||
|     CONF_DNS_ADDRESS, | ||||
|     CONF_IP_ADDRESS, | ||||
|     CONF_MAC_ADDRESS, | ||||
|     ENTITY_CATEGORY_DIAGNOSTIC, | ||||
| ) | ||||
|   | ||||
| @@ -14,7 +14,7 @@ from esphome.const import ( | ||||
| from esphome.core import CORE, Lambda | ||||
|  | ||||
| DEPENDENCIES = ["network"] | ||||
| AUTO_LOAD = ["json"] | ||||
| AUTO_LOAD = ["json", "watchdog"] | ||||
|  | ||||
| http_request_ns = cg.esphome_ns.namespace("http_request") | ||||
| HttpRequestComponent = http_request_ns.class_("HttpRequestComponent", cg.Component) | ||||
|   | ||||
| @@ -3,12 +3,12 @@ | ||||
| #ifdef USE_ARDUINO | ||||
|  | ||||
| #include "esphome/components/network/util.h" | ||||
| #include "esphome/components/watchdog/watchdog.h" | ||||
|  | ||||
| #include "esphome/core/application.h" | ||||
| #include "esphome/core/defines.h" | ||||
| #include "esphome/core/log.h" | ||||
|  | ||||
| #include "watchdog.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace http_request { | ||||
|  | ||||
|   | ||||
| @@ -3,6 +3,8 @@ | ||||
| #ifdef USE_ESP_IDF | ||||
|  | ||||
| #include "esphome/components/network/util.h" | ||||
| #include "esphome/components/watchdog/watchdog.h" | ||||
|  | ||||
| #include "esphome/core/application.h" | ||||
| #include "esphome/core/defines.h" | ||||
| #include "esphome/core/log.h" | ||||
| @@ -11,8 +13,6 @@ | ||||
| #include "esp_crt_bundle.h" | ||||
| #endif | ||||
|  | ||||
| #include "watchdog.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace http_request { | ||||
|  | ||||
|   | ||||
| @@ -1,11 +1,11 @@ | ||||
| #include "ota_http_request.h" | ||||
| #include "../watchdog.h" | ||||
|  | ||||
| #include "esphome/core/application.h" | ||||
| #include "esphome/core/defines.h" | ||||
| #include "esphome/core/log.h" | ||||
|  | ||||
| #include "esphome/components/md5/md5.h" | ||||
| #include "esphome/components/watchdog/watchdog.h" | ||||
| #include "esphome/components/ota/ota_backend.h" | ||||
| #include "esphome/components/ota/ota_backend_arduino_esp32.h" | ||||
| #include "esphome/components/ota/ota_backend_arduino_esp8266.h" | ||||
|   | ||||
| @@ -16,13 +16,20 @@ from esphome.final_validate import full_config | ||||
| from esphome.helpers import write_file_if_changed | ||||
|  | ||||
| from . import defines as df, helpers, lv_validation as lvalid | ||||
| from .btn import btn_spec | ||||
| from .label import label_spec | ||||
| from .lvcode import ConstantLiteral, LvContext | ||||
|  | ||||
| # from .menu import menu_spec | ||||
| from .obj import obj_spec | ||||
| from .schemas import WIDGET_TYPES, any_widget_schema, obj_schema | ||||
| from .types import FontEngine, LvglComponent, lv_disp_t_ptr, lv_font_t, lvgl_ns | ||||
| from .schemas import any_widget_schema, obj_schema | ||||
| from .touchscreens import touchscreen_schema, touchscreens_to_code | ||||
| from .types import ( | ||||
|     WIDGET_TYPES, | ||||
|     FontEngine, | ||||
|     LvglComponent, | ||||
|     lv_disp_t_ptr, | ||||
|     lv_font_t, | ||||
|     lvgl_ns, | ||||
| ) | ||||
| from .widget import LvScrActType, Widget, add_widgets, set_obj_properties | ||||
|  | ||||
| DOMAIN = "lvgl" | ||||
| @@ -31,11 +38,8 @@ AUTO_LOAD = ("key_provider",) | ||||
| CODEOWNERS = ("@clydebarrow",) | ||||
| LOGGER = logging.getLogger(__name__) | ||||
|  | ||||
| for widg in ( | ||||
|     label_spec, | ||||
|     obj_spec, | ||||
| ): | ||||
|     WIDGET_TYPES[widg.name] = widg | ||||
| for w_type in (label_spec, obj_spec, btn_spec): | ||||
|     WIDGET_TYPES[w_type.name] = w_type | ||||
|  | ||||
| lv_scr_act_spec = LvScrActType() | ||||
| lv_scr_act = Widget.create( | ||||
| @@ -93,7 +97,7 @@ def final_validation(config): | ||||
|                 "Using auto_clear_enabled: true in display config not compatible with LVGL" | ||||
|             ) | ||||
|     buffer_frac = config[CONF_BUFFER_SIZE] | ||||
|     if not CORE.is_host and buffer_frac > 0.5 and "psram" not in global_config: | ||||
|     if CORE.is_esp32 and buffer_frac > 0.5 and "psram" not in global_config: | ||||
|         LOGGER.warning("buffer_size: may need to be reduced without PSRAM") | ||||
|  | ||||
|  | ||||
| @@ -132,7 +136,7 @@ async def to_code(config): | ||||
|     cg.add_global(lvgl_ns.using) | ||||
|     lv_component = cg.new_Pvariable(config[CONF_ID]) | ||||
|     await cg.register_component(lv_component, config) | ||||
|     Widget.create(config[CONF_ID], lv_component, WIDGET_TYPES[df.CONF_OBJ], config) | ||||
|     Widget.create(config[CONF_ID], lv_component, obj_spec, config) | ||||
|     for display in config[df.CONF_DISPLAYS]: | ||||
|         cg.add(lv_component.add_display(await cg.get_variable(display))) | ||||
|  | ||||
| @@ -152,7 +156,7 @@ async def to_code(config): | ||||
|         await cg.get_variable(font) | ||||
|         cg.new_Pvariable(ID(f"{font}_engine", True, type=FontEngine), MockObj(font)) | ||||
|     default_font = config[df.CONF_DEFAULT_FONT] | ||||
|     if default_font not in helpers.lv_fonts_used: | ||||
|     if not lvalid.is_lv_font(default_font): | ||||
|         add_define( | ||||
|             "LV_FONT_CUSTOM_DECLARE", f"LV_FONT_DECLARE(*{df.DEFAULT_ESPHOME_FONT})" | ||||
|         ) | ||||
| @@ -161,12 +165,15 @@ async def to_code(config): | ||||
|             True, | ||||
|             type=lv_font_t.operator("ptr").operator("const"), | ||||
|         ) | ||||
|         cg.new_variable(globfont_id, MockObj(default_font)) | ||||
|         cg.new_variable( | ||||
|             globfont_id, MockObj(await lvalid.lv_font.process(default_font)) | ||||
|         ) | ||||
|         add_define("LV_FONT_DEFAULT", df.DEFAULT_ESPHOME_FONT) | ||||
|     else: | ||||
|         add_define("LV_FONT_DEFAULT", default_font) | ||||
|         add_define("LV_FONT_DEFAULT", await lvalid.lv_font.process(default_font)) | ||||
|  | ||||
|     with LvContext(): | ||||
|         await touchscreens_to_code(lv_component, config) | ||||
|         await set_obj_properties(lv_scr_act, config) | ||||
|         await add_widgets(lv_scr_act, config) | ||||
|     Widget.set_completed() | ||||
| @@ -190,7 +197,7 @@ FINAL_VALIDATE_SCHEMA = final_validation | ||||
|  | ||||
| CONFIG_SCHEMA = ( | ||||
|     cv.polling_component_schema("1s") | ||||
|     .extend(obj_schema("obj")) | ||||
|     .extend(obj_schema(obj_spec)) | ||||
|     .extend( | ||||
|         { | ||||
|             cv.GenerateID(CONF_ID): cv.declare_id(LvglComponent), | ||||
| @@ -207,6 +214,7 @@ CONFIG_SCHEMA = ( | ||||
|             ), | ||||
|             cv.Optional(df.CONF_WIDGETS): cv.ensure_list(WIDGET_SCHEMA), | ||||
|             cv.Optional(df.CONF_TRANSPARENCY_KEY, default=0x000400): lvalid.lv_color, | ||||
|             cv.GenerateID(df.CONF_TOUCHSCREENS): touchscreen_schema, | ||||
|         } | ||||
|     ) | ||||
| ).add_extra(cv.has_at_least_one_key(CONF_PAGES, df.CONF_WIDGETS)) | ||||
|   | ||||
							
								
								
									
										25
									
								
								esphome/components/lvgl/btn.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								esphome/components/lvgl/btn.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| from esphome.const import CONF_BUTTON | ||||
| from esphome.cpp_generator import MockObjClass | ||||
|  | ||||
| from .defines import CONF_MAIN | ||||
| from .types import LvBoolean, WidgetType | ||||
|  | ||||
|  | ||||
| class BtnType(WidgetType): | ||||
|     def __init__(self): | ||||
|         super().__init__(CONF_BUTTON, LvBoolean("lv_btn_t"), (CONF_MAIN,)) | ||||
|  | ||||
|     async def to_code(self, w, config): | ||||
|         return [] | ||||
|  | ||||
|     def obj_creator(self, parent: MockObjClass, config: dict): | ||||
|         """ | ||||
|         LVGL 8 calls buttons `btn` | ||||
|         """ | ||||
|         return f"lv_btn_create({parent})" | ||||
|  | ||||
|     def get_uses(self): | ||||
|         return ("btn",) | ||||
|  | ||||
|  | ||||
| btn_spec = BtnType() | ||||
| @@ -446,6 +446,7 @@ CONF_TILE_ID = "tile_id" | ||||
| CONF_TILES = "tiles" | ||||
| CONF_TITLE = "title" | ||||
| CONF_TOP_LAYER = "top_layer" | ||||
| CONF_TOUCHSCREENS = "touchscreens" | ||||
| CONF_TRANSPARENCY_KEY = "transparency_key" | ||||
| CONF_THEME = "theme" | ||||
| CONF_VISIBLE_ROW_COUNT = "visible_row_count" | ||||
| @@ -474,14 +475,8 @@ LV_KEYS = LvConstant( | ||||
| ) | ||||
|  | ||||
|  | ||||
| # list of widgets and the parts allowed | ||||
| WIDGET_PARTS = { | ||||
|     CONF_LABEL: (CONF_MAIN, CONF_SCROLLBAR, CONF_SELECTED), | ||||
|     CONF_OBJ: (CONF_MAIN,), | ||||
| } | ||||
|  | ||||
| DEFAULT_ESPHOME_FONT = "esphome_lv_default_font" | ||||
|  | ||||
|  | ||||
| def join_enums(enums, prefix=""): | ||||
|     return "|".join(f"(int){prefix}{e.upper()}" for e in enums) | ||||
|     return ConstantLiteral("|".join(f"(int){prefix}{e.upper()}" for e in enums)) | ||||
|   | ||||
| @@ -22,7 +22,6 @@ def add_lv_use(*names): | ||||
|  | ||||
| lv_fonts_used = set() | ||||
| esphome_fonts_used = set() | ||||
| REQUIRED_COMPONENTS = {} | ||||
| lvgl_components_required = set() | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -1,16 +1,27 @@ | ||||
| import esphome.config_validation as cv | ||||
|  | ||||
| from .defines import CONF_LABEL, CONF_LONG_MODE, CONF_RECOLOR, CONF_TEXT, LV_LONG_MODES | ||||
| from .defines import ( | ||||
|     CONF_LABEL, | ||||
|     CONF_LONG_MODE, | ||||
|     CONF_MAIN, | ||||
|     CONF_RECOLOR, | ||||
|     CONF_SCROLLBAR, | ||||
|     CONF_SELECTED, | ||||
|     CONF_TEXT, | ||||
|     LV_LONG_MODES, | ||||
| ) | ||||
| from .lv_validation import lv_bool, lv_text | ||||
| from .schemas import TEXT_SCHEMA | ||||
| from .types import lv_label_t | ||||
| from .widget import Widget, WidgetType | ||||
| from .types import LvText, WidgetType | ||||
| from .widget import Widget | ||||
|  | ||||
|  | ||||
| class LabelType(WidgetType): | ||||
|     def __init__(self): | ||||
|         super().__init__( | ||||
|             CONF_LABEL, | ||||
|             LvText("lv_label_t"), | ||||
|             (CONF_MAIN, CONF_SCROLLBAR, CONF_SELECTED), | ||||
|             TEXT_SCHEMA.extend( | ||||
|                 { | ||||
|                     cv.Optional(CONF_RECOLOR): lv_bool, | ||||
| @@ -19,10 +30,6 @@ class LabelType(WidgetType): | ||||
|             ), | ||||
|         ) | ||||
|  | ||||
|     @property | ||||
|     def w_type(self): | ||||
|         return lv_label_t | ||||
|  | ||||
|     async def to_code(self, w: Widget, config): | ||||
|         """For a text object, create and set text""" | ||||
|         if value := config.get(CONF_TEXT): | ||||
|   | ||||
| @@ -8,6 +8,7 @@ import esphome.config_validation as cv | ||||
| from esphome.const import CONF_ARGS, CONF_COLOR, CONF_FORMAT | ||||
| from esphome.core import HexInt | ||||
| from esphome.cpp_generator import MockObj | ||||
| from esphome.cpp_types import uint32 | ||||
| from esphome.helpers import cpp_string_escape | ||||
| from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor | ||||
|  | ||||
| @@ -23,6 +24,28 @@ from .lvcode import ConstantLiteral, lv_expr | ||||
| from .types import lv_font_t | ||||
|  | ||||
|  | ||||
| def literal_mapper(value, args=()): | ||||
|     if isinstance(value, str): | ||||
|         return ConstantLiteral(value) | ||||
|     return value | ||||
|  | ||||
|  | ||||
| opacity_consts = LvConstant("LV_OPA_", "TRANSP", "COVER") | ||||
|  | ||||
|  | ||||
| @schema_extractor("one_of") | ||||
| def opacity_validator(value): | ||||
|     if value == SCHEMA_EXTRACT: | ||||
|         return opacity_consts.choices | ||||
|     value = cv.Any(cv.percentage, opacity_consts.one_of)(value) | ||||
|     if isinstance(value, float): | ||||
|         return int(value * 255) | ||||
|     return value | ||||
|  | ||||
|  | ||||
| opacity = LValidator(opacity_validator, uint32, retmapper=literal_mapper) | ||||
|  | ||||
|  | ||||
| @schema_extractor("one_of") | ||||
| def color(value): | ||||
|     if value == SCHEMA_EXTRACT: | ||||
| @@ -43,16 +66,24 @@ def color_retmapper(value): | ||||
|     return lv_expr.color_from(MockObj(value)) | ||||
|  | ||||
|  | ||||
| def pixels_or_percent(value): | ||||
| lv_color = LValidator(color, ty.lv_color_t, retmapper=color_retmapper) | ||||
|  | ||||
|  | ||||
| def pixels_or_percent_validator(value): | ||||
|     """A length in one axis - either a number (pixels) or a percentage""" | ||||
|     if value == SCHEMA_EXTRACT: | ||||
|         return ["pixels", "..%"] | ||||
|     if isinstance(value, int): | ||||
|         return str(cv.int_(value)) | ||||
|         return cv.int_(value) | ||||
|     # Will throw an exception if not a percentage. | ||||
|     return f"lv_pct({int(cv.percentage(value) * 100)})" | ||||
|  | ||||
|  | ||||
| pixels_or_percent = LValidator( | ||||
|     pixels_or_percent_validator, uint32, retmapper=literal_mapper | ||||
| ) | ||||
|  | ||||
|  | ||||
| def zoom(value): | ||||
|     value = cv.float_range(0.1, 10.0)(value) | ||||
|     return int(value * 256) | ||||
| @@ -68,7 +99,7 @@ def angle(value): | ||||
|  | ||||
|  | ||||
| @schema_extractor("one_of") | ||||
| def size(value): | ||||
| def size_validator(value): | ||||
|     """A size in one axis - one of "size_content", a number (pixels) or a percentage""" | ||||
|     if value == SCHEMA_EXTRACT: | ||||
|         return ["size_content", "pixels", "..%"] | ||||
| @@ -79,28 +110,42 @@ def size(value): | ||||
|             return "LV_SIZE_CONTENT" | ||||
|         raise cv.Invalid("must be 'size_content', a pixel position or a percentage") | ||||
|     if isinstance(value, int): | ||||
|         return str(cv.int_(value)) | ||||
|         return cv.int_(value) | ||||
|     # Will throw an exception if not a percentage. | ||||
|     return f"lv_pct({int(cv.percentage(value) * 100)})" | ||||
|  | ||||
|  | ||||
| size = LValidator(size_validator, uint32, retmapper=literal_mapper) | ||||
|  | ||||
| radius_consts = LvConstant("LV_RADIUS_", "CIRCLE") | ||||
|  | ||||
|  | ||||
| @schema_extractor("one_of") | ||||
| def opacity(value): | ||||
|     consts = LvConstant("LV_OPA_", "TRANSP", "COVER") | ||||
| def radius_validator(value): | ||||
|     if value == SCHEMA_EXTRACT: | ||||
|         return consts.choices | ||||
|     value = cv.Any(cv.percentage, consts.one_of)(value) | ||||
|         return radius_consts.choices | ||||
|     value = cv.Any(size, cv.percentage, radius_consts.one_of)(value) | ||||
|     if isinstance(value, float): | ||||
|         return int(value * 255) | ||||
|     return value | ||||
|  | ||||
|  | ||||
| def id_name(value): | ||||
|     if value == SCHEMA_EXTRACT: | ||||
|         return "id" | ||||
|     return cv.validate_id_name(value) | ||||
|  | ||||
|  | ||||
| radius = LValidator(radius_validator, uint32, retmapper=literal_mapper) | ||||
|  | ||||
|  | ||||
| def stop_value(value): | ||||
|     return cv.int_range(0, 255)(value) | ||||
|  | ||||
|  | ||||
| lv_color = LValidator(color, ty.lv_color_t, retmapper=color_retmapper) | ||||
| lv_bool = LValidator(cv.boolean, cg.bool_, BinarySensor, "get_state()") | ||||
| lv_bool = LValidator( | ||||
|     cv.boolean, cg.bool_, BinarySensor, "get_state()", retmapper=literal_mapper | ||||
| ) | ||||
|  | ||||
|  | ||||
| def lvms_validator_(value): | ||||
| @@ -145,26 +190,32 @@ lv_float = LValidator(cv.float_, cg.float_, Sensor, "get_state()") | ||||
| lv_int = LValidator(cv.int_, cg.int_, Sensor, "get_state()") | ||||
|  | ||||
|  | ||||
| def is_lv_font(font): | ||||
|     return isinstance(font, str) and font.lower() in LV_FONTS | ||||
|  | ||||
|  | ||||
| class LvFont(LValidator): | ||||
|     def __init__(self): | ||||
|         def lv_builtin_font(value): | ||||
|             fontval = cv.one_of(*LV_FONTS, lower=True)(value) | ||||
|             lv_fonts_used.add(fontval) | ||||
|             return "&lv_font_" + fontval | ||||
|             return fontval | ||||
|  | ||||
|         def validator(value): | ||||
|             if value == SCHEMA_EXTRACT: | ||||
|                 return LV_FONTS | ||||
|             if isinstance(value, str) and value.lower() in LV_FONTS: | ||||
|             if is_lv_font(value): | ||||
|                 return lv_builtin_font(value) | ||||
|             fontval = cv.use_id(Font)(value) | ||||
|             esphome_fonts_used.add(fontval) | ||||
|             return requires_component("font")(f"{fontval}_engine->get_lv_font()") | ||||
|             return requires_component("font")(fontval) | ||||
|  | ||||
|         super().__init__(validator, lv_font_t) | ||||
|  | ||||
|     async def process(self, value, args=()): | ||||
|         return ConstantLiteral(value) | ||||
|         if is_lv_font(value): | ||||
|             return ConstantLiteral(f"&lv_font_{value}") | ||||
|         return ConstantLiteral(f"{value}_engine->get_lv_font()") | ||||
|  | ||||
|  | ||||
| lv_font = LvFont() | ||||
|   | ||||
| @@ -38,7 +38,9 @@ void LvglComponent::setup() { | ||||
|   auto buf_bytes = buffer_pixels * LV_COLOR_DEPTH / 8; | ||||
|   auto *buf = lv_custom_mem_alloc(buf_bytes); | ||||
|   if (buf == nullptr) { | ||||
| #if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_ERROR | ||||
|     ESP_LOGE(TAG, "Malloc failed to allocate %zu bytes", buf_bytes); | ||||
| #endif | ||||
|     this->mark_failed(); | ||||
|     this->status_set_error("Memory allocation failure"); | ||||
|     return; | ||||
| @@ -85,7 +87,9 @@ size_t lv_millis(void) { return esphome::millis(); } | ||||
| void *lv_custom_mem_alloc(size_t size) { | ||||
|   auto *ptr = malloc(size);  // NOLINT | ||||
|   if (ptr == nullptr) { | ||||
| #if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_ERROR | ||||
|     esphome::ESP_LOGE(esphome::lvgl::TAG, "Failed to allocate %zu bytes", size); | ||||
| #endif | ||||
|   } | ||||
|   return ptr; | ||||
| } | ||||
| @@ -102,7 +106,9 @@ void *lv_custom_mem_alloc(size_t size) { | ||||
|     ptr = heap_caps_malloc(size, cap_bits); | ||||
|   } | ||||
|   if (ptr == nullptr) { | ||||
| #if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_ERROR | ||||
|     esphome::ESP_LOGE(esphome::lvgl::TAG, "Failed to allocate %zu bytes", size); | ||||
| #endif | ||||
|     return nullptr; | ||||
|   } | ||||
| #ifdef ESPHOME_LOG_HAS_VERBOSE | ||||
|   | ||||
| @@ -18,23 +18,27 @@ | ||||
| #ifdef USE_LVGL_FONT | ||||
| #include "esphome/components/font/font.h" | ||||
| #endif | ||||
| #ifdef USE_LVGL_TOUCHSCREEN | ||||
| #include "esphome/components/touchscreen/touchscreen.h" | ||||
| #endif  // USE_LVGL_TOUCHSCREEN | ||||
|  | ||||
| namespace esphome { | ||||
| namespace lvgl { | ||||
|  | ||||
| extern lv_event_code_t lv_custom_event;  // NOLINT | ||||
| #ifdef USE_LVGL_COLOR | ||||
| static lv_color_t lv_color_from(Color color) { return lv_color_make(color.red, color.green, color.blue); } | ||||
| #endif | ||||
| inline lv_color_t lv_color_from(Color color) { return lv_color_make(color.red, color.green, color.blue); } | ||||
| #endif  // USE_LVGL_COLOR | ||||
| #if LV_COLOR_DEPTH == 16 | ||||
| static const display::ColorBitness LV_BITNESS = display::ColorBitness::COLOR_BITNESS_565; | ||||
| #elif LV_COLOR_DEPTH == 32 | ||||
| static const display::ColorBitness LV_BITNESS = display::ColorBitness::COLOR_BITNESS_888; | ||||
| #else | ||||
| #else   // LV_COLOR_DEPTH | ||||
| static const display::ColorBitness LV_BITNESS = display::ColorBitness::COLOR_BITNESS_332; | ||||
| #endif | ||||
| #endif  // LV_COLOR_DEPTH | ||||
|  | ||||
| // Parent class for things that wrap an LVGL object | ||||
| class LvCompound { | ||||
| class LvCompound final { | ||||
|  public: | ||||
|   virtual void set_obj(lv_obj_t *lv_obj) { this->obj = lv_obj; } | ||||
|   lv_obj_t *obj{}; | ||||
| @@ -99,6 +103,14 @@ class LvglComponent : public PollingComponent { | ||||
|   void set_full_refresh(bool full_refresh) { this->full_refresh_ = full_refresh; } | ||||
|   void set_buffer_frac(size_t frac) { this->buffer_frac_ = frac; } | ||||
|   lv_disp_t *get_disp() { return this->disp_; } | ||||
|   void set_paused(bool paused, bool show_snow) { | ||||
|     this->paused_ = paused; | ||||
|     if (!paused && lv_scr_act() != nullptr) { | ||||
|       lv_disp_trig_activity(this->disp_);  // resets the inactivity time | ||||
|       lv_obj_invalidate(lv_scr_act()); | ||||
|     } | ||||
|   } | ||||
|   bool is_paused() const { return this->paused_; } | ||||
|  | ||||
|  protected: | ||||
|   void draw_buffer_(const lv_area_t *area, const uint8_t *ptr); | ||||
| @@ -107,13 +119,48 @@ class LvglComponent : public PollingComponent { | ||||
|   lv_disp_draw_buf_t draw_buf_{}; | ||||
|   lv_disp_drv_t disp_drv_{}; | ||||
|   lv_disp_t *disp_{}; | ||||
|   bool paused_{}; | ||||
|  | ||||
|   std::vector<std::function<void(lv_disp_t *)>> init_lambdas_; | ||||
|   size_t buffer_frac_{1}; | ||||
|   bool full_refresh_{}; | ||||
| }; | ||||
|  | ||||
| #ifdef USE_LVGL_TOUCHSCREEN | ||||
| class LVTouchListener : public touchscreen::TouchListener, public Parented<LvglComponent> { | ||||
|  public: | ||||
|   LVTouchListener(uint16_t long_press_time, uint16_t long_press_repeat_time) { | ||||
|     lv_indev_drv_init(&this->drv_); | ||||
|     this->drv_.long_press_repeat_time = long_press_repeat_time; | ||||
|     this->drv_.long_press_time = long_press_time; | ||||
|     this->drv_.type = LV_INDEV_TYPE_POINTER; | ||||
|     this->drv_.user_data = this; | ||||
|     this->drv_.read_cb = [](lv_indev_drv_t *d, lv_indev_data_t *data) { | ||||
|       auto *l = static_cast<LVTouchListener *>(d->user_data); | ||||
|       if (l->touch_pressed_) { | ||||
|         data->point.x = l->touch_point_.x; | ||||
|         data->point.y = l->touch_point_.y; | ||||
|         data->state = LV_INDEV_STATE_PRESSED; | ||||
|       } else { | ||||
|         data->state = LV_INDEV_STATE_RELEASED; | ||||
|       } | ||||
|     }; | ||||
|   } | ||||
|   void update(const touchscreen::TouchPoints_t &tpoints) override { | ||||
|     this->touch_pressed_ = !this->parent_->is_paused() && !tpoints.empty(); | ||||
|     if (this->touch_pressed_) | ||||
|       this->touch_point_ = tpoints[0]; | ||||
|   } | ||||
|   void release() override { touch_pressed_ = false; } | ||||
|   lv_indev_drv_t *get_drv() { return &this->drv_; } | ||||
|  | ||||
|  protected: | ||||
|   lv_indev_drv_t drv_{}; | ||||
|   touchscreen::TouchPoint touch_point_{}; | ||||
|   bool touch_pressed_{}; | ||||
| }; | ||||
| #endif  // USE_LVGL_TOUCHSCREEN | ||||
| }  // namespace lvgl | ||||
| }  // namespace esphome | ||||
|  | ||||
| #endif | ||||
| #endif  // USE_LVGL | ||||
|   | ||||
| @@ -1,6 +1,5 @@ | ||||
| from .defines import CONF_OBJ | ||||
| from .types import lv_obj_t | ||||
| from .widget import WidgetType | ||||
| from .defines import CONF_MAIN, CONF_OBJ | ||||
| from .types import WidgetType, lv_obj_t | ||||
|  | ||||
|  | ||||
| class ObjType(WidgetType): | ||||
| @@ -9,11 +8,7 @@ class ObjType(WidgetType): | ||||
|     """ | ||||
|  | ||||
|     def __init__(self): | ||||
|         super().__init__(CONF_OBJ, schema={}, modify_schema={}) | ||||
|  | ||||
|     @property | ||||
|     def w_type(self): | ||||
|         return lv_obj_t | ||||
|         super().__init__(CONF_OBJ, lv_obj_t, (CONF_MAIN,), schema={}, modify_schema={}) | ||||
|  | ||||
|     async def to_code(self, w, config): | ||||
|         return [] | ||||
|   | ||||
| @@ -3,15 +3,9 @@ from esphome.const import CONF_ARGS, CONF_FORMAT, CONF_ID, CONF_STATE, CONF_TYPE | ||||
| from esphome.schema_extractors import SCHEMA_EXTRACT | ||||
|  | ||||
| from . import defines as df, lv_validation as lvalid, types as ty | ||||
| from .defines import WIDGET_PARTS | ||||
| from .helpers import ( | ||||
|     REQUIRED_COMPONENTS, | ||||
|     add_lv_use, | ||||
|     requires_component, | ||||
|     validate_printf, | ||||
| ) | ||||
| from .helpers import add_lv_use, requires_component, validate_printf | ||||
| from .lv_validation import lv_font | ||||
| from .types import WIDGET_TYPES, get_widget_type | ||||
| from .types import WIDGET_TYPES, WidgetType | ||||
|  | ||||
| # A schema for text properties | ||||
| TEXT_SCHEMA = cv.Schema( | ||||
| @@ -46,9 +40,9 @@ STYLE_PROPS = { | ||||
|     "bg_dither_mode": df.LvConstant("LV_DITHER_", "NONE", "ORDERED", "ERR_DIFF").one_of, | ||||
|     "bg_grad_dir": df.LvConstant("LV_GRAD_DIR_", "NONE", "HOR", "VER").one_of, | ||||
|     "bg_grad_stop": lvalid.stop_value, | ||||
|     "bg_img_opa": lvalid.opacity, | ||||
|     "bg_img_recolor": lvalid.lv_color, | ||||
|     "bg_img_recolor_opa": lvalid.opacity, | ||||
|     "bg_image_opa": lvalid.opacity, | ||||
|     "bg_image_recolor": lvalid.lv_color, | ||||
|     "bg_image_recolor_opa": lvalid.opacity, | ||||
|     "bg_main_stop": lvalid.stop_value, | ||||
|     "bg_opa": lvalid.opacity, | ||||
|     "border_color": lvalid.lv_color, | ||||
| @@ -60,8 +54,8 @@ STYLE_PROPS = { | ||||
|     "border_width": cv.positive_int, | ||||
|     "clip_corner": lvalid.lv_bool, | ||||
|     "height": lvalid.size, | ||||
|     "img_recolor": lvalid.lv_color, | ||||
|     "img_recolor_opa": lvalid.opacity, | ||||
|     "image_recolor": lvalid.lv_color, | ||||
|     "image_recolor_opa": lvalid.opacity, | ||||
|     "line_width": cv.positive_int, | ||||
|     "line_dash_width": cv.positive_int, | ||||
|     "line_dash_gap": cv.positive_int, | ||||
| @@ -108,12 +102,21 @@ STYLE_PROPS = { | ||||
|     "max_width": lvalid.pixels_or_percent, | ||||
|     "min_height": lvalid.pixels_or_percent, | ||||
|     "min_width": lvalid.pixels_or_percent, | ||||
|     "radius": cv.Any(lvalid.size, df.LvConstant("LV_RADIUS_", "CIRCLE").one_of), | ||||
|     "radius": lvalid.radius, | ||||
|     "width": lvalid.size, | ||||
|     "x": lvalid.pixels_or_percent, | ||||
|     "y": lvalid.pixels_or_percent, | ||||
| } | ||||
|  | ||||
| STYLE_REMAP = { | ||||
|     "bg_image_opa": "bg_img_opa", | ||||
|     "bg_image_recolor": "bg_img_recolor", | ||||
|     "bg_image_recolor_opa": "bg_img_recolor_opa", | ||||
|     "bg_image_src": "bg_img_src", | ||||
|     "image_recolor": "img_recolor", | ||||
|     "image_recolor_opa": "img_recolor_opa", | ||||
| } | ||||
|  | ||||
| # Complete object style schema | ||||
| STYLE_SCHEMA = cv.Schema({cv.Optional(k): v for k, v in STYLE_PROPS.items()}).extend( | ||||
|     { | ||||
| @@ -132,25 +135,23 @@ SET_STATE_SCHEMA = cv.Schema( | ||||
|     {cv.Optional(state): lvalid.lv_bool for state in df.STATES} | ||||
| ) | ||||
| # Setting object flags | ||||
| FLAG_SCHEMA = cv.Schema({cv.Optional(flag): cv.boolean for flag in df.OBJ_FLAGS}) | ||||
| FLAG_SCHEMA = cv.Schema({cv.Optional(flag): lvalid.lv_bool for flag in df.OBJ_FLAGS}) | ||||
| FLAG_LIST = cv.ensure_list(df.LvConstant("LV_OBJ_FLAG_", *df.OBJ_FLAGS).one_of) | ||||
|  | ||||
|  | ||||
| def part_schema(widget_type): | ||||
| def part_schema(widget_type: WidgetType): | ||||
|     """ | ||||
|     Generate a schema for the various parts (e.g. main:, indicator:) of a widget type | ||||
|     :param widget_type:  The type of widget to generate for | ||||
|     :return: | ||||
|     """ | ||||
|     parts = WIDGET_PARTS.get(widget_type) | ||||
|     if parts is None: | ||||
|         parts = (df.CONF_MAIN,) | ||||
|     parts = widget_type.parts | ||||
|     return cv.Schema({cv.Optional(part): STATE_SCHEMA for part in parts}).extend( | ||||
|         STATE_SCHEMA | ||||
|     ) | ||||
|  | ||||
|  | ||||
| def obj_schema(widget_type: str): | ||||
| def obj_schema(widget_type: WidgetType): | ||||
|     """ | ||||
|     Create a schema for a widget type itself i.e. no allowance for children | ||||
|     :param widget_type: | ||||
| @@ -187,13 +188,12 @@ STYLED_TEXT_SCHEMA = cv.maybe_simple_value( | ||||
|     STYLE_SCHEMA.extend(TEXT_SCHEMA), key=df.CONF_TEXT | ||||
| ) | ||||
|  | ||||
|  | ||||
| ALL_STYLES = { | ||||
|     **STYLE_PROPS, | ||||
| } | ||||
|  | ||||
|  | ||||
| def container_validator(schema, widget_type): | ||||
| def container_validator(schema, widget_type: WidgetType): | ||||
|     """ | ||||
|     Create a validator for a container given the widget type | ||||
|     :param schema: Base schema to extend | ||||
| @@ -203,13 +203,16 @@ def container_validator(schema, widget_type): | ||||
|  | ||||
|     def validator(value): | ||||
|         result = schema | ||||
|         if w_sch := WIDGET_TYPES[widget_type].schema: | ||||
|         if w_sch := widget_type.schema: | ||||
|             result = result.extend(w_sch) | ||||
|         if value and (layout := value.get(df.CONF_LAYOUT)): | ||||
|             if not isinstance(layout, dict): | ||||
|                 raise cv.Invalid("Layout value must be a dict") | ||||
|             ltype = layout.get(CONF_TYPE) | ||||
|             add_lv_use(ltype) | ||||
|         result = result.extend( | ||||
|             {cv.Optional(df.CONF_WIDGETS): cv.ensure_list(any_widget_schema())} | ||||
|         ) | ||||
|         if value == SCHEMA_EXTRACT: | ||||
|             return result | ||||
|         return result(value) | ||||
| @@ -217,7 +220,7 @@ def container_validator(schema, widget_type): | ||||
|     return validator | ||||
|  | ||||
|  | ||||
| def container_schema(widget_type, extras=None): | ||||
| def container_schema(widget_type: WidgetType, extras=None): | ||||
|     """ | ||||
|     Create a schema for a container widget of a given type. All obj properties are available, plus | ||||
|     the extras passed in, plus any defined for the specific widget being specified. | ||||
| @@ -225,15 +228,16 @@ def container_schema(widget_type, extras=None): | ||||
|     :param extras:  Additional options to be made available, e.g. layout properties for children | ||||
|     :return: The schema for this type of widget. | ||||
|     """ | ||||
|     lv_type = get_widget_type(widget_type) | ||||
|     schema = obj_schema(widget_type).extend({cv.GenerateID(): cv.declare_id(lv_type)}) | ||||
|     schema = obj_schema(widget_type).extend( | ||||
|         {cv.GenerateID(): cv.declare_id(widget_type.w_type)} | ||||
|     ) | ||||
|     if extras: | ||||
|         schema = schema.extend(extras) | ||||
|     # Delayed evaluation for recursion | ||||
|     return container_validator(schema, widget_type) | ||||
|  | ||||
|  | ||||
| def widget_schema(widget_type, extras=None): | ||||
| def widget_schema(widget_type: WidgetType, extras=None): | ||||
|     """ | ||||
|     Create a schema for a given widget type | ||||
|     :param widget_type: The name of the widget | ||||
| @@ -241,9 +245,9 @@ def widget_schema(widget_type, extras=None): | ||||
|     :return: | ||||
|     """ | ||||
|     validator = container_schema(widget_type, extras=extras) | ||||
|     if required := REQUIRED_COMPONENTS.get(widget_type): | ||||
|     if required := widget_type.required_component: | ||||
|         validator = cv.All(validator, requires_component(required)) | ||||
|     return cv.Exclusive(widget_type, df.CONF_WIDGETS), validator | ||||
|     return cv.Exclusive(widget_type.name, df.CONF_WIDGETS), validator | ||||
|  | ||||
|  | ||||
| # All widget schemas must be defined before this is called. | ||||
| @@ -257,4 +261,4 @@ def any_widget_schema(extras=None): | ||||
|     :param extras: Additional schema to be applied to each generated one | ||||
|     :return: | ||||
|     """ | ||||
|     return cv.Any(dict(widget_schema(wt, extras) for wt in WIDGET_PARTS)) | ||||
|     return cv.Any(dict(widget_schema(wt, extras) for wt in WIDGET_TYPES.values())) | ||||
|   | ||||
							
								
								
									
										46
									
								
								esphome/components/lvgl/touchscreens.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								esphome/components/lvgl/touchscreens.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| import esphome.codegen as cg | ||||
| from esphome.components.touchscreen import CONF_TOUCHSCREEN_ID, Touchscreen | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import CONF_ID | ||||
| from esphome.core import CORE, TimePeriod | ||||
|  | ||||
| from .defines import ( | ||||
|     CONF_LONG_PRESS_REPEAT_TIME, | ||||
|     CONF_LONG_PRESS_TIME, | ||||
|     CONF_TOUCHSCREENS, | ||||
| ) | ||||
| from .helpers import lvgl_components_required | ||||
| from .lv_validation import lv_milliseconds | ||||
| from .lvcode import lv | ||||
| from .types import LVTouchListener | ||||
|  | ||||
| PRESS_TIME = cv.All(lv_milliseconds, cv.Range(max=TimePeriod(milliseconds=65535))) | ||||
| CONF_TOUCHSCREEN = "touchscreen" | ||||
| TOUCHSCREENS_CONFIG = cv.maybe_simple_value( | ||||
|     { | ||||
|         cv.Required(CONF_TOUCHSCREEN_ID): cv.use_id(Touchscreen), | ||||
|         cv.Optional(CONF_LONG_PRESS_TIME, default="400ms"): PRESS_TIME, | ||||
|         cv.Optional(CONF_LONG_PRESS_REPEAT_TIME, default="100ms"): PRESS_TIME, | ||||
|         cv.GenerateID(): cv.declare_id(LVTouchListener), | ||||
|     }, | ||||
|     key=CONF_TOUCHSCREEN_ID, | ||||
| ) | ||||
|  | ||||
|  | ||||
| def touchscreen_schema(config): | ||||
|     value = cv.ensure_list(TOUCHSCREENS_CONFIG)(config) | ||||
|     if value or CONF_TOUCHSCREEN not in CORE.loaded_integrations: | ||||
|         return value | ||||
|     return [TOUCHSCREENS_CONFIG(config)] | ||||
|  | ||||
|  | ||||
| async def touchscreens_to_code(var, config): | ||||
|     for tconf in config.get(CONF_TOUCHSCREENS) or (): | ||||
|         lvgl_components_required.add(CONF_TOUCHSCREEN) | ||||
|         touchscreen = await cg.get_variable(tconf[CONF_TOUCHSCREEN_ID]) | ||||
|         lpt = tconf[CONF_LONG_PRESS_TIME].total_milliseconds | ||||
|         lprt = tconf[CONF_LONG_PRESS_REPEAT_TIME].total_milliseconds | ||||
|         listener = cg.new_Pvariable(tconf[CONF_ID], lpt, lprt) | ||||
|         await cg.register_parented(listener, var) | ||||
|         lv.indev_drv_register(listener.get_drv()) | ||||
|         cg.add(touchscreen.register_listener(listener)) | ||||
| @@ -1,7 +1,22 @@ | ||||
| from esphome import codegen as cg | ||||
| from esphome.core import ID | ||||
| from esphome.cpp_generator import MockObjClass | ||||
|  | ||||
| from .defines import CONF_TEXT | ||||
|  | ||||
|  | ||||
| class LvType(cg.MockObjClass): | ||||
|     def __init__(self, *args, **kwargs): | ||||
|         parens = kwargs.pop("parents", ()) | ||||
|         super().__init__(*args, parents=parens + (lv_obj_base_t,)) | ||||
|         self.args = kwargs.pop("largs", [(lv_obj_t_ptr, "obj")]) | ||||
|         self.value = kwargs.pop("lvalue", lambda w: w.obj) | ||||
|         self.has_on_value = kwargs.pop("has_on_value", False) | ||||
|         self.value_property = None | ||||
|  | ||||
|     def get_arg_type(self): | ||||
|         return self.args[0][0] if len(self.args) else None | ||||
|  | ||||
| from .defines import CONF_LABEL, CONF_OBJ, CONF_TEXT | ||||
|  | ||||
| uint16_t_ptr = cg.uint16.operator("ptr") | ||||
| lvgl_ns = cg.esphome_ns.namespace("lvgl") | ||||
| @@ -18,25 +33,15 @@ lv_obj_base_t = cg.global_ns.class_("lv_obj_t", lv_pseudo_button_t) | ||||
| lv_obj_t_ptr = lv_obj_base_t.operator("ptr") | ||||
| lv_disp_t_ptr = cg.global_ns.struct("lv_disp_t").operator("ptr") | ||||
| lv_color_t = cg.global_ns.struct("lv_color_t") | ||||
| LVTouchListener = lvgl_ns.class_("LVTouchListener") | ||||
| LVEncoderListener = lvgl_ns.class_("LVEncoderListener") | ||||
| lv_obj_t = LvType("lv_obj_t") | ||||
|  | ||||
|  | ||||
| # this will be populated later, in __init__.py to avoid circular imports. | ||||
| WIDGET_TYPES: dict = {} | ||||
|  | ||||
|  | ||||
| class LvType(cg.MockObjClass): | ||||
|     def __init__(self, *args, **kwargs): | ||||
|         parens = kwargs.pop("parents", ()) | ||||
|         super().__init__(*args, parents=parens + (lv_obj_base_t,)) | ||||
|         self.args = kwargs.pop("largs", [(lv_obj_t_ptr, "obj")]) | ||||
|         self.value = kwargs.pop("lvalue", lambda w: w.obj) | ||||
|         self.has_on_value = kwargs.pop("has_on_value", False) | ||||
|         self.value_property = None | ||||
|  | ||||
|     def get_arg_type(self): | ||||
|         return self.args[0][0] if len(self.args) else None | ||||
|  | ||||
|  | ||||
| class LvText(LvType): | ||||
|     def __init__(self, *args, **kwargs): | ||||
|         super().__init__( | ||||
| @@ -48,17 +53,74 @@ class LvText(LvType): | ||||
|         self.value_property = CONF_TEXT | ||||
|  | ||||
|  | ||||
| lv_obj_t = LvType("lv_obj_t") | ||||
| lv_label_t = LvText("lv_label_t") | ||||
|  | ||||
| LV_TYPES = { | ||||
|     CONF_LABEL: lv_label_t, | ||||
|     CONF_OBJ: lv_obj_t, | ||||
| } | ||||
|  | ||||
|  | ||||
| def get_widget_type(typestr: str) -> LvType: | ||||
|     return LV_TYPES[typestr] | ||||
| class LvBoolean(LvType): | ||||
|     def __init__(self, *args, **kwargs): | ||||
|         super().__init__( | ||||
|             *args, | ||||
|             largs=[(cg.bool_, "x")], | ||||
|             lvalue=lambda w: w.is_checked(), | ||||
|             has_on_value=True, | ||||
|             **kwargs, | ||||
|         ) | ||||
|  | ||||
|  | ||||
| CUSTOM_EVENT = ID("lv_custom_event", False, type=lv_event_code_t) | ||||
|  | ||||
|  | ||||
| class WidgetType: | ||||
|     """ | ||||
|     Describes a type of Widget, e.g. "bar" or "line" | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, name, w_type, parts, schema=None, modify_schema=None): | ||||
|         """ | ||||
|         :param name: The widget name, e.g. "bar" | ||||
|         :param w_type: The C type of the widget | ||||
|         :param parts: What parts this widget supports | ||||
|         :param schema: The config schema for defining a widget | ||||
|         :param modify_schema: A schema to update the widget | ||||
|         """ | ||||
|         self.name = name | ||||
|         self.w_type = w_type | ||||
|         self.parts = parts | ||||
|         self.schema = schema or {} | ||||
|         if modify_schema is None: | ||||
|             self.modify_schema = schema | ||||
|         else: | ||||
|             self.modify_schema = modify_schema | ||||
|  | ||||
|     @property | ||||
|     def animated(self): | ||||
|         return False | ||||
|  | ||||
|     @property | ||||
|     def required_component(self): | ||||
|         return None | ||||
|  | ||||
|     def is_compound(self): | ||||
|         return self.w_type.inherits_from(LvCompound) | ||||
|  | ||||
|     async def to_code(self, w, config: dict): | ||||
|         """ | ||||
|         Generate code for a given widget | ||||
|         :param w: The widget | ||||
|         :param config: Its configuration | ||||
|         :return: Generated code as a list of text lines | ||||
|         """ | ||||
|         raise NotImplementedError(f"No to_code defined for {self.name}") | ||||
|  | ||||
|     def obj_creator(self, parent: MockObjClass, config: dict): | ||||
|         """ | ||||
|         Create an instance of the widget type | ||||
|         :param parent: The parent to which it should be attached | ||||
|         :param config:  Its configuration | ||||
|         :return: Generated code as a single text line | ||||
|         """ | ||||
|         return f"lv_{self.name}_create({parent})" | ||||
|  | ||||
|     def get_uses(self): | ||||
|         """ | ||||
|         Get a list of other widgets used by this one | ||||
|         :return: | ||||
|         """ | ||||
|         return () | ||||
|   | ||||
| @@ -21,78 +21,19 @@ from .defines import ( | ||||
| ) | ||||
| from .helpers import add_lv_use | ||||
| from .lvcode import ConstantLiteral, add_line_marks, lv, lv_add, lv_assign, lv_obj | ||||
| from .schemas import ALL_STYLES | ||||
| from .types import WIDGET_TYPES, LvCompound, lv_obj_t | ||||
| from .schemas import ALL_STYLES, STYLE_REMAP | ||||
| from .types import WIDGET_TYPES, WidgetType, lv_obj_t | ||||
|  | ||||
| EVENT_LAMB = "event_lamb__" | ||||
|  | ||||
|  | ||||
| class WidgetType: | ||||
|     """ | ||||
|     Describes a type of Widget, e.g. "bar" or "line" | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, name, schema=None, modify_schema=None): | ||||
|         """ | ||||
|         :param name: The widget name, e.g. "bar" | ||||
|         :param schema: The config schema for defining a widget | ||||
|         :param modify_schema: A schema to update the widget | ||||
|         """ | ||||
|         self.name = name | ||||
|         self.schema = schema or {} | ||||
|         if modify_schema is None: | ||||
|             self.modify_schema = schema | ||||
|         else: | ||||
|             self.modify_schema = modify_schema | ||||
|  | ||||
|     @property | ||||
|     def animated(self): | ||||
|         return False | ||||
|  | ||||
|     @property | ||||
|     def w_type(self): | ||||
|         """ | ||||
|         Get the type associated with this widget | ||||
|         :return: | ||||
|         """ | ||||
|         return lv_obj_t | ||||
|  | ||||
|     def is_compound(self): | ||||
|         return self.w_type.inherits_from(LvCompound) | ||||
|  | ||||
|     async def to_code(self, w, config: dict): | ||||
|         """ | ||||
|         Generate code for a given widget | ||||
|         :param w: The widget | ||||
|         :param config: Its configuration | ||||
|         :return: Generated code as a list of text lines | ||||
|         """ | ||||
|         raise NotImplementedError(f"No to_code defined for {self.name}") | ||||
|  | ||||
|     def obj_creator(self, parent: MockObjClass, config: dict): | ||||
|         """ | ||||
|         Create an instance of the widget type | ||||
|         :param parent: The parent to which it should be attached | ||||
|         :param config:  Its configuration | ||||
|         :return: Generated code as a single text line | ||||
|         """ | ||||
|         return f"lv_{self.name}_create({parent})" | ||||
|  | ||||
|     def get_uses(self): | ||||
|         """ | ||||
|         Get a list of other widgets used by this one | ||||
|         :return: | ||||
|         """ | ||||
|         return () | ||||
|  | ||||
|  | ||||
| class LvScrActType(WidgetType): | ||||
|     """ | ||||
|     A "widget" representing the active screen. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self): | ||||
|         super().__init__("lv_scr_act()") | ||||
|         super().__init__("lv_scr_act()", lv_obj_t, ()) | ||||
|  | ||||
|     def obj_creator(self, parent: MockObjClass, config: dict): | ||||
|         return [] | ||||
| @@ -263,7 +204,9 @@ async def set_obj_properties(w: Widget, config): | ||||
|             }.items(): | ||||
|                 if isinstance(ALL_STYLES[prop], LValidator): | ||||
|                     value = await ALL_STYLES[prop].process(value) | ||||
|                 w.set_style(prop, value, lv_state) | ||||
|                     # Remapping for backwards compatibility of style names | ||||
|                 prop_r = STYLE_REMAP.get(prop, prop) | ||||
|                 w.set_style(prop_r, value, lv_state) | ||||
|     flag_clr = set() | ||||
|     flag_set = set() | ||||
|     props = parts[CONF_MAIN][CONF_DEFAULT] | ||||
| @@ -291,10 +234,10 @@ async def set_obj_properties(w: Widget, config): | ||||
|             else: | ||||
|                 clears.add(key) | ||||
|         if adds: | ||||
|             adds = ConstantLiteral(join_enums(adds, "LV_STATE_")) | ||||
|             adds = join_enums(adds, "LV_STATE_") | ||||
|             w.add_state(adds) | ||||
|         if clears: | ||||
|             clears = ConstantLiteral(join_enums(clears, "LV_STATE_")) | ||||
|             clears = join_enums(clears, "LV_STATE_") | ||||
|             w.clear_state(clears) | ||||
|         for key, value in lambs.items(): | ||||
|             lamb = await cg.process_lambda(value, [], return_type=cg.bool_) | ||||
|   | ||||
| @@ -110,7 +110,7 @@ void MitsubishiClimate::transmit_state() { | ||||
|   // Byte 15: HVAC specfic, i.e. POWERFUL, SMART SET, PLASMA, always 0x00 | ||||
|   // Byte 16: Constant 0x00 | ||||
|   // Byte 17: Checksum: SUM[Byte0...Byte16] | ||||
|   uint8_t remote_state[18] = {0x23, 0xCB, 0x26, 0x01, 0x00, 0x20, 0x08, 0x00, 0x00, | ||||
|   uint8_t remote_state[18] = {0x23, 0xCB, 0x26, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, | ||||
|                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; | ||||
|  | ||||
|   switch (this->mode) { | ||||
| @@ -136,6 +136,12 @@ void MitsubishiClimate::transmit_state() { | ||||
|       break; | ||||
|     case climate::CLIMATE_MODE_OFF: | ||||
|     default: | ||||
|       remote_state[6] = MITSUBISHI_MODE_COOL; | ||||
|       remote_state[8] = MITSUBISHI_MODE_A_COOL; | ||||
|       if (this->supports_heat_) { | ||||
|         remote_state[6] = MITSUBISHI_MODE_HEAT; | ||||
|         remote_state[8] = MITSUBISHI_MODE_A_HEAT; | ||||
|       } | ||||
|       remote_state[5] = MITSUBISHI_OFF; | ||||
|       break; | ||||
|   } | ||||
|   | ||||
| @@ -1,10 +1,15 @@ | ||||
| from esphome import automation | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome import automation | ||||
| from esphome.const import ( | ||||
|     CONF_ESPHOME, | ||||
|     CONF_ON_ERROR, | ||||
|     CONF_OTA, | ||||
|     CONF_PLATFORM, | ||||
|     CONF_TRIGGER_ID, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
|  | ||||
| from esphome.const import CONF_ESPHOME, CONF_OTA, CONF_PLATFORM, CONF_TRIGGER_ID | ||||
|  | ||||
| CODEOWNERS = ["@esphome/core"] | ||||
| AUTO_LOAD = ["md5", "safe_mode"] | ||||
|  | ||||
| @@ -13,7 +18,6 @@ IS_PLATFORM_COMPONENT = True | ||||
| CONF_ON_ABORT = "on_abort" | ||||
| CONF_ON_BEGIN = "on_begin" | ||||
| CONF_ON_END = "on_end" | ||||
| CONF_ON_ERROR = "on_error" | ||||
| CONF_ON_PROGRESS = "on_progress" | ||||
| CONF_ON_STATE_CHANGE = "on_state_change" | ||||
|  | ||||
|   | ||||
| @@ -44,6 +44,8 @@ class PIDClimate : public climate::Climate, public Component { | ||||
|   float get_kp() { return controller_.kp_; } | ||||
|   float get_ki() { return controller_.ki_; } | ||||
|   float get_kd() { return controller_.kd_; } | ||||
|   float get_min_integral() { return controller_.min_integral_; } | ||||
|   float get_max_integral() { return controller_.max_integral_; } | ||||
|   float get_proportional_term() const { return controller_.proportional_term_; } | ||||
|   float get_integral_term() const { return controller_.integral_term_; } | ||||
|   float get_derivative_term() const { return controller_.derivative_term_; } | ||||
|   | ||||
| @@ -1,10 +1,9 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
|  | ||||
| from esphome.components import binary_sensor, display | ||||
| from esphome.const import CONF_PAGE_ID | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import CONF_PAGE_ID, CONF_PAGES | ||||
|  | ||||
| from .. import touchscreen_ns, CONF_TOUCHSCREEN_ID, Touchscreen, TouchListener | ||||
| from .. import CONF_TOUCHSCREEN_ID, TouchListener, Touchscreen, touchscreen_ns | ||||
|  | ||||
| DEPENDENCIES = ["touchscreen"] | ||||
|  | ||||
| @@ -22,7 +21,7 @@ CONF_Y_MIN = "y_min" | ||||
| CONF_Y_MAX = "y_max" | ||||
|  | ||||
|  | ||||
| def validate_coords(config): | ||||
| def _validate_coords(config): | ||||
|     if ( | ||||
|         config[CONF_X_MAX] < config[CONF_X_MIN] | ||||
|         or config[CONF_Y_MAX] < config[CONF_Y_MIN] | ||||
| @@ -33,6 +32,15 @@ def validate_coords(config): | ||||
|     return config | ||||
|  | ||||
|  | ||||
| def _set_pages(config: dict) -> dict: | ||||
|     if CONF_PAGES in config or CONF_PAGE_ID not in config: | ||||
|         return config | ||||
|  | ||||
|     config = config.copy() | ||||
|     config[CONF_PAGES] = [config.pop(CONF_PAGE_ID)] | ||||
|     return config | ||||
|  | ||||
|  | ||||
| CONFIG_SCHEMA = cv.All( | ||||
|     binary_sensor.binary_sensor_schema(TouchscreenBinarySensor) | ||||
|     .extend( | ||||
| @@ -42,11 +50,17 @@ CONFIG_SCHEMA = cv.All( | ||||
|             cv.Required(CONF_X_MAX): cv.int_range(min=0, max=2000), | ||||
|             cv.Required(CONF_Y_MIN): cv.int_range(min=0, max=2000), | ||||
|             cv.Required(CONF_Y_MAX): cv.int_range(min=0, max=2000), | ||||
|             cv.Optional(CONF_PAGE_ID): cv.use_id(display.DisplayPage), | ||||
|             cv.Exclusive(CONF_PAGE_ID, group_of_exclusion=CONF_PAGES): cv.use_id( | ||||
|                 display.DisplayPage | ||||
|             ), | ||||
|             cv.Exclusive(CONF_PAGES, group_of_exclusion=CONF_PAGES): cv.ensure_list( | ||||
|                 cv.use_id(display.DisplayPage) | ||||
|             ), | ||||
|         } | ||||
|     ) | ||||
|     .extend(cv.COMPONENT_SCHEMA), | ||||
|     validate_coords, | ||||
|     _validate_coords, | ||||
|     _set_pages, | ||||
| ) | ||||
|  | ||||
|  | ||||
| @@ -64,6 +78,6 @@ async def to_code(config): | ||||
|         ) | ||||
|     ) | ||||
|  | ||||
|     if CONF_PAGE_ID in config: | ||||
|         page = await cg.get_variable(config[CONF_PAGE_ID]) | ||||
|         cg.add(var.set_page(page)) | ||||
|     for page_id in config.get(CONF_PAGES, []): | ||||
|         page = await cg.get_variable(page_id) | ||||
|         cg.add(var.add_page(page)) | ||||
|   | ||||
| @@ -11,8 +11,9 @@ void TouchscreenBinarySensor::setup() { | ||||
| void TouchscreenBinarySensor::touch(TouchPoint tp) { | ||||
|   bool touched = (tp.x >= this->x_min_ && tp.x <= this->x_max_ && tp.y >= this->y_min_ && tp.y <= this->y_max_); | ||||
|  | ||||
|   if (this->page_ != nullptr) { | ||||
|     touched &= this->page_ == this->parent_->get_display()->get_active_page(); | ||||
|   if (!this->pages_.empty()) { | ||||
|     auto *current_page = this->parent_->get_display()->get_active_page(); | ||||
|     touched &= std::find(this->pages_.begin(), this->pages_.end(), current_page) != this->pages_.end(); | ||||
|   } | ||||
|   if (touched) { | ||||
|     this->publish_state(true); | ||||
|   | ||||
| @@ -6,6 +6,8 @@ | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/core/helpers.h" | ||||
|  | ||||
| #include <vector> | ||||
|  | ||||
| namespace esphome { | ||||
| namespace touchscreen { | ||||
|  | ||||
| @@ -30,14 +32,14 @@ class TouchscreenBinarySensor : public binary_sensor::BinarySensor, | ||||
|   int16_t get_width() { return this->x_max_ - this->x_min_; } | ||||
|   int16_t get_height() { return this->y_max_ - this->y_min_; } | ||||
|  | ||||
|   void set_page(display::DisplayPage *page) { this->page_ = page; } | ||||
|   void add_page(display::DisplayPage *page) { this->pages_.push_back(page); } | ||||
|  | ||||
|   void touch(TouchPoint tp) override; | ||||
|   void release() override; | ||||
|  | ||||
|  protected: | ||||
|   int16_t x_min_, x_max_, y_min_, y_max_; | ||||
|   display::DisplayPage *page_{nullptr}; | ||||
|   std::vector<display::DisplayPage *> pages_{}; | ||||
| }; | ||||
|  | ||||
| }  // namespace touchscreen | ||||
|   | ||||
| @@ -1,18 +1,18 @@ | ||||
| import esphome.config_validation as cv | ||||
| import esphome.codegen as cg | ||||
|  | ||||
| from esphome.const import ( | ||||
|     CONF_ID, | ||||
|     CONF_MICROPHONE, | ||||
|     CONF_SPEAKER, | ||||
|     CONF_MEDIA_PLAYER, | ||||
|     CONF_ON_CLIENT_CONNECTED, | ||||
|     CONF_ON_CLIENT_DISCONNECTED, | ||||
|     CONF_ON_IDLE, | ||||
| ) | ||||
| from esphome import automation | ||||
| from esphome.automation import register_action, register_condition | ||||
| from esphome.components import microphone, speaker, media_player | ||||
| import esphome.codegen as cg | ||||
| from esphome.components import media_player, microphone, speaker | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import ( | ||||
|     CONF_ID, | ||||
|     CONF_MEDIA_PLAYER, | ||||
|     CONF_MICROPHONE, | ||||
|     CONF_ON_CLIENT_CONNECTED, | ||||
|     CONF_ON_CLIENT_DISCONNECTED, | ||||
|     CONF_ON_ERROR, | ||||
|     CONF_ON_IDLE, | ||||
|     CONF_SPEAKER, | ||||
| ) | ||||
|  | ||||
| AUTO_LOAD = ["socket"] | ||||
| DEPENDENCIES = ["api", "microphone"] | ||||
| @@ -20,7 +20,6 @@ DEPENDENCIES = ["api", "microphone"] | ||||
| CODEOWNERS = ["@jesserockz"] | ||||
|  | ||||
| CONF_ON_END = "on_end" | ||||
| CONF_ON_ERROR = "on_error" | ||||
| CONF_ON_INTENT_END = "on_intent_end" | ||||
| CONF_ON_INTENT_START = "on_intent_start" | ||||
| CONF_ON_LISTENING = "on_listening" | ||||
|   | ||||
							
								
								
									
										1
									
								
								esphome/components/watchdog/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								esphome/components/watchdog/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| CODEOWNERS = ["@oarcher"] | ||||
| @@ -15,7 +15,6 @@ | ||||
| #endif | ||||
| 
 | ||||
| namespace esphome { | ||||
| namespace http_request { | ||||
| namespace watchdog { | ||||
| 
 | ||||
| static const char *const TAG = "http_request.watchdog"; | ||||
| @@ -72,5 +71,4 @@ uint32_t WatchdogManager::get_timeout_() { | ||||
| } | ||||
| 
 | ||||
| }  // namespace watchdog
 | ||||
| }  // namespace http_request
 | ||||
| }  // namespace esphome
 | ||||
| @@ -5,7 +5,6 @@ | ||||
| #include <cstdint> | ||||
| 
 | ||||
| namespace esphome { | ||||
| namespace http_request { | ||||
| namespace watchdog { | ||||
| 
 | ||||
| class WatchdogManager { | ||||
| @@ -22,5 +21,4 @@ class WatchdogManager { | ||||
| }; | ||||
| 
 | ||||
| }  // namespace watchdog
 | ||||
| }  // namespace http_request
 | ||||
| }  // namespace esphome
 | ||||
| @@ -1,15 +1,19 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| import esphome.final_validate as fv | ||||
| from esphome import automation | ||||
| from esphome.automation import Condition | ||||
| import esphome.codegen as cg | ||||
| from esphome.components.esp32 import add_idf_sdkconfig_option, const, get_esp32_variant | ||||
| from esphome.components.network import IPAddress | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import ( | ||||
|     CONF_AP, | ||||
|     CONF_BSSID, | ||||
|     CONF_CERTIFICATE, | ||||
|     CONF_CERTIFICATE_AUTHORITY, | ||||
|     CONF_CHANNEL, | ||||
|     CONF_DNS1, | ||||
|     CONF_DNS2, | ||||
|     CONF_DOMAIN, | ||||
|     CONF_EAP, | ||||
|     CONF_ENABLE_BTM, | ||||
|     CONF_ENABLE_ON_BOOT, | ||||
|     CONF_ENABLE_RRM, | ||||
| @@ -17,29 +21,26 @@ from esphome.const import ( | ||||
|     CONF_GATEWAY, | ||||
|     CONF_HIDDEN, | ||||
|     CONF_ID, | ||||
|     CONF_IDENTITY, | ||||
|     CONF_KEY, | ||||
|     CONF_MANUAL_IP, | ||||
|     CONF_NETWORKS, | ||||
|     CONF_ON_CONNECT, | ||||
|     CONF_ON_DISCONNECT, | ||||
|     CONF_PASSWORD, | ||||
|     CONF_POWER_SAVE_MODE, | ||||
|     CONF_PRIORITY, | ||||
|     CONF_REBOOT_TIMEOUT, | ||||
|     CONF_SSID, | ||||
|     CONF_STATIC_IP, | ||||
|     CONF_SUBNET, | ||||
|     CONF_USE_ADDRESS, | ||||
|     CONF_PRIORITY, | ||||
|     CONF_IDENTITY, | ||||
|     CONF_CERTIFICATE_AUTHORITY, | ||||
|     CONF_CERTIFICATE, | ||||
|     CONF_KEY, | ||||
|     CONF_USERNAME, | ||||
|     CONF_EAP, | ||||
|     CONF_TTLS_PHASE_2, | ||||
|     CONF_ON_CONNECT, | ||||
|     CONF_ON_DISCONNECT, | ||||
|     CONF_USE_ADDRESS, | ||||
|     CONF_USERNAME, | ||||
| ) | ||||
| from esphome.core import CORE, HexInt, coroutine_with_priority | ||||
| from esphome.components.esp32 import add_idf_sdkconfig_option, get_esp32_variant, const | ||||
| from esphome.components.network import IPAddress | ||||
| import esphome.final_validate as fv | ||||
|  | ||||
| from . import wpa2_eap | ||||
|  | ||||
| AUTO_LOAD = ["network"] | ||||
|   | ||||
| @@ -7,16 +7,15 @@ so that it doesn't crash if it's not installed. | ||||
| import logging | ||||
| from pathlib import Path | ||||
|  | ||||
| from esphome.core import CORE | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import ( | ||||
|     CONF_USERNAME, | ||||
|     CONF_IDENTITY, | ||||
|     CONF_PASSWORD, | ||||
|     CONF_CERTIFICATE, | ||||
|     CONF_IDENTITY, | ||||
|     CONF_KEY, | ||||
|     CONF_PASSWORD, | ||||
|     CONF_USERNAME, | ||||
| ) | ||||
|  | ||||
| from esphome.core import CORE | ||||
|  | ||||
| _LOGGER = logging.getLogger(__name__) | ||||
|  | ||||
| @@ -49,8 +48,8 @@ def wrapped_load_pem_x509_certificate(value): | ||||
| def wrapped_load_pem_private_key(value, password): | ||||
|     validate_cryptography_installed() | ||||
|  | ||||
|     from cryptography.hazmat.primitives.serialization import load_pem_private_key | ||||
|     from cryptography.hazmat.backends import default_backend | ||||
|     from cryptography.hazmat.primitives.serialization import load_pem_private_key | ||||
|  | ||||
|     if password: | ||||
|         password = password.encode("UTF-8") | ||||
| @@ -91,7 +90,7 @@ def _validate_load_private_key(key, cert_pw): | ||||
|  | ||||
|  | ||||
| def _check_private_key_cert_match(key, cert): | ||||
|     from cryptography.hazmat.primitives.asymmetric import rsa, ec | ||||
|     from cryptography.hazmat.primitives.asymmetric import ec, rsa | ||||
|  | ||||
|     def check_match_a(): | ||||
|         return key.public_key().public_numbers() == cert.public_key().public_numbers() | ||||
|   | ||||
| @@ -1,13 +1,13 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.components import text_sensor | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import ( | ||||
|     CONF_BSSID, | ||||
|     CONF_DNS_ADDRESS, | ||||
|     CONF_IP_ADDRESS, | ||||
|     CONF_MAC_ADDRESS, | ||||
|     CONF_SCAN_RESULTS, | ||||
|     CONF_SSID, | ||||
|     CONF_MAC_ADDRESS, | ||||
|     CONF_DNS_ADDRESS, | ||||
|     ENTITY_CATEGORY_DIAGNOSTIC, | ||||
| ) | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.components import sensor | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import ( | ||||
|     DEVICE_CLASS_SIGNAL_STRENGTH, | ||||
|     ENTITY_CATEGORY_DIAGNOSTIC, | ||||
|   | ||||
| @@ -1,40 +1,38 @@ | ||||
| from __future__ import annotations | ||||
|  | ||||
| import abc | ||||
| from contextlib import contextmanager | ||||
| import contextvars | ||||
| import functools | ||||
| import heapq | ||||
| import logging | ||||
| import re | ||||
|  | ||||
| from typing import Union, Any | ||||
|  | ||||
| from contextlib import contextmanager | ||||
| import contextvars | ||||
| from typing import Any, Union | ||||
|  | ||||
| import voluptuous as vol | ||||
|  | ||||
| from esphome import core, yaml_util, loader, pins | ||||
| import esphome.core.config as core_config | ||||
| from esphome import core, loader, pins, yaml_util | ||||
| from esphome.config_helpers import Extend, Remove | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import ( | ||||
|     CONF_ESPHOME, | ||||
|     CONF_ID, | ||||
|     CONF_PLATFORM, | ||||
|     CONF_PACKAGES, | ||||
|     CONF_SUBSTITUTIONS, | ||||
|     CONF_EXTERNAL_COMPONENTS, | ||||
|     CONF_ID, | ||||
|     CONF_PACKAGES, | ||||
|     CONF_PLATFORM, | ||||
|     CONF_SUBSTITUTIONS, | ||||
|     TARGET_PLATFORMS, | ||||
| ) | ||||
| from esphome.core import CORE, EsphomeError, DocumentRange | ||||
| from esphome.helpers import indent | ||||
| from esphome.util import safe_print, OrderedDict | ||||
|  | ||||
| from esphome.config_helpers import Extend, Remove | ||||
| from esphome.loader import get_component, get_platform, ComponentManifest | ||||
| from esphome.yaml_util import is_secret, ESPHomeDataBase, ESPForceValue | ||||
| from esphome.voluptuous_schema import ExtraKeysInvalid | ||||
| from esphome.log import color, Fore | ||||
| from esphome.core import CORE, DocumentRange, EsphomeError | ||||
| import esphome.core.config as core_config | ||||
| import esphome.final_validate as fv | ||||
| import esphome.config_validation as cv | ||||
| from esphome.types import ConfigType, ConfigFragmentType | ||||
| from esphome.helpers import indent | ||||
| from esphome.loader import ComponentManifest, get_component, get_platform | ||||
| from esphome.log import Fore, color | ||||
| from esphome.types import ConfigFragmentType, ConfigType | ||||
| from esphome.util import OrderedDict, safe_print | ||||
| from esphome.voluptuous_schema import ExtraKeysInvalid | ||||
| from esphome.yaml_util import ESPForceValue, ESPHomeDataBase, is_secret | ||||
|  | ||||
| _LOGGER = logging.getLogger(__name__) | ||||
|  | ||||
|   | ||||
| @@ -1,13 +1,13 @@ | ||||
| """Helpers for config validation using voluptuous.""" | ||||
|  | ||||
| from contextlib import contextmanager | ||||
| from dataclasses import dataclass | ||||
| from datetime import datetime | ||||
| import logging | ||||
| import os | ||||
| import re | ||||
| from contextlib import contextmanager | ||||
| import uuid as uuid_ | ||||
| from datetime import datetime | ||||
| from string import ascii_letters, digits | ||||
| import uuid as uuid_ | ||||
|  | ||||
| import voluptuous as vol | ||||
|  | ||||
| @@ -17,37 +17,37 @@ from esphome.config_helpers import Extend, Remove | ||||
| from esphome.const import ( | ||||
|     ALLOWED_NAME_CHARS, | ||||
|     CONF_AVAILABILITY, | ||||
|     CONF_COMMAND_TOPIC, | ||||
|     CONF_COMMAND_RETAIN, | ||||
|     CONF_COMMAND_TOPIC, | ||||
|     CONF_DAY, | ||||
|     CONF_DISABLED_BY_DEFAULT, | ||||
|     CONF_DISCOVERY, | ||||
|     CONF_ENTITY_CATEGORY, | ||||
|     CONF_HOUR, | ||||
|     CONF_ICON, | ||||
|     CONF_ID, | ||||
|     CONF_INTERNAL, | ||||
|     CONF_MINUTE, | ||||
|     CONF_MONTH, | ||||
|     CONF_NAME, | ||||
|     CONF_PASSWORD, | ||||
|     CONF_PATH, | ||||
|     CONF_PAYLOAD_AVAILABLE, | ||||
|     CONF_PAYLOAD_NOT_AVAILABLE, | ||||
|     CONF_RETAIN, | ||||
|     CONF_QOS, | ||||
|     CONF_REF, | ||||
|     CONF_RETAIN, | ||||
|     CONF_SECOND, | ||||
|     CONF_SETUP_PRIORITY, | ||||
|     CONF_STATE_TOPIC, | ||||
|     CONF_TOPIC, | ||||
|     CONF_YEAR, | ||||
|     CONF_MONTH, | ||||
|     CONF_DAY, | ||||
|     CONF_HOUR, | ||||
|     CONF_MINUTE, | ||||
|     CONF_SECOND, | ||||
|     CONF_VALUE, | ||||
|     CONF_UPDATE_INTERVAL, | ||||
|     CONF_TYPE_ID, | ||||
|     CONF_TYPE, | ||||
|     CONF_REF, | ||||
|     CONF_TYPE_ID, | ||||
|     CONF_UPDATE_INTERVAL, | ||||
|     CONF_URL, | ||||
|     CONF_PATH, | ||||
|     CONF_USERNAME, | ||||
|     CONF_PASSWORD, | ||||
|     CONF_VALUE, | ||||
|     CONF_YEAR, | ||||
|     ENTITY_CATEGORY_CONFIG, | ||||
|     ENTITY_CATEGORY_DIAGNOSTIC, | ||||
|     ENTITY_CATEGORY_NONE, | ||||
| @@ -71,15 +71,15 @@ from esphome.core import ( | ||||
|     TimePeriod, | ||||
|     TimePeriodMicroseconds, | ||||
|     TimePeriodMilliseconds, | ||||
|     TimePeriodMinutes, | ||||
|     TimePeriodNanoseconds, | ||||
|     TimePeriodSeconds, | ||||
|     TimePeriodMinutes, | ||||
| ) | ||||
| from esphome.helpers import list_starts_with, add_class_to_obj | ||||
| from esphome.helpers import add_class_to_obj, list_starts_with | ||||
| from esphome.schema_extractors import ( | ||||
|     SCHEMA_EXTRACT, | ||||
|     schema_extractor_list, | ||||
|     schema_extractor, | ||||
|     schema_extractor_list, | ||||
|     schema_extractor_registry, | ||||
|     schema_extractor_typed, | ||||
| ) | ||||
| @@ -1686,9 +1686,9 @@ class SplitDefault(Optional): | ||||
|         if CORE.is_esp32: | ||||
|             from esphome.components.esp32 import get_esp32_variant | ||||
|             from esphome.components.esp32.const import ( | ||||
|                 VARIANT_ESP32C3, | ||||
|                 VARIANT_ESP32S2, | ||||
|                 VARIANT_ESP32S3, | ||||
|                 VARIANT_ESP32C3, | ||||
|             ) | ||||
|  | ||||
|             variant = get_esp32_variant() | ||||
|   | ||||
| @@ -539,6 +539,7 @@ CONF_ON_DOUBLE_CLICK = "on_double_click" | ||||
| CONF_ON_ENROLLMENT_DONE = "on_enrollment_done" | ||||
| CONF_ON_ENROLLMENT_FAILED = "on_enrollment_failed" | ||||
| CONF_ON_ENROLLMENT_SCAN = "on_enrollment_scan" | ||||
| CONF_ON_ERROR = "on_error" | ||||
| CONF_ON_EVENT = "on_event" | ||||
| CONF_ON_FINGER_SCAN_INVALID = "on_finger_scan_invalid" | ||||
| CONF_ON_FINGER_SCAN_MATCHED = "on_finger_scan_matched" | ||||
| @@ -1032,11 +1033,13 @@ UNIT_KILOWATT_HOURS = "kWh" | ||||
| UNIT_LUX = "lx" | ||||
| UNIT_METER = "m" | ||||
| UNIT_METER_PER_SECOND_SQUARED = "m/s²" | ||||
| UNIT_MICROAMP = "µA" | ||||
| UNIT_MICROGRAMS_PER_CUBIC_METER = "µg/m³" | ||||
| UNIT_MICROMETER = "µm" | ||||
| UNIT_MICROSIEMENS_PER_CENTIMETER = "µS/cm" | ||||
| UNIT_MICROSILVERTS_PER_HOUR = "µSv/h" | ||||
| UNIT_MICROTESLA = "µT" | ||||
| UNIT_MILLIAMP = "mA" | ||||
| UNIT_MILLIGRAMS_PER_CUBIC_METER = "mg/m³" | ||||
| UNIT_MILLIMETER = "mm" | ||||
| UNIT_MILLISECOND = "ms" | ||||
|   | ||||
| @@ -7,26 +7,29 @@ from typing import TYPE_CHECKING, Optional, Union | ||||
| from esphome.const import ( | ||||
|     CONF_COMMENT, | ||||
|     CONF_ESPHOME, | ||||
|     CONF_USE_ADDRESS, | ||||
|     CONF_ETHERNET, | ||||
|     CONF_PORT, | ||||
|     CONF_USE_ADDRESS, | ||||
|     CONF_WEB_SERVER, | ||||
|     CONF_WIFI, | ||||
|     CONF_PORT, | ||||
|     KEY_CORE, | ||||
|     KEY_TARGET_FRAMEWORK, | ||||
|     KEY_TARGET_PLATFORM, | ||||
|     PLATFORM_BK72XX, | ||||
|     PLATFORM_ESP32, | ||||
|     PLATFORM_ESP8266, | ||||
|     PLATFORM_BK72XX, | ||||
|     PLATFORM_RTL87XX, | ||||
|     PLATFORM_RP2040, | ||||
|     PLATFORM_HOST, | ||||
|     PLATFORM_RP2040, | ||||
|     PLATFORM_RTL87XX, | ||||
| ) | ||||
| 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.coroutine import (  # noqa: F401 | ||||
|     FakeAwaitable as _FakeAwaitable, | ||||
|     FakeEventLoop as _FakeEventLoop, | ||||
|     coroutine, | ||||
|     coroutine_with_priority, | ||||
| ) | ||||
| from esphome.helpers import ensure_unique_string, get_str_env, is_ha_addon | ||||
| from esphome.util import OrderedDict | ||||
|  | ||||
|   | ||||
| @@ -3,9 +3,9 @@ import multiprocessing | ||||
| import os | ||||
| import re | ||||
|  | ||||
| from esphome import automation | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome import automation | ||||
| from esphome.const import ( | ||||
|     CONF_ARDUINO_VERSION, | ||||
|     CONF_AREA, | ||||
| @@ -16,11 +16,11 @@ from esphome.const import ( | ||||
|     CONF_COMPILE_PROCESS_LIMIT, | ||||
|     CONF_ESPHOME, | ||||
|     CONF_FRAMEWORK, | ||||
|     CONF_FRIENDLY_NAME, | ||||
|     CONF_INCLUDES, | ||||
|     CONF_LIBRARIES, | ||||
|     CONF_MIN_VERSION, | ||||
|     CONF_NAME, | ||||
|     CONF_FRIENDLY_NAME, | ||||
|     CONF_ON_BOOT, | ||||
|     CONF_ON_LOOP, | ||||
|     CONF_ON_SHUTDOWN, | ||||
| @@ -34,8 +34,8 @@ from esphome.const import ( | ||||
|     CONF_TYPE, | ||||
|     CONF_VERSION, | ||||
|     KEY_CORE, | ||||
|     TARGET_PLATFORMS, | ||||
|     PLATFORM_ESP8266, | ||||
|     TARGET_PLATFORMS, | ||||
|     __version__ as ESPHOME_VERSION, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
|   | ||||
| @@ -41,6 +41,7 @@ | ||||
| #define USE_LVGL | ||||
| #define USE_LVGL_FONT | ||||
| #define USE_LVGL_IMAGE | ||||
| #define USE_LVGL_TOUCHSCREEN | ||||
| #define USE_MDNS | ||||
| #define USE_MEDIA_PLAYER | ||||
| #define USE_MQTT | ||||
|   | ||||
| @@ -1,6 +1,5 @@ | ||||
| import esphome.final_validate as fv | ||||
|  | ||||
| from esphome.const import CONF_ID | ||||
| import esphome.final_validate as fv | ||||
|  | ||||
|  | ||||
| def inherit_property_from(property_to_inherit, parent_id_property, transform=None): | ||||
|   | ||||
| @@ -43,13 +43,13 @@ the last `yield` expression defines what is returned. | ||||
| """ | ||||
|  | ||||
| import collections | ||||
| from collections.abc import Awaitable, Generator, Iterator | ||||
| import functools | ||||
| import heapq | ||||
| import inspect | ||||
| import logging | ||||
| import types | ||||
| from typing import Any, Callable | ||||
| from collections.abc import Awaitable, Generator, Iterator | ||||
|  | ||||
| _LOGGER = logging.getLogger(__name__) | ||||
|  | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| import abc | ||||
| from collections.abc import Sequence | ||||
| import inspect | ||||
| import math | ||||
| import re | ||||
| from collections.abc import Sequence | ||||
| from typing import Any, Callable, Optional, Union | ||||
|  | ||||
| from esphome.core import ( | ||||
|   | ||||
| @@ -12,15 +12,13 @@ from esphome.const import ( | ||||
|     CONF_UPDATE_INTERVAL, | ||||
|     KEY_PAST_SAFE_MODE, | ||||
| ) | ||||
|  | ||||
| from esphome.core import coroutine, ID, CORE | ||||
| from esphome.core import CORE, ID, coroutine | ||||
| from esphome.coroutine import FakeAwaitable | ||||
| from esphome.types import ConfigType, ConfigFragmentType | ||||
| from esphome.cpp_generator import add, get_variable | ||||
| from esphome.cpp_types import App | ||||
| from esphome.helpers import sanitize, snake_case | ||||
| from esphome.types import ConfigFragmentType, ConfigType | ||||
| from esphome.util import Registry, RegistryEntry | ||||
| from esphome.helpers import snake_case, sanitize | ||||
|  | ||||
|  | ||||
| _LOGGER = logging.getLogger(__name__) | ||||
|  | ||||
|   | ||||
| @@ -1,13 +1,13 @@ | ||||
| from __future__ import annotations | ||||
|  | ||||
| import asyncio | ||||
| from collections.abc import Coroutine | ||||
| import contextlib | ||||
| import logging | ||||
| import threading | ||||
| from dataclasses import dataclass | ||||
| from functools import partial | ||||
| import logging | ||||
| import threading | ||||
| from typing import TYPE_CHECKING, Any, Callable | ||||
| from collections.abc import Coroutine | ||||
|  | ||||
| from ..zeroconf import DiscoveredImport | ||||
| from .dns import DNSCache | ||||
|   | ||||
| @@ -1,14 +1,14 @@ | ||||
| from __future__ import annotations | ||||
|  | ||||
| import asyncio | ||||
| from asyncio import events | ||||
| from concurrent.futures import ThreadPoolExecutor | ||||
| import logging | ||||
| import os | ||||
| import socket | ||||
| import threading | ||||
| import traceback | ||||
| from asyncio import events | ||||
| from concurrent.futures import ThreadPoolExecutor | ||||
| from time import monotonic | ||||
| import traceback | ||||
| from typing import Any | ||||
|  | ||||
| from esphome.storage_json import EsphomeStorageJSON, esphome_storage_path | ||||
|   | ||||
| @@ -1,9 +1,9 @@ | ||||
| from __future__ import annotations | ||||
|  | ||||
| import asyncio | ||||
| from collections import defaultdict | ||||
| import logging | ||||
| import os | ||||
| from collections import defaultdict | ||||
| from typing import TYPE_CHECKING, Any | ||||
|  | ||||
| from esphome import const, util | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| import logging | ||||
| import os | ||||
| import tempfile | ||||
| from pathlib import Path | ||||
| import tempfile | ||||
|  | ||||
| _LOGGER = logging.getLogger(__name__) | ||||
|  | ||||
|   | ||||
| @@ -2,6 +2,7 @@ from __future__ import annotations | ||||
|  | ||||
| import asyncio | ||||
| import base64 | ||||
| from collections.abc import Iterable | ||||
| import datetime | ||||
| import functools | ||||
| import gzip | ||||
| @@ -9,13 +10,12 @@ import hashlib | ||||
| import json | ||||
| import logging | ||||
| import os | ||||
| from pathlib import Path | ||||
| import secrets | ||||
| import shutil | ||||
| import subprocess | ||||
| import threading | ||||
| import time | ||||
| from collections.abc import Iterable | ||||
| from pathlib import Path | ||||
| from typing import TYPE_CHECKING, Any, Callable, TypeVar | ||||
| from urllib.parse import urlparse | ||||
|  | ||||
| @@ -26,13 +26,13 @@ import tornado.httpserver | ||||
| import tornado.httputil | ||||
| import tornado.ioloop | ||||
| import tornado.iostream | ||||
| from tornado.log import access_log | ||||
| import tornado.netutil | ||||
| import tornado.process | ||||
| import tornado.queues | ||||
| import tornado.web | ||||
| import tornado.websocket | ||||
| import yaml | ||||
| from tornado.log import access_log | ||||
| from yaml.nodes import Node | ||||
|  | ||||
| from esphome import const, platformio_api, yaml_util | ||||
|   | ||||
| @@ -1,13 +1,15 @@ | ||||
| from __future__ import annotations | ||||
|  | ||||
| import logging | ||||
| from pathlib import Path | ||||
| import os | ||||
| from datetime import datetime | ||||
| import logging | ||||
| import os | ||||
| from pathlib import Path | ||||
|  | ||||
| import requests | ||||
|  | ||||
| import esphome.config_validation as cv | ||||
| from esphome.core import CORE, TimePeriodSeconds | ||||
| from esphome.const import __version__ | ||||
| from esphome.core import CORE, TimePeriodSeconds | ||||
|  | ||||
| _LOGGER = logging.getLogger(__name__) | ||||
| CODEOWNERS = ["@landonr"] | ||||
|   | ||||
| @@ -1,9 +1,9 @@ | ||||
| from abc import ABC, abstractmethod | ||||
| from typing import Any | ||||
| import contextvars | ||||
| from typing import Any | ||||
|  | ||||
| from esphome.types import ConfigFragmentType, ID, ConfigPathType | ||||
| import esphome.config_validation as cv | ||||
| from esphome.types import ID, ConfigFragmentType, ConfigPathType | ||||
|  | ||||
|  | ||||
| class FinalValidateConfig(ABC): | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| import hashlib | ||||
| import logging | ||||
| import re | ||||
| import subprocess | ||||
| import urllib.parse | ||||
| from dataclasses import dataclass | ||||
| from datetime import datetime | ||||
| import hashlib | ||||
| import logging | ||||
| from pathlib import Path | ||||
| import re | ||||
| import subprocess | ||||
| from typing import Callable, Optional | ||||
| import urllib.parse | ||||
|  | ||||
| import esphome.config_validation as cv | ||||
| from esphome.core import CORE, TimePeriodSeconds | ||||
|   | ||||
| @@ -1,14 +1,13 @@ | ||||
| import codecs | ||||
| from contextlib import suppress | ||||
|  | ||||
| import logging | ||||
| import os | ||||
| import platform | ||||
| from pathlib import Path | ||||
| from typing import Union | ||||
| import tempfile | ||||
| from urllib.parse import urlparse | ||||
| import platform | ||||
| import re | ||||
| import tempfile | ||||
| from typing import Union | ||||
| from urllib.parse import urlparse | ||||
|  | ||||
| _LOGGER = logging.getLogger(__name__) | ||||
|  | ||||
| @@ -129,9 +128,10 @@ def _resolve_with_zeroconf(host): | ||||
|  | ||||
|  | ||||
| def resolve_ip_address(host): | ||||
|     from esphome.core import EsphomeError | ||||
|     import socket | ||||
|  | ||||
|     from esphome.core import EsphomeError | ||||
|  | ||||
|     errs = [] | ||||
|  | ||||
|     if host.endswith(".local"): | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| from datetime import datetime | ||||
| import hashlib | ||||
| import json | ||||
| import logging | ||||
| import ssl | ||||
| import sys | ||||
| import time | ||||
| import json | ||||
|  | ||||
| import paho.mqtt.client as mqtt | ||||
|  | ||||
| @@ -24,9 +24,9 @@ from esphome.const import ( | ||||
|     CONF_USERNAME, | ||||
| ) | ||||
| from esphome.core import CORE, EsphomeError | ||||
| from esphome.log import color, Fore | ||||
| from esphome.helpers import get_int_env, get_str_env | ||||
| from esphome.log import Fore, color | ||||
| from esphome.util import safe_print | ||||
| from esphome.helpers import get_str_env, get_int_env | ||||
|  | ||||
| _LOGGER = logging.getLogger(__name__) | ||||
|  | ||||
|   | ||||
| @@ -1,20 +1,20 @@ | ||||
| import operator | ||||
| from functools import reduce | ||||
| import esphome.config_validation as cv | ||||
| from esphome.core import CORE | ||||
| import operator | ||||
|  | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import ( | ||||
|     CONF_ALLOW_OTHER_USES, | ||||
|     CONF_IGNORE_STRAPPING_WARNING, | ||||
|     CONF_INPUT, | ||||
|     CONF_INVERTED, | ||||
|     CONF_MODE, | ||||
|     CONF_NUMBER, | ||||
|     CONF_OPEN_DRAIN, | ||||
|     CONF_OUTPUT, | ||||
|     CONF_PULLDOWN, | ||||
|     CONF_PULLUP, | ||||
|     CONF_IGNORE_STRAPPING_WARNING, | ||||
|     CONF_ALLOW_OTHER_USES, | ||||
|     CONF_INVERTED, | ||||
| ) | ||||
| from esphome.core import CORE | ||||
|  | ||||
|  | ||||
| class PinRegistry(dict): | ||||
|   | ||||
| @@ -1,12 +1,11 @@ | ||||
| from dataclasses import dataclass | ||||
| import json | ||||
| from typing import Union | ||||
| from pathlib import Path | ||||
|  | ||||
| import logging | ||||
| import os | ||||
| from pathlib import Path | ||||
| import re | ||||
| import subprocess | ||||
| from typing import Union | ||||
|  | ||||
| from esphome.const import CONF_COMPILE_PROCESS_LIMIT, CONF_ESPHOME, KEY_CORE | ||||
| from esphome.core import CORE, EsphomeError | ||||
| @@ -20,9 +19,10 @@ def patch_structhash(): | ||||
|     # removed/added. This might have unintended consequences, but this improves compile | ||||
|     # times greatly when adding/removing components and a simple clean build solves | ||||
|     # all issues | ||||
|     from platformio.run import helpers, cli | ||||
|     from os.path import join, isdir, getmtime | ||||
|     from os import makedirs | ||||
|     from os.path import getmtime, isdir, join | ||||
|  | ||||
|     from platformio.run import cli, helpers | ||||
|  | ||||
|     def patched_clean_build_dir(build_dir, *args): | ||||
|         from platformio import fs | ||||
|   | ||||
| @@ -1,10 +1,11 @@ | ||||
| from __future__ import annotations | ||||
|  | ||||
| import binascii | ||||
| import codecs | ||||
| from datetime import datetime | ||||
| import json | ||||
| import logging | ||||
| import os | ||||
| from datetime import datetime | ||||
|  | ||||
| from esphome import const | ||||
| from esphome.const import CONF_DISABLED, CONF_MDNS | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
|  | ||||
| from typing import Union | ||||
|  | ||||
| from esphome.core import ID, Lambda, EsphomeCore | ||||
| from esphome.core import ID, EsphomeCore, Lambda | ||||
|  | ||||
| ConfigFragmentType = Union[ | ||||
|     str, | ||||
|   | ||||
| @@ -1,13 +1,12 @@ | ||||
| from typing import Union | ||||
|  | ||||
| import collections | ||||
| import io | ||||
| import logging | ||||
| import os | ||||
| from pathlib import Path | ||||
| import re | ||||
| import subprocess | ||||
| import sys | ||||
| from pathlib import Path | ||||
| from typing import Union | ||||
|  | ||||
| from esphome import const | ||||
|  | ||||
|   | ||||
| @@ -2,6 +2,7 @@ import difflib | ||||
| import itertools | ||||
|  | ||||
| import voluptuous as vol | ||||
|  | ||||
| from esphome.schema_extractors import schema_extractor_extended | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -1,13 +1,14 @@ | ||||
| from __future__ import annotations | ||||
|  | ||||
| from io import StringIO | ||||
| import json | ||||
| import os | ||||
| from io import StringIO | ||||
| from typing import Any | ||||
|  | ||||
| from esphome.yaml_util import parse_yaml | ||||
| from esphome.config import validate_config, _format_vol_invalid, Config | ||||
| from esphome.core import CORE, DocumentRange | ||||
| from esphome.config import Config, _format_vol_invalid, validate_config | ||||
| import esphome.config_validation as cv | ||||
| from esphome.core import CORE, DocumentRange | ||||
| from esphome.yaml_util import parse_yaml | ||||
|  | ||||
|  | ||||
| def _get_invalid_range(res: Config, invalid: cv.Invalid) -> DocumentRange | None: | ||||
|   | ||||
| @@ -276,8 +276,8 @@ def wizard(path): | ||||
|     from esphome.components.bk72xx import boards as bk72xx_boards | ||||
|     from esphome.components.esp32 import boards as esp32_boards | ||||
|     from esphome.components.esp8266 import boards as esp8266_boards | ||||
|     from esphome.components.rtl87xx import boards as rtl87xx_boards | ||||
|     from esphome.components.rp2040 import boards as rp2040_boards | ||||
|     from esphome.components.rtl87xx import boards as rtl87xx_boards | ||||
|  | ||||
|     if not path.endswith(".yaml") and not path.endswith(".yml"): | ||||
|         safe_print( | ||||
|   | ||||
| @@ -1,27 +1,27 @@ | ||||
| import logging | ||||
| import os | ||||
| import re | ||||
| from pathlib import Path | ||||
| import re | ||||
| from typing import Union | ||||
|  | ||||
| from esphome.config import iter_components, iter_component_configs | ||||
| from esphome import loader | ||||
| from esphome.config import iter_component_configs, iter_components | ||||
| from esphome.const import ( | ||||
|     ENV_NOGITIGNORE, | ||||
|     HEADER_FILE_EXTENSIONS, | ||||
|     SOURCE_FILE_EXTENSIONS, | ||||
|     __version__, | ||||
|     ENV_NOGITIGNORE, | ||||
| ) | ||||
| from esphome.core import CORE, EsphomeError | ||||
| from esphome.helpers import ( | ||||
|     mkdir_p, | ||||
|     read_file, | ||||
|     write_file_if_changed, | ||||
|     walk_files, | ||||
|     copy_file_if_changed, | ||||
|     get_bool_env, | ||||
|     mkdir_p, | ||||
|     read_file, | ||||
|     walk_files, | ||||
|     write_file_if_changed, | ||||
| ) | ||||
| from esphome.storage_json import StorageJSON, storage_path | ||||
| from esphome import loader | ||||
|  | ||||
| _LOGGER = logging.getLogger(__name__) | ||||
|  | ||||
|   | ||||
| @@ -3,16 +3,16 @@ from __future__ import annotations | ||||
| import fnmatch | ||||
| import functools | ||||
| import inspect | ||||
| from io import TextIOWrapper | ||||
| import logging | ||||
| import math | ||||
| import os | ||||
| import uuid | ||||
| from io import TextIOWrapper | ||||
| from typing import Any | ||||
| import uuid | ||||
|  | ||||
| import yaml | ||||
| import yaml.constructor | ||||
| from yaml import SafeLoader as PurePythonLoader | ||||
| import yaml.constructor | ||||
|  | ||||
| try: | ||||
|     from yaml import CSafeLoader as FastestAvailableSafeLoader | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| from __future__ import annotations | ||||
|  | ||||
| import asyncio | ||||
| import logging | ||||
| from dataclasses import dataclass | ||||
| import logging | ||||
| from typing import Callable | ||||
|  | ||||
| from zeroconf import IPVersion, ServiceInfo, ServiceStateChange, Zeroconf | ||||
|   | ||||
| @@ -0,0 +1,10 @@ | ||||
| touchscreen: | ||||
|   - platform: ft63x6 | ||||
|     id: tft_touch | ||||
|     display: tft_display | ||||
|     update_interval: 50ms | ||||
|     threshold: 1 | ||||
|     calibration: | ||||
|       x_max: 240 | ||||
|       y_max: 320 | ||||
|  | ||||
|   | ||||
							
								
								
									
										25
									
								
								tests/components/lvgl/logo-text.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								tests/components/lvgl/logo-text.svg
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <svg id="Layer_2" data-name="Layer 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 596.64 116.88"> | ||||
|   <defs> | ||||
|     <style> | ||||
|       .cls-1 { | ||||
|         fill: #1d2126; | ||||
|         stroke-width: 0px; | ||||
|       } | ||||
|     </style> | ||||
|   </defs> | ||||
|   <g id="Layer_1-2" data-name="Layer 1"> | ||||
|     <g> | ||||
|       <g> | ||||
|         <path class="cls-1" d="M211.37,84.7v11.25h-43.5V25.87h43.5v11.34h-31.59v18.14h28.22v10.55h-28.22v18.8h31.59Z"/> | ||||
|         <path class="cls-1" d="M245.41,24.6c6.41,0,11.73,1.56,15.98,4.69,4.25,3.12,6.86,7.3,7.83,12.52l-11.2,3.05c-.63-3-2.09-5.31-4.38-6.94-2.3-1.62-5.13-2.44-8.51-2.44-3.63,0-6.5.87-8.62,2.6-2.13,1.73-3.19,4.04-3.19,6.91,0,4.53,2.81,7.47,8.44,8.81l11.44,2.86c5.91,1.53,10.33,3.96,13.27,7.29,2.94,3.33,4.41,7.43,4.41,12.3,0,6.25-2.27,11.3-6.8,15.16-4.53,3.86-10.59,5.79-18.19,5.79-6.84,0-12.63-1.61-17.34-4.83-4.66-3.34-7.41-7.75-8.25-13.22l11.2-2.91c.41,3.09,1.95,5.52,4.62,7.27,2.67,1.75,6.07,2.62,10.2,2.62s7.09-.84,9.35-2.51c2.27-1.67,3.4-3.94,3.4-6.82,0-4.5-2.81-7.47-8.44-8.91l-11.44-2.77c-5.88-1.34-10.29-3.73-13.24-7.15s-4.43-7.6-4.43-12.54c0-6.19,2.2-11.21,6.59-15.07,4.39-3.86,10.16-5.79,17.32-5.79Z"/> | ||||
|         <path class="cls-1" d="M332.92,48.7c0,6.88-2.09,12.44-6.26,16.69-4.17,4.25-9.79,6.38-16.85,6.38h-15.75v24.19h-11.91V25.87h27.75c7.12,0,12.74,2.06,16.85,6.16,4.11,4.11,6.16,9.66,6.16,16.66ZM320.45,48.42c0-3.53-1.1-6.4-3.3-8.6s-5.32-3.3-9.35-3.3h-13.73v24.8h13.55c4.12,0,7.3-1.17,9.52-3.52,2.22-2.34,3.33-5.47,3.33-9.38Z"/> | ||||
|         <path class="cls-1" d="M343.56,25.87h11.91v29.3l30.89.09v-29.39h12v70.08h-12v-30.14l-30.89-.09v30.23h-11.91V25.87Z"/> | ||||
|         <path class="cls-1" d="M434.17,47.29c7.25,0,13.16,2.33,17.72,6.98,4.56,4.66,6.84,10.64,6.84,17.95s-2.28,13.25-6.84,17.91c-4.56,4.66-10.47,6.98-17.72,6.98s-13.25-2.33-17.81-6.98c-4.56-4.66-6.84-10.62-6.84-17.91s2.28-13.34,6.84-17.98c4.56-4.64,10.5-6.96,17.81-6.96ZM434.17,86.9c3.87,0,7.02-1.37,9.45-4.1,2.42-2.73,3.63-6.29,3.63-10.66s-1.21-7.91-3.63-10.62c-2.42-2.7-5.57-4.05-9.45-4.05s-7.17,1.35-9.61,4.05c-2.44,2.7-3.66,6.24-3.66,10.62s1.22,7.93,3.66,10.66c2.44,2.73,5.64,4.1,9.61,4.1Z"/> | ||||
|         <path class="cls-1" d="M540.67,65.81v30.14h-11.02v-28.41c0-3.28-.84-5.84-2.53-7.69-1.69-1.84-3.98-2.77-6.89-2.77-3.09,0-5.56,1.01-7.41,3.02-1.84,2.02-2.77,4.84-2.77,8.46v27.38h-11.16v-28.41c0-3.28-.82-5.84-2.46-7.69-1.64-1.84-3.91-2.77-6.82-2.77-3.09,0-5.58,1.01-7.45,3.02s-2.81,4.84-2.81,8.46v27.38h-11.34v-47.34h10.55l.38,4.55c2.75-4.03,7.23-6.05,13.45-6.05,3.62,0,6.77.75,9.42,2.25,2.66,1.5,4.67,3.69,6.05,6.56,1.16-2.75,3.07-4.91,5.74-6.47,2.67-1.56,5.85-2.34,9.54-2.34,5.37,0,9.64,1.66,12.8,4.97,3.16,3.31,4.73,7.89,4.73,13.73Z"/> | ||||
|         <path class="cls-1" d="M596.64,76.45h-36.28c.38,3.56,1.72,6.28,4.03,8.16,2.31,1.88,5.25,2.81,8.81,2.81,5.78,0,9.83-2.41,12.14-7.22l9.47,3.75c-1.78,4.16-4.59,7.41-8.41,9.75-3.83,2.34-8.23,3.52-13.2,3.52-7,0-12.68-2.29-17.04-6.87-4.36-4.58-6.54-10.59-6.54-18.02s2.2-13.48,6.59-18.14c4.39-4.66,10.13-6.98,17.23-6.98s12.58,2.3,16.83,6.89c4.25,4.59,6.38,10.64,6.38,18.14v4.22ZM560.55,68.48h24.56c-.22-3.84-1.38-6.77-3.49-8.79s-4.95-3.02-8.51-3.02-6.41,1.02-8.62,3.07c-2.22,2.05-3.53,4.96-3.94,8.74Z"/> | ||||
|       </g> | ||||
|       <path class="cls-1" d="M114.7,51.58L65.3,2.19c-2.92-2.92-7.69-2.92-10.61,0L5.3,51.58c-2.92,2.92-5.3,8.68-5.3,12.8v45c0,4.12,3.38,7.5,7.5,7.5h29.5V42.21c0-1.66,1.34-3,3-3h40c1.66,0,3,1.34,3,3v12c0,1.66-1.34,3-3,3h-25v6h25c1.66,0,3,1.34,3,3v12c0,1.66-1.34,3-3,3h-25v6h25c1.66,0,3,1.34,3,3v12c0,1.66-1.34,3-3,3h-28c-1.66,0-3-1.34-3-3s1.34-3,3-3h25v-6h-25c-1.66,0-3-1.34-3-3v-12c0-1.66,1.34-3,3-3h25v-6h-25c-1.66,0-3-1.34-3-3v-12c0-1.66,1.34-3,3-3h25v-6h-34v71.67h69.5c4.12,0,7.5-3.38,7.5-7.5v-45c0-4.12-2.39-9.89-5.3-12.8Z"/> | ||||
|     </g> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 3.6 KiB | 
| @@ -1,9 +1,10 @@ | ||||
| color: | ||||
|   - id: light_blue | ||||
|     hex: "3340FF" | ||||
|  | ||||
| lvgl: | ||||
|   log_level: TRACE | ||||
|   bg_color: light_blue | ||||
|   touchscreens: | ||||
|     - touchscreen_id: tft_touch | ||||
|       long_press_repeat_time: 200ms | ||||
|       long_press_time: 500ms | ||||
|   widgets: | ||||
|     - label: | ||||
|         text: Hello world | ||||
| @@ -17,8 +18,101 @@ lvgl: | ||||
|         text_color: 0xFFFFFF | ||||
|         align: bottom_mid | ||||
|         text_font: space16 | ||||
|     - obj: | ||||
|         align: center | ||||
|         arc_opa: COVER | ||||
|         arc_color: 0xFF0000 | ||||
|         arc_rounded: false | ||||
|         arc_width: 3 | ||||
|         anim_time: 1s | ||||
|         bg_color: light_blue | ||||
|         bg_grad_color: light_blue | ||||
|         bg_dither_mode: ordered | ||||
|         bg_grad_dir: hor | ||||
|         bg_grad_stop: 128 | ||||
|         bg_image_opa: transp | ||||
|         bg_image_recolor: light_blue | ||||
|         bg_image_recolor_opa: 50% | ||||
|         bg_main_stop: 0 | ||||
|         bg_opa: 20% | ||||
|         border_color: 0x00FF00 | ||||
|         border_opa: cover | ||||
|         border_post: true | ||||
|         border_side: [bottom, left] | ||||
|         border_width: 4 | ||||
|         clip_corner: false | ||||
|         height: 50% | ||||
|         image_recolor: light_blue | ||||
|         image_recolor_opa: cover | ||||
|         line_width: 10 | ||||
|         line_dash_width: 10 | ||||
|         line_dash_gap: 10 | ||||
|         line_rounded: false | ||||
|         line_color: light_blue | ||||
|         opa: cover | ||||
|         opa_layered: cover | ||||
|         outline_color: light_blue | ||||
|         outline_opa: cover | ||||
|         outline_pad: 10px | ||||
|         outline_width: 10px | ||||
|         pad_all: 10px | ||||
|         pad_bottom: 10px | ||||
|         pad_column: 10px | ||||
|         pad_left: 10px | ||||
|         pad_right: 10px | ||||
|         pad_row: 10px | ||||
|         pad_top: 10px | ||||
|         shadow_color: light_blue | ||||
|         shadow_ofs_x: 5 | ||||
|         shadow_ofs_y: 5 | ||||
|         shadow_opa: cover | ||||
|         shadow_spread: 5 | ||||
|         shadow_width: 10 | ||||
|         text_align: auto | ||||
|         text_color: light_blue | ||||
|         text_decor: [underline, strikethrough] | ||||
|         text_font: montserrat_18 | ||||
|         text_letter_space: 4 | ||||
|         text_line_space: 4 | ||||
|         text_opa: cover | ||||
|         transform_angle: 180 | ||||
|         transform_height: 100 | ||||
|         transform_pivot_x: 50% | ||||
|         transform_pivot_y: 50% | ||||
|         transform_zoom: 0.5 | ||||
|         translate_x: 10 | ||||
|         translate_y: 10 | ||||
|         max_height: 100 | ||||
|         max_width: 200 | ||||
|         min_height: 20% | ||||
|         min_width: 20% | ||||
|         radius: circle | ||||
|         width: 10px | ||||
|         x: 100 | ||||
|         y: 120 | ||||
|     - button: | ||||
|         width: 20% | ||||
|         height: 10% | ||||
|         pressed: | ||||
|           bg_color: light_blue | ||||
|         widgets: | ||||
|           - label: | ||||
|               text: Button | ||||
|  | ||||
| font: | ||||
|   - file: "gfonts://Roboto" | ||||
|     id: space16 | ||||
|     bpp: 4 | ||||
|  | ||||
| image: | ||||
|   - id: cat_img | ||||
|     resize: 256x48 | ||||
|     file: $component_dir/logo-text.svg | ||||
|   - id: dog_img | ||||
|     file: $component_dir/logo-text.svg | ||||
|     resize: 256x48 | ||||
|     type: TRANSPARENT_BINARY | ||||
|  | ||||
| color: | ||||
|   - id: light_blue | ||||
|     hex: "3340FF" | ||||
|   | ||||
| @@ -19,7 +19,9 @@ display: | ||||
|       mirror_y: true | ||||
|     data_rate: 80MHz | ||||
|     cs_pin: GPIO20 | ||||
|     dc_pin: GPIO15 | ||||
|     dc_pin: | ||||
|       number: GPIO15 | ||||
|       ignore_strapping_warning: true | ||||
|     auto_clear_enabled: false | ||||
|     invert_colors: false | ||||
|     update_interval: never | ||||
|   | ||||
		Reference in New Issue
	
	Block a user