Merge branch 'esphome:dev' into gsm

This commit is contained in:
Olivier ARCHER 2024-07-30 13:10:24 +02:00 committed by GitHub
commit 8061104496
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
98 changed files with 887 additions and 609 deletions

View file

@ -46,7 +46,7 @@ jobs:
with: with:
python-version: "3.9" python-version: "3.9"
- name: Set up Docker Buildx - 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 - name: Set up QEMU
uses: docker/setup-qemu-action@v3.2.0 uses: docker/setup-qemu-action@v3.2.0

View file

@ -90,7 +90,7 @@ jobs:
python-version: "3.9" python-version: "3.9"
- name: Set up Docker Buildx - 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 - name: Set up QEMU
if: matrix.platform != 'linux/amd64' if: matrix.platform != 'linux/amd64'
uses: docker/setup-qemu-action@v3.2.0 uses: docker/setup-qemu-action@v3.2.0
@ -184,7 +184,7 @@ jobs:
merge-multiple: true merge-multiple: true
- name: Set up Docker Buildx - 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 - name: Log in to docker hub
if: matrix.registry == 'dockerhub' if: matrix.registry == 'dockerhub'

View file

@ -428,6 +428,7 @@ esphome/components/veml7700/* @latonita
esphome/components/version/* @esphome/core esphome/components/version/* @esphome/core
esphome/components/voice_assistant/* @jesserockz esphome/components/voice_assistant/* @jesserockz
esphome/components/wake_on_lan/* @clydebarrow @willwill2will54 esphome/components/wake_on_lan/* @clydebarrow @willwill2will54
esphome/components/watchdog/* @oarcher
esphome/components/waveshare_epaper/* @clydebarrow esphome/components/waveshare_epaper/* @clydebarrow
esphome/components/web_server_base/* @OttoWinter esphome/components/web_server_base/* @OttoWinter
esphome/components/web_server_idf/* @dentra esphome/components/web_server_idf/* @dentra

View file

@ -1,12 +1,12 @@
# PYTHON_ARGCOMPLETE_OK # PYTHON_ARGCOMPLETE_OK
import argparse import argparse
from datetime import datetime
import functools import functools
import logging import logging
import os import os
import re import re
import sys import sys
import time import time
from datetime import datetime
import argcomplete import argcomplete
@ -39,14 +39,14 @@ from esphome.const import (
) )
from esphome.core import CORE, EsphomeError, coroutine from esphome.core import CORE, EsphomeError, coroutine
from esphome.helpers import indent, is_ip_address from esphome.helpers import indent, is_ip_address
from esphome.log import Fore, color, setup_log
from esphome.util import ( from esphome.util import (
get_serial_ports,
list_yaml_files,
run_external_command, run_external_command,
run_external_process, run_external_process,
safe_print, safe_print,
list_yaml_files,
get_serial_ports,
) )
from esphome.log import color, setup_log, Fore
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -116,6 +116,7 @@ def get_port_type(port):
def run_miniterm(config, port): def run_miniterm(config, port):
import serial import serial
from esphome import platformio_api from esphome import platformio_api
if CONF_LOGGER not in config: if CONF_LOGGER not in config:
@ -596,9 +597,10 @@ def command_update_all(args):
def command_idedata(args, config): def command_idedata(args, config):
from esphome import platformio_api
import json import json
from esphome import platformio_api
logging.disable(logging.INFO) logging.disable(logging.INFO)
logging.disable(logging.WARNING) logging.disable(logging.WARNING)
@ -747,7 +749,14 @@ def parse_args(argv):
) )
parser = argparse.ArgumentParser( 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) mqtt_options = argparse.ArgumentParser(add_help=False)
@ -948,67 +957,6 @@ def parse_args(argv):
# a deprecation warning). # a deprecation warning).
arguments = argv[1:] 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) argcomplete.autocomplete(parser)
return parser.parse_args(arguments) return parser.parse_args(arguments)
@ -1023,13 +971,6 @@ def run_esphome(argv):
# Show timestamp for dashboard access logs # Show timestamp for dashboard access logs
args.command == "dashboard", 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): if sys.version_info < (3, 8, 0):
_LOGGER.error( _LOGGER.error(

View file

@ -7,10 +7,10 @@ from esphome.const import (
CONF_ELSE, CONF_ELSE,
CONF_ID, CONF_ID,
CONF_THEN, CONF_THEN,
CONF_TIME,
CONF_TIMEOUT, CONF_TIMEOUT,
CONF_TRIGGER_ID, CONF_TRIGGER_ID,
CONF_TYPE_ID, CONF_TYPE_ID,
CONF_TIME,
CONF_UPDATE_INTERVAL, CONF_UPDATE_INTERVAL,
) )
from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor

View file

@ -8,55 +8,78 @@
# want to break suddenly due to a rename (this file will get backports for features). # want to break suddenly due to a rename (this file will get backports for features).
# pylint: disable=unused-import # pylint: disable=unused-import
from esphome.cpp_generator import ( # noqa from esphome.cpp_generator import ( # noqa: F401
ArrayInitializer,
Expression, Expression,
LineComment,
MockObj,
MockObjClass,
Pvariable,
RawExpression, RawExpression,
RawStatement, RawStatement,
TemplateArguments,
StructInitializer,
ArrayInitializer,
safe_exp,
Statement, Statement,
LineComment, StructInitializer,
progmem_array, TemplateArguments,
static_const_array,
statement,
variable,
with_local_variable,
new_variable,
Pvariable,
new_Pvariable,
add, add,
add_global,
add_library,
add_build_flag, add_build_flag,
add_define, add_define,
add_global,
add_library,
add_platformio_option, add_platformio_option,
get_variable, get_variable,
get_variable_with_full_id, get_variable_with_full_id,
process_lambda,
is_template, is_template,
new_Pvariable,
new_variable,
process_lambda,
progmem_array,
safe_exp,
statement,
static_const_array,
templatable, templatable,
MockObj, variable,
MockObjClass, with_local_variable,
) )
from esphome.cpp_helpers import ( # noqa from esphome.cpp_helpers import ( # noqa: F401
gpio_pin_expression,
register_component,
build_registry_entry, build_registry_entry,
build_registry_list, build_registry_list,
extract_registry_entry_config, extract_registry_entry_config,
register_parented, gpio_pin_expression,
past_safe_mode, past_safe_mode,
register_component,
register_parented,
) )
from esphome.cpp_types import ( # noqa from esphome.cpp_types import ( # noqa: F401
global_ns, NAN,
void, App,
nullptr, Application,
float_, Component,
double, ComponentPtr,
Controller,
EntityBase,
EntityCategory,
ESPTime,
GPIOPin,
InternalGPIOPin,
JsonObject,
JsonObjectConst,
Parented,
PollingComponent,
arduino_json_ns,
bool_, bool_,
const_char_ptr,
double,
esphome_ns,
float_,
global_ns,
gpio_Flags,
int16,
int32,
int64,
int_, int_,
nullptr,
optional,
size_t,
std_ns, std_ns,
std_shared_ptr, std_shared_ptr,
std_string, std_string,
@ -66,28 +89,5 @@ from esphome.cpp_types import ( # noqa
uint16, uint16,
uint32, uint32,
uint64, uint64,
int16, void,
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,
) )

View file

@ -1,7 +1,8 @@
import esphome.codegen as cg from esphome import automation
import esphome.config_validation as cv
from esphome.automation import maybe_simple_id 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 ( from esphome.const import (
CONF_CHARACTERISTIC_UUID, CONF_CHARACTERISTIC_UUID,
CONF_ID, CONF_ID,
@ -13,7 +14,6 @@ from esphome.const import (
CONF_TRIGGER_ID, CONF_TRIGGER_ID,
CONF_VALUE, CONF_VALUE,
) )
from esphome import automation
AUTO_LOAD = ["esp32_ble_client"] AUTO_LOAD = ["esp32_ble_client"]
CODEOWNERS = ["@buxtronix", "@clydebarrow"] CODEOWNERS = ["@buxtronix", "@clydebarrow"]

View file

@ -1,6 +1,6 @@
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import ble_client, esp32_ble_tracker, output 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 esphome.const import CONF_CHARACTERISTIC_UUID, CONF_ID, CONF_SERVICE_UUID
from .. import ble_client_ns from .. import ble_client_ns

View file

@ -1,17 +1,18 @@
from esphome import automation
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components import ble_client, esp32_ble_tracker, sensor
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.components import sensor, ble_client, esp32_ble_tracker
from esphome.const import ( from esphome.const import (
CONF_CHARACTERISTIC_UUID, CONF_CHARACTERISTIC_UUID,
CONF_LAMBDA, CONF_LAMBDA,
CONF_SERVICE_UUID,
CONF_TRIGGER_ID, CONF_TRIGGER_ID,
CONF_TYPE, CONF_TYPE,
CONF_SERVICE_UUID,
DEVICE_CLASS_SIGNAL_STRENGTH, DEVICE_CLASS_SIGNAL_STRENGTH,
STATE_CLASS_MEASUREMENT, STATE_CLASS_MEASUREMENT,
UNIT_DECIBEL_MILLIWATT, UNIT_DECIBEL_MILLIWATT,
) )
from esphome import automation
from .. import ble_client_ns from .. import ble_client_ns
DEPENDENCIES = ["ble_client"] DEPENDENCIES = ["ble_client"]

View file

@ -1,7 +1,8 @@
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components import ble_client, switch
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.components import switch, ble_client
from esphome.const import ICON_BLUETOOTH from esphome.const import ICON_BLUETOOTH
from .. import ble_client_ns from .. import ble_client_ns
BLEClientSwitch = ble_client_ns.class_( BLEClientSwitch = ble_client_ns.class_(

View file

@ -1,13 +1,14 @@
from esphome import automation
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components import ble_client, esp32_ble_tracker, text_sensor
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.components import text_sensor, ble_client, esp32_ble_tracker
from esphome.const import ( from esphome.const import (
CONF_CHARACTERISTIC_UUID, CONF_CHARACTERISTIC_UUID,
CONF_ID, CONF_ID,
CONF_TRIGGER_ID,
CONF_SERVICE_UUID, CONF_SERVICE_UUID,
CONF_TRIGGER_ID,
) )
from esphome import automation
from .. import ble_client_ns from .. import ble_client_ns
DEPENDENCIES = ["ble_client"] DEPENDENCIES = ["ble_client"]

View file

@ -1,13 +1,13 @@
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import binary_sensor, esp32_ble_tracker from esphome.components import binary_sensor, esp32_ble_tracker
import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_MAC_ADDRESS,
CONF_SERVICE_UUID,
CONF_IBEACON_MAJOR, CONF_IBEACON_MAJOR,
CONF_IBEACON_MINOR, CONF_IBEACON_MINOR,
CONF_IBEACON_UUID, CONF_IBEACON_UUID,
CONF_MAC_ADDRESS,
CONF_MIN_RSSI, CONF_MIN_RSSI,
CONF_SERVICE_UUID,
CONF_TIMEOUT, CONF_TIMEOUT,
) )

View file

@ -1,12 +1,12 @@
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components import esp32_ble_tracker, sensor
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.components import sensor, esp32_ble_tracker
from esphome.const import ( from esphome.const import (
CONF_IBEACON_MAJOR, CONF_IBEACON_MAJOR,
CONF_IBEACON_MINOR, CONF_IBEACON_MINOR,
CONF_IBEACON_UUID, CONF_IBEACON_UUID,
CONF_SERVICE_UUID,
CONF_MAC_ADDRESS, CONF_MAC_ADDRESS,
CONF_SERVICE_UUID,
DEVICE_CLASS_SIGNAL_STRENGTH, DEVICE_CLASS_SIGNAL_STRENGTH,
STATE_CLASS_MEASUREMENT, STATE_CLASS_MEASUREMENT,
UNIT_DECIBEL_MILLIWATT, UNIT_DECIBEL_MILLIWATT,

View file

@ -1,6 +1,6 @@
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components import esp32_ble_tracker, text_sensor
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.components import text_sensor, esp32_ble_tracker
DEPENDENCIES = ["esp32_ble_tracker"] DEPENDENCIES = ["esp32_ble_tracker"]

View file

@ -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 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 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"] AUTO_LOAD = ["esp32_ble_client", "esp32_ble_tracker"]
DEPENDENCIES = ["api", "esp32"] DEPENDENCIES = ["api", "esp32"]

View file

@ -1,11 +1,12 @@
from dataclasses import dataclass from dataclasses import dataclass
from typing import Union, Optional
from pathlib import Path
import logging import logging
import os 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 ( from esphome.const import (
CONF_ADVANCED, CONF_ADVANCED,
CONF_BOARD, CONF_BOARD,
@ -15,6 +16,7 @@ from esphome.const import (
CONF_IGNORE_EFUSE_MAC_CRC, CONF_IGNORE_EFUSE_MAC_CRC,
CONF_NAME, CONF_NAME,
CONF_PATH, CONF_PATH,
CONF_PLATFORM_VERSION,
CONF_PLATFORMIO_OPTIONS, CONF_PLATFORMIO_OPTIONS,
CONF_REF, CONF_REF,
CONF_REFRESH, CONF_REFRESH,
@ -32,13 +34,12 @@ from esphome.const import (
TYPE_GIT, TYPE_GIT,
TYPE_LOCAL, TYPE_LOCAL,
__version__, __version__,
CONF_PLATFORM_VERSION,
) )
from esphome.core import CORE, HexInt, TimePeriod from esphome.core import CORE, HexInt, TimePeriod
import esphome.config_validation as cv import esphome.final_validate as fv
import esphome.codegen as cg from esphome.helpers import copy_file_if_changed, mkdir_p, write_file_if_changed
from esphome import git
from .boards import BOARDS
from .const import ( # noqa from .const import ( # noqa
KEY_BOARD, KEY_BOARD,
KEY_COMPONENTS, KEY_COMPONENTS,
@ -54,12 +55,10 @@ from .const import ( # noqa
VARIANT_FRIENDLY, VARIANT_FRIENDLY,
VARIANTS, VARIANTS,
) )
from .boards import BOARDS
# force import gpio to register pin schema # force import gpio to register pin schema
from .gpio import esp32_pin_to_code # noqa from .gpio import esp32_pin_to_code # noqa
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
CODEOWNERS = ["@esphome/core"] CODEOWNERS = ["@esphome/core"]
AUTO_LOAD = ["preferences"] AUTO_LOAD = ["preferences"]

View file

@ -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 = { ESP32_BASE_PINS = {
"TX": 1, "TX": 1,

View file

@ -1,22 +1,22 @@
from dataclasses import dataclass from dataclasses import dataclass
from typing import Any
import logging 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 ( from esphome.const import (
CONF_ID, CONF_ID,
CONF_IGNORE_PIN_VALIDATION_ERROR,
CONF_IGNORE_STRAPPING_WARNING,
CONF_INVERTED, CONF_INVERTED,
CONF_MODE, CONF_MODE,
CONF_NUMBER, CONF_NUMBER,
CONF_OPEN_DRAIN, CONF_OPEN_DRAIN,
CONF_OUTPUT, CONF_OUTPUT,
CONF_IGNORE_PIN_VALIDATION_ERROR,
CONF_IGNORE_STRAPPING_WARNING,
PLATFORM_ESP32, PLATFORM_ESP32,
) )
from esphome import pins
from esphome.core import CORE from esphome.core import CORE
import esphome.config_validation as cv
import esphome.codegen as cg
from . import boards from . import boards
from .const import ( from .const import (
@ -24,22 +24,21 @@ from .const import (
KEY_ESP32, KEY_ESP32,
KEY_VARIANT, KEY_VARIANT,
VARIANT_ESP32, VARIANT_ESP32,
VARIANT_ESP32C3,
VARIANT_ESP32S2,
VARIANT_ESP32S3,
VARIANT_ESP32C2, VARIANT_ESP32C2,
VARIANT_ESP32C3,
VARIANT_ESP32C6, VARIANT_ESP32C6,
VARIANT_ESP32H2, VARIANT_ESP32H2,
VARIANT_ESP32S2,
VARIANT_ESP32S3,
esp32_ns, esp32_ns,
) )
from .gpio_esp32 import esp32_validate_gpio_pin, esp32_validate_supports 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_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_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_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) ESP32InternalGPIOPin = esp32_ns.class_("ESP32InternalGPIOPin", cg.InternalGPIOPin)

View file

@ -1,5 +1,6 @@
import logging import logging
import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_INPUT, CONF_INPUT,
CONF_MODE, CONF_MODE,
@ -8,10 +9,8 @@ from esphome.const import (
CONF_PULLDOWN, CONF_PULLDOWN,
CONF_PULLUP, CONF_PULLUP,
) )
import esphome.config_validation as cv
from esphome.pins import check_strapping_pin from esphome.pins import check_strapping_pin
_ESP_SDIO_PINS = { _ESP_SDIO_PINS = {
6: "Flash Clock", 6: "Flash Clock",
7: "Flash Data 0", 7: "Flash Data 0",

View file

@ -1,10 +1,9 @@
import logging import logging
import esphome.config_validation as cv
from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER
from esphome.pins import check_strapping_pin from esphome.pins import check_strapping_pin
import esphome.config_validation as cv
_ESP32C2_STRAPPING_PINS = {8, 9} _ESP32C2_STRAPPING_PINS = {8, 9}
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View file

@ -1,11 +1,7 @@
import logging import logging
from esphome.const import (
CONF_INPUT,
CONF_MODE,
CONF_NUMBER,
)
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER
from esphome.pins import check_strapping_pin from esphome.pins import check_strapping_pin
_ESP32C3_SPI_PSRAM_PINS = { _ESP32C3_SPI_PSRAM_PINS = {

View file

@ -1,8 +1,7 @@
import logging import logging
from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER
from esphome.pins import check_strapping_pin from esphome.pins import check_strapping_pin
_ESP32C6_SPI_PSRAM_PINS = { _ESP32C6_SPI_PSRAM_PINS = {

View file

@ -1,8 +1,7 @@
import logging import logging
from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER
import esphome.config_validation as cv 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} _ESP32H2_SPI_FLASH_PINS = {6, 7, 15, 16, 17, 18, 19, 20, 21}

View file

@ -1,5 +1,6 @@
import logging import logging
import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_INPUT, CONF_INPUT,
CONF_MODE, CONF_MODE,
@ -8,8 +9,6 @@ from esphome.const import (
CONF_PULLDOWN, CONF_PULLDOWN,
CONF_PULLUP, CONF_PULLUP,
) )
import esphome.config_validation as cv
from esphome.pins import check_strapping_pin from esphome.pins import check_strapping_pin
_ESP32S2_SPI_PSRAM_PINS = { _ESP32S2_SPI_PSRAM_PINS = {

View file

@ -1,12 +1,7 @@
import logging import logging
from esphome.const import (
CONF_INPUT,
CONF_MODE,
CONF_NUMBER,
)
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER
from esphome.pins import check_strapping_pin from esphome.pins import check_strapping_pin
_ESP_32S3_SPI_PSRAM_PINS = { _ESP_32S3_SPI_PSRAM_PINS = {

View file

@ -1,9 +1,9 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import automation 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.const import CONF_ENABLE_ON_BOOT, CONF_ID
from esphome.core import CORE from esphome.core import CORE
from esphome.components.esp32 import add_idf_sdkconfig_option, get_esp32_variant, const
DEPENDENCIES = ["esp32"] DEPENDENCIES = ["esp32"]
CODEOWNERS = ["@jesserockz", "@Rapsssito"] CODEOWNERS = ["@jesserockz", "@Rapsssito"]

View file

@ -1,10 +1,10 @@
import esphome.codegen as cg 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 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"] AUTO_LOAD = ["esp32_ble"]
DEPENDENCIES = ["esp32"] DEPENDENCIES = ["esp32"]

View file

@ -1,5 +1,4 @@
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components import esp32_ble_tracker from esphome.components import esp32_ble_tracker
AUTO_LOAD = ["esp32_ble_tracker"] AUTO_LOAD = ["esp32_ble_tracker"]

View file

@ -1,9 +1,9 @@
import esphome.codegen as cg 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 import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_MODEL from esphome.const import CONF_ID, CONF_MODEL
from esphome.components import esp32_ble
from esphome.core import CORE from esphome.core import CORE
from esphome.components.esp32 import add_idf_sdkconfig_option
AUTO_LOAD = ["esp32_ble"] AUTO_LOAD = ["esp32_ble"]
CODEOWNERS = ["@jesserockz", "@clydebarrow", "@Rapsssito"] CODEOWNERS = ["@jesserockz", "@clydebarrow", "@Rapsssito"]

View file

@ -1,10 +1,10 @@
import re import re
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import automation from esphome import automation
import esphome.codegen as cg
from esphome.components import esp32_ble from esphome.components import esp32_ble
from esphome.components.esp32 import add_idf_sdkconfig_option from esphome.components.esp32 import add_idf_sdkconfig_option
import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_ACTIVE, CONF_ACTIVE,
CONF_DURATION, CONF_DURATION,

View file

@ -1,6 +1,4 @@
from esphome import pins from esphome import pins
import esphome.config_validation as cv
import esphome.final_validate as fv
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components.esp32 import add_idf_sdkconfig_option, get_esp32_variant from esphome.components.esp32 import add_idf_sdkconfig_option, get_esp32_variant
from esphome.components.esp32.const import ( from esphome.components.esp32.const import (
@ -8,31 +6,33 @@ from esphome.components.esp32.const import (
VARIANT_ESP32S2, VARIANT_ESP32S2,
VARIANT_ESP32S3, 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 ( from esphome.const import (
CONF_DOMAIN, CONF_ADDRESS,
CONF_ID, CONF_CLK_PIN,
CONF_VALUE, CONF_CS_PIN,
CONF_MANUAL_IP,
CONF_STATIC_IP,
CONF_TYPE,
CONF_USE_ADDRESS,
CONF_GATEWAY,
CONF_SUBNET,
CONF_DNS1, CONF_DNS1,
CONF_DNS2, CONF_DNS2,
CONF_CLK_PIN, CONF_DOMAIN,
CONF_GATEWAY,
CONF_ID,
CONF_INTERRUPT_PIN,
CONF_MANUAL_IP,
CONF_MISO_PIN, CONF_MISO_PIN,
CONF_MOSI_PIN, CONF_MOSI_PIN,
CONF_CS_PIN, CONF_PAGE_ID,
CONF_INTERRUPT_PIN,
CONF_RESET_PIN, CONF_RESET_PIN,
CONF_SPI, CONF_SPI,
CONF_PAGE_ID, CONF_STATIC_IP,
CONF_ADDRESS, CONF_SUBNET,
CONF_TYPE,
CONF_USE_ADDRESS,
CONF_VALUE,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, coroutine_with_priority
from esphome.components.network import IPAddress import esphome.final_validate as fv
from esphome.components.spi import get_spi_interface, CONF_INTERFACE_INDEX
CONFLICTS_WITH = ["wifi"] CONFLICTS_WITH = ["wifi"]
DEPENDENCIES = ["esp32"] DEPENDENCIES = ["esp32"]

View file

@ -1,9 +1,9 @@
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import text_sensor from esphome.components import text_sensor
import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_IP_ADDRESS,
CONF_DNS_ADDRESS, CONF_DNS_ADDRESS,
CONF_IP_ADDRESS,
CONF_MAC_ADDRESS, CONF_MAC_ADDRESS,
ENTITY_CATEGORY_DIAGNOSTIC, ENTITY_CATEGORY_DIAGNOSTIC,
) )

View file

@ -14,7 +14,7 @@ from esphome.const import (
from esphome.core import CORE, Lambda from esphome.core import CORE, Lambda
DEPENDENCIES = ["network"] DEPENDENCIES = ["network"]
AUTO_LOAD = ["json"] AUTO_LOAD = ["json", "watchdog"]
http_request_ns = cg.esphome_ns.namespace("http_request") http_request_ns = cg.esphome_ns.namespace("http_request")
HttpRequestComponent = http_request_ns.class_("HttpRequestComponent", cg.Component) HttpRequestComponent = http_request_ns.class_("HttpRequestComponent", cg.Component)

View file

@ -3,12 +3,12 @@
#ifdef USE_ARDUINO #ifdef USE_ARDUINO
#include "esphome/components/network/util.h" #include "esphome/components/network/util.h"
#include "esphome/components/watchdog/watchdog.h"
#include "esphome/core/application.h" #include "esphome/core/application.h"
#include "esphome/core/defines.h" #include "esphome/core/defines.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
#include "watchdog.h"
namespace esphome { namespace esphome {
namespace http_request { namespace http_request {

View file

@ -3,6 +3,8 @@
#ifdef USE_ESP_IDF #ifdef USE_ESP_IDF
#include "esphome/components/network/util.h" #include "esphome/components/network/util.h"
#include "esphome/components/watchdog/watchdog.h"
#include "esphome/core/application.h" #include "esphome/core/application.h"
#include "esphome/core/defines.h" #include "esphome/core/defines.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
@ -11,8 +13,6 @@
#include "esp_crt_bundle.h" #include "esp_crt_bundle.h"
#endif #endif
#include "watchdog.h"
namespace esphome { namespace esphome {
namespace http_request { namespace http_request {

View file

@ -1,11 +1,11 @@
#include "ota_http_request.h" #include "ota_http_request.h"
#include "../watchdog.h"
#include "esphome/core/application.h" #include "esphome/core/application.h"
#include "esphome/core/defines.h" #include "esphome/core/defines.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
#include "esphome/components/md5/md5.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.h"
#include "esphome/components/ota/ota_backend_arduino_esp32.h" #include "esphome/components/ota/ota_backend_arduino_esp32.h"
#include "esphome/components/ota/ota_backend_arduino_esp8266.h" #include "esphome/components/ota/ota_backend_arduino_esp8266.h"

View file

@ -16,13 +16,20 @@ from esphome.final_validate import full_config
from esphome.helpers import write_file_if_changed from esphome.helpers import write_file_if_changed
from . import defines as df, helpers, lv_validation as lvalid from . import defines as df, helpers, lv_validation as lvalid
from .btn import btn_spec
from .label import label_spec from .label import label_spec
from .lvcode import ConstantLiteral, LvContext from .lvcode import ConstantLiteral, LvContext
# from .menu import menu_spec
from .obj import obj_spec from .obj import obj_spec
from .schemas import WIDGET_TYPES, any_widget_schema, obj_schema from .schemas import any_widget_schema, obj_schema
from .types import FontEngine, LvglComponent, lv_disp_t_ptr, lv_font_t, lvgl_ns 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 from .widget import LvScrActType, Widget, add_widgets, set_obj_properties
DOMAIN = "lvgl" DOMAIN = "lvgl"
@ -31,11 +38,8 @@ AUTO_LOAD = ("key_provider",)
CODEOWNERS = ("@clydebarrow",) CODEOWNERS = ("@clydebarrow",)
LOGGER = logging.getLogger(__name__) LOGGER = logging.getLogger(__name__)
for widg in ( for w_type in (label_spec, obj_spec, btn_spec):
label_spec, WIDGET_TYPES[w_type.name] = w_type
obj_spec,
):
WIDGET_TYPES[widg.name] = widg
lv_scr_act_spec = LvScrActType() lv_scr_act_spec = LvScrActType()
lv_scr_act = Widget.create( 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" "Using auto_clear_enabled: true in display config not compatible with LVGL"
) )
buffer_frac = config[CONF_BUFFER_SIZE] 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") 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) cg.add_global(lvgl_ns.using)
lv_component = cg.new_Pvariable(config[CONF_ID]) lv_component = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(lv_component, config) 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]: for display in config[df.CONF_DISPLAYS]:
cg.add(lv_component.add_display(await cg.get_variable(display))) 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) await cg.get_variable(font)
cg.new_Pvariable(ID(f"{font}_engine", True, type=FontEngine), MockObj(font)) cg.new_Pvariable(ID(f"{font}_engine", True, type=FontEngine), MockObj(font))
default_font = config[df.CONF_DEFAULT_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( add_define(
"LV_FONT_CUSTOM_DECLARE", f"LV_FONT_DECLARE(*{df.DEFAULT_ESPHOME_FONT})" "LV_FONT_CUSTOM_DECLARE", f"LV_FONT_DECLARE(*{df.DEFAULT_ESPHOME_FONT})"
) )
@ -161,12 +165,15 @@ async def to_code(config):
True, True,
type=lv_font_t.operator("ptr").operator("const"), 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) add_define("LV_FONT_DEFAULT", df.DEFAULT_ESPHOME_FONT)
else: else:
add_define("LV_FONT_DEFAULT", default_font) add_define("LV_FONT_DEFAULT", await lvalid.lv_font.process(default_font))
with LvContext(): with LvContext():
await touchscreens_to_code(lv_component, config)
await set_obj_properties(lv_scr_act, config) await set_obj_properties(lv_scr_act, config)
await add_widgets(lv_scr_act, config) await add_widgets(lv_scr_act, config)
Widget.set_completed() Widget.set_completed()
@ -190,7 +197,7 @@ FINAL_VALIDATE_SCHEMA = final_validation
CONFIG_SCHEMA = ( CONFIG_SCHEMA = (
cv.polling_component_schema("1s") cv.polling_component_schema("1s")
.extend(obj_schema("obj")) .extend(obj_schema(obj_spec))
.extend( .extend(
{ {
cv.GenerateID(CONF_ID): cv.declare_id(LvglComponent), 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_WIDGETS): cv.ensure_list(WIDGET_SCHEMA),
cv.Optional(df.CONF_TRANSPARENCY_KEY, default=0x000400): lvalid.lv_color, 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)) ).add_extra(cv.has_at_least_one_key(CONF_PAGES, df.CONF_WIDGETS))

View 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()

View file

@ -446,6 +446,7 @@ CONF_TILE_ID = "tile_id"
CONF_TILES = "tiles" CONF_TILES = "tiles"
CONF_TITLE = "title" CONF_TITLE = "title"
CONF_TOP_LAYER = "top_layer" CONF_TOP_LAYER = "top_layer"
CONF_TOUCHSCREENS = "touchscreens"
CONF_TRANSPARENCY_KEY = "transparency_key" CONF_TRANSPARENCY_KEY = "transparency_key"
CONF_THEME = "theme" CONF_THEME = "theme"
CONF_VISIBLE_ROW_COUNT = "visible_row_count" 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" DEFAULT_ESPHOME_FONT = "esphome_lv_default_font"
def join_enums(enums, prefix=""): 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))

View file

@ -22,7 +22,6 @@ def add_lv_use(*names):
lv_fonts_used = set() lv_fonts_used = set()
esphome_fonts_used = set() esphome_fonts_used = set()
REQUIRED_COMPONENTS = {}
lvgl_components_required = set() lvgl_components_required = set()

View file

@ -1,16 +1,27 @@
import esphome.config_validation as cv 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 .lv_validation import lv_bool, lv_text
from .schemas import TEXT_SCHEMA from .schemas import TEXT_SCHEMA
from .types import lv_label_t from .types import LvText, WidgetType
from .widget import Widget, WidgetType from .widget import Widget
class LabelType(WidgetType): class LabelType(WidgetType):
def __init__(self): def __init__(self):
super().__init__( super().__init__(
CONF_LABEL, CONF_LABEL,
LvText("lv_label_t"),
(CONF_MAIN, CONF_SCROLLBAR, CONF_SELECTED),
TEXT_SCHEMA.extend( TEXT_SCHEMA.extend(
{ {
cv.Optional(CONF_RECOLOR): lv_bool, 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): async def to_code(self, w: Widget, config):
"""For a text object, create and set text""" """For a text object, create and set text"""
if value := config.get(CONF_TEXT): if value := config.get(CONF_TEXT):

View file

@ -8,6 +8,7 @@ import esphome.config_validation as cv
from esphome.const import CONF_ARGS, CONF_COLOR, CONF_FORMAT from esphome.const import CONF_ARGS, CONF_COLOR, CONF_FORMAT
from esphome.core import HexInt from esphome.core import HexInt
from esphome.cpp_generator import MockObj from esphome.cpp_generator import MockObj
from esphome.cpp_types import uint32
from esphome.helpers import cpp_string_escape from esphome.helpers import cpp_string_escape
from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor 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 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") @schema_extractor("one_of")
def color(value): def color(value):
if value == SCHEMA_EXTRACT: if value == SCHEMA_EXTRACT:
@ -43,16 +66,24 @@ def color_retmapper(value):
return lv_expr.color_from(MockObj(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""" """A length in one axis - either a number (pixels) or a percentage"""
if value == SCHEMA_EXTRACT: if value == SCHEMA_EXTRACT:
return ["pixels", "..%"] return ["pixels", "..%"]
if isinstance(value, int): if isinstance(value, int):
return str(cv.int_(value)) return cv.int_(value)
# Will throw an exception if not a percentage. # Will throw an exception if not a percentage.
return f"lv_pct({int(cv.percentage(value) * 100)})" return f"lv_pct({int(cv.percentage(value) * 100)})"
pixels_or_percent = LValidator(
pixels_or_percent_validator, uint32, retmapper=literal_mapper
)
def zoom(value): def zoom(value):
value = cv.float_range(0.1, 10.0)(value) value = cv.float_range(0.1, 10.0)(value)
return int(value * 256) return int(value * 256)
@ -68,7 +99,7 @@ def angle(value):
@schema_extractor("one_of") @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""" """A size in one axis - one of "size_content", a number (pixels) or a percentage"""
if value == SCHEMA_EXTRACT: if value == SCHEMA_EXTRACT:
return ["size_content", "pixels", "..%"] return ["size_content", "pixels", "..%"]
@ -79,28 +110,42 @@ def size(value):
return "LV_SIZE_CONTENT" return "LV_SIZE_CONTENT"
raise cv.Invalid("must be 'size_content', a pixel position or a percentage") raise cv.Invalid("must be 'size_content', a pixel position or a percentage")
if isinstance(value, int): if isinstance(value, int):
return str(cv.int_(value)) return cv.int_(value)
# Will throw an exception if not a percentage. # Will throw an exception if not a percentage.
return f"lv_pct({int(cv.percentage(value) * 100)})" 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") @schema_extractor("one_of")
def opacity(value): def radius_validator(value):
consts = LvConstant("LV_OPA_", "TRANSP", "COVER")
if value == SCHEMA_EXTRACT: if value == SCHEMA_EXTRACT:
return consts.choices return radius_consts.choices
value = cv.Any(cv.percentage, consts.one_of)(value) value = cv.Any(size, cv.percentage, radius_consts.one_of)(value)
if isinstance(value, float): if isinstance(value, float):
return int(value * 255) return int(value * 255)
return value 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): def stop_value(value):
return cv.int_range(0, 255)(value) return cv.int_range(0, 255)(value)
lv_color = LValidator(color, ty.lv_color_t, retmapper=color_retmapper) lv_bool = LValidator(
lv_bool = LValidator(cv.boolean, cg.bool_, BinarySensor, "get_state()") cv.boolean, cg.bool_, BinarySensor, "get_state()", retmapper=literal_mapper
)
def lvms_validator_(value): 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()") 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): class LvFont(LValidator):
def __init__(self): def __init__(self):
def lv_builtin_font(value): def lv_builtin_font(value):
fontval = cv.one_of(*LV_FONTS, lower=True)(value) fontval = cv.one_of(*LV_FONTS, lower=True)(value)
lv_fonts_used.add(fontval) lv_fonts_used.add(fontval)
return "&lv_font_" + fontval return fontval
def validator(value): def validator(value):
if value == SCHEMA_EXTRACT: if value == SCHEMA_EXTRACT:
return LV_FONTS return LV_FONTS
if isinstance(value, str) and value.lower() in LV_FONTS: if is_lv_font(value):
return lv_builtin_font(value) return lv_builtin_font(value)
fontval = cv.use_id(Font)(value) fontval = cv.use_id(Font)(value)
esphome_fonts_used.add(fontval) 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) super().__init__(validator, lv_font_t)
async def process(self, value, args=()): 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() lv_font = LvFont()

View file

@ -38,7 +38,9 @@ void LvglComponent::setup() {
auto buf_bytes = buffer_pixels * LV_COLOR_DEPTH / 8; auto buf_bytes = buffer_pixels * LV_COLOR_DEPTH / 8;
auto *buf = lv_custom_mem_alloc(buf_bytes); auto *buf = lv_custom_mem_alloc(buf_bytes);
if (buf == nullptr) { if (buf == nullptr) {
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_ERROR
ESP_LOGE(TAG, "Malloc failed to allocate %zu bytes", buf_bytes); ESP_LOGE(TAG, "Malloc failed to allocate %zu bytes", buf_bytes);
#endif
this->mark_failed(); this->mark_failed();
this->status_set_error("Memory allocation failure"); this->status_set_error("Memory allocation failure");
return; return;
@ -85,7 +87,9 @@ size_t lv_millis(void) { return esphome::millis(); }
void *lv_custom_mem_alloc(size_t size) { void *lv_custom_mem_alloc(size_t size) {
auto *ptr = malloc(size); // NOLINT auto *ptr = malloc(size); // NOLINT
if (ptr == nullptr) { if (ptr == nullptr) {
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_ERROR
esphome::ESP_LOGE(esphome::lvgl::TAG, "Failed to allocate %zu bytes", size); esphome::ESP_LOGE(esphome::lvgl::TAG, "Failed to allocate %zu bytes", size);
#endif
} }
return ptr; return ptr;
} }
@ -102,7 +106,9 @@ void *lv_custom_mem_alloc(size_t size) {
ptr = heap_caps_malloc(size, cap_bits); ptr = heap_caps_malloc(size, cap_bits);
} }
if (ptr == nullptr) { if (ptr == nullptr) {
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_ERROR
esphome::ESP_LOGE(esphome::lvgl::TAG, "Failed to allocate %zu bytes", size); esphome::ESP_LOGE(esphome::lvgl::TAG, "Failed to allocate %zu bytes", size);
#endif
return nullptr; return nullptr;
} }
#ifdef ESPHOME_LOG_HAS_VERBOSE #ifdef ESPHOME_LOG_HAS_VERBOSE

View file

@ -18,23 +18,27 @@
#ifdef USE_LVGL_FONT #ifdef USE_LVGL_FONT
#include "esphome/components/font/font.h" #include "esphome/components/font/font.h"
#endif #endif
#ifdef USE_LVGL_TOUCHSCREEN
#include "esphome/components/touchscreen/touchscreen.h"
#endif // USE_LVGL_TOUCHSCREEN
namespace esphome { namespace esphome {
namespace lvgl { namespace lvgl {
extern lv_event_code_t lv_custom_event; // NOLINT extern lv_event_code_t lv_custom_event; // NOLINT
#ifdef USE_LVGL_COLOR #ifdef USE_LVGL_COLOR
static lv_color_t lv_color_from(Color color) { return lv_color_make(color.red, color.green, color.blue); } inline lv_color_t lv_color_from(Color color) { return lv_color_make(color.red, color.green, color.blue); }
#endif #endif // USE_LVGL_COLOR
#if LV_COLOR_DEPTH == 16 #if LV_COLOR_DEPTH == 16
static const display::ColorBitness LV_BITNESS = display::ColorBitness::COLOR_BITNESS_565; static const display::ColorBitness LV_BITNESS = display::ColorBitness::COLOR_BITNESS_565;
#elif LV_COLOR_DEPTH == 32 #elif LV_COLOR_DEPTH == 32
static const display::ColorBitness LV_BITNESS = display::ColorBitness::COLOR_BITNESS_888; 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; 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 // Parent class for things that wrap an LVGL object
class LvCompound { class LvCompound final {
public: public:
virtual void set_obj(lv_obj_t *lv_obj) { this->obj = lv_obj; } virtual void set_obj(lv_obj_t *lv_obj) { this->obj = lv_obj; }
lv_obj_t *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_full_refresh(bool full_refresh) { this->full_refresh_ = full_refresh; }
void set_buffer_frac(size_t frac) { this->buffer_frac_ = frac; } void set_buffer_frac(size_t frac) { this->buffer_frac_ = frac; }
lv_disp_t *get_disp() { return this->disp_; } 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: protected:
void draw_buffer_(const lv_area_t *area, const uint8_t *ptr); 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_draw_buf_t draw_buf_{};
lv_disp_drv_t disp_drv_{}; lv_disp_drv_t disp_drv_{};
lv_disp_t *disp_{}; lv_disp_t *disp_{};
bool paused_{};
std::vector<std::function<void(lv_disp_t *)>> init_lambdas_; std::vector<std::function<void(lv_disp_t *)>> init_lambdas_;
size_t buffer_frac_{1}; size_t buffer_frac_{1};
bool full_refresh_{}; 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 lvgl
} // namespace esphome } // namespace esphome
#endif #endif // USE_LVGL

View file

@ -1,6 +1,5 @@
from .defines import CONF_OBJ from .defines import CONF_MAIN, CONF_OBJ
from .types import lv_obj_t from .types import WidgetType, lv_obj_t
from .widget import WidgetType
class ObjType(WidgetType): class ObjType(WidgetType):
@ -9,11 +8,7 @@ class ObjType(WidgetType):
""" """
def __init__(self): def __init__(self):
super().__init__(CONF_OBJ, schema={}, modify_schema={}) super().__init__(CONF_OBJ, lv_obj_t, (CONF_MAIN,), schema={}, modify_schema={})
@property
def w_type(self):
return lv_obj_t
async def to_code(self, w, config): async def to_code(self, w, config):
return [] return []

View file

@ -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 esphome.schema_extractors import SCHEMA_EXTRACT
from . import defines as df, lv_validation as lvalid, types as ty from . import defines as df, lv_validation as lvalid, types as ty
from .defines import WIDGET_PARTS from .helpers import add_lv_use, requires_component, validate_printf
from .helpers import (
REQUIRED_COMPONENTS,
add_lv_use,
requires_component,
validate_printf,
)
from .lv_validation import lv_font 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 # A schema for text properties
TEXT_SCHEMA = cv.Schema( TEXT_SCHEMA = cv.Schema(
@ -46,9 +40,9 @@ STYLE_PROPS = {
"bg_dither_mode": df.LvConstant("LV_DITHER_", "NONE", "ORDERED", "ERR_DIFF").one_of, "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_dir": df.LvConstant("LV_GRAD_DIR_", "NONE", "HOR", "VER").one_of,
"bg_grad_stop": lvalid.stop_value, "bg_grad_stop": lvalid.stop_value,
"bg_img_opa": lvalid.opacity, "bg_image_opa": lvalid.opacity,
"bg_img_recolor": lvalid.lv_color, "bg_image_recolor": lvalid.lv_color,
"bg_img_recolor_opa": lvalid.opacity, "bg_image_recolor_opa": lvalid.opacity,
"bg_main_stop": lvalid.stop_value, "bg_main_stop": lvalid.stop_value,
"bg_opa": lvalid.opacity, "bg_opa": lvalid.opacity,
"border_color": lvalid.lv_color, "border_color": lvalid.lv_color,
@ -60,8 +54,8 @@ STYLE_PROPS = {
"border_width": cv.positive_int, "border_width": cv.positive_int,
"clip_corner": lvalid.lv_bool, "clip_corner": lvalid.lv_bool,
"height": lvalid.size, "height": lvalid.size,
"img_recolor": lvalid.lv_color, "image_recolor": lvalid.lv_color,
"img_recolor_opa": lvalid.opacity, "image_recolor_opa": lvalid.opacity,
"line_width": cv.positive_int, "line_width": cv.positive_int,
"line_dash_width": cv.positive_int, "line_dash_width": cv.positive_int,
"line_dash_gap": cv.positive_int, "line_dash_gap": cv.positive_int,
@ -108,12 +102,21 @@ STYLE_PROPS = {
"max_width": lvalid.pixels_or_percent, "max_width": lvalid.pixels_or_percent,
"min_height": lvalid.pixels_or_percent, "min_height": lvalid.pixels_or_percent,
"min_width": 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, "width": lvalid.size,
"x": lvalid.pixels_or_percent, "x": lvalid.pixels_or_percent,
"y": 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 # Complete object style schema
STYLE_SCHEMA = cv.Schema({cv.Optional(k): v for k, v in STYLE_PROPS.items()}).extend( 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} {cv.Optional(state): lvalid.lv_bool for state in df.STATES}
) )
# Setting object flags # 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) 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 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 :param widget_type: The type of widget to generate for
:return: :return:
""" """
parts = WIDGET_PARTS.get(widget_type) parts = widget_type.parts
if parts is None:
parts = (df.CONF_MAIN,)
return cv.Schema({cv.Optional(part): STATE_SCHEMA for part in parts}).extend( return cv.Schema({cv.Optional(part): STATE_SCHEMA for part in parts}).extend(
STATE_SCHEMA 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 Create a schema for a widget type itself i.e. no allowance for children
:param widget_type: :param widget_type:
@ -187,13 +188,12 @@ STYLED_TEXT_SCHEMA = cv.maybe_simple_value(
STYLE_SCHEMA.extend(TEXT_SCHEMA), key=df.CONF_TEXT STYLE_SCHEMA.extend(TEXT_SCHEMA), key=df.CONF_TEXT
) )
ALL_STYLES = { ALL_STYLES = {
**STYLE_PROPS, **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 Create a validator for a container given the widget type
:param schema: Base schema to extend :param schema: Base schema to extend
@ -203,13 +203,16 @@ def container_validator(schema, widget_type):
def validator(value): def validator(value):
result = schema result = schema
if w_sch := WIDGET_TYPES[widget_type].schema: if w_sch := widget_type.schema:
result = result.extend(w_sch) result = result.extend(w_sch)
if value and (layout := value.get(df.CONF_LAYOUT)): if value and (layout := value.get(df.CONF_LAYOUT)):
if not isinstance(layout, dict): if not isinstance(layout, dict):
raise cv.Invalid("Layout value must be a dict") raise cv.Invalid("Layout value must be a dict")
ltype = layout.get(CONF_TYPE) ltype = layout.get(CONF_TYPE)
add_lv_use(ltype) add_lv_use(ltype)
result = result.extend(
{cv.Optional(df.CONF_WIDGETS): cv.ensure_list(any_widget_schema())}
)
if value == SCHEMA_EXTRACT: if value == SCHEMA_EXTRACT:
return result return result
return result(value) return result(value)
@ -217,7 +220,7 @@ def container_validator(schema, widget_type):
return validator 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 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. 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 :param extras: Additional options to be made available, e.g. layout properties for children
:return: The schema for this type of widget. :return: The schema for this type of widget.
""" """
lv_type = get_widget_type(widget_type) schema = obj_schema(widget_type).extend(
schema = obj_schema(widget_type).extend({cv.GenerateID(): cv.declare_id(lv_type)}) {cv.GenerateID(): cv.declare_id(widget_type.w_type)}
)
if extras: if extras:
schema = schema.extend(extras) schema = schema.extend(extras)
# Delayed evaluation for recursion # Delayed evaluation for recursion
return container_validator(schema, widget_type) 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 Create a schema for a given widget type
:param widget_type: The name of the widget :param widget_type: The name of the widget
@ -241,9 +245,9 @@ def widget_schema(widget_type, extras=None):
:return: :return:
""" """
validator = container_schema(widget_type, extras=extras) 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)) 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. # 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 :param extras: Additional schema to be applied to each generated one
:return: :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()))

View 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))

View file

@ -1,7 +1,22 @@
from esphome import codegen as cg from esphome import codegen as cg
from esphome.core import ID 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") uint16_t_ptr = cg.uint16.operator("ptr")
lvgl_ns = cg.esphome_ns.namespace("lvgl") 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_obj_t_ptr = lv_obj_base_t.operator("ptr")
lv_disp_t_ptr = cg.global_ns.struct("lv_disp_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") 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. # this will be populated later, in __init__.py to avoid circular imports.
WIDGET_TYPES: dict = {} 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): class LvText(LvType):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__( super().__init__(
@ -48,17 +53,74 @@ class LvText(LvType):
self.value_property = CONF_TEXT self.value_property = CONF_TEXT
lv_obj_t = LvType("lv_obj_t") class LvBoolean(LvType):
lv_label_t = LvText("lv_label_t") def __init__(self, *args, **kwargs):
super().__init__(
LV_TYPES = { *args,
CONF_LABEL: lv_label_t, largs=[(cg.bool_, "x")],
CONF_OBJ: lv_obj_t, lvalue=lambda w: w.is_checked(),
} has_on_value=True,
**kwargs,
)
def get_widget_type(typestr: str) -> LvType:
return LV_TYPES[typestr]
CUSTOM_EVENT = ID("lv_custom_event", False, type=lv_event_code_t) 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 ()

View file

@ -21,78 +21,19 @@ from .defines import (
) )
from .helpers import add_lv_use from .helpers import add_lv_use
from .lvcode import ConstantLiteral, add_line_marks, lv, lv_add, lv_assign, lv_obj from .lvcode import ConstantLiteral, add_line_marks, lv, lv_add, lv_assign, lv_obj
from .schemas import ALL_STYLES from .schemas import ALL_STYLES, STYLE_REMAP
from .types import WIDGET_TYPES, LvCompound, lv_obj_t from .types import WIDGET_TYPES, WidgetType, lv_obj_t
EVENT_LAMB = "event_lamb__" 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): class LvScrActType(WidgetType):
""" """
A "widget" representing the active screen. A "widget" representing the active screen.
""" """
def __init__(self): def __init__(self):
super().__init__("lv_scr_act()") super().__init__("lv_scr_act()", lv_obj_t, ())
def obj_creator(self, parent: MockObjClass, config: dict): def obj_creator(self, parent: MockObjClass, config: dict):
return [] return []
@ -263,7 +204,9 @@ async def set_obj_properties(w: Widget, config):
}.items(): }.items():
if isinstance(ALL_STYLES[prop], LValidator): if isinstance(ALL_STYLES[prop], LValidator):
value = await ALL_STYLES[prop].process(value) 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_clr = set()
flag_set = set() flag_set = set()
props = parts[CONF_MAIN][CONF_DEFAULT] props = parts[CONF_MAIN][CONF_DEFAULT]
@ -291,10 +234,10 @@ async def set_obj_properties(w: Widget, config):
else: else:
clears.add(key) clears.add(key)
if adds: if adds:
adds = ConstantLiteral(join_enums(adds, "LV_STATE_")) adds = join_enums(adds, "LV_STATE_")
w.add_state(adds) w.add_state(adds)
if clears: if clears:
clears = ConstantLiteral(join_enums(clears, "LV_STATE_")) clears = join_enums(clears, "LV_STATE_")
w.clear_state(clears) w.clear_state(clears)
for key, value in lambs.items(): for key, value in lambs.items():
lamb = await cg.process_lambda(value, [], return_type=cg.bool_) lamb = await cg.process_lambda(value, [], return_type=cg.bool_)

View file

@ -110,7 +110,7 @@ void MitsubishiClimate::transmit_state() {
// Byte 15: HVAC specfic, i.e. POWERFUL, SMART SET, PLASMA, always 0x00 // Byte 15: HVAC specfic, i.e. POWERFUL, SMART SET, PLASMA, always 0x00
// Byte 16: Constant 0x00 // Byte 16: Constant 0x00
// Byte 17: Checksum: SUM[Byte0...Byte16] // 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}; 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
switch (this->mode) { switch (this->mode) {
@ -136,6 +136,12 @@ void MitsubishiClimate::transmit_state() {
break; break;
case climate::CLIMATE_MODE_OFF: case climate::CLIMATE_MODE_OFF:
default: 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; remote_state[5] = MITSUBISHI_OFF;
break; break;
} }

View file

@ -1,10 +1,15 @@
from esphome import automation
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv 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.core import CORE, coroutine_with_priority
from esphome.const import CONF_ESPHOME, CONF_OTA, CONF_PLATFORM, CONF_TRIGGER_ID
CODEOWNERS = ["@esphome/core"] CODEOWNERS = ["@esphome/core"]
AUTO_LOAD = ["md5", "safe_mode"] AUTO_LOAD = ["md5", "safe_mode"]
@ -13,7 +18,6 @@ IS_PLATFORM_COMPONENT = True
CONF_ON_ABORT = "on_abort" CONF_ON_ABORT = "on_abort"
CONF_ON_BEGIN = "on_begin" CONF_ON_BEGIN = "on_begin"
CONF_ON_END = "on_end" CONF_ON_END = "on_end"
CONF_ON_ERROR = "on_error"
CONF_ON_PROGRESS = "on_progress" CONF_ON_PROGRESS = "on_progress"
CONF_ON_STATE_CHANGE = "on_state_change" CONF_ON_STATE_CHANGE = "on_state_change"

View file

@ -44,6 +44,8 @@ class PIDClimate : public climate::Climate, public Component {
float get_kp() { return controller_.kp_; } float get_kp() { return controller_.kp_; }
float get_ki() { return controller_.ki_; } float get_ki() { return controller_.ki_; }
float get_kd() { return controller_.kd_; } 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_proportional_term() const { return controller_.proportional_term_; }
float get_integral_term() const { return controller_.integral_term_; } float get_integral_term() const { return controller_.integral_term_; }
float get_derivative_term() const { return controller_.derivative_term_; } float get_derivative_term() const { return controller_.derivative_term_; }

View file

@ -1,10 +1,9 @@
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import binary_sensor, display 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"] DEPENDENCIES = ["touchscreen"]
@ -22,7 +21,7 @@ CONF_Y_MIN = "y_min"
CONF_Y_MAX = "y_max" CONF_Y_MAX = "y_max"
def validate_coords(config): def _validate_coords(config):
if ( if (
config[CONF_X_MAX] < config[CONF_X_MIN] config[CONF_X_MAX] < config[CONF_X_MIN]
or config[CONF_Y_MAX] < config[CONF_Y_MIN] or config[CONF_Y_MAX] < config[CONF_Y_MIN]
@ -33,6 +32,15 @@ def validate_coords(config):
return 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( CONFIG_SCHEMA = cv.All(
binary_sensor.binary_sensor_schema(TouchscreenBinarySensor) binary_sensor.binary_sensor_schema(TouchscreenBinarySensor)
.extend( .extend(
@ -42,11 +50,17 @@ CONFIG_SCHEMA = cv.All(
cv.Required(CONF_X_MAX): cv.int_range(min=0, max=2000), 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_MIN): cv.int_range(min=0, max=2000),
cv.Required(CONF_Y_MAX): 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), .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: for page_id in config.get(CONF_PAGES, []):
page = await cg.get_variable(config[CONF_PAGE_ID]) page = await cg.get_variable(page_id)
cg.add(var.set_page(page)) cg.add(var.add_page(page))

View file

@ -11,8 +11,9 @@ void TouchscreenBinarySensor::setup() {
void TouchscreenBinarySensor::touch(TouchPoint tp) { 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_); 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) { if (!this->pages_.empty()) {
touched &= this->page_ == this->parent_->get_display()->get_active_page(); 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) { if (touched) {
this->publish_state(true); this->publish_state(true);

View file

@ -6,6 +6,8 @@
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include "esphome/core/helpers.h" #include "esphome/core/helpers.h"
#include <vector>
namespace esphome { namespace esphome {
namespace touchscreen { 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_width() { return this->x_max_ - this->x_min_; }
int16_t get_height() { return this->y_max_ - this->y_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 touch(TouchPoint tp) override;
void release() override; void release() override;
protected: protected:
int16_t x_min_, x_max_, y_min_, y_max_; int16_t x_min_, x_max_, y_min_, y_max_;
display::DisplayPage *page_{nullptr}; std::vector<display::DisplayPage *> pages_{};
}; };
} // namespace touchscreen } // namespace touchscreen

View file

@ -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 import automation
from esphome.automation import register_action, register_condition 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"] AUTO_LOAD = ["socket"]
DEPENDENCIES = ["api", "microphone"] DEPENDENCIES = ["api", "microphone"]
@ -20,7 +20,6 @@ DEPENDENCIES = ["api", "microphone"]
CODEOWNERS = ["@jesserockz"] CODEOWNERS = ["@jesserockz"]
CONF_ON_END = "on_end" CONF_ON_END = "on_end"
CONF_ON_ERROR = "on_error"
CONF_ON_INTENT_END = "on_intent_end" CONF_ON_INTENT_END = "on_intent_end"
CONF_ON_INTENT_START = "on_intent_start" CONF_ON_INTENT_START = "on_intent_start"
CONF_ON_LISTENING = "on_listening" CONF_ON_LISTENING = "on_listening"

View file

@ -0,0 +1 @@
CODEOWNERS = ["@oarcher"]

View file

@ -15,7 +15,6 @@
#endif #endif
namespace esphome { namespace esphome {
namespace http_request {
namespace watchdog { namespace watchdog {
static const char *const TAG = "http_request.watchdog"; static const char *const TAG = "http_request.watchdog";
@ -72,5 +71,4 @@ uint32_t WatchdogManager::get_timeout_() {
} }
} // namespace watchdog } // namespace watchdog
} // namespace http_request
} // namespace esphome } // namespace esphome

View file

@ -5,7 +5,6 @@
#include <cstdint> #include <cstdint>
namespace esphome { namespace esphome {
namespace http_request {
namespace watchdog { namespace watchdog {
class WatchdogManager { class WatchdogManager {
@ -22,5 +21,4 @@ class WatchdogManager {
}; };
} // namespace watchdog } // namespace watchdog
} // namespace http_request
} // namespace esphome } // namespace esphome

View file

@ -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 import automation
from esphome.automation import Condition 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 ( from esphome.const import (
CONF_AP, CONF_AP,
CONF_BSSID, CONF_BSSID,
CONF_CERTIFICATE,
CONF_CERTIFICATE_AUTHORITY,
CONF_CHANNEL, CONF_CHANNEL,
CONF_DNS1, CONF_DNS1,
CONF_DNS2, CONF_DNS2,
CONF_DOMAIN, CONF_DOMAIN,
CONF_EAP,
CONF_ENABLE_BTM, CONF_ENABLE_BTM,
CONF_ENABLE_ON_BOOT, CONF_ENABLE_ON_BOOT,
CONF_ENABLE_RRM, CONF_ENABLE_RRM,
@ -17,29 +21,26 @@ from esphome.const import (
CONF_GATEWAY, CONF_GATEWAY,
CONF_HIDDEN, CONF_HIDDEN,
CONF_ID, CONF_ID,
CONF_IDENTITY,
CONF_KEY,
CONF_MANUAL_IP, CONF_MANUAL_IP,
CONF_NETWORKS, CONF_NETWORKS,
CONF_ON_CONNECT,
CONF_ON_DISCONNECT,
CONF_PASSWORD, CONF_PASSWORD,
CONF_POWER_SAVE_MODE, CONF_POWER_SAVE_MODE,
CONF_PRIORITY,
CONF_REBOOT_TIMEOUT, CONF_REBOOT_TIMEOUT,
CONF_SSID, CONF_SSID,
CONF_STATIC_IP, CONF_STATIC_IP,
CONF_SUBNET, 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_TTLS_PHASE_2,
CONF_ON_CONNECT, CONF_USE_ADDRESS,
CONF_ON_DISCONNECT, CONF_USERNAME,
) )
from esphome.core import CORE, HexInt, coroutine_with_priority from esphome.core import CORE, HexInt, coroutine_with_priority
from esphome.components.esp32 import add_idf_sdkconfig_option, get_esp32_variant, const import esphome.final_validate as fv
from esphome.components.network import IPAddress
from . import wpa2_eap from . import wpa2_eap
AUTO_LOAD = ["network"] AUTO_LOAD = ["network"]

View file

@ -7,16 +7,15 @@ so that it doesn't crash if it's not installed.
import logging import logging
from pathlib import Path from pathlib import Path
from esphome.core import CORE
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_USERNAME,
CONF_IDENTITY,
CONF_PASSWORD,
CONF_CERTIFICATE, CONF_CERTIFICATE,
CONF_IDENTITY,
CONF_KEY, CONF_KEY,
CONF_PASSWORD,
CONF_USERNAME,
) )
from esphome.core import CORE
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -49,8 +48,8 @@ def wrapped_load_pem_x509_certificate(value):
def wrapped_load_pem_private_key(value, password): def wrapped_load_pem_private_key(value, password):
validate_cryptography_installed() validate_cryptography_installed()
from cryptography.hazmat.primitives.serialization import load_pem_private_key
from cryptography.hazmat.backends import default_backend from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.serialization import load_pem_private_key
if password: if password:
password = password.encode("UTF-8") 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): 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(): def check_match_a():
return key.public_key().public_numbers() == cert.public_key().public_numbers() return key.public_key().public_numbers() == cert.public_key().public_numbers()

View file

@ -1,13 +1,13 @@
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import text_sensor from esphome.components import text_sensor
import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_BSSID, CONF_BSSID,
CONF_DNS_ADDRESS,
CONF_IP_ADDRESS, CONF_IP_ADDRESS,
CONF_MAC_ADDRESS,
CONF_SCAN_RESULTS, CONF_SCAN_RESULTS,
CONF_SSID, CONF_SSID,
CONF_MAC_ADDRESS,
CONF_DNS_ADDRESS,
ENTITY_CATEGORY_DIAGNOSTIC, ENTITY_CATEGORY_DIAGNOSTIC,
) )

View file

@ -1,6 +1,6 @@
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor from esphome.components import sensor
import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
DEVICE_CLASS_SIGNAL_STRENGTH, DEVICE_CLASS_SIGNAL_STRENGTH,
ENTITY_CATEGORY_DIAGNOSTIC, ENTITY_CATEGORY_DIAGNOSTIC,

View file

@ -1,40 +1,38 @@
from __future__ import annotations from __future__ import annotations
import abc import abc
from contextlib import contextmanager
import contextvars
import functools import functools
import heapq import heapq
import logging import logging
import re import re
from typing import Any, Union
from typing import Union, Any
from contextlib import contextmanager
import contextvars
import voluptuous as vol import voluptuous as vol
from esphome import core, yaml_util, loader, pins from esphome import core, loader, pins, yaml_util
import esphome.core.config as core_config from esphome.config_helpers import Extend, Remove
import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_ESPHOME, CONF_ESPHOME,
CONF_ID,
CONF_PLATFORM,
CONF_PACKAGES,
CONF_SUBSTITUTIONS,
CONF_EXTERNAL_COMPONENTS, CONF_EXTERNAL_COMPONENTS,
CONF_ID,
CONF_PACKAGES,
CONF_PLATFORM,
CONF_SUBSTITUTIONS,
TARGET_PLATFORMS, TARGET_PLATFORMS,
) )
from esphome.core import CORE, EsphomeError, DocumentRange from esphome.core import CORE, DocumentRange, EsphomeError
from esphome.helpers import indent import esphome.core.config as core_config
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
import esphome.final_validate as fv import esphome.final_validate as fv
import esphome.config_validation as cv from esphome.helpers import indent
from esphome.types import ConfigType, ConfigFragmentType 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__) _LOGGER = logging.getLogger(__name__)

View file

@ -1,13 +1,13 @@
"""Helpers for config validation using voluptuous.""" """Helpers for config validation using voluptuous."""
from contextlib import contextmanager
from dataclasses import dataclass from dataclasses import dataclass
from datetime import datetime
import logging import logging
import os import os
import re import re
from contextlib import contextmanager
import uuid as uuid_
from datetime import datetime
from string import ascii_letters, digits from string import ascii_letters, digits
import uuid as uuid_
import voluptuous as vol import voluptuous as vol
@ -17,37 +17,37 @@ from esphome.config_helpers import Extend, Remove
from esphome.const import ( from esphome.const import (
ALLOWED_NAME_CHARS, ALLOWED_NAME_CHARS,
CONF_AVAILABILITY, CONF_AVAILABILITY,
CONF_COMMAND_TOPIC,
CONF_COMMAND_RETAIN, CONF_COMMAND_RETAIN,
CONF_COMMAND_TOPIC,
CONF_DAY,
CONF_DISABLED_BY_DEFAULT, CONF_DISABLED_BY_DEFAULT,
CONF_DISCOVERY, CONF_DISCOVERY,
CONF_ENTITY_CATEGORY, CONF_ENTITY_CATEGORY,
CONF_HOUR,
CONF_ICON, CONF_ICON,
CONF_ID, CONF_ID,
CONF_INTERNAL, CONF_INTERNAL,
CONF_MINUTE,
CONF_MONTH,
CONF_NAME, CONF_NAME,
CONF_PASSWORD,
CONF_PATH,
CONF_PAYLOAD_AVAILABLE, CONF_PAYLOAD_AVAILABLE,
CONF_PAYLOAD_NOT_AVAILABLE, CONF_PAYLOAD_NOT_AVAILABLE,
CONF_RETAIN,
CONF_QOS, CONF_QOS,
CONF_REF,
CONF_RETAIN,
CONF_SECOND,
CONF_SETUP_PRIORITY, CONF_SETUP_PRIORITY,
CONF_STATE_TOPIC, CONF_STATE_TOPIC,
CONF_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_TYPE,
CONF_REF, CONF_TYPE_ID,
CONF_UPDATE_INTERVAL,
CONF_URL, CONF_URL,
CONF_PATH,
CONF_USERNAME, CONF_USERNAME,
CONF_PASSWORD, CONF_VALUE,
CONF_YEAR,
ENTITY_CATEGORY_CONFIG, ENTITY_CATEGORY_CONFIG,
ENTITY_CATEGORY_DIAGNOSTIC, ENTITY_CATEGORY_DIAGNOSTIC,
ENTITY_CATEGORY_NONE, ENTITY_CATEGORY_NONE,
@ -71,15 +71,15 @@ from esphome.core import (
TimePeriod, TimePeriod,
TimePeriodMicroseconds, TimePeriodMicroseconds,
TimePeriodMilliseconds, TimePeriodMilliseconds,
TimePeriodMinutes,
TimePeriodNanoseconds, TimePeriodNanoseconds,
TimePeriodSeconds, 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 ( from esphome.schema_extractors import (
SCHEMA_EXTRACT, SCHEMA_EXTRACT,
schema_extractor_list,
schema_extractor, schema_extractor,
schema_extractor_list,
schema_extractor_registry, schema_extractor_registry,
schema_extractor_typed, schema_extractor_typed,
) )
@ -1686,9 +1686,9 @@ class SplitDefault(Optional):
if CORE.is_esp32: if CORE.is_esp32:
from esphome.components.esp32 import get_esp32_variant from esphome.components.esp32 import get_esp32_variant
from esphome.components.esp32.const import ( from esphome.components.esp32.const import (
VARIANT_ESP32C3,
VARIANT_ESP32S2, VARIANT_ESP32S2,
VARIANT_ESP32S3, VARIANT_ESP32S3,
VARIANT_ESP32C3,
) )
variant = get_esp32_variant() variant = get_esp32_variant()

View file

@ -539,6 +539,7 @@ CONF_ON_DOUBLE_CLICK = "on_double_click"
CONF_ON_ENROLLMENT_DONE = "on_enrollment_done" CONF_ON_ENROLLMENT_DONE = "on_enrollment_done"
CONF_ON_ENROLLMENT_FAILED = "on_enrollment_failed" CONF_ON_ENROLLMENT_FAILED = "on_enrollment_failed"
CONF_ON_ENROLLMENT_SCAN = "on_enrollment_scan" CONF_ON_ENROLLMENT_SCAN = "on_enrollment_scan"
CONF_ON_ERROR = "on_error"
CONF_ON_EVENT = "on_event" CONF_ON_EVENT = "on_event"
CONF_ON_FINGER_SCAN_INVALID = "on_finger_scan_invalid" CONF_ON_FINGER_SCAN_INVALID = "on_finger_scan_invalid"
CONF_ON_FINGER_SCAN_MATCHED = "on_finger_scan_matched" CONF_ON_FINGER_SCAN_MATCHED = "on_finger_scan_matched"
@ -1032,11 +1033,13 @@ UNIT_KILOWATT_HOURS = "kWh"
UNIT_LUX = "lx" UNIT_LUX = "lx"
UNIT_METER = "m" UNIT_METER = "m"
UNIT_METER_PER_SECOND_SQUARED = "m/s²" UNIT_METER_PER_SECOND_SQUARED = "m/s²"
UNIT_MICROAMP = "µA"
UNIT_MICROGRAMS_PER_CUBIC_METER = "µg/m³" UNIT_MICROGRAMS_PER_CUBIC_METER = "µg/m³"
UNIT_MICROMETER = "µm" UNIT_MICROMETER = "µm"
UNIT_MICROSIEMENS_PER_CENTIMETER = "µS/cm" UNIT_MICROSIEMENS_PER_CENTIMETER = "µS/cm"
UNIT_MICROSILVERTS_PER_HOUR = "µSv/h" UNIT_MICROSILVERTS_PER_HOUR = "µSv/h"
UNIT_MICROTESLA = "µT" UNIT_MICROTESLA = "µT"
UNIT_MILLIAMP = "mA"
UNIT_MILLIGRAMS_PER_CUBIC_METER = "mg/m³" UNIT_MILLIGRAMS_PER_CUBIC_METER = "mg/m³"
UNIT_MILLIMETER = "mm" UNIT_MILLIMETER = "mm"
UNIT_MILLISECOND = "ms" UNIT_MILLISECOND = "ms"

View file

@ -7,26 +7,29 @@ from typing import TYPE_CHECKING, Optional, Union
from esphome.const import ( from esphome.const import (
CONF_COMMENT, CONF_COMMENT,
CONF_ESPHOME, CONF_ESPHOME,
CONF_USE_ADDRESS,
CONF_ETHERNET, CONF_ETHERNET,
CONF_PORT,
CONF_USE_ADDRESS,
CONF_WEB_SERVER, CONF_WEB_SERVER,
CONF_WIFI, CONF_WIFI,
CONF_PORT,
KEY_CORE, KEY_CORE,
KEY_TARGET_FRAMEWORK, KEY_TARGET_FRAMEWORK,
KEY_TARGET_PLATFORM, KEY_TARGET_PLATFORM,
PLATFORM_BK72XX,
PLATFORM_ESP32, PLATFORM_ESP32,
PLATFORM_ESP8266, PLATFORM_ESP8266,
PLATFORM_BK72XX,
PLATFORM_RTL87XX,
PLATFORM_RP2040,
PLATFORM_HOST, PLATFORM_HOST,
PLATFORM_RP2040,
PLATFORM_RTL87XX,
) )
from esphome.coroutine import FakeAwaitable as _FakeAwaitable
from esphome.coroutine import FakeEventLoop as _FakeEventLoop
# pylint: disable=unused-import # 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.helpers import ensure_unique_string, get_str_env, is_ha_addon
from esphome.util import OrderedDict from esphome.util import OrderedDict

View file

@ -3,9 +3,9 @@ import multiprocessing
import os import os
import re import re
from esphome import automation
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome import automation
from esphome.const import ( from esphome.const import (
CONF_ARDUINO_VERSION, CONF_ARDUINO_VERSION,
CONF_AREA, CONF_AREA,
@ -16,11 +16,11 @@ from esphome.const import (
CONF_COMPILE_PROCESS_LIMIT, CONF_COMPILE_PROCESS_LIMIT,
CONF_ESPHOME, CONF_ESPHOME,
CONF_FRAMEWORK, CONF_FRAMEWORK,
CONF_FRIENDLY_NAME,
CONF_INCLUDES, CONF_INCLUDES,
CONF_LIBRARIES, CONF_LIBRARIES,
CONF_MIN_VERSION, CONF_MIN_VERSION,
CONF_NAME, CONF_NAME,
CONF_FRIENDLY_NAME,
CONF_ON_BOOT, CONF_ON_BOOT,
CONF_ON_LOOP, CONF_ON_LOOP,
CONF_ON_SHUTDOWN, CONF_ON_SHUTDOWN,
@ -34,8 +34,8 @@ from esphome.const import (
CONF_TYPE, CONF_TYPE,
CONF_VERSION, CONF_VERSION,
KEY_CORE, KEY_CORE,
TARGET_PLATFORMS,
PLATFORM_ESP8266, PLATFORM_ESP8266,
TARGET_PLATFORMS,
__version__ as ESPHOME_VERSION, __version__ as ESPHOME_VERSION,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, coroutine_with_priority

View file

@ -41,6 +41,7 @@
#define USE_LVGL #define USE_LVGL
#define USE_LVGL_FONT #define USE_LVGL_FONT
#define USE_LVGL_IMAGE #define USE_LVGL_IMAGE
#define USE_LVGL_TOUCHSCREEN
#define USE_MDNS #define USE_MDNS
#define USE_MEDIA_PLAYER #define USE_MEDIA_PLAYER
#define USE_MQTT #define USE_MQTT

View file

@ -1,6 +1,5 @@
import esphome.final_validate as fv
from esphome.const import CONF_ID from esphome.const import CONF_ID
import esphome.final_validate as fv
def inherit_property_from(property_to_inherit, parent_id_property, transform=None): def inherit_property_from(property_to_inherit, parent_id_property, transform=None):

View file

@ -43,13 +43,13 @@ the last `yield` expression defines what is returned.
""" """
import collections import collections
from collections.abc import Awaitable, Generator, Iterator
import functools import functools
import heapq import heapq
import inspect import inspect
import logging import logging
import types import types
from typing import Any, Callable from typing import Any, Callable
from collections.abc import Awaitable, Generator, Iterator
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View file

@ -1,8 +1,8 @@
import abc import abc
from collections.abc import Sequence
import inspect import inspect
import math import math
import re import re
from collections.abc import Sequence
from typing import Any, Callable, Optional, Union from typing import Any, Callable, Optional, Union
from esphome.core import ( from esphome.core import (

View file

@ -12,15 +12,13 @@ from esphome.const import (
CONF_UPDATE_INTERVAL, CONF_UPDATE_INTERVAL,
KEY_PAST_SAFE_MODE, KEY_PAST_SAFE_MODE,
) )
from esphome.core import CORE, ID, coroutine
from esphome.core import coroutine, ID, CORE
from esphome.coroutine import FakeAwaitable from esphome.coroutine import FakeAwaitable
from esphome.types import ConfigType, ConfigFragmentType
from esphome.cpp_generator import add, get_variable from esphome.cpp_generator import add, get_variable
from esphome.cpp_types import App 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.util import Registry, RegistryEntry
from esphome.helpers import snake_case, sanitize
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View file

@ -1,13 +1,13 @@
from __future__ import annotations from __future__ import annotations
import asyncio import asyncio
from collections.abc import Coroutine
import contextlib import contextlib
import logging
import threading
from dataclasses import dataclass from dataclasses import dataclass
from functools import partial from functools import partial
import logging
import threading
from typing import TYPE_CHECKING, Any, Callable from typing import TYPE_CHECKING, Any, Callable
from collections.abc import Coroutine
from ..zeroconf import DiscoveredImport from ..zeroconf import DiscoveredImport
from .dns import DNSCache from .dns import DNSCache

View file

@ -1,14 +1,14 @@
from __future__ import annotations from __future__ import annotations
import asyncio import asyncio
from asyncio import events
from concurrent.futures import ThreadPoolExecutor
import logging import logging
import os import os
import socket import socket
import threading import threading
import traceback
from asyncio import events
from concurrent.futures import ThreadPoolExecutor
from time import monotonic from time import monotonic
import traceback
from typing import Any from typing import Any
from esphome.storage_json import EsphomeStorageJSON, esphome_storage_path from esphome.storage_json import EsphomeStorageJSON, esphome_storage_path

View file

@ -1,9 +1,9 @@
from __future__ import annotations from __future__ import annotations
import asyncio import asyncio
from collections import defaultdict
import logging import logging
import os import os
from collections import defaultdict
from typing import TYPE_CHECKING, Any from typing import TYPE_CHECKING, Any
from esphome import const, util from esphome import const, util

View file

@ -1,7 +1,7 @@
import logging import logging
import os import os
import tempfile
from pathlib import Path from pathlib import Path
import tempfile
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View file

@ -2,6 +2,7 @@ from __future__ import annotations
import asyncio import asyncio
import base64 import base64
from collections.abc import Iterable
import datetime import datetime
import functools import functools
import gzip import gzip
@ -9,13 +10,12 @@ import hashlib
import json import json
import logging import logging
import os import os
from pathlib import Path
import secrets import secrets
import shutil import shutil
import subprocess import subprocess
import threading import threading
import time import time
from collections.abc import Iterable
from pathlib import Path
from typing import TYPE_CHECKING, Any, Callable, TypeVar from typing import TYPE_CHECKING, Any, Callable, TypeVar
from urllib.parse import urlparse from urllib.parse import urlparse
@ -26,13 +26,13 @@ import tornado.httpserver
import tornado.httputil import tornado.httputil
import tornado.ioloop import tornado.ioloop
import tornado.iostream import tornado.iostream
from tornado.log import access_log
import tornado.netutil import tornado.netutil
import tornado.process import tornado.process
import tornado.queues import tornado.queues
import tornado.web import tornado.web
import tornado.websocket import tornado.websocket
import yaml import yaml
from tornado.log import access_log
from yaml.nodes import Node from yaml.nodes import Node
from esphome import const, platformio_api, yaml_util from esphome import const, platformio_api, yaml_util

View file

@ -1,13 +1,15 @@
from __future__ import annotations from __future__ import annotations
import logging
from pathlib import Path
import os
from datetime import datetime from datetime import datetime
import logging
import os
from pathlib import Path
import requests import requests
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.core import CORE, TimePeriodSeconds
from esphome.const import __version__ from esphome.const import __version__
from esphome.core import CORE, TimePeriodSeconds
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
CODEOWNERS = ["@landonr"] CODEOWNERS = ["@landonr"]

View file

@ -1,9 +1,9 @@
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from typing import Any
import contextvars import contextvars
from typing import Any
from esphome.types import ConfigFragmentType, ID, ConfigPathType
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.types import ID, ConfigFragmentType, ConfigPathType
class FinalValidateConfig(ABC): class FinalValidateConfig(ABC):

View file

@ -1,12 +1,12 @@
import hashlib
import logging
import re
import subprocess
import urllib.parse
from dataclasses import dataclass from dataclasses import dataclass
from datetime import datetime from datetime import datetime
import hashlib
import logging
from pathlib import Path from pathlib import Path
import re
import subprocess
from typing import Callable, Optional from typing import Callable, Optional
import urllib.parse
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.core import CORE, TimePeriodSeconds from esphome.core import CORE, TimePeriodSeconds

View file

@ -1,14 +1,13 @@
import codecs import codecs
from contextlib import suppress from contextlib import suppress
import logging import logging
import os import os
import platform
from pathlib import Path from pathlib import Path
from typing import Union import platform
import tempfile
from urllib.parse import urlparse
import re import re
import tempfile
from typing import Union
from urllib.parse import urlparse
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -129,9 +128,10 @@ def _resolve_with_zeroconf(host):
def resolve_ip_address(host): def resolve_ip_address(host):
from esphome.core import EsphomeError
import socket import socket
from esphome.core import EsphomeError
errs = [] errs = []
if host.endswith(".local"): if host.endswith(".local"):

View file

@ -1,10 +1,10 @@
from datetime import datetime from datetime import datetime
import hashlib import hashlib
import json
import logging import logging
import ssl import ssl
import sys import sys
import time import time
import json
import paho.mqtt.client as mqtt import paho.mqtt.client as mqtt
@ -24,9 +24,9 @@ from esphome.const import (
CONF_USERNAME, CONF_USERNAME,
) )
from esphome.core import CORE, EsphomeError 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.util import safe_print
from esphome.helpers import get_str_env, get_int_env
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View file

@ -1,20 +1,20 @@
import operator
from functools import reduce from functools import reduce
import esphome.config_validation as cv import operator
from esphome.core import CORE
import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_ALLOW_OTHER_USES,
CONF_IGNORE_STRAPPING_WARNING,
CONF_INPUT, CONF_INPUT,
CONF_INVERTED,
CONF_MODE, CONF_MODE,
CONF_NUMBER, CONF_NUMBER,
CONF_OPEN_DRAIN, CONF_OPEN_DRAIN,
CONF_OUTPUT, CONF_OUTPUT,
CONF_PULLDOWN, CONF_PULLDOWN,
CONF_PULLUP, CONF_PULLUP,
CONF_IGNORE_STRAPPING_WARNING,
CONF_ALLOW_OTHER_USES,
CONF_INVERTED,
) )
from esphome.core import CORE
class PinRegistry(dict): class PinRegistry(dict):

View file

@ -1,12 +1,11 @@
from dataclasses import dataclass from dataclasses import dataclass
import json import json
from typing import Union
from pathlib import Path
import logging import logging
import os import os
from pathlib import Path
import re import re
import subprocess import subprocess
from typing import Union
from esphome.const import CONF_COMPILE_PROCESS_LIMIT, CONF_ESPHOME, KEY_CORE from esphome.const import CONF_COMPILE_PROCESS_LIMIT, CONF_ESPHOME, KEY_CORE
from esphome.core import CORE, EsphomeError from esphome.core import CORE, EsphomeError
@ -20,9 +19,10 @@ def patch_structhash():
# removed/added. This might have unintended consequences, but this improves compile # removed/added. This might have unintended consequences, but this improves compile
# times greatly when adding/removing components and a simple clean build solves # times greatly when adding/removing components and a simple clean build solves
# all issues # all issues
from platformio.run import helpers, cli
from os.path import join, isdir, getmtime
from os import makedirs 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): def patched_clean_build_dir(build_dir, *args):
from platformio import fs from platformio import fs

View file

@ -1,10 +1,11 @@
from __future__ import annotations from __future__ import annotations
import binascii import binascii
import codecs import codecs
from datetime import datetime
import json import json
import logging import logging
import os import os
from datetime import datetime
from esphome import const from esphome import const
from esphome.const import CONF_DISABLED, CONF_MDNS from esphome.const import CONF_DISABLED, CONF_MDNS

View file

@ -2,7 +2,7 @@
from typing import Union from typing import Union
from esphome.core import ID, Lambda, EsphomeCore from esphome.core import ID, EsphomeCore, Lambda
ConfigFragmentType = Union[ ConfigFragmentType = Union[
str, str,

View file

@ -1,13 +1,12 @@
from typing import Union
import collections import collections
import io import io
import logging import logging
import os import os
from pathlib import Path
import re import re
import subprocess import subprocess
import sys import sys
from pathlib import Path from typing import Union
from esphome import const from esphome import const

View file

@ -2,6 +2,7 @@ import difflib
import itertools import itertools
import voluptuous as vol import voluptuous as vol
from esphome.schema_extractors import schema_extractor_extended from esphome.schema_extractors import schema_extractor_extended

View file

@ -1,13 +1,14 @@
from __future__ import annotations from __future__ import annotations
from io import StringIO
import json import json
import os import os
from io import StringIO
from typing import Any from typing import Any
from esphome.yaml_util import parse_yaml from esphome.config import Config, _format_vol_invalid, validate_config
from esphome.config import validate_config, _format_vol_invalid, Config
from esphome.core import CORE, DocumentRange
import esphome.config_validation as cv 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: def _get_invalid_range(res: Config, invalid: cv.Invalid) -> DocumentRange | None:

View file

@ -276,8 +276,8 @@ def wizard(path):
from esphome.components.bk72xx import boards as bk72xx_boards from esphome.components.bk72xx import boards as bk72xx_boards
from esphome.components.esp32 import boards as esp32_boards from esphome.components.esp32 import boards as esp32_boards
from esphome.components.esp8266 import boards as esp8266_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.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"): if not path.endswith(".yaml") and not path.endswith(".yml"):
safe_print( safe_print(

View file

@ -1,27 +1,27 @@
import logging import logging
import os import os
import re
from pathlib import Path from pathlib import Path
import re
from typing import Union 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 ( from esphome.const import (
ENV_NOGITIGNORE,
HEADER_FILE_EXTENSIONS, HEADER_FILE_EXTENSIONS,
SOURCE_FILE_EXTENSIONS, SOURCE_FILE_EXTENSIONS,
__version__, __version__,
ENV_NOGITIGNORE,
) )
from esphome.core import CORE, EsphomeError from esphome.core import CORE, EsphomeError
from esphome.helpers import ( from esphome.helpers import (
mkdir_p,
read_file,
write_file_if_changed,
walk_files,
copy_file_if_changed, copy_file_if_changed,
get_bool_env, get_bool_env,
mkdir_p,
read_file,
walk_files,
write_file_if_changed,
) )
from esphome.storage_json import StorageJSON, storage_path from esphome.storage_json import StorageJSON, storage_path
from esphome import loader
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View file

@ -3,16 +3,16 @@ from __future__ import annotations
import fnmatch import fnmatch
import functools import functools
import inspect import inspect
from io import TextIOWrapper
import logging import logging
import math import math
import os import os
import uuid
from io import TextIOWrapper
from typing import Any from typing import Any
import uuid
import yaml import yaml
import yaml.constructor
from yaml import SafeLoader as PurePythonLoader from yaml import SafeLoader as PurePythonLoader
import yaml.constructor
try: try:
from yaml import CSafeLoader as FastestAvailableSafeLoader from yaml import CSafeLoader as FastestAvailableSafeLoader

View file

@ -1,8 +1,8 @@
from __future__ import annotations from __future__ import annotations
import asyncio import asyncio
import logging
from dataclasses import dataclass from dataclasses import dataclass
import logging
from typing import Callable from typing import Callable
from zeroconf import IPVersion, ServiceInfo, ServiceStateChange, Zeroconf from zeroconf import IPVersion, ServiceInfo, ServiceStateChange, Zeroconf

View file

@ -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

View 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

View file

@ -1,9 +1,10 @@
color:
- id: light_blue
hex: "3340FF"
lvgl: lvgl:
log_level: TRACE
bg_color: light_blue bg_color: light_blue
touchscreens:
- touchscreen_id: tft_touch
long_press_repeat_time: 200ms
long_press_time: 500ms
widgets: widgets:
- label: - label:
text: Hello world text: Hello world
@ -17,8 +18,101 @@ lvgl:
text_color: 0xFFFFFF text_color: 0xFFFFFF
align: bottom_mid align: bottom_mid
text_font: space16 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: font:
- file: "gfonts://Roboto" - file: "gfonts://Roboto"
id: space16 id: space16
bpp: 4 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"

View file

@ -19,7 +19,9 @@ display:
mirror_y: true mirror_y: true
data_rate: 80MHz data_rate: 80MHz
cs_pin: GPIO20 cs_pin: GPIO20
dc_pin: GPIO15 dc_pin:
number: GPIO15
ignore_strapping_warning: true
auto_clear_enabled: false auto_clear_enabled: false
invert_colors: false invert_colors: false
update_interval: never update_interval: never