mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	Merge branch 'dev' into bump-2022.2.0b1
This commit is contained in:
		
							
								
								
									
										10
									
								
								.clang-tidy
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								.clang-tidy
									
									
									
									
									
								
							| @@ -68,8 +68,6 @@ Checks: >- | |||||||
|   -modernize-use-nodiscard, |   -modernize-use-nodiscard, | ||||||
|   -mpi-*, |   -mpi-*, | ||||||
|   -objc-*, |   -objc-*, | ||||||
|   -readability-braces-around-statements, |  | ||||||
|   -readability-const-return-type, |  | ||||||
|   -readability-convert-member-functions-to-static, |   -readability-convert-member-functions-to-static, | ||||||
|   -readability-else-after-return, |   -readability-else-after-return, | ||||||
|   -readability-function-cognitive-complexity, |   -readability-function-cognitive-complexity, | ||||||
| @@ -77,10 +75,6 @@ Checks: >- | |||||||
|   -readability-isolate-declaration, |   -readability-isolate-declaration, | ||||||
|   -readability-magic-numbers, |   -readability-magic-numbers, | ||||||
|   -readability-make-member-function-const, |   -readability-make-member-function-const, | ||||||
|   -readability-named-parameter, |  | ||||||
|   -readability-qualified-auto, |  | ||||||
|   -readability-redundant-access-specifiers, |  | ||||||
|   -readability-redundant-member-init, |  | ||||||
|   -readability-redundant-string-init, |   -readability-redundant-string-init, | ||||||
|   -readability-uppercase-literal-suffix, |   -readability-uppercase-literal-suffix, | ||||||
|   -readability-use-anyofallof, |   -readability-use-anyofallof, | ||||||
| @@ -114,6 +108,8 @@ CheckOptions: | |||||||
|     value:           'make_unique' |     value:           'make_unique' | ||||||
|   - key:             modernize-make-unique.MakeSmartPtrFunctionHeader |   - key:             modernize-make-unique.MakeSmartPtrFunctionHeader | ||||||
|     value:           'esphome/core/helpers.h' |     value:           'esphome/core/helpers.h' | ||||||
|  |   - key:             readability-braces-around-statements.ShortStatementLines | ||||||
|  |     value:           2 | ||||||
|   - key:             readability-identifier-naming.LocalVariableCase |   - key:             readability-identifier-naming.LocalVariableCase | ||||||
|     value:           'lower_case' |     value:           'lower_case' | ||||||
|   - key:             readability-identifier-naming.ClassCase |   - key:             readability-identifier-naming.ClassCase | ||||||
| @@ -160,3 +156,5 @@ CheckOptions: | |||||||
|     value:           'lower_case' |     value:           'lower_case' | ||||||
|   - key:             readability-identifier-naming.VirtualMethodSuffix |   - key:             readability-identifier-naming.VirtualMethodSuffix | ||||||
|     value:           '' |     value:           '' | ||||||
|  |   - key:             readability-qualified-auto.AddConstToQualified | ||||||
|  |     value:           0 | ||||||
|   | |||||||
							
								
								
									
										4
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							| @@ -137,7 +137,7 @@ jobs: | |||||||
|           --build-type "${{ matrix.build_type }}" \ |           --build-type "${{ matrix.build_type }}" \ | ||||||
|           manifest |           manifest | ||||||
|  |  | ||||||
|   deploy-hassio-repo: |   deploy-ha-addon-repo: | ||||||
|     if: github.repository == 'esphome/esphome' && github.event_name == 'release' |     if: github.repository == 'esphome/esphome' && github.event_name == 'release' | ||||||
|     runs-on: ubuntu-latest |     runs-on: ubuntu-latest | ||||||
|     needs: [deploy-docker] |     needs: [deploy-docker] | ||||||
| @@ -150,5 +150,5 @@ jobs: | |||||||
|             -u ":$TOKEN" \ |             -u ":$TOKEN" \ | ||||||
|             -X POST \ |             -X POST \ | ||||||
|             -H "Accept: application/vnd.github.v3+json" \ |             -H "Accept: application/vnd.github.v3+json" \ | ||||||
|             https://api.github.com/repos/esphome/hassio/actions/workflows/bump-version.yml/dispatches \ |             https://api.github.com/repos/esphome/home-assistant-addon/actions/workflows/bump-version.yml/dispatches \ | ||||||
|             -d "{\"ref\":\"main\",\"inputs\":{\"version\":\"$TAG\"}}" |             -d "{\"ref\":\"main\",\"inputs\":{\"version\":\"$TAG\"}}" | ||||||
|   | |||||||
| @@ -3,4 +3,4 @@ ports: | |||||||
|   onOpen: open-preview |   onOpen: open-preview | ||||||
| tasks: | tasks: | ||||||
| - before: pyenv local $(pyenv version | grep '^3\.' | cut -d ' ' -f 1) && script/setup | - before: pyenv local $(pyenv version | grep '^3\.' | cut -d ' ' -f 1) && script/setup | ||||||
|   command: python -m esphome config dashboard |   command: python -m esphome dashboard config | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ | |||||||
| # See https://pre-commit.com/hooks.html for more hooks | # See https://pre-commit.com/hooks.html for more hooks | ||||||
| repos: | repos: | ||||||
|   - repo: https://github.com/ambv/black |   - repo: https://github.com/ambv/black | ||||||
|     rev: 20.8b1 |     rev: 22.1.0 | ||||||
|     hooks: |     hooks: | ||||||
|     - id: black |     - id: black | ||||||
|       args: |       args: | ||||||
| @@ -10,7 +10,7 @@ repos: | |||||||
|         - --quiet |         - --quiet | ||||||
|       files: ^((esphome|script|tests)/.+)?[^/]+\.py$ |       files: ^((esphome|script|tests)/.+)?[^/]+\.py$ | ||||||
|   - repo: https://gitlab.com/pycqa/flake8 |   - repo: https://gitlab.com/pycqa/flake8 | ||||||
|     rev: 3.8.4 |     rev: 4.0.1 | ||||||
|     hooks: |     hooks: | ||||||
|       - id: flake8 |       - id: flake8 | ||||||
|         additional_dependencies: |         additional_dependencies: | ||||||
|   | |||||||
							
								
								
									
										12
									
								
								CODEOWNERS
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								CODEOWNERS
									
									
									
									
									
								
							| @@ -54,6 +54,7 @@ esphome/components/dfplayer/* @glmnet | |||||||
| esphome/components/dht/* @OttoWinter | esphome/components/dht/* @OttoWinter | ||||||
| esphome/components/ds1307/* @badbadc0ffee | esphome/components/ds1307/* @badbadc0ffee | ||||||
| esphome/components/dsmr/* @glmnet @zuidwijk | esphome/components/dsmr/* @glmnet @zuidwijk | ||||||
|  | esphome/components/ektf2232/* @jesserockz | ||||||
| esphome/components/esp32/* @esphome/core | esphome/components/esp32/* @esphome/core | ||||||
| esphome/components/esp32_ble/* @jesserockz | esphome/components/esp32_ble/* @jesserockz | ||||||
| esphome/components/esp32_ble_server/* @jesserockz | esphome/components/esp32_ble_server/* @jesserockz | ||||||
| @@ -88,9 +89,12 @@ esphome/components/json/* @OttoWinter | |||||||
| esphome/components/kalman_combinator/* @Cat-Ion | esphome/components/kalman_combinator/* @Cat-Ion | ||||||
| esphome/components/ledc/* @OttoWinter | esphome/components/ledc/* @OttoWinter | ||||||
| esphome/components/light/* @esphome/core | esphome/components/light/* @esphome/core | ||||||
|  | esphome/components/lilygo_t5_47/touchscreen/* @jesserockz | ||||||
|  | esphome/components/lock/* @esphome/core | ||||||
| esphome/components/logger/* @esphome/core | esphome/components/logger/* @esphome/core | ||||||
| esphome/components/ltr390/* @sjtrny | esphome/components/ltr390/* @sjtrny | ||||||
| esphome/components/max7219digit/* @rspaargaren | esphome/components/max7219digit/* @rspaargaren | ||||||
|  | esphome/components/max9611/* @mckaymatthew | ||||||
| esphome/components/mcp23008/* @jesserockz | esphome/components/mcp23008/* @jesserockz | ||||||
| esphome/components/mcp23017/* @jesserockz | esphome/components/mcp23017/* @jesserockz | ||||||
| esphome/components/mcp23s08/* @SenexCrenshaw @jesserockz | esphome/components/mcp23s08/* @SenexCrenshaw @jesserockz | ||||||
| @@ -107,10 +111,12 @@ esphome/components/mdns/* @esphome/core | |||||||
| esphome/components/midea/* @dudanov | esphome/components/midea/* @dudanov | ||||||
| esphome/components/midea_ir/* @dudanov | esphome/components/midea_ir/* @dudanov | ||||||
| esphome/components/mitsubishi/* @RubyBailey | esphome/components/mitsubishi/* @RubyBailey | ||||||
|  | esphome/components/mlx90393/* @functionpointer | ||||||
| esphome/components/modbus_controller/* @martgras | esphome/components/modbus_controller/* @martgras | ||||||
| esphome/components/modbus_controller/binary_sensor/* @martgras | esphome/components/modbus_controller/binary_sensor/* @martgras | ||||||
| esphome/components/modbus_controller/number/* @martgras | esphome/components/modbus_controller/number/* @martgras | ||||||
| esphome/components/modbus_controller/output/* @martgras | esphome/components/modbus_controller/output/* @martgras | ||||||
|  | esphome/components/modbus_controller/select/* @martgras @stegm | ||||||
| esphome/components/modbus_controller/sensor/* @martgras | esphome/components/modbus_controller/sensor/* @martgras | ||||||
| esphome/components/modbus_controller/switch/* @martgras | esphome/components/modbus_controller/switch/* @martgras | ||||||
| esphome/components/modbus_controller/text_sensor/* @martgras | esphome/components/modbus_controller/text_sensor/* @martgras | ||||||
| @@ -136,6 +142,9 @@ esphome/components/preferences/* @esphome/core | |||||||
| esphome/components/psram/* @esphome/core | esphome/components/psram/* @esphome/core | ||||||
| esphome/components/pulse_meter/* @stevebaxter | esphome/components/pulse_meter/* @stevebaxter | ||||||
| esphome/components/pvvx_mithermometer/* @pasiz | esphome/components/pvvx_mithermometer/* @pasiz | ||||||
|  | esphome/components/qr_code/* @wjtje | ||||||
|  | esphome/components/radon_eye_ble/* @jeffeb3 | ||||||
|  | esphome/components/radon_eye_rd200/* @jeffeb3 | ||||||
| esphome/components/rc522/* @glmnet | esphome/components/rc522/* @glmnet | ||||||
| esphome/components/rc522_i2c/* @glmnet | esphome/components/rc522_i2c/* @glmnet | ||||||
| esphome/components/rc522_spi/* @glmnet | esphome/components/rc522_spi/* @glmnet | ||||||
| @@ -187,6 +196,7 @@ esphome/components/tmp102/* @timsavage | |||||||
| esphome/components/tmp117/* @Azimath | esphome/components/tmp117/* @Azimath | ||||||
| esphome/components/tof10120/* @wstrzalka | esphome/components/tof10120/* @wstrzalka | ||||||
| esphome/components/toshiba/* @kbx81 | esphome/components/toshiba/* @kbx81 | ||||||
|  | esphome/components/touchscreen/* @jesserockz | ||||||
| esphome/components/tsl2591/* @wjcarpenter | esphome/components/tsl2591/* @wjcarpenter | ||||||
| esphome/components/tuya/binary_sensor/* @jesserockz | esphome/components/tuya/binary_sensor/* @jesserockz | ||||||
| esphome/components/tuya/climate/* @jesserockz | esphome/components/tuya/climate/* @jesserockz | ||||||
| @@ -197,8 +207,10 @@ esphome/components/tuya/text_sensor/* @dentra | |||||||
| esphome/components/uart/* @esphome/core | esphome/components/uart/* @esphome/core | ||||||
| esphome/components/ultrasonic/* @OttoWinter | esphome/components/ultrasonic/* @OttoWinter | ||||||
| esphome/components/version/* @esphome/core | esphome/components/version/* @esphome/core | ||||||
|  | esphome/components/wake_on_lan/* @willwill2will54 | ||||||
| esphome/components/web_server_base/* @OttoWinter | esphome/components/web_server_base/* @OttoWinter | ||||||
| esphome/components/whirlpool/* @glmnet | esphome/components/whirlpool/* @glmnet | ||||||
| esphome/components/xiaomi_lywsd03mmc/* @ahpohl | esphome/components/xiaomi_lywsd03mmc/* @ahpohl | ||||||
|  | esphome/components/xiaomi_mhoc303/* @drug123 | ||||||
| esphome/components/xiaomi_mhoc401/* @vevsvevs | esphome/components/xiaomi_mhoc401/* @vevsvevs | ||||||
| esphome/components/xpt2046/* @numo68 | esphome/components/xpt2046/* @numo68 | ||||||
|   | |||||||
| @@ -4,4 +4,5 @@ include requirements.txt | |||||||
| include esphome/dashboard/templates/*.html | include esphome/dashboard/templates/*.html | ||||||
| recursive-include esphome/dashboard/static *.ico *.js *.css *.woff* LICENSE | recursive-include esphome/dashboard/static *.ico *.js *.css *.woff* LICENSE | ||||||
| recursive-include esphome *.cpp *.h *.tcc | recursive-include esphome *.cpp *.h *.tcc | ||||||
|  | recursive-include esphome *.py.script | ||||||
| recursive-include esphome LICENSE.txt | recursive-include esphome LICENSE.txt | ||||||
|   | |||||||
| @@ -8,9 +8,9 @@ ARG BASEIMGTYPE=docker | |||||||
| FROM ghcr.io/hassio-addons/debian-base/amd64:5.2.3 AS base-hassio-amd64 | FROM ghcr.io/hassio-addons/debian-base/amd64:5.2.3 AS base-hassio-amd64 | ||||||
| FROM ghcr.io/hassio-addons/debian-base/aarch64:5.2.3 AS base-hassio-arm64 | FROM ghcr.io/hassio-addons/debian-base/aarch64:5.2.3 AS base-hassio-arm64 | ||||||
| FROM ghcr.io/hassio-addons/debian-base/armv7:5.2.3 AS base-hassio-armv7 | FROM ghcr.io/hassio-addons/debian-base/armv7:5.2.3 AS base-hassio-armv7 | ||||||
| FROM debian:bullseye-20211220-slim AS base-docker-amd64 | FROM debian:bullseye-20220125-slim AS base-docker-amd64 | ||||||
| FROM debian:bullseye-20211220-slim AS base-docker-arm64 | FROM debian:bullseye-20220125-slim AS base-docker-arm64 | ||||||
| FROM debian:bullseye-20211220-slim AS base-docker-armv7 | FROM debian:bullseye-20220125-slim AS base-docker-armv7 | ||||||
|  |  | ||||||
| # Use TARGETARCH/TARGETVARIANT defined by docker | # Use TARGETARCH/TARGETVARIANT defined by docker | ||||||
| # https://docs.docker.com/engine/reference/builder/#automatic-platform-args-in-the-global-scope | # https://docs.docker.com/engine/reference/builder/#automatic-platform-args-in-the-global-scope | ||||||
| @@ -23,7 +23,7 @@ RUN \ | |||||||
|         python3=3.9.2-3 \ |         python3=3.9.2-3 \ | ||||||
|         python3-pip=20.3.4-4 \ |         python3-pip=20.3.4-4 \ | ||||||
|         python3-setuptools=52.0.0-4 \ |         python3-setuptools=52.0.0-4 \ | ||||||
|         python3-pil=8.1.2+dfsg-0.3 \ |         python3-pil=8.1.2+dfsg-0.3+deb11u1 \ | ||||||
|         python3-cryptography=3.3.2-1 \ |         python3-cryptography=3.3.2-1 \ | ||||||
|         iputils-ping=3:20210202-1 \ |         iputils-ping=3:20210202-1 \ | ||||||
|         git=1:2.30.2-1 \ |         git=1:2.30.2-1 \ | ||||||
| @@ -102,7 +102,7 @@ RUN \ | |||||||
| ARG BUILD_VERSION=dev | ARG BUILD_VERSION=dev | ||||||
|  |  | ||||||
| # Copy root filesystem | # Copy root filesystem | ||||||
| COPY docker/hassio-rootfs/ / | COPY docker/ha-addon-rootfs/ / | ||||||
|  |  | ||||||
| # First install requirements to leverage caching when requirements don't change | # First install requirements to leverage caching when requirements don't change | ||||||
| COPY requirements.txt requirements_optional.txt docker/platformio_install_deps.py platformio.ini / | COPY requirements.txt requirements_optional.txt docker/platformio_install_deps.py platformio.ini / | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ server { | |||||||
|     ssl_certificate_key /ssl/%%keyfile%%; |     ssl_certificate_key /ssl/%%keyfile%%; | ||||||
| 
 | 
 | ||||||
|     # Clear Hass.io Ingress header |     # Clear Hass.io Ingress header | ||||||
|     proxy_set_header X-Hassio-Ingress ""; |     proxy_set_header X-HA-Ingress ""; | ||||||
| 
 | 
 | ||||||
|     # Redirect http requests to https on the same port. |     # Redirect http requests to https on the same port. | ||||||
|     # https://rageagainstshell.com/2016/11/redirect-http-to-https-on-the-same-port-in-nginx/ |     # https://rageagainstshell.com/2016/11/redirect-http-to-https-on-the-same-port-in-nginx/ | ||||||
| @@ -4,7 +4,7 @@ server { | |||||||
|     include /etc/nginx/includes/server_params.conf; |     include /etc/nginx/includes/server_params.conf; | ||||||
|     include /etc/nginx/includes/proxy_params.conf; |     include /etc/nginx/includes/proxy_params.conf; | ||||||
|     # Clear Hass.io Ingress header |     # Clear Hass.io Ingress header | ||||||
|     proxy_set_header X-Hassio-Ingress ""; |     proxy_set_header X-HA-Ingress ""; | ||||||
| 
 | 
 | ||||||
|     location / { |     location / { | ||||||
|         proxy_pass http://esphome; |         proxy_pass http://esphome; | ||||||
| @@ -3,8 +3,8 @@ server { | |||||||
| 
 | 
 | ||||||
|     include /etc/nginx/includes/server_params.conf; |     include /etc/nginx/includes/server_params.conf; | ||||||
|     include /etc/nginx/includes/proxy_params.conf; |     include /etc/nginx/includes/proxy_params.conf; | ||||||
|     # Set Hass.io Ingress header |     # Set Home Assistant Ingress header | ||||||
|     proxy_set_header X-Hassio-Ingress "YES"; |     proxy_set_header X-HA-Ingress "YES"; | ||||||
| 
 | 
 | ||||||
|     location / { |     location / { | ||||||
|         # Only allow from Hass.io supervisor |         # Only allow from Hass.io supervisor | ||||||
| @@ -4,7 +4,7 @@ | |||||||
| # Runs the ESPHome dashboard | # Runs the ESPHome dashboard | ||||||
| # ============================================================================== | # ============================================================================== | ||||||
| 
 | 
 | ||||||
| export ESPHOME_IS_HASSIO=true | export ESPHOME_IS_HA_ADDON=true | ||||||
| 
 | 
 | ||||||
| if bashio::config.true 'leave_front_door_open'; then | if bashio::config.true 'leave_front_door_open'; then | ||||||
|     export DISABLE_HA_AUTHENTICATION=true |     export DISABLE_HA_AUTHENTICATION=true | ||||||
| @@ -32,4 +32,4 @@ export PLATFORMIO_CACHE_DIR="${pio_cache_base}/cache" | |||||||
| export PLATFORMIO_GLOBALLIB_DIR=/piolibs | export PLATFORMIO_GLOBALLIB_DIR=/piolibs | ||||||
| 
 | 
 | ||||||
| bashio::log.info "Starting ESPHome dashboard..." | bashio::log.info "Starting ESPHome dashboard..." | ||||||
| exec esphome dashboard /config/esphome --socket /var/run/esphome.sock --hassio | exec esphome dashboard /config/esphome --socket /var/run/esphome.sock --ha-addon | ||||||
| @@ -661,7 +661,7 @@ def parse_args(argv): | |||||||
|         "--open-ui", help="Open the dashboard UI in a browser.", action="store_true" |         "--open-ui", help="Open the dashboard UI in a browser.", action="store_true" | ||||||
|     ) |     ) | ||||||
|     parser_dashboard.add_argument( |     parser_dashboard.add_argument( | ||||||
|         "--hassio", help=argparse.SUPPRESS, action="store_true" |         "--ha-addon", help=argparse.SUPPRESS, action="store_true" | ||||||
|     ) |     ) | ||||||
|     parser_dashboard.add_argument( |     parser_dashboard.add_argument( | ||||||
|         "--socket", help="Make the dashboard serve under a unix socket", type=str |         "--socket", help="Make the dashboard serve under a unix socket", type=str | ||||||
|   | |||||||
| @@ -63,6 +63,7 @@ from esphome.cpp_types import (  # noqa | |||||||
|     uint32, |     uint32, | ||||||
|     uint64, |     uint64, | ||||||
|     int32, |     int32, | ||||||
|  |     int64, | ||||||
|     const_char_ptr, |     const_char_ptr, | ||||||
|     NAN, |     NAN, | ||||||
|     esphome_ns, |     esphome_ns, | ||||||
| @@ -81,4 +82,5 @@ from esphome.cpp_types import (  # noqa | |||||||
|     InternalGPIOPin, |     InternalGPIOPin, | ||||||
|     gpio_Flags, |     gpio_Flags, | ||||||
|     EntityCategory, |     EntityCategory, | ||||||
|  |     Parented, | ||||||
| ) | ) | ||||||
|   | |||||||
| @@ -52,10 +52,10 @@ uint32_t IRAM_ATTR HOT AcDimmerDataStore::timer_intr(uint32_t now) { | |||||||
|     this->gate_pin.digital_write(false); |     this->gate_pin.digital_write(false); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   if (time_since_zc < this->enable_time_us) |   if (time_since_zc < this->enable_time_us) { | ||||||
|     // Next event is enable, return time until that event |     // Next event is enable, return time until that event | ||||||
|     return this->enable_time_us - time_since_zc; |     return this->enable_time_us - time_since_zc; | ||||||
|   else if (time_since_zc < disable_time_us) { |   } else if (time_since_zc < disable_time_us) { | ||||||
|     // Next event is disable, return time until that event |     // Next event is disable, return time until that event | ||||||
|     return this->disable_time_us - time_since_zc; |     return this->disable_time_us - time_since_zc; | ||||||
|   } |   } | ||||||
| @@ -74,9 +74,10 @@ uint32_t IRAM_ATTR HOT timer_interrupt() { | |||||||
|   uint32_t min_dt_us = 1000; |   uint32_t min_dt_us = 1000; | ||||||
|   uint32_t now = micros(); |   uint32_t now = micros(); | ||||||
|   for (auto *dimmer : all_dimmers) { |   for (auto *dimmer : all_dimmers) { | ||||||
|     if (dimmer == nullptr) |     if (dimmer == nullptr) { | ||||||
|       // no more dimmers |       // no more dimmers | ||||||
|       break; |       break; | ||||||
|  |     } | ||||||
|     uint32_t res = dimmer->timer_intr(now); |     uint32_t res = dimmer->timer_intr(now); | ||||||
|     if (res != 0 && res < min_dt_us) |     if (res != 0 && res < min_dt_us) | ||||||
|       min_dt_us = res; |       min_dt_us = res; | ||||||
| @@ -212,12 +213,13 @@ void AcDimmer::dump_config() { | |||||||
|   LOG_PIN("  Zero-Cross Pin: ", this->zero_cross_pin_); |   LOG_PIN("  Zero-Cross Pin: ", this->zero_cross_pin_); | ||||||
|   ESP_LOGCONFIG(TAG, "   Min Power: %.1f%%", this->store_.min_power / 10.0f); |   ESP_LOGCONFIG(TAG, "   Min Power: %.1f%%", this->store_.min_power / 10.0f); | ||||||
|   ESP_LOGCONFIG(TAG, "   Init with half cycle: %s", YESNO(this->init_with_half_cycle_)); |   ESP_LOGCONFIG(TAG, "   Init with half cycle: %s", YESNO(this->init_with_half_cycle_)); | ||||||
|   if (method_ == DIM_METHOD_LEADING_PULSE) |   if (method_ == DIM_METHOD_LEADING_PULSE) { | ||||||
|     ESP_LOGCONFIG(TAG, "   Method: leading pulse"); |     ESP_LOGCONFIG(TAG, "   Method: leading pulse"); | ||||||
|   else if (method_ == DIM_METHOD_LEADING) |   } else if (method_ == DIM_METHOD_LEADING) { | ||||||
|     ESP_LOGCONFIG(TAG, "   Method: leading"); |     ESP_LOGCONFIG(TAG, "   Method: leading"); | ||||||
|   else |   } else { | ||||||
|     ESP_LOGCONFIG(TAG, "   Method: trailing"); |     ESP_LOGCONFIG(TAG, "   Method: trailing"); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   LOG_FLOAT_OUTPUT(this); |   LOG_FLOAT_OUTPUT(this); | ||||||
|   ESP_LOGV(TAG, "  Estimated Frequency: %.3fHz", 1e6f / this->store_.cycle_time_us / 2); |   ESP_LOGV(TAG, "  Estimated Frequency: %.3fHz", 1e6f / this->store_.cycle_time_us / 2); | ||||||
|   | |||||||
| @@ -13,7 +13,6 @@ class AdalightLightEffect : public light::AddressableLightEffect, public uart::U | |||||||
|  public: |  public: | ||||||
|   AdalightLightEffect(const std::string &name); |   AdalightLightEffect(const std::string &name); | ||||||
|  |  | ||||||
|  public: |  | ||||||
|   void start() override; |   void start() override; | ||||||
|   void stop() override; |   void stop() override; | ||||||
|   void apply(light::AddressableLight &it, const Color ¤t_color) override; |   void apply(light::AddressableLight &it, const Color ¤t_color) override; | ||||||
| @@ -30,7 +29,6 @@ class AdalightLightEffect : public light::AddressableLightEffect, public uart::U | |||||||
|   void blank_all_leds_(light::AddressableLight &it); |   void blank_all_leds_(light::AddressableLight &it); | ||||||
|   Frame parse_frame_(light::AddressableLight &it); |   Frame parse_frame_(light::AddressableLight &it); | ||||||
|  |  | ||||||
|  protected: |  | ||||||
|   uint32_t last_ack_{0}; |   uint32_t last_ack_{0}; | ||||||
|   uint32_t last_byte_{0}; |   uint32_t last_byte_{0}; | ||||||
|   uint32_t last_reset_{0}; |   uint32_t last_reset_{0}; | ||||||
|   | |||||||
| @@ -15,6 +15,11 @@ namespace esphome { | |||||||
| namespace adc { | namespace adc { | ||||||
|  |  | ||||||
| static const char *const TAG = "adc"; | static const char *const TAG = "adc"; | ||||||
|  | // 13 bits for S3 / 12 bit for all other esp32 variants | ||||||
|  | // create a const to avoid the repated cast to enum | ||||||
|  | #ifdef USE_ESP32 | ||||||
|  | static const adc_bits_width_t ADC_WIDTH_MAX_SOC_BITS = static_cast<adc_bits_width_t>(ADC_WIDTH_MAX - 1); | ||||||
|  | #endif | ||||||
|  |  | ||||||
| void ADCSensor::setup() { | void ADCSensor::setup() { | ||||||
|   ESP_LOGCONFIG(TAG, "Setting up ADC '%s'...", this->get_name().c_str()); |   ESP_LOGCONFIG(TAG, "Setting up ADC '%s'...", this->get_name().c_str()); | ||||||
| @@ -23,14 +28,14 @@ void ADCSensor::setup() { | |||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #ifdef USE_ESP32 | #ifdef USE_ESP32 | ||||||
|   adc1_config_width(ADC_WIDTH_BIT_12); |   adc1_config_width(ADC_WIDTH_MAX_SOC_BITS); | ||||||
|   if (!autorange_) { |   if (!autorange_) { | ||||||
|     adc1_config_channel_atten(channel_, attenuation_); |     adc1_config_channel_atten(channel_, attenuation_); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   // load characteristics for each attenuation |   // load characteristics for each attenuation | ||||||
|   for (int i = 0; i < (int) ADC_ATTEN_MAX; i++) { |   for (int i = 0; i < (int) ADC_ATTEN_MAX; i++) { | ||||||
|     auto cal_value = esp_adc_cal_characterize(ADC_UNIT_1, (adc_atten_t) i, ADC_WIDTH_BIT_12, |     auto cal_value = esp_adc_cal_characterize(ADC_UNIT_1, (adc_atten_t) i, ADC_WIDTH_MAX_SOC_BITS, | ||||||
|                                               1100,  // default vref |                                               1100,  // default vref | ||||||
|                                               &cal_characteristics_[i]); |                                               &cal_characteristics_[i]); | ||||||
|     switch (cal_value) { |     switch (cal_value) { | ||||||
| @@ -65,9 +70,9 @@ void ADCSensor::dump_config() { | |||||||
|  |  | ||||||
| #ifdef USE_ESP32 | #ifdef USE_ESP32 | ||||||
|   LOG_PIN("  Pin: ", pin_); |   LOG_PIN("  Pin: ", pin_); | ||||||
|   if (autorange_) |   if (autorange_) { | ||||||
|     ESP_LOGCONFIG(TAG, " Attenuation: auto"); |     ESP_LOGCONFIG(TAG, " Attenuation: auto"); | ||||||
|   else |   } else { | ||||||
|     switch (this->attenuation_) { |     switch (this->attenuation_) { | ||||||
|       case ADC_ATTEN_DB_0: |       case ADC_ATTEN_DB_0: | ||||||
|         ESP_LOGCONFIG(TAG, " Attenuation: 0db (max 1.1V)"); |         ESP_LOGCONFIG(TAG, " Attenuation: 0db (max 1.1V)"); | ||||||
| @@ -84,6 +89,7 @@ void ADCSensor::dump_config() { | |||||||
|       default:  // This is to satisfy the unused ADC_ATTEN_MAX |       default:  // This is to satisfy the unused ADC_ATTEN_MAX | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|  |   } | ||||||
| #endif  // USE_ESP32 | #endif  // USE_ESP32 | ||||||
|   LOG_UPDATE_INTERVAL(this); |   LOG_UPDATE_INTERVAL(this); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -24,7 +24,7 @@ void AirthingsWaveMini::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt | |||||||
|  |  | ||||||
|     case ESP_GATTC_SEARCH_CMPL_EVT: { |     case ESP_GATTC_SEARCH_CMPL_EVT: { | ||||||
|       this->handle_ = 0; |       this->handle_ = 0; | ||||||
|       auto chr = this->parent()->get_characteristic(service_uuid_, sensors_data_characteristic_uuid_); |       auto *chr = this->parent()->get_characteristic(service_uuid_, sensors_data_characteristic_uuid_); | ||||||
|       if (chr == nullptr) { |       if (chr == nullptr) { | ||||||
|         ESP_LOGW(TAG, "No sensor characteristic found at service %s char %s", service_uuid_.to_string().c_str(), |         ESP_LOGW(TAG, "No sensor characteristic found at service %s char %s", service_uuid_.to_string().c_str(), | ||||||
|                  sensors_data_characteristic_uuid_.to_string().c_str()); |                  sensors_data_characteristic_uuid_.to_string().c_str()); | ||||||
| @@ -56,7 +56,7 @@ void AirthingsWaveMini::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt | |||||||
| } | } | ||||||
|  |  | ||||||
| void AirthingsWaveMini::read_sensors_(uint8_t *raw_value, uint16_t value_len) { | void AirthingsWaveMini::read_sensors_(uint8_t *raw_value, uint16_t value_len) { | ||||||
|   auto value = (WaveMiniReadings *) raw_value; |   auto *value = (WaveMiniReadings *) raw_value; | ||||||
|  |  | ||||||
|   if (sizeof(WaveMiniReadings) <= value_len) { |   if (sizeof(WaveMiniReadings) <= value_len) { | ||||||
|     this->humidity_sensor_->publish_state(value->humidity / 100.0f); |     this->humidity_sensor_->publish_state(value->humidity / 100.0f); | ||||||
|   | |||||||
| @@ -24,7 +24,7 @@ void AirthingsWavePlus::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt | |||||||
|  |  | ||||||
|     case ESP_GATTC_SEARCH_CMPL_EVT: { |     case ESP_GATTC_SEARCH_CMPL_EVT: { | ||||||
|       this->handle_ = 0; |       this->handle_ = 0; | ||||||
|       auto chr = this->parent()->get_characteristic(service_uuid_, sensors_data_characteristic_uuid_); |       auto *chr = this->parent()->get_characteristic(service_uuid_, sensors_data_characteristic_uuid_); | ||||||
|       if (chr == nullptr) { |       if (chr == nullptr) { | ||||||
|         ESP_LOGW(TAG, "No sensor characteristic found at service %s char %s", service_uuid_.to_string().c_str(), |         ESP_LOGW(TAG, "No sensor characteristic found at service %s char %s", service_uuid_.to_string().c_str(), | ||||||
|                  sensors_data_characteristic_uuid_.to_string().c_str()); |                  sensors_data_characteristic_uuid_.to_string().c_str()); | ||||||
| @@ -56,7 +56,7 @@ void AirthingsWavePlus::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt | |||||||
| } | } | ||||||
|  |  | ||||||
| void AirthingsWavePlus::read_sensors_(uint8_t *raw_value, uint16_t value_len) { | void AirthingsWavePlus::read_sensors_(uint8_t *raw_value, uint16_t value_len) { | ||||||
|   auto value = (WavePlusReadings *) raw_value; |   auto *value = (WavePlusReadings *) raw_value; | ||||||
|  |  | ||||||
|   if (sizeof(WavePlusReadings) <= value_len) { |   if (sizeof(WavePlusReadings) <= value_len) { | ||||||
|     ESP_LOGD(TAG, "version = %d", value->version); |     ESP_LOGD(TAG, "version = %d", value->version); | ||||||
|   | |||||||
| @@ -19,12 +19,14 @@ uint16_t crc_16(uint8_t *ptr, uint8_t length) { | |||||||
|   //------------------------------ |   //------------------------------ | ||||||
|   while (length--) { |   while (length--) { | ||||||
|     crc ^= *ptr++; |     crc ^= *ptr++; | ||||||
|     for (i = 0; i < 8; i++) |     for (i = 0; i < 8; i++) { | ||||||
|       if ((crc & 0x01) != 0) { |       if ((crc & 0x01) != 0) { | ||||||
|         crc >>= 1; |         crc >>= 1; | ||||||
|         crc ^= 0xA001; |         crc ^= 0xA001; | ||||||
|       } else |       } else { | ||||||
|         crc >>= 1; |         crc >>= 1; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|   } |   } | ||||||
|   return crc; |   return crc; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -39,7 +39,7 @@ void Am43::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_i | |||||||
|       break; |       break; | ||||||
|     } |     } | ||||||
|     case ESP_GATTC_SEARCH_CMPL_EVT: { |     case ESP_GATTC_SEARCH_CMPL_EVT: { | ||||||
|       auto chr = this->parent_->get_characteristic(AM43_SERVICE_UUID, AM43_CHARACTERISTIC_UUID); |       auto *chr = this->parent_->get_characteristic(AM43_SERVICE_UUID, AM43_CHARACTERISTIC_UUID); | ||||||
|       if (chr == nullptr) { |       if (chr == nullptr) { | ||||||
|         if (this->parent_->get_characteristic(AM43_TUYA_SERVICE_UUID, AM43_TUYA_CHARACTERISTIC_UUID) != nullptr) { |         if (this->parent_->get_characteristic(AM43_TUYA_SERVICE_UUID, AM43_TUYA_CHARACTERISTIC_UUID) != nullptr) { | ||||||
|           ESP_LOGE(TAG, "[%s] Detected a Tuya AM43 which is not supported, sorry.", |           ESP_LOGE(TAG, "[%s] Detected a Tuya AM43 which is not supported, sorry.", | ||||||
| @@ -75,13 +75,14 @@ void Am43::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_i | |||||||
|  |  | ||||||
|       if (this->current_sensor_ > 0) { |       if (this->current_sensor_ > 0) { | ||||||
|         if (this->illuminance_ != nullptr) { |         if (this->illuminance_ != nullptr) { | ||||||
|           auto packet = this->encoder_->get_light_level_request(); |           auto *packet = this->encoder_->get_light_level_request(); | ||||||
|           auto status = esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, |           auto status = esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, | ||||||
|                                                  packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, |                                                  packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, | ||||||
|                                                  ESP_GATT_AUTH_REQ_NONE); |                                                  ESP_GATT_AUTH_REQ_NONE); | ||||||
|           if (status) |           if (status) { | ||||||
|             ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), |             ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), | ||||||
|                      status); |                      status); | ||||||
|  |           } | ||||||
|         } |         } | ||||||
|         this->current_sensor_ = 0; |         this->current_sensor_ = 0; | ||||||
|       } |       } | ||||||
| @@ -99,7 +100,7 @@ void Am43::update() { | |||||||
|   } |   } | ||||||
|   if (this->current_sensor_ == 0) { |   if (this->current_sensor_ == 0) { | ||||||
|     if (this->battery_ != nullptr) { |     if (this->battery_ != nullptr) { | ||||||
|       auto packet = this->encoder_->get_battery_level_request(); |       auto *packet = this->encoder_->get_battery_level_request(); | ||||||
|       auto status = |       auto status = | ||||||
|           esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, packet->length, |           esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, packet->length, | ||||||
|                                    packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE); |                                    packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE); | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ from esphome.const import CONF_ID, CONF_PIN | |||||||
|  |  | ||||||
| CODEOWNERS = ["@buxtronix"] | CODEOWNERS = ["@buxtronix"] | ||||||
| DEPENDENCIES = ["ble_client"] | DEPENDENCIES = ["ble_client"] | ||||||
| AUTO_LOAD = ["am43"] | AUTO_LOAD = ["am43", "sensor"] | ||||||
|  |  | ||||||
| CONF_INVERT_POSITION = "invert_position" | CONF_INVERT_POSITION = "invert_position" | ||||||
|  |  | ||||||
|   | |||||||
| @@ -25,15 +25,16 @@ void Am43Component::setup() { | |||||||
|  |  | ||||||
| void Am43Component::loop() { | void Am43Component::loop() { | ||||||
|   if (this->node_state == espbt::ClientState::ESTABLISHED && !this->logged_in_) { |   if (this->node_state == espbt::ClientState::ESTABLISHED && !this->logged_in_) { | ||||||
|     auto packet = this->encoder_->get_send_pin_request(this->pin_); |     auto *packet = this->encoder_->get_send_pin_request(this->pin_); | ||||||
|     auto status = |     auto status = | ||||||
|         esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, packet->length, |         esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, packet->length, | ||||||
|                                  packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE); |                                  packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE); | ||||||
|     ESP_LOGI(TAG, "[%s] Logging into AM43", this->get_name().c_str()); |     ESP_LOGI(TAG, "[%s] Logging into AM43", this->get_name().c_str()); | ||||||
|     if (status) |     if (status) { | ||||||
|       ESP_LOGW(TAG, "[%s] Error writing set_pin to device, error = %d", this->get_name().c_str(), status); |       ESP_LOGW(TAG, "[%s] Error writing set_pin to device, error = %d", this->get_name().c_str(), status); | ||||||
|     else |     } else { | ||||||
|       this->logged_in_ = true; |       this->logged_in_ = true; | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -51,7 +52,7 @@ void Am43Component::control(const CoverCall &call) { | |||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|   if (call.get_stop()) { |   if (call.get_stop()) { | ||||||
|     auto packet = this->encoder_->get_stop_request(); |     auto *packet = this->encoder_->get_stop_request(); | ||||||
|     auto status = |     auto status = | ||||||
|         esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, packet->length, |         esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, packet->length, | ||||||
|                                  packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE); |                                  packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE); | ||||||
| @@ -63,7 +64,7 @@ void Am43Component::control(const CoverCall &call) { | |||||||
|  |  | ||||||
|     if (this->invert_position_) |     if (this->invert_position_) | ||||||
|       pos = 1 - pos; |       pos = 1 - pos; | ||||||
|     auto packet = this->encoder_->get_set_position_request(100 - (uint8_t)(pos * 100)); |     auto *packet = this->encoder_->get_set_position_request(100 - (uint8_t)(pos * 100)); | ||||||
|     auto status = |     auto status = | ||||||
|         esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, packet->length, |         esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, packet->length, | ||||||
|                                  packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE); |                                  packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE); | ||||||
| @@ -80,7 +81,7 @@ void Am43Component::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_ | |||||||
|       break; |       break; | ||||||
|     } |     } | ||||||
|     case ESP_GATTC_SEARCH_CMPL_EVT: { |     case ESP_GATTC_SEARCH_CMPL_EVT: { | ||||||
|       auto chr = this->parent_->get_characteristic(AM43_SERVICE_UUID, AM43_CHARACTERISTIC_UUID); |       auto *chr = this->parent_->get_characteristic(AM43_SERVICE_UUID, AM43_CHARACTERISTIC_UUID); | ||||||
|       if (chr == nullptr) { |       if (chr == nullptr) { | ||||||
|         if (this->parent_->get_characteristic(AM43_TUYA_SERVICE_UUID, AM43_TUYA_CHARACTERISTIC_UUID) != nullptr) { |         if (this->parent_->get_characteristic(AM43_TUYA_SERVICE_UUID, AM43_TUYA_CHARACTERISTIC_UUID) != nullptr) { | ||||||
|           ESP_LOGE(TAG, "[%s] Detected a Tuya AM43 which is not supported, sorry.", this->get_name().c_str()); |           ESP_LOGE(TAG, "[%s] Detected a Tuya AM43 which is not supported, sorry.", this->get_name().c_str()); | ||||||
| @@ -120,7 +121,7 @@ void Am43Component::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_ | |||||||
|       if (this->decoder_->has_pin_response()) { |       if (this->decoder_->has_pin_response()) { | ||||||
|         if (this->decoder_->pin_ok_) { |         if (this->decoder_->pin_ok_) { | ||||||
|           ESP_LOGI(TAG, "[%s] AM43 pin accepted.", this->get_name().c_str()); |           ESP_LOGI(TAG, "[%s] AM43 pin accepted.", this->get_name().c_str()); | ||||||
|           auto packet = this->encoder_->get_position_request(); |           auto *packet = this->encoder_->get_position_request(); | ||||||
|           auto status = esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, |           auto status = esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, | ||||||
|                                                  packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, |                                                  packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, | ||||||
|                                                  ESP_GATT_AUTH_REQ_NONE); |                                                  ESP_GATT_AUTH_REQ_NONE); | ||||||
|   | |||||||
| @@ -40,7 +40,7 @@ void Anova::control(const ClimateCall &call) { | |||||||
|       ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status); |       ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status); | ||||||
|   } |   } | ||||||
|   if (call.get_target_temperature().has_value()) { |   if (call.get_target_temperature().has_value()) { | ||||||
|     auto pkt = this->codec_->get_set_target_temp_request(*call.get_target_temperature()); |     auto *pkt = this->codec_->get_set_target_temp_request(*call.get_target_temperature()); | ||||||
|     auto status = esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, |     auto status = esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, | ||||||
|                                            pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE); |                                            pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE); | ||||||
|     if (status) |     if (status) | ||||||
| @@ -57,7 +57,7 @@ void Anova::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_ | |||||||
|       break; |       break; | ||||||
|     } |     } | ||||||
|     case ESP_GATTC_SEARCH_CMPL_EVT: { |     case ESP_GATTC_SEARCH_CMPL_EVT: { | ||||||
|       auto chr = this->parent_->get_characteristic(ANOVA_SERVICE_UUID, ANOVA_CHARACTERISTIC_UUID); |       auto *chr = this->parent_->get_characteristic(ANOVA_SERVICE_UUID, ANOVA_CHARACTERISTIC_UUID); | ||||||
|       if (chr == nullptr) { |       if (chr == nullptr) { | ||||||
|         ESP_LOGW(TAG, "[%s] No control service found at device, not an Anova..?", this->get_name().c_str()); |         ESP_LOGW(TAG, "[%s] No control service found at device, not an Anova..?", this->get_name().c_str()); | ||||||
|         ESP_LOGW(TAG, "[%s] Note, this component does not currently support Anova Nano.", this->get_name().c_str()); |         ESP_LOGW(TAG, "[%s] Note, this component does not currently support Anova Nano.", this->get_name().c_str()); | ||||||
| @@ -114,9 +114,10 @@ void Anova::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_ | |||||||
|           auto status = |           auto status = | ||||||
|               esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, pkt->length, |               esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, pkt->length, | ||||||
|                                        pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE); |                                        pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE); | ||||||
|           if (status) |           if (status) { | ||||||
|             ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), |             ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), | ||||||
|                      status); |                      status); | ||||||
|  |           } | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|       break; |       break; | ||||||
| @@ -133,7 +134,7 @@ void Anova::update() { | |||||||
|     return; |     return; | ||||||
|  |  | ||||||
|   if (this->current_request_ < 2) { |   if (this->current_request_ < 2) { | ||||||
|     auto pkt = this->codec_->get_read_device_status_request(); |     auto *pkt = this->codec_->get_read_device_status_request(); | ||||||
|     if (this->current_request_ == 0) |     if (this->current_request_ == 0) | ||||||
|       this->codec_->get_set_unit_request(this->fahrenheit_ ? 'f' : 'c'); |       this->codec_->get_set_unit_request(this->fahrenheit_ ? 'f' : 'c'); | ||||||
|     auto status = esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, |     auto status = esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, | ||||||
|   | |||||||
| @@ -36,7 +36,7 @@ class Anova : public climate::Climate, public esphome::ble_client::BLEClientNode | |||||||
|     traits.set_visual_temperature_step(0.1); |     traits.set_visual_temperature_step(0.1); | ||||||
|     return traits; |     return traits; | ||||||
|   } |   } | ||||||
|   void set_unit_of_measurement(const char *); |   void set_unit_of_measurement(const char *unit); | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   std::unique_ptr<AnovaCodec> codec_; |   std::unique_ptr<AnovaCodec> codec_; | ||||||
|   | |||||||
| @@ -225,9 +225,10 @@ void APDS9960::read_gesture_data_() { | |||||||
|  |  | ||||||
|   uint8_t fifo_level; |   uint8_t fifo_level; | ||||||
|   APDS9960_WARNING_CHECK(this->read_byte(0xAE, &fifo_level), "Reading FIFO level failed."); |   APDS9960_WARNING_CHECK(this->read_byte(0xAE, &fifo_level), "Reading FIFO level failed."); | ||||||
|   if (fifo_level == 0) |   if (fifo_level == 0) { | ||||||
|     // no data to process |     // no data to process | ||||||
|     return; |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|   APDS9960_WARNING_CHECK(fifo_level <= 32, "FIFO level has invalid value.") |   APDS9960_WARNING_CHECK(fifo_level <= 32, "FIFO level has invalid value.") | ||||||
|  |  | ||||||
|   | |||||||
| @@ -41,6 +41,7 @@ service APIConnection { | |||||||
|   rpc number_command (NumberCommandRequest) returns (void) {} |   rpc number_command (NumberCommandRequest) returns (void) {} | ||||||
|   rpc select_command (SelectCommandRequest) returns (void) {} |   rpc select_command (SelectCommandRequest) returns (void) {} | ||||||
|   rpc button_command (ButtonCommandRequest) returns (void) {} |   rpc button_command (ButtonCommandRequest) returns (void) {} | ||||||
|  |   rpc lock_command (LockCommandRequest) returns (void) {} | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -95,6 +96,9 @@ message HelloResponse { | |||||||
|   // and only exists for debugging/logging purposes. |   // and only exists for debugging/logging purposes. | ||||||
|   // For example "ESPHome v1.10.0 on ESP8266" |   // For example "ESPHome v1.10.0 on ESP8266" | ||||||
|   string server_info = 3; |   string server_info = 3; | ||||||
|  |  | ||||||
|  |   // The name of the server (App.get_name()) | ||||||
|  |   string name = 4; | ||||||
| } | } | ||||||
|  |  | ||||||
| // Message sent at the beginning of each connection to authenticate the client | // Message sent at the beginning of each connection to authenticate the client | ||||||
| @@ -525,6 +529,7 @@ message ListEntitiesSwitchResponse { | |||||||
|   bool assumed_state = 6; |   bool assumed_state = 6; | ||||||
|   bool disabled_by_default = 7; |   bool disabled_by_default = 7; | ||||||
|   EntityCategory entity_category = 8; |   EntityCategory entity_category = 8; | ||||||
|  |   string device_class = 9; | ||||||
| } | } | ||||||
| message SwitchStateResponse { | message SwitchStateResponse { | ||||||
|   option (id) = 26; |   option (id) = 26; | ||||||
| @@ -953,6 +958,63 @@ message SelectCommandRequest { | |||||||
|   string state = 2; |   string state = 2; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // ==================== LOCK ==================== | ||||||
|  | enum LockState { | ||||||
|  |   LOCK_STATE_NONE = 0; | ||||||
|  |   LOCK_STATE_LOCKED = 1; | ||||||
|  |   LOCK_STATE_UNLOCKED = 2; | ||||||
|  |   LOCK_STATE_JAMMED = 3; | ||||||
|  |   LOCK_STATE_LOCKING = 4; | ||||||
|  |   LOCK_STATE_UNLOCKING = 5; | ||||||
|  | } | ||||||
|  | enum LockCommand  { | ||||||
|  |   LOCK_UNLOCK = 0; | ||||||
|  |   LOCK_LOCK = 1; | ||||||
|  |   LOCK_OPEN = 2; | ||||||
|  | } | ||||||
|  | message ListEntitiesLockResponse { | ||||||
|  |   option (id) = 58; | ||||||
|  |   option (source) = SOURCE_SERVER; | ||||||
|  |   option (ifdef) = "USE_LOCK"; | ||||||
|  |  | ||||||
|  |   string object_id = 1; | ||||||
|  |   fixed32 key = 2; | ||||||
|  |   string name = 3; | ||||||
|  |   string unique_id = 4; | ||||||
|  |  | ||||||
|  |   string icon = 5; | ||||||
|  |   bool disabled_by_default = 6; | ||||||
|  |   EntityCategory entity_category = 7; | ||||||
|  |   bool assumed_state = 8; | ||||||
|  |  | ||||||
|  |   bool supports_open = 9; | ||||||
|  |   bool requires_code = 10; | ||||||
|  |  | ||||||
|  |   # Not yet implemented: | ||||||
|  |   string code_format = 11; | ||||||
|  | } | ||||||
|  | message LockStateResponse { | ||||||
|  |   option (id) = 59; | ||||||
|  |   option (source) = SOURCE_SERVER; | ||||||
|  |   option (ifdef) = "USE_LOCK"; | ||||||
|  |   option (no_delay) = true; | ||||||
|  |   fixed32 key = 1; | ||||||
|  |   LockState state = 2; | ||||||
|  | } | ||||||
|  | message LockCommandRequest { | ||||||
|  |   option (id) = 60; | ||||||
|  |   option (source) = SOURCE_CLIENT; | ||||||
|  |   option (ifdef) = "USE_LOCK"; | ||||||
|  |   option (no_delay) = true; | ||||||
|  |   fixed32 key = 1; | ||||||
|  |   LockCommand command = 2; | ||||||
|  |  | ||||||
|  |   # Not yet implemented: | ||||||
|  |   bool has_code = 3; | ||||||
|  |   string code = 4; | ||||||
|  | } | ||||||
|  |  | ||||||
| // ==================== BUTTON ==================== | // ==================== BUTTON ==================== | ||||||
| message ListEntitiesButtonResponse { | message ListEntitiesButtonResponse { | ||||||
|   option (id) = 61; |   option (id) = 61; | ||||||
| @@ -977,3 +1039,4 @@ message ButtonCommandRequest { | |||||||
|  |  | ||||||
|   fixed32 key = 1; |   fixed32 key = 1; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -255,7 +255,7 @@ void APIConnection::cover_command(const CoverCommandRequest &msg) { | |||||||
| // Shut-up about usage of deprecated speed_level_to_enum/speed_enum_to_level functions for a bit. | // Shut-up about usage of deprecated speed_level_to_enum/speed_enum_to_level functions for a bit. | ||||||
| #pragma GCC diagnostic push | #pragma GCC diagnostic push | ||||||
| #pragma GCC diagnostic ignored "-Wdeprecated-declarations" | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" | ||||||
| bool APIConnection::send_fan_state(fan::FanState *fan) { | bool APIConnection::send_fan_state(fan::Fan *fan) { | ||||||
|   if (!this->state_subscription_) |   if (!this->state_subscription_) | ||||||
|     return false; |     return false; | ||||||
|  |  | ||||||
| @@ -273,7 +273,7 @@ bool APIConnection::send_fan_state(fan::FanState *fan) { | |||||||
|     resp.direction = static_cast<enums::FanDirection>(fan->direction); |     resp.direction = static_cast<enums::FanDirection>(fan->direction); | ||||||
|   return this->send_fan_state_response(resp); |   return this->send_fan_state_response(resp); | ||||||
| } | } | ||||||
| bool APIConnection::send_fan_info(fan::FanState *fan) { | bool APIConnection::send_fan_info(fan::Fan *fan) { | ||||||
|   auto traits = fan->get_traits(); |   auto traits = fan->get_traits(); | ||||||
|   ListEntitiesFanResponse msg; |   ListEntitiesFanResponse msg; | ||||||
|   msg.key = fan->get_object_id_hash(); |   msg.key = fan->get_object_id_hash(); | ||||||
| @@ -290,7 +290,7 @@ bool APIConnection::send_fan_info(fan::FanState *fan) { | |||||||
|   return this->send_list_entities_fan_response(msg); |   return this->send_list_entities_fan_response(msg); | ||||||
| } | } | ||||||
| void APIConnection::fan_command(const FanCommandRequest &msg) { | void APIConnection::fan_command(const FanCommandRequest &msg) { | ||||||
|   fan::FanState *fan = App.get_fan_by_key(msg.key); |   fan::Fan *fan = App.get_fan_by_key(msg.key); | ||||||
|   if (fan == nullptr) |   if (fan == nullptr) | ||||||
|     return; |     return; | ||||||
|  |  | ||||||
| @@ -462,6 +462,7 @@ bool APIConnection::send_switch_info(switch_::Switch *a_switch) { | |||||||
|   msg.assumed_state = a_switch->assumed_state(); |   msg.assumed_state = a_switch->assumed_state(); | ||||||
|   msg.disabled_by_default = a_switch->is_disabled_by_default(); |   msg.disabled_by_default = a_switch->is_disabled_by_default(); | ||||||
|   msg.entity_category = static_cast<enums::EntityCategory>(a_switch->get_entity_category()); |   msg.entity_category = static_cast<enums::EntityCategory>(a_switch->get_entity_category()); | ||||||
|  |   msg.device_class = a_switch->get_device_class(); | ||||||
|   return this->send_list_entities_switch_response(msg); |   return this->send_list_entities_switch_response(msg); | ||||||
| } | } | ||||||
| void APIConnection::switch_command(const SwitchCommandRequest &msg) { | void APIConnection::switch_command(const SwitchCommandRequest &msg) { | ||||||
| @@ -469,10 +470,11 @@ void APIConnection::switch_command(const SwitchCommandRequest &msg) { | |||||||
|   if (a_switch == nullptr) |   if (a_switch == nullptr) | ||||||
|     return; |     return; | ||||||
|  |  | ||||||
|   if (msg.state) |   if (msg.state) { | ||||||
|     a_switch->turn_on(); |     a_switch->turn_on(); | ||||||
|   else |   } else { | ||||||
|     a_switch->turn_off(); |     a_switch->turn_off(); | ||||||
|  |   } | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| @@ -699,6 +701,49 @@ void APIConnection::button_command(const ButtonCommandRequest &msg) { | |||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #ifdef USE_LOCK | ||||||
|  | bool APIConnection::send_lock_state(lock::Lock *a_lock, lock::LockState state) { | ||||||
|  |   if (!this->state_subscription_) | ||||||
|  |     return false; | ||||||
|  |  | ||||||
|  |   LockStateResponse resp{}; | ||||||
|  |   resp.key = a_lock->get_object_id_hash(); | ||||||
|  |   resp.state = static_cast<enums::LockState>(state); | ||||||
|  |   return this->send_lock_state_response(resp); | ||||||
|  | } | ||||||
|  | bool APIConnection::send_lock_info(lock::Lock *a_lock) { | ||||||
|  |   ListEntitiesLockResponse msg; | ||||||
|  |   msg.key = a_lock->get_object_id_hash(); | ||||||
|  |   msg.object_id = a_lock->get_object_id(); | ||||||
|  |   msg.name = a_lock->get_name(); | ||||||
|  |   msg.unique_id = get_default_unique_id("lock", a_lock); | ||||||
|  |   msg.icon = a_lock->get_icon(); | ||||||
|  |   msg.assumed_state = a_lock->traits.get_assumed_state(); | ||||||
|  |   msg.disabled_by_default = a_lock->is_disabled_by_default(); | ||||||
|  |   msg.entity_category = static_cast<enums::EntityCategory>(a_lock->get_entity_category()); | ||||||
|  |   msg.supports_open = a_lock->traits.get_supports_open(); | ||||||
|  |   msg.requires_code = a_lock->traits.get_requires_code(); | ||||||
|  |   return this->send_list_entities_lock_response(msg); | ||||||
|  | } | ||||||
|  | void APIConnection::lock_command(const LockCommandRequest &msg) { | ||||||
|  |   lock::Lock *a_lock = App.get_lock_by_key(msg.key); | ||||||
|  |   if (a_lock == nullptr) | ||||||
|  |     return; | ||||||
|  |  | ||||||
|  |   switch (msg.command) { | ||||||
|  |     case enums::LOCK_UNLOCK: | ||||||
|  |       a_lock->unlock(); | ||||||
|  |       break; | ||||||
|  |     case enums::LOCK_LOCK: | ||||||
|  |       a_lock->lock(); | ||||||
|  |       break; | ||||||
|  |     case enums::LOCK_OPEN: | ||||||
|  |       a_lock->open(); | ||||||
|  |       break; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #ifdef USE_ESP32_CAMERA | #ifdef USE_ESP32_CAMERA | ||||||
| void APIConnection::send_camera_state(std::shared_ptr<esp32_camera::CameraImage> image) { | void APIConnection::send_camera_state(std::shared_ptr<esp32_camera::CameraImage> image) { | ||||||
|   if (!this->state_subscription_) |   if (!this->state_subscription_) | ||||||
| @@ -766,6 +811,8 @@ HelloResponse APIConnection::hello(const HelloRequest &msg) { | |||||||
|   resp.api_version_major = 1; |   resp.api_version_major = 1; | ||||||
|   resp.api_version_minor = 6; |   resp.api_version_minor = 6; | ||||||
|   resp.server_info = App.get_name() + " (esphome v" ESPHOME_VERSION ")"; |   resp.server_info = App.get_name() + " (esphome v" ESPHOME_VERSION ")"; | ||||||
|  |   resp.name = App.get_name(); | ||||||
|  |  | ||||||
|   this->connection_state_ = ConnectionState::CONNECTED; |   this->connection_state_ = ConnectionState::CONNECTED; | ||||||
|   return resp; |   return resp; | ||||||
| } | } | ||||||
| @@ -803,15 +850,16 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) { | |||||||
|   resp.project_version = ESPHOME_PROJECT_VERSION; |   resp.project_version = ESPHOME_PROJECT_VERSION; | ||||||
| #endif | #endif | ||||||
| #ifdef USE_WEBSERVER | #ifdef USE_WEBSERVER | ||||||
|   resp.webserver_port = WEBSERVER_PORT; |   resp.webserver_port = USE_WEBSERVER_PORT; | ||||||
| #endif | #endif | ||||||
|   return resp; |   return resp; | ||||||
| } | } | ||||||
| void APIConnection::on_home_assistant_state_response(const HomeAssistantStateResponse &msg) { | void APIConnection::on_home_assistant_state_response(const HomeAssistantStateResponse &msg) { | ||||||
|   for (auto &it : this->parent_->get_state_subs()) |   for (auto &it : this->parent_->get_state_subs()) { | ||||||
|     if (it.entity_id == msg.entity_id && it.attribute.value() == msg.attribute) { |     if (it.entity_id == msg.entity_id && it.attribute.value() == msg.attribute) { | ||||||
|       it.callback(msg.state); |       it.callback(msg.state); | ||||||
|     } |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
| void APIConnection::execute_service(const ExecuteServiceRequest &msg) { | void APIConnection::execute_service(const ExecuteServiceRequest &msg) { | ||||||
|   bool found = false; |   bool found = false; | ||||||
|   | |||||||
| @@ -32,8 +32,8 @@ class APIConnection : public APIServerConnection { | |||||||
|   void cover_command(const CoverCommandRequest &msg) override; |   void cover_command(const CoverCommandRequest &msg) override; | ||||||
| #endif | #endif | ||||||
| #ifdef USE_FAN | #ifdef USE_FAN | ||||||
|   bool send_fan_state(fan::FanState *fan); |   bool send_fan_state(fan::Fan *fan); | ||||||
|   bool send_fan_info(fan::FanState *fan); |   bool send_fan_info(fan::Fan *fan); | ||||||
|   void fan_command(const FanCommandRequest &msg) override; |   void fan_command(const FanCommandRequest &msg) override; | ||||||
| #endif | #endif | ||||||
| #ifdef USE_LIGHT | #ifdef USE_LIGHT | ||||||
| @@ -77,6 +77,11 @@ class APIConnection : public APIServerConnection { | |||||||
| #ifdef USE_BUTTON | #ifdef USE_BUTTON | ||||||
|   bool send_button_info(button::Button *button); |   bool send_button_info(button::Button *button); | ||||||
|   void button_command(const ButtonCommandRequest &msg) override; |   void button_command(const ButtonCommandRequest &msg) override; | ||||||
|  | #endif | ||||||
|  | #ifdef USE_LOCK | ||||||
|  |   bool send_lock_state(lock::Lock *a_lock, lock::LockState state); | ||||||
|  |   bool send_lock_info(lock::Lock *a_lock); | ||||||
|  |   void lock_command(const LockCommandRequest &msg) override; | ||||||
| #endif | #endif | ||||||
|   bool send_log_message(int level, const char *tag, const char *line); |   bool send_log_message(int level, const char *tag, const char *line); | ||||||
|   void send_homeassistant_service_call(const HomeassistantServiceResponse &call) { |   void send_homeassistant_service_call(const HomeassistantServiceResponse &call) { | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ | |||||||
| #include "esphome/core/log.h" | #include "esphome/core/log.h" | ||||||
| #include "esphome/core/hal.h" | #include "esphome/core/hal.h" | ||||||
| #include "esphome/core/helpers.h" | #include "esphome/core/helpers.h" | ||||||
|  | #include "esphome/core/application.h" | ||||||
| #include "proto.h" | #include "proto.h" | ||||||
| #include <cstring> | #include <cstring> | ||||||
|  |  | ||||||
| @@ -302,9 +303,16 @@ APIError APINoiseFrameHelper::state_action_() { | |||||||
|   } |   } | ||||||
|   if (state_ == State::SERVER_HELLO) { |   if (state_ == State::SERVER_HELLO) { | ||||||
|     // send server hello |     // send server hello | ||||||
|     uint8_t msg[1]; |     std::vector<uint8_t> msg; | ||||||
|     msg[0] = 0x01;  // chosen proto |     // chosen proto | ||||||
|     aerr = write_frame_(msg, 1); |     msg.push_back(0x01); | ||||||
|  |  | ||||||
|  |     // node name, terminated by null byte | ||||||
|  |     const std::string &name = App.get_name(); | ||||||
|  |     const uint8_t *name_ptr = reinterpret_cast<const uint8_t *>(name.c_str()); | ||||||
|  |     msg.insert(msg.end(), name_ptr, name_ptr + name.size() + 1); | ||||||
|  |  | ||||||
|  |     aerr = write_frame_(msg.data(), msg.size()); | ||||||
|     if (aerr != APIError::OK) |     if (aerr != APIError::OK) | ||||||
|       return aerr; |       return aerr; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -278,6 +278,36 @@ template<> const char *proto_enum_to_string<enums::NumberMode>(enums::NumberMode | |||||||
|       return "UNKNOWN"; |       return "UNKNOWN"; | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | template<> const char *proto_enum_to_string<enums::LockState>(enums::LockState value) { | ||||||
|  |   switch (value) { | ||||||
|  |     case enums::LOCK_STATE_NONE: | ||||||
|  |       return "LOCK_STATE_NONE"; | ||||||
|  |     case enums::LOCK_STATE_LOCKED: | ||||||
|  |       return "LOCK_STATE_LOCKED"; | ||||||
|  |     case enums::LOCK_STATE_UNLOCKED: | ||||||
|  |       return "LOCK_STATE_UNLOCKED"; | ||||||
|  |     case enums::LOCK_STATE_JAMMED: | ||||||
|  |       return "LOCK_STATE_JAMMED"; | ||||||
|  |     case enums::LOCK_STATE_LOCKING: | ||||||
|  |       return "LOCK_STATE_LOCKING"; | ||||||
|  |     case enums::LOCK_STATE_UNLOCKING: | ||||||
|  |       return "LOCK_STATE_UNLOCKING"; | ||||||
|  |     default: | ||||||
|  |       return "UNKNOWN"; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | template<> const char *proto_enum_to_string<enums::LockCommand>(enums::LockCommand value) { | ||||||
|  |   switch (value) { | ||||||
|  |     case enums::LOCK_UNLOCK: | ||||||
|  |       return "LOCK_UNLOCK"; | ||||||
|  |     case enums::LOCK_LOCK: | ||||||
|  |       return "LOCK_LOCK"; | ||||||
|  |     case enums::LOCK_OPEN: | ||||||
|  |       return "LOCK_OPEN"; | ||||||
|  |     default: | ||||||
|  |       return "UNKNOWN"; | ||||||
|  |   } | ||||||
|  | } | ||||||
| bool HelloRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) { | bool HelloRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) { | ||||||
|   switch (field_id) { |   switch (field_id) { | ||||||
|     case 1: { |     case 1: { | ||||||
| @@ -319,6 +349,10 @@ bool HelloResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) | |||||||
|       this->server_info = value.as_string(); |       this->server_info = value.as_string(); | ||||||
|       return true; |       return true; | ||||||
|     } |     } | ||||||
|  |     case 4: { | ||||||
|  |       this->name = value.as_string(); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|     default: |     default: | ||||||
|       return false; |       return false; | ||||||
|   } |   } | ||||||
| @@ -327,6 +361,7 @@ void HelloResponse::encode(ProtoWriteBuffer buffer) const { | |||||||
|   buffer.encode_uint32(1, this->api_version_major); |   buffer.encode_uint32(1, this->api_version_major); | ||||||
|   buffer.encode_uint32(2, this->api_version_minor); |   buffer.encode_uint32(2, this->api_version_minor); | ||||||
|   buffer.encode_string(3, this->server_info); |   buffer.encode_string(3, this->server_info); | ||||||
|  |   buffer.encode_string(4, this->name); | ||||||
| } | } | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
| void HelloResponse::dump_to(std::string &out) const { | void HelloResponse::dump_to(std::string &out) const { | ||||||
| @@ -345,6 +380,10 @@ void HelloResponse::dump_to(std::string &out) const { | |||||||
|   out.append("  server_info: "); |   out.append("  server_info: "); | ||||||
|   out.append("'").append(this->server_info).append("'"); |   out.append("'").append(this->server_info).append("'"); | ||||||
|   out.append("\n"); |   out.append("\n"); | ||||||
|  |  | ||||||
|  |   out.append("  name: "); | ||||||
|  |   out.append("'").append(this->name).append("'"); | ||||||
|  |   out.append("\n"); | ||||||
|   out.append("}"); |   out.append("}"); | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| @@ -2138,6 +2177,10 @@ bool ListEntitiesSwitchResponse::decode_length(uint32_t field_id, ProtoLengthDel | |||||||
|       this->icon = value.as_string(); |       this->icon = value.as_string(); | ||||||
|       return true; |       return true; | ||||||
|     } |     } | ||||||
|  |     case 9: { | ||||||
|  |       this->device_class = value.as_string(); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|     default: |     default: | ||||||
|       return false; |       return false; | ||||||
|   } |   } | ||||||
| @@ -2161,6 +2204,7 @@ void ListEntitiesSwitchResponse::encode(ProtoWriteBuffer buffer) const { | |||||||
|   buffer.encode_bool(6, this->assumed_state); |   buffer.encode_bool(6, this->assumed_state); | ||||||
|   buffer.encode_bool(7, this->disabled_by_default); |   buffer.encode_bool(7, this->disabled_by_default); | ||||||
|   buffer.encode_enum<enums::EntityCategory>(8, this->entity_category); |   buffer.encode_enum<enums::EntityCategory>(8, this->entity_category); | ||||||
|  |   buffer.encode_string(9, this->device_class); | ||||||
| } | } | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
| void ListEntitiesSwitchResponse::dump_to(std::string &out) const { | void ListEntitiesSwitchResponse::dump_to(std::string &out) const { | ||||||
| @@ -2198,6 +2242,10 @@ void ListEntitiesSwitchResponse::dump_to(std::string &out) const { | |||||||
|   out.append("  entity_category: "); |   out.append("  entity_category: "); | ||||||
|   out.append(proto_enum_to_string<enums::EntityCategory>(this->entity_category)); |   out.append(proto_enum_to_string<enums::EntityCategory>(this->entity_category)); | ||||||
|   out.append("\n"); |   out.append("\n"); | ||||||
|  |  | ||||||
|  |   out.append("  device_class: "); | ||||||
|  |   out.append("'").append(this->device_class).append("'"); | ||||||
|  |   out.append("\n"); | ||||||
|   out.append("}"); |   out.append("}"); | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| @@ -4177,6 +4225,234 @@ void SelectCommandRequest::dump_to(std::string &out) const { | |||||||
|   out.append("}"); |   out.append("}"); | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | bool ListEntitiesLockResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { | ||||||
|  |   switch (field_id) { | ||||||
|  |     case 6: { | ||||||
|  |       this->disabled_by_default = value.as_bool(); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |     case 7: { | ||||||
|  |       this->entity_category = value.as_enum<enums::EntityCategory>(); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |     case 8: { | ||||||
|  |       this->assumed_state = value.as_bool(); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |     case 9: { | ||||||
|  |       this->supports_open = value.as_bool(); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |     case 10: { | ||||||
|  |       this->requires_code = value.as_bool(); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |     default: | ||||||
|  |       return false; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | bool ListEntitiesLockResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) { | ||||||
|  |   switch (field_id) { | ||||||
|  |     case 1: { | ||||||
|  |       this->object_id = value.as_string(); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |     case 3: { | ||||||
|  |       this->name = value.as_string(); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |     case 4: { | ||||||
|  |       this->unique_id = value.as_string(); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |     case 5: { | ||||||
|  |       this->icon = value.as_string(); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |     case 11: { | ||||||
|  |       this->code_format = value.as_string(); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |     default: | ||||||
|  |       return false; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | bool ListEntitiesLockResponse::decode_32bit(uint32_t field_id, Proto32Bit value) { | ||||||
|  |   switch (field_id) { | ||||||
|  |     case 2: { | ||||||
|  |       this->key = value.as_fixed32(); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |     default: | ||||||
|  |       return false; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | void ListEntitiesLockResponse::encode(ProtoWriteBuffer buffer) const { | ||||||
|  |   buffer.encode_string(1, this->object_id); | ||||||
|  |   buffer.encode_fixed32(2, this->key); | ||||||
|  |   buffer.encode_string(3, this->name); | ||||||
|  |   buffer.encode_string(4, this->unique_id); | ||||||
|  |   buffer.encode_string(5, this->icon); | ||||||
|  |   buffer.encode_bool(6, this->disabled_by_default); | ||||||
|  |   buffer.encode_enum<enums::EntityCategory>(7, this->entity_category); | ||||||
|  |   buffer.encode_bool(8, this->assumed_state); | ||||||
|  |   buffer.encode_bool(9, this->supports_open); | ||||||
|  |   buffer.encode_bool(10, this->requires_code); | ||||||
|  |   buffer.encode_string(11, this->code_format); | ||||||
|  | } | ||||||
|  | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|  | void ListEntitiesLockResponse::dump_to(std::string &out) const { | ||||||
|  |   __attribute__((unused)) char buffer[64]; | ||||||
|  |   out.append("ListEntitiesLockResponse {\n"); | ||||||
|  |   out.append("  object_id: "); | ||||||
|  |   out.append("'").append(this->object_id).append("'"); | ||||||
|  |   out.append("\n"); | ||||||
|  |  | ||||||
|  |   out.append("  key: "); | ||||||
|  |   sprintf(buffer, "%u", this->key); | ||||||
|  |   out.append(buffer); | ||||||
|  |   out.append("\n"); | ||||||
|  |  | ||||||
|  |   out.append("  name: "); | ||||||
|  |   out.append("'").append(this->name).append("'"); | ||||||
|  |   out.append("\n"); | ||||||
|  |  | ||||||
|  |   out.append("  unique_id: "); | ||||||
|  |   out.append("'").append(this->unique_id).append("'"); | ||||||
|  |   out.append("\n"); | ||||||
|  |  | ||||||
|  |   out.append("  icon: "); | ||||||
|  |   out.append("'").append(this->icon).append("'"); | ||||||
|  |   out.append("\n"); | ||||||
|  |  | ||||||
|  |   out.append("  disabled_by_default: "); | ||||||
|  |   out.append(YESNO(this->disabled_by_default)); | ||||||
|  |   out.append("\n"); | ||||||
|  |  | ||||||
|  |   out.append("  entity_category: "); | ||||||
|  |   out.append(proto_enum_to_string<enums::EntityCategory>(this->entity_category)); | ||||||
|  |   out.append("\n"); | ||||||
|  |  | ||||||
|  |   out.append("  assumed_state: "); | ||||||
|  |   out.append(YESNO(this->assumed_state)); | ||||||
|  |   out.append("\n"); | ||||||
|  |  | ||||||
|  |   out.append("  supports_open: "); | ||||||
|  |   out.append(YESNO(this->supports_open)); | ||||||
|  |   out.append("\n"); | ||||||
|  |  | ||||||
|  |   out.append("  requires_code: "); | ||||||
|  |   out.append(YESNO(this->requires_code)); | ||||||
|  |   out.append("\n"); | ||||||
|  |  | ||||||
|  |   out.append("  code_format: "); | ||||||
|  |   out.append("'").append(this->code_format).append("'"); | ||||||
|  |   out.append("\n"); | ||||||
|  |   out.append("}"); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | bool LockStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { | ||||||
|  |   switch (field_id) { | ||||||
|  |     case 2: { | ||||||
|  |       this->state = value.as_enum<enums::LockState>(); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |     default: | ||||||
|  |       return false; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | bool LockStateResponse::decode_32bit(uint32_t field_id, Proto32Bit value) { | ||||||
|  |   switch (field_id) { | ||||||
|  |     case 1: { | ||||||
|  |       this->key = value.as_fixed32(); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |     default: | ||||||
|  |       return false; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | void LockStateResponse::encode(ProtoWriteBuffer buffer) const { | ||||||
|  |   buffer.encode_fixed32(1, this->key); | ||||||
|  |   buffer.encode_enum<enums::LockState>(2, this->state); | ||||||
|  | } | ||||||
|  | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|  | void LockStateResponse::dump_to(std::string &out) const { | ||||||
|  |   __attribute__((unused)) char buffer[64]; | ||||||
|  |   out.append("LockStateResponse {\n"); | ||||||
|  |   out.append("  key: "); | ||||||
|  |   sprintf(buffer, "%u", this->key); | ||||||
|  |   out.append(buffer); | ||||||
|  |   out.append("\n"); | ||||||
|  |  | ||||||
|  |   out.append("  state: "); | ||||||
|  |   out.append(proto_enum_to_string<enums::LockState>(this->state)); | ||||||
|  |   out.append("\n"); | ||||||
|  |   out.append("}"); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | bool LockCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { | ||||||
|  |   switch (field_id) { | ||||||
|  |     case 2: { | ||||||
|  |       this->command = value.as_enum<enums::LockCommand>(); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |     case 3: { | ||||||
|  |       this->has_code = value.as_bool(); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |     default: | ||||||
|  |       return false; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | bool LockCommandRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) { | ||||||
|  |   switch (field_id) { | ||||||
|  |     case 4: { | ||||||
|  |       this->code = value.as_string(); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |     default: | ||||||
|  |       return false; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | bool LockCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) { | ||||||
|  |   switch (field_id) { | ||||||
|  |     case 1: { | ||||||
|  |       this->key = value.as_fixed32(); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |     default: | ||||||
|  |       return false; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | void LockCommandRequest::encode(ProtoWriteBuffer buffer) const { | ||||||
|  |   buffer.encode_fixed32(1, this->key); | ||||||
|  |   buffer.encode_enum<enums::LockCommand>(2, this->command); | ||||||
|  |   buffer.encode_bool(3, this->has_code); | ||||||
|  |   buffer.encode_string(4, this->code); | ||||||
|  | } | ||||||
|  | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|  | void LockCommandRequest::dump_to(std::string &out) const { | ||||||
|  |   __attribute__((unused)) char buffer[64]; | ||||||
|  |   out.append("LockCommandRequest {\n"); | ||||||
|  |   out.append("  key: "); | ||||||
|  |   sprintf(buffer, "%u", this->key); | ||||||
|  |   out.append(buffer); | ||||||
|  |   out.append("\n"); | ||||||
|  |  | ||||||
|  |   out.append("  command: "); | ||||||
|  |   out.append(proto_enum_to_string<enums::LockCommand>(this->command)); | ||||||
|  |   out.append("\n"); | ||||||
|  |  | ||||||
|  |   out.append("  has_code: "); | ||||||
|  |   out.append(YESNO(this->has_code)); | ||||||
|  |   out.append("\n"); | ||||||
|  |  | ||||||
|  |   out.append("  code: "); | ||||||
|  |   out.append("'").append(this->code).append("'"); | ||||||
|  |   out.append("\n"); | ||||||
|  |   out.append("}"); | ||||||
|  | } | ||||||
|  | #endif | ||||||
| bool ListEntitiesButtonResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { | bool ListEntitiesButtonResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { | ||||||
|   switch (field_id) { |   switch (field_id) { | ||||||
|     case 6: { |     case 6: { | ||||||
| @@ -4239,7 +4515,7 @@ void ListEntitiesButtonResponse::encode(ProtoWriteBuffer buffer) const { | |||||||
| } | } | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
| void ListEntitiesButtonResponse::dump_to(std::string &out) const { | void ListEntitiesButtonResponse::dump_to(std::string &out) const { | ||||||
|   char buffer[64]; |   __attribute__((unused)) char buffer[64]; | ||||||
|   out.append("ListEntitiesButtonResponse {\n"); |   out.append("ListEntitiesButtonResponse {\n"); | ||||||
|   out.append("  object_id: "); |   out.append("  object_id: "); | ||||||
|   out.append("'").append(this->object_id).append("'"); |   out.append("'").append(this->object_id).append("'"); | ||||||
| @@ -4289,7 +4565,7 @@ bool ButtonCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) { | |||||||
| void ButtonCommandRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_fixed32(1, this->key); } | void ButtonCommandRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_fixed32(1, this->key); } | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
| void ButtonCommandRequest::dump_to(std::string &out) const { | void ButtonCommandRequest::dump_to(std::string &out) const { | ||||||
|   char buffer[64]; |   __attribute__((unused)) char buffer[64]; | ||||||
|   out.append("ButtonCommandRequest {\n"); |   out.append("ButtonCommandRequest {\n"); | ||||||
|   out.append("  key: "); |   out.append("  key: "); | ||||||
|   sprintf(buffer, "%u", this->key); |   sprintf(buffer, "%u", this->key); | ||||||
|   | |||||||
| @@ -128,6 +128,19 @@ enum NumberMode : uint32_t { | |||||||
|   NUMBER_MODE_BOX = 1, |   NUMBER_MODE_BOX = 1, | ||||||
|   NUMBER_MODE_SLIDER = 2, |   NUMBER_MODE_SLIDER = 2, | ||||||
| }; | }; | ||||||
|  | enum LockState : uint32_t { | ||||||
|  |   LOCK_STATE_NONE = 0, | ||||||
|  |   LOCK_STATE_LOCKED = 1, | ||||||
|  |   LOCK_STATE_UNLOCKED = 2, | ||||||
|  |   LOCK_STATE_JAMMED = 3, | ||||||
|  |   LOCK_STATE_LOCKING = 4, | ||||||
|  |   LOCK_STATE_UNLOCKING = 5, | ||||||
|  | }; | ||||||
|  | enum LockCommand : uint32_t { | ||||||
|  |   LOCK_UNLOCK = 0, | ||||||
|  |   LOCK_LOCK = 1, | ||||||
|  |   LOCK_OPEN = 2, | ||||||
|  | }; | ||||||
|  |  | ||||||
| }  // namespace enums | }  // namespace enums | ||||||
|  |  | ||||||
| @@ -147,6 +160,7 @@ class HelloResponse : public ProtoMessage { | |||||||
|   uint32_t api_version_major{0}; |   uint32_t api_version_major{0}; | ||||||
|   uint32_t api_version_minor{0}; |   uint32_t api_version_minor{0}; | ||||||
|   std::string server_info{}; |   std::string server_info{}; | ||||||
|  |   std::string name{}; | ||||||
|   void encode(ProtoWriteBuffer buffer) const override; |   void encode(ProtoWriteBuffer buffer) const override; | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|   void dump_to(std::string &out) const override; |   void dump_to(std::string &out) const override; | ||||||
| @@ -566,6 +580,7 @@ class ListEntitiesSwitchResponse : public ProtoMessage { | |||||||
|   bool assumed_state{false}; |   bool assumed_state{false}; | ||||||
|   bool disabled_by_default{false}; |   bool disabled_by_default{false}; | ||||||
|   enums::EntityCategory entity_category{}; |   enums::EntityCategory entity_category{}; | ||||||
|  |   std::string device_class{}; | ||||||
|   void encode(ProtoWriteBuffer buffer) const override; |   void encode(ProtoWriteBuffer buffer) const override; | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|   void dump_to(std::string &out) const override; |   void dump_to(std::string &out) const override; | ||||||
| @@ -1048,6 +1063,58 @@ class SelectCommandRequest : public ProtoMessage { | |||||||
|   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; |   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||||
|   bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; |   bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; | ||||||
| }; | }; | ||||||
|  | class ListEntitiesLockResponse : public ProtoMessage { | ||||||
|  |  public: | ||||||
|  |   std::string object_id{}; | ||||||
|  |   uint32_t key{0}; | ||||||
|  |   std::string name{}; | ||||||
|  |   std::string unique_id{}; | ||||||
|  |   std::string icon{}; | ||||||
|  |   bool disabled_by_default{false}; | ||||||
|  |   enums::EntityCategory entity_category{}; | ||||||
|  |   bool assumed_state{false}; | ||||||
|  |   bool supports_open{false}; | ||||||
|  |   bool requires_code{false}; | ||||||
|  |   std::string code_format{}; | ||||||
|  |   void encode(ProtoWriteBuffer buffer) const override; | ||||||
|  | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|  |   void dump_to(std::string &out) const override; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||||
|  |   bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; | ||||||
|  |   bool decode_varint(uint32_t field_id, ProtoVarInt value) override; | ||||||
|  | }; | ||||||
|  | class LockStateResponse : public ProtoMessage { | ||||||
|  |  public: | ||||||
|  |   uint32_t key{0}; | ||||||
|  |   enums::LockState state{}; | ||||||
|  |   void encode(ProtoWriteBuffer buffer) const override; | ||||||
|  | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|  |   void dump_to(std::string &out) const override; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||||
|  |   bool decode_varint(uint32_t field_id, ProtoVarInt value) override; | ||||||
|  | }; | ||||||
|  | class LockCommandRequest : public ProtoMessage { | ||||||
|  |  public: | ||||||
|  |   uint32_t key{0}; | ||||||
|  |   enums::LockCommand command{}; | ||||||
|  |   bool has_code{false}; | ||||||
|  |   std::string code{}; | ||||||
|  |   void encode(ProtoWriteBuffer buffer) const override; | ||||||
|  | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|  |   void dump_to(std::string &out) const override; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   bool decode_32bit(uint32_t field_id, Proto32Bit value) override; | ||||||
|  |   bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; | ||||||
|  |   bool decode_varint(uint32_t field_id, ProtoVarInt value) override; | ||||||
|  | }; | ||||||
| class ListEntitiesButtonResponse : public ProtoMessage { | class ListEntitiesButtonResponse : public ProtoMessage { | ||||||
|  public: |  public: | ||||||
|   std::string object_id{}; |   std::string object_id{}; | ||||||
|   | |||||||
| @@ -282,6 +282,24 @@ bool APIServerConnectionBase::send_select_state_response(const SelectStateRespon | |||||||
| #endif | #endif | ||||||
| #ifdef USE_SELECT | #ifdef USE_SELECT | ||||||
| #endif | #endif | ||||||
|  | #ifdef USE_LOCK | ||||||
|  | bool APIServerConnectionBase::send_list_entities_lock_response(const ListEntitiesLockResponse &msg) { | ||||||
|  | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|  |   ESP_LOGVV(TAG, "send_list_entities_lock_response: %s", msg.dump().c_str()); | ||||||
|  | #endif | ||||||
|  |   return this->send_message_<ListEntitiesLockResponse>(msg, 58); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | #ifdef USE_LOCK | ||||||
|  | bool APIServerConnectionBase::send_lock_state_response(const LockStateResponse &msg) { | ||||||
|  | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|  |   ESP_LOGVV(TAG, "send_lock_state_response: %s", msg.dump().c_str()); | ||||||
|  | #endif | ||||||
|  |   return this->send_message_<LockStateResponse>(msg, 59); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | #ifdef USE_LOCK | ||||||
|  | #endif | ||||||
| #ifdef USE_BUTTON | #ifdef USE_BUTTON | ||||||
| bool APIServerConnectionBase::send_list_entities_button_response(const ListEntitiesButtonResponse &msg) { | bool APIServerConnectionBase::send_list_entities_button_response(const ListEntitiesButtonResponse &msg) { | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
| @@ -523,6 +541,17 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, | |||||||
|       ESP_LOGVV(TAG, "on_select_command_request: %s", msg.dump().c_str()); |       ESP_LOGVV(TAG, "on_select_command_request: %s", msg.dump().c_str()); | ||||||
| #endif | #endif | ||||||
|       this->on_select_command_request(msg); |       this->on_select_command_request(msg); | ||||||
|  | #endif | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |     case 60: { | ||||||
|  | #ifdef USE_LOCK | ||||||
|  |       LockCommandRequest msg; | ||||||
|  |       msg.decode(msg_data, msg_size); | ||||||
|  | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|  |       ESP_LOGVV(TAG, "on_lock_command_request: %s", msg.dump().c_str()); | ||||||
|  | #endif | ||||||
|  |       this->on_lock_command_request(msg); | ||||||
| #endif | #endif | ||||||
|       break; |       break; | ||||||
|     } |     } | ||||||
| @@ -771,6 +800,19 @@ void APIServerConnection::on_button_command_request(const ButtonCommandRequest & | |||||||
|   this->button_command(msg); |   this->button_command(msg); | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | #ifdef USE_LOCK | ||||||
|  | void APIServerConnection::on_lock_command_request(const LockCommandRequest &msg) { | ||||||
|  |   if (!this->is_connection_setup()) { | ||||||
|  |     this->on_no_setup_connection(); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   if (!this->is_authenticated()) { | ||||||
|  |     this->on_unauthenticated_access(); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   this->lock_command(msg); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
| }  // namespace api | }  // namespace api | ||||||
| }  // namespace esphome | }  // namespace esphome | ||||||
|   | |||||||
| @@ -130,6 +130,15 @@ class APIServerConnectionBase : public ProtoService { | |||||||
| #ifdef USE_SELECT | #ifdef USE_SELECT | ||||||
|   virtual void on_select_command_request(const SelectCommandRequest &value){}; |   virtual void on_select_command_request(const SelectCommandRequest &value){}; | ||||||
| #endif | #endif | ||||||
|  | #ifdef USE_LOCK | ||||||
|  |   bool send_list_entities_lock_response(const ListEntitiesLockResponse &msg); | ||||||
|  | #endif | ||||||
|  | #ifdef USE_LOCK | ||||||
|  |   bool send_lock_state_response(const LockStateResponse &msg); | ||||||
|  | #endif | ||||||
|  | #ifdef USE_LOCK | ||||||
|  |   virtual void on_lock_command_request(const LockCommandRequest &value){}; | ||||||
|  | #endif | ||||||
| #ifdef USE_BUTTON | #ifdef USE_BUTTON | ||||||
|   bool send_list_entities_button_response(const ListEntitiesButtonResponse &msg); |   bool send_list_entities_button_response(const ListEntitiesButtonResponse &msg); | ||||||
| #endif | #endif | ||||||
| @@ -180,6 +189,9 @@ class APIServerConnection : public APIServerConnectionBase { | |||||||
| #endif | #endif | ||||||
| #ifdef USE_BUTTON | #ifdef USE_BUTTON | ||||||
|   virtual void button_command(const ButtonCommandRequest &msg) = 0; |   virtual void button_command(const ButtonCommandRequest &msg) = 0; | ||||||
|  | #endif | ||||||
|  | #ifdef USE_LOCK | ||||||
|  |   virtual void lock_command(const LockCommandRequest &msg) = 0; | ||||||
| #endif | #endif | ||||||
|  protected: |  protected: | ||||||
|   void on_hello_request(const HelloRequest &msg) override; |   void on_hello_request(const HelloRequest &msg) override; | ||||||
| @@ -221,6 +233,9 @@ class APIServerConnection : public APIServerConnectionBase { | |||||||
| #ifdef USE_BUTTON | #ifdef USE_BUTTON | ||||||
|   void on_button_command_request(const ButtonCommandRequest &msg) override; |   void on_button_command_request(const ButtonCommandRequest &msg) override; | ||||||
| #endif | #endif | ||||||
|  | #ifdef USE_LOCK | ||||||
|  |   void on_lock_command_request(const LockCommandRequest &msg) override; | ||||||
|  | #endif | ||||||
| }; | }; | ||||||
|  |  | ||||||
| }  // namespace api | }  // namespace api | ||||||
|   | |||||||
| @@ -24,7 +24,7 @@ static const char *const TAG = "api"; | |||||||
| void APIServer::setup() { | void APIServer::setup() { | ||||||
|   ESP_LOGCONFIG(TAG, "Setting up Home Assistant API server..."); |   ESP_LOGCONFIG(TAG, "Setting up Home Assistant API server..."); | ||||||
|   this->setup_controller(); |   this->setup_controller(); | ||||||
|   socket_ = socket::socket(AF_INET, SOCK_STREAM, 0); |   socket_ = socket::socket_ip(SOCK_STREAM, 0); | ||||||
|   if (socket_ == nullptr) { |   if (socket_ == nullptr) { | ||||||
|     ESP_LOGW(TAG, "Could not create socket."); |     ESP_LOGW(TAG, "Could not create socket."); | ||||||
|     this->mark_failed(); |     this->mark_failed(); | ||||||
| @@ -43,13 +43,16 @@ void APIServer::setup() { | |||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   struct sockaddr_in server; |   struct sockaddr_storage server; | ||||||
|   memset(&server, 0, sizeof(server)); |  | ||||||
|   server.sin_family = AF_INET; |  | ||||||
|   server.sin_addr.s_addr = ESPHOME_INADDR_ANY; |  | ||||||
|   server.sin_port = htons(this->port_); |  | ||||||
|  |  | ||||||
|   err = socket_->bind((struct sockaddr *) &server, sizeof(server)); |   socklen_t sl = socket::set_sockaddr_any((struct sockaddr *) &server, sizeof(server), htons(this->port_)); | ||||||
|  |   if (sl == 0) { | ||||||
|  |     ESP_LOGW(TAG, "Socket unable to set sockaddr: errno %d", errno); | ||||||
|  |     this->mark_failed(); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   err = socket_->bind((struct sockaddr *) &server, sl); | ||||||
|   if (err != 0) { |   if (err != 0) { | ||||||
|     ESP_LOGW(TAG, "Socket unable to bind: errno %d", errno); |     ESP_LOGW(TAG, "Socket unable to bind: errno %d", errno); | ||||||
|     this->mark_failed(); |     this->mark_failed(); | ||||||
| @@ -80,9 +83,10 @@ void APIServer::setup() { | |||||||
|   if (esp32_camera::global_esp32_camera != nullptr && !esp32_camera::global_esp32_camera->is_internal()) { |   if (esp32_camera::global_esp32_camera != nullptr && !esp32_camera::global_esp32_camera->is_internal()) { | ||||||
|     esp32_camera::global_esp32_camera->add_image_callback( |     esp32_camera::global_esp32_camera->add_image_callback( | ||||||
|         [this](const std::shared_ptr<esp32_camera::CameraImage> &image) { |         [this](const std::shared_ptr<esp32_camera::CameraImage> &image) { | ||||||
|           for (auto &c : this->clients_) |           for (auto &c : this->clients_) { | ||||||
|             if (!c->remove_) |             if (!c->remove_) | ||||||
|               c->send_camera_state(image); |               c->send_camera_state(image); | ||||||
|  |           } | ||||||
|         }); |         }); | ||||||
|   } |   } | ||||||
| #endif | #endif | ||||||
| @@ -188,7 +192,7 @@ void APIServer::on_cover_update(cover::Cover *obj) { | |||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #ifdef USE_FAN | #ifdef USE_FAN | ||||||
| void APIServer::on_fan_update(fan::FanState *obj) { | void APIServer::on_fan_update(fan::Fan *obj) { | ||||||
|   if (obj->is_internal()) |   if (obj->is_internal()) | ||||||
|     return; |     return; | ||||||
|   for (auto &c : this->clients_) |   for (auto &c : this->clients_) | ||||||
| @@ -259,6 +263,15 @@ void APIServer::on_select_update(select::Select *obj, const std::string &state) | |||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #ifdef USE_LOCK | ||||||
|  | void APIServer::on_lock_update(lock::Lock *obj) { | ||||||
|  |   if (obj->is_internal()) | ||||||
|  |     return; | ||||||
|  |   for (auto &c : this->clients_) | ||||||
|  |     c->send_lock_state(obj, obj->state); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
| float APIServer::get_setup_priority() const { return setup_priority::AFTER_WIFI; } | float APIServer::get_setup_priority() const { return setup_priority::AFTER_WIFI; } | ||||||
| void APIServer::set_port(uint16_t port) { this->port_ = port; } | void APIServer::set_port(uint16_t port) { this->port_ = port; } | ||||||
| APIServer *global_api_server = nullptr;  // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) | APIServer *global_api_server = nullptr;  // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) | ||||||
|   | |||||||
| @@ -44,7 +44,7 @@ class APIServer : public Component, public Controller { | |||||||
|   void on_cover_update(cover::Cover *obj) override; |   void on_cover_update(cover::Cover *obj) override; | ||||||
| #endif | #endif | ||||||
| #ifdef USE_FAN | #ifdef USE_FAN | ||||||
|   void on_fan_update(fan::FanState *obj) override; |   void on_fan_update(fan::Fan *obj) override; | ||||||
| #endif | #endif | ||||||
| #ifdef USE_LIGHT | #ifdef USE_LIGHT | ||||||
|   void on_light_update(light::LightState *obj) override; |   void on_light_update(light::LightState *obj) override; | ||||||
| @@ -66,6 +66,9 @@ class APIServer : public Component, public Controller { | |||||||
| #endif | #endif | ||||||
| #ifdef USE_SELECT | #ifdef USE_SELECT | ||||||
|   void on_select_update(select::Select *obj, const std::string &state) override; |   void on_select_update(select::Select *obj, const std::string &state) override; | ||||||
|  | #endif | ||||||
|  | #ifdef USE_LOCK | ||||||
|  |   void on_lock_update(lock::Lock *obj) override; | ||||||
| #endif | #endif | ||||||
|   void send_homeassistant_service_call(const HomeassistantServiceResponse &call); |   void send_homeassistant_service_call(const HomeassistantServiceResponse &call); | ||||||
|   void register_user_service(UserServiceDescriptor *descriptor) { this->user_services_.push_back(descriptor); } |   void register_user_service(UserServiceDescriptor *descriptor) { this->user_services_.push_back(descriptor); } | ||||||
|   | |||||||
| @@ -16,7 +16,7 @@ bool ListEntitiesIterator::on_binary_sensor(binary_sensor::BinarySensor *binary_ | |||||||
| bool ListEntitiesIterator::on_cover(cover::Cover *cover) { return this->client_->send_cover_info(cover); } | bool ListEntitiesIterator::on_cover(cover::Cover *cover) { return this->client_->send_cover_info(cover); } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_FAN | #ifdef USE_FAN | ||||||
| bool ListEntitiesIterator::on_fan(fan::FanState *fan) { return this->client_->send_fan_info(fan); } | bool ListEntitiesIterator::on_fan(fan::Fan *fan) { return this->client_->send_fan_info(fan); } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_LIGHT | #ifdef USE_LIGHT | ||||||
| bool ListEntitiesIterator::on_light(light::LightState *light) { return this->client_->send_light_info(light); } | bool ListEntitiesIterator::on_light(light::LightState *light) { return this->client_->send_light_info(light); } | ||||||
| @@ -35,6 +35,9 @@ bool ListEntitiesIterator::on_text_sensor(text_sensor::TextSensor *text_sensor) | |||||||
|   return this->client_->send_text_sensor_info(text_sensor); |   return this->client_->send_text_sensor_info(text_sensor); | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | #ifdef USE_LOCK | ||||||
|  | bool ListEntitiesIterator::on_lock(lock::Lock *a_lock) { return this->client_->send_lock_info(a_lock); } | ||||||
|  | #endif | ||||||
|  |  | ||||||
| bool ListEntitiesIterator::on_end() { return this->client_->send_list_info_done(); } | bool ListEntitiesIterator::on_end() { return this->client_->send_list_info_done(); } | ||||||
| ListEntitiesIterator::ListEntitiesIterator(APIServer *server, APIConnection *client) | ListEntitiesIterator::ListEntitiesIterator(APIServer *server, APIConnection *client) | ||||||
|   | |||||||
| @@ -19,7 +19,7 @@ class ListEntitiesIterator : public ComponentIterator { | |||||||
|   bool on_cover(cover::Cover *cover) override; |   bool on_cover(cover::Cover *cover) override; | ||||||
| #endif | #endif | ||||||
| #ifdef USE_FAN | #ifdef USE_FAN | ||||||
|   bool on_fan(fan::FanState *fan) override; |   bool on_fan(fan::Fan *fan) override; | ||||||
| #endif | #endif | ||||||
| #ifdef USE_LIGHT | #ifdef USE_LIGHT | ||||||
|   bool on_light(light::LightState *light) override; |   bool on_light(light::LightState *light) override; | ||||||
| @@ -48,6 +48,9 @@ class ListEntitiesIterator : public ComponentIterator { | |||||||
| #endif | #endif | ||||||
| #ifdef USE_SELECT | #ifdef USE_SELECT | ||||||
|   bool on_select(select::Select *select) override; |   bool on_select(select::Select *select) override; | ||||||
|  | #endif | ||||||
|  | #ifdef USE_LOCK | ||||||
|  |   bool on_lock(lock::Lock *a_lock) override; | ||||||
| #endif | #endif | ||||||
|   bool on_end() override; |   bool on_end() override; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -55,17 +55,19 @@ class ProtoVarInt { | |||||||
|   } |   } | ||||||
|   int32_t as_sint32() const { |   int32_t as_sint32() const { | ||||||
|     // with ZigZag encoding |     // with ZigZag encoding | ||||||
|     if (this->value_ & 1) |     if (this->value_ & 1) { | ||||||
|       return static_cast<int32_t>(~(this->value_ >> 1)); |       return static_cast<int32_t>(~(this->value_ >> 1)); | ||||||
|     else |     } else { | ||||||
|       return static_cast<int32_t>(this->value_ >> 1); |       return static_cast<int32_t>(this->value_ >> 1); | ||||||
|  |     } | ||||||
|   } |   } | ||||||
|   int64_t as_sint64() const { |   int64_t as_sint64() const { | ||||||
|     // with ZigZag encoding |     // with ZigZag encoding | ||||||
|     if (this->value_ & 1) |     if (this->value_ & 1) { | ||||||
|       return static_cast<int64_t>(~(this->value_ >> 1)); |       return static_cast<int64_t>(~(this->value_ >> 1)); | ||||||
|     else |     } else { | ||||||
|       return static_cast<int64_t>(this->value_ >> 1); |       return static_cast<int64_t>(this->value_ >> 1); | ||||||
|  |     } | ||||||
|   } |   } | ||||||
|   void encode(std::vector<uint8_t> &out) { |   void encode(std::vector<uint8_t> &out) { | ||||||
|     uint32_t val = this->value_; |     uint32_t val = this->value_; | ||||||
| @@ -220,10 +222,11 @@ class ProtoWriteBuffer { | |||||||
|   } |   } | ||||||
|   void encode_sint32(uint32_t field_id, int32_t value, bool force = false) { |   void encode_sint32(uint32_t field_id, int32_t value, bool force = false) { | ||||||
|     uint32_t uvalue; |     uint32_t uvalue; | ||||||
|     if (value < 0) |     if (value < 0) { | ||||||
|       uvalue = ~(value << 1); |       uvalue = ~(value << 1); | ||||||
|     else |     } else { | ||||||
|       uvalue = value << 1; |       uvalue = value << 1; | ||||||
|  |     } | ||||||
|     this->encode_uint32(field_id, uvalue, force); |     this->encode_uint32(field_id, uvalue, force); | ||||||
|   } |   } | ||||||
|   template<class C> void encode_message(uint32_t field_id, const C &value, bool force = false) { |   template<class C> void encode_message(uint32_t field_id, const C &value, bool force = false) { | ||||||
|   | |||||||
| @@ -14,7 +14,7 @@ bool InitialStateIterator::on_binary_sensor(binary_sensor::BinarySensor *binary_ | |||||||
| bool InitialStateIterator::on_cover(cover::Cover *cover) { return this->client_->send_cover_state(cover); } | bool InitialStateIterator::on_cover(cover::Cover *cover) { return this->client_->send_cover_state(cover); } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_FAN | #ifdef USE_FAN | ||||||
| bool InitialStateIterator::on_fan(fan::FanState *fan) { return this->client_->send_fan_state(fan); } | bool InitialStateIterator::on_fan(fan::Fan *fan) { return this->client_->send_fan_state(fan); } | ||||||
| #endif | #endif | ||||||
| #ifdef USE_LIGHT | #ifdef USE_LIGHT | ||||||
| bool InitialStateIterator::on_light(light::LightState *light) { return this->client_->send_light_state(light); } | bool InitialStateIterator::on_light(light::LightState *light) { return this->client_->send_light_state(light); } | ||||||
| @@ -47,6 +47,9 @@ bool InitialStateIterator::on_select(select::Select *select) { | |||||||
|   return this->client_->send_select_state(select, select->state); |   return this->client_->send_select_state(select, select->state); | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | #ifdef USE_LOCK | ||||||
|  | bool InitialStateIterator::on_lock(lock::Lock *a_lock) { return this->client_->send_lock_state(a_lock, a_lock->state); } | ||||||
|  | #endif | ||||||
| InitialStateIterator::InitialStateIterator(APIServer *server, APIConnection *client) | InitialStateIterator::InitialStateIterator(APIServer *server, APIConnection *client) | ||||||
|     : ComponentIterator(server), client_(client) {} |     : ComponentIterator(server), client_(client) {} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -20,7 +20,7 @@ class InitialStateIterator : public ComponentIterator { | |||||||
|   bool on_cover(cover::Cover *cover) override; |   bool on_cover(cover::Cover *cover) override; | ||||||
| #endif | #endif | ||||||
| #ifdef USE_FAN | #ifdef USE_FAN | ||||||
|   bool on_fan(fan::FanState *fan) override; |   bool on_fan(fan::Fan *fan) override; | ||||||
| #endif | #endif | ||||||
| #ifdef USE_LIGHT | #ifdef USE_LIGHT | ||||||
|   bool on_light(light::LightState *light) override; |   bool on_light(light::LightState *light) override; | ||||||
| @@ -45,6 +45,9 @@ class InitialStateIterator : public ComponentIterator { | |||||||
| #endif | #endif | ||||||
| #ifdef USE_SELECT | #ifdef USE_SELECT | ||||||
|   bool on_select(select::Select *select) override; |   bool on_select(select::Select *select) override; | ||||||
|  | #endif | ||||||
|  | #ifdef USE_LOCK | ||||||
|  |   bool on_lock(lock::Lock *a_lock) override; | ||||||
| #endif | #endif | ||||||
|  protected: |  protected: | ||||||
|   APIConnection *client_; |   APIConnection *client_; | ||||||
|   | |||||||
| @@ -52,7 +52,7 @@ template<typename... Ts> class UserServiceBase : public UserServiceDescriptor { | |||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   virtual void execute(Ts... x) = 0; |   virtual void execute(Ts... x) = 0; | ||||||
|   template<int... S> void execute_(std::vector<ExecuteServiceArgument> args, seq<S...>) { |   template<int... S> void execute_(std::vector<ExecuteServiceArgument> args, seq<S...> type) { | ||||||
|     this->execute((get_execute_arg_value<Ts>(args[S]))...); |     this->execute((get_execute_arg_value<Ts>(args[S]))...); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -212,6 +212,21 @@ void ComponentIterator::advance() { | |||||||
|         } |         } | ||||||
|       } |       } | ||||||
|       break; |       break; | ||||||
|  | #endif | ||||||
|  | #ifdef USE_LOCK | ||||||
|  |     case IteratorState::LOCK: | ||||||
|  |       if (this->at_ >= App.get_locks().size()) { | ||||||
|  |         advance_platform = true; | ||||||
|  |       } else { | ||||||
|  |         auto *a_lock = App.get_locks()[this->at_]; | ||||||
|  |         if (a_lock->is_internal()) { | ||||||
|  |           success = true; | ||||||
|  |           break; | ||||||
|  |         } else { | ||||||
|  |           success = this->on_lock(a_lock); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       break; | ||||||
| #endif | #endif | ||||||
|     case IteratorState::MAX: |     case IteratorState::MAX: | ||||||
|       if (this->on_end()) { |       if (this->on_end()) { | ||||||
|   | |||||||
| @@ -27,7 +27,7 @@ class ComponentIterator { | |||||||
|   virtual bool on_cover(cover::Cover *cover) = 0; |   virtual bool on_cover(cover::Cover *cover) = 0; | ||||||
| #endif | #endif | ||||||
| #ifdef USE_FAN | #ifdef USE_FAN | ||||||
|   virtual bool on_fan(fan::FanState *fan) = 0; |   virtual bool on_fan(fan::Fan *fan) = 0; | ||||||
| #endif | #endif | ||||||
| #ifdef USE_LIGHT | #ifdef USE_LIGHT | ||||||
|   virtual bool on_light(light::LightState *light) = 0; |   virtual bool on_light(light::LightState *light) = 0; | ||||||
| @@ -56,6 +56,9 @@ class ComponentIterator { | |||||||
| #endif | #endif | ||||||
| #ifdef USE_SELECT | #ifdef USE_SELECT | ||||||
|   virtual bool on_select(select::Select *select) = 0; |   virtual bool on_select(select::Select *select) = 0; | ||||||
|  | #endif | ||||||
|  | #ifdef USE_LOCK | ||||||
|  |   virtual bool on_lock(lock::Lock *a_lock) = 0; | ||||||
| #endif | #endif | ||||||
|   virtual bool on_end(); |   virtual bool on_end(); | ||||||
|  |  | ||||||
| @@ -99,6 +102,9 @@ class ComponentIterator { | |||||||
| #endif | #endif | ||||||
| #ifdef USE_SELECT | #ifdef USE_SELECT | ||||||
|     SELECT, |     SELECT, | ||||||
|  | #endif | ||||||
|  | #ifdef USE_LOCK | ||||||
|  |     LOCK, | ||||||
| #endif | #endif | ||||||
|     MAX, |     MAX, | ||||||
|   } state_{IteratorState::NONE}; |   } state_{IteratorState::NONE}; | ||||||
|   | |||||||
| @@ -58,10 +58,11 @@ void AS3935Component::loop() { | |||||||
|  |  | ||||||
| void AS3935Component::write_indoor(bool indoor) { | void AS3935Component::write_indoor(bool indoor) { | ||||||
|   ESP_LOGV(TAG, "Setting indoor to %d", indoor); |   ESP_LOGV(TAG, "Setting indoor to %d", indoor); | ||||||
|   if (indoor) |   if (indoor) { | ||||||
|     this->write_register(AFE_GAIN, GAIN_MASK, INDOOR, 1); |     this->write_register(AFE_GAIN, GAIN_MASK, INDOOR, 1); | ||||||
|   else |   } else { | ||||||
|     this->write_register(AFE_GAIN, GAIN_MASK, OUTDOOR, 1); |     this->write_register(AFE_GAIN, GAIN_MASK, OUTDOOR, 1); | ||||||
|  |   } | ||||||
| } | } | ||||||
| // REG0x01, bits[3:0], manufacturer default: 0010 (2). | // REG0x01, bits[3:0], manufacturer default: 0010 (2). | ||||||
| // This setting determines the threshold for events that trigger the | // This setting determines the threshold for events that trigger the | ||||||
|   | |||||||
| @@ -97,7 +97,7 @@ void BalluClimate::transmit_state() { | |||||||
|  |  | ||||||
|   // Send code |   // Send code | ||||||
|   auto transmit = this->transmitter_->transmit(); |   auto transmit = this->transmitter_->transmit(); | ||||||
|   auto data = transmit.get_data(); |   auto *data = transmit.get_data(); | ||||||
|  |  | ||||||
|   data->set_carrier_frequency(38000); |   data->set_carrier_frequency(38000); | ||||||
|  |  | ||||||
| @@ -130,10 +130,10 @@ bool BalluClimate::on_receive(remote_base::RemoteReceiveData data) { | |||||||
|   for (int i = 0; i < BALLU_STATE_LENGTH; i++) { |   for (int i = 0; i < BALLU_STATE_LENGTH; i++) { | ||||||
|     // Read bit |     // Read bit | ||||||
|     for (int j = 0; j < 8; j++) { |     for (int j = 0; j < 8; j++) { | ||||||
|       if (data.expect_item(BALLU_BIT_MARK, BALLU_ONE_SPACE)) |       if (data.expect_item(BALLU_BIT_MARK, BALLU_ONE_SPACE)) { | ||||||
|         remote_state[i] |= 1 << j; |         remote_state[i] |= 1 << j; | ||||||
|  |  | ||||||
|       else if (!data.expect_item(BALLU_BIT_MARK, BALLU_ZERO_SPACE)) { |       } else if (!data.expect_item(BALLU_BIT_MARK, BALLU_ZERO_SPACE)) { | ||||||
|         ESP_LOGV(TAG, "Byte %d bit %d fail", i, j); |         ESP_LOGV(TAG, "Byte %d bit %d fail", i, j); | ||||||
|         return false; |         return false; | ||||||
|       } |       } | ||||||
|   | |||||||
| @@ -21,12 +21,13 @@ void BangBangClimate::setup() { | |||||||
|     restore->to_call(this).perform(); |     restore->to_call(this).perform(); | ||||||
|   } else { |   } else { | ||||||
|     // restore from defaults, change_away handles those for us |     // restore from defaults, change_away handles those for us | ||||||
|     if (supports_cool_ && supports_heat_) |     if (supports_cool_ && supports_heat_) { | ||||||
|       this->mode = climate::CLIMATE_MODE_HEAT_COOL; |       this->mode = climate::CLIMATE_MODE_HEAT_COOL; | ||||||
|     else if (supports_cool_) |     } else if (supports_cool_) { | ||||||
|       this->mode = climate::CLIMATE_MODE_COOL; |       this->mode = climate::CLIMATE_MODE_COOL; | ||||||
|     else if (supports_heat_) |     } else if (supports_heat_) { | ||||||
|       this->mode = climate::CLIMATE_MODE_HEAT; |       this->mode = climate::CLIMATE_MODE_HEAT; | ||||||
|  |     } | ||||||
|     this->change_away_(false); |     this->change_away_(false); | ||||||
|   } |   } | ||||||
| } | } | ||||||
| @@ -56,11 +57,12 @@ climate::ClimateTraits BangBangClimate::traits() { | |||||||
|   if (supports_cool_ && supports_heat_) |   if (supports_cool_ && supports_heat_) | ||||||
|     traits.add_supported_mode(climate::CLIMATE_MODE_HEAT_COOL); |     traits.add_supported_mode(climate::CLIMATE_MODE_HEAT_COOL); | ||||||
|   traits.set_supports_two_point_target_temperature(true); |   traits.set_supports_two_point_target_temperature(true); | ||||||
|   if (supports_away_) |   if (supports_away_) { | ||||||
|     traits.set_supported_presets({ |     traits.set_supported_presets({ | ||||||
|         climate::CLIMATE_PRESET_HOME, |         climate::CLIMATE_PRESET_HOME, | ||||||
|         climate::CLIMATE_PRESET_AWAY, |         climate::CLIMATE_PRESET_AWAY, | ||||||
|     }); |     }); | ||||||
|  |   } | ||||||
|   traits.set_supports_action(true); |   traits.set_supports_action(true); | ||||||
|   return traits; |   return traits; | ||||||
| } | } | ||||||
| @@ -82,17 +84,19 @@ void BangBangClimate::compute_state_() { | |||||||
|   if (too_cold) { |   if (too_cold) { | ||||||
|     // too cold -> enable heating if possible and enabled, else idle |     // too cold -> enable heating if possible and enabled, else idle | ||||||
|     if (this->supports_heat_ && |     if (this->supports_heat_ && | ||||||
|         (this->mode == climate::CLIMATE_MODE_HEAT_COOL || this->mode == climate::CLIMATE_MODE_HEAT)) |         (this->mode == climate::CLIMATE_MODE_HEAT_COOL || this->mode == climate::CLIMATE_MODE_HEAT)) { | ||||||
|       target_action = climate::CLIMATE_ACTION_HEATING; |       target_action = climate::CLIMATE_ACTION_HEATING; | ||||||
|     else |     } else { | ||||||
|       target_action = climate::CLIMATE_ACTION_IDLE; |       target_action = climate::CLIMATE_ACTION_IDLE; | ||||||
|  |     } | ||||||
|   } else if (too_hot) { |   } else if (too_hot) { | ||||||
|     // too hot -> enable cooling if possible and enabled, else idle |     // too hot -> enable cooling if possible and enabled, else idle | ||||||
|     if (this->supports_cool_ && |     if (this->supports_cool_ && | ||||||
|         (this->mode == climate::CLIMATE_MODE_HEAT_COOL || this->mode == climate::CLIMATE_MODE_COOL)) |         (this->mode == climate::CLIMATE_MODE_HEAT_COOL || this->mode == climate::CLIMATE_MODE_COOL)) { | ||||||
|       target_action = climate::CLIMATE_ACTION_COOLING; |       target_action = climate::CLIMATE_ACTION_COOLING; | ||||||
|     else |     } else { | ||||||
|       target_action = climate::CLIMATE_ACTION_IDLE; |       target_action = climate::CLIMATE_ACTION_IDLE; | ||||||
|  |     } | ||||||
|   } else { |   } else { | ||||||
|     // neither too hot nor too cold -> in range |     // neither too hot nor too cold -> in range | ||||||
|     if (this->supports_cool_ && this->supports_heat_ && this->mode == climate::CLIMATE_MODE_HEAT_COOL) { |     if (this->supports_cool_ && this->supports_heat_ && this->mode == climate::CLIMATE_MODE_HEAT_COOL) { | ||||||
| @@ -107,9 +111,10 @@ void BangBangClimate::compute_state_() { | |||||||
|   this->switch_to_action_(target_action); |   this->switch_to_action_(target_action); | ||||||
| } | } | ||||||
| void BangBangClimate::switch_to_action_(climate::ClimateAction action) { | void BangBangClimate::switch_to_action_(climate::ClimateAction action) { | ||||||
|   if (action == this->action) |   if (action == this->action) { | ||||||
|     // already in target mode |     // already in target mode | ||||||
|     return; |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|   if ((action == climate::CLIMATE_ACTION_OFF && this->action == climate::CLIMATE_ACTION_IDLE) || |   if ((action == climate::CLIMATE_ACTION_OFF && this->action == climate::CLIMATE_ACTION_IDLE) || | ||||||
|       (action == climate::CLIMATE_ACTION_IDLE && this->action == climate::CLIMATE_ACTION_OFF)) { |       (action == climate::CLIMATE_ACTION_IDLE && this->action == climate::CLIMATE_ACTION_OFF)) { | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ from esphome.const import ( | |||||||
| ) | ) | ||||||
| from .. import binary_ns | from .. import binary_ns | ||||||
|  |  | ||||||
| BinaryFan = binary_ns.class_("BinaryFan", cg.Component) | BinaryFan = binary_ns.class_("BinaryFan", fan.Fan, cg.Component) | ||||||
|  |  | ||||||
| CONFIG_SCHEMA = fan.FAN_SCHEMA.extend( | CONFIG_SCHEMA = fan.FAN_SCHEMA.extend( | ||||||
|     { |     { | ||||||
| @@ -24,9 +24,8 @@ CONFIG_SCHEMA = fan.FAN_SCHEMA.extend( | |||||||
| async def to_code(config): | async def to_code(config): | ||||||
|     var = cg.new_Pvariable(config[CONF_OUTPUT_ID]) |     var = cg.new_Pvariable(config[CONF_OUTPUT_ID]) | ||||||
|     await cg.register_component(var, config) |     await cg.register_component(var, config) | ||||||
|  |     await fan.register_fan(var, config) | ||||||
|  |  | ||||||
|     fan_ = await fan.create_fan_state(config) |  | ||||||
|     cg.add(var.set_fan(fan_)) |  | ||||||
|     output_ = await cg.get_variable(config[CONF_OUTPUT]) |     output_ = await cg.get_variable(config[CONF_OUTPUT]) | ||||||
|     cg.add(var.set_output(output_)) |     cg.add(var.set_output(output_)) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,59 +6,35 @@ namespace binary { | |||||||
|  |  | ||||||
| static const char *const TAG = "binary.fan"; | static const char *const TAG = "binary.fan"; | ||||||
|  |  | ||||||
| void binary::BinaryFan::dump_config() { |  | ||||||
|   ESP_LOGCONFIG(TAG, "Fan '%s':", this->fan_->get_name().c_str()); |  | ||||||
|   if (this->fan_->get_traits().supports_oscillation()) { |  | ||||||
|     ESP_LOGCONFIG(TAG, "  Oscillation: YES"); |  | ||||||
|   } |  | ||||||
|   if (this->fan_->get_traits().supports_direction()) { |  | ||||||
|     ESP_LOGCONFIG(TAG, "  Direction: YES"); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| void BinaryFan::setup() { | void BinaryFan::setup() { | ||||||
|   auto traits = fan::FanTraits(this->oscillating_ != nullptr, false, this->direction_ != nullptr, 0); |   auto restore = this->restore_state_(); | ||||||
|   this->fan_->set_traits(traits); |   if (restore.has_value()) { | ||||||
|   this->fan_->add_on_state_callback([this]() { this->next_update_ = true; }); |     restore->apply(*this); | ||||||
| } |     this->write_state_(); | ||||||
| void BinaryFan::loop() { |  | ||||||
|   if (!this->next_update_) { |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   this->next_update_ = false; |  | ||||||
|  |  | ||||||
|   { |  | ||||||
|     bool enable = this->fan_->state; |  | ||||||
|     if (enable) |  | ||||||
|       this->output_->turn_on(); |  | ||||||
|     else |  | ||||||
|       this->output_->turn_off(); |  | ||||||
|     ESP_LOGD(TAG, "Setting binary state: %s", ONOFF(enable)); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   if (this->oscillating_ != nullptr) { |  | ||||||
|     bool enable = this->fan_->oscillating; |  | ||||||
|     if (enable) { |  | ||||||
|       this->oscillating_->turn_on(); |  | ||||||
|     } else { |  | ||||||
|       this->oscillating_->turn_off(); |  | ||||||
|     } |  | ||||||
|     ESP_LOGD(TAG, "Setting oscillation: %s", ONOFF(enable)); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   if (this->direction_ != nullptr) { |  | ||||||
|     bool enable = this->fan_->direction == fan::FAN_DIRECTION_REVERSE; |  | ||||||
|     if (enable) { |  | ||||||
|       this->direction_->turn_on(); |  | ||||||
|     } else { |  | ||||||
|       this->direction_->turn_off(); |  | ||||||
|     } |  | ||||||
|     ESP_LOGD(TAG, "Setting reverse direction: %s", ONOFF(enable)); |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | void BinaryFan::dump_config() { LOG_FAN("", "Binary Fan", this); } | ||||||
|  | fan::FanTraits BinaryFan::get_traits() { | ||||||
|  |   return fan::FanTraits(this->oscillating_ != nullptr, false, this->direction_ != nullptr, 0); | ||||||
|  | } | ||||||
|  | void BinaryFan::control(const fan::FanCall &call) { | ||||||
|  |   if (call.get_state().has_value()) | ||||||
|  |     this->state = *call.get_state(); | ||||||
|  |   if (call.get_oscillating().has_value()) | ||||||
|  |     this->oscillating = *call.get_oscillating(); | ||||||
|  |   if (call.get_direction().has_value()) | ||||||
|  |     this->direction = *call.get_direction(); | ||||||
|  |  | ||||||
| // We need a higher priority than the FanState component to make sure that the traits are set |   this->write_state_(); | ||||||
| // when that component sets itself up. |   this->publish_state(); | ||||||
| float BinaryFan::get_setup_priority() const { return fan_->get_setup_priority() + 1.0f; } | } | ||||||
|  | void BinaryFan::write_state_() { | ||||||
|  |   this->output_->set_state(this->state); | ||||||
|  |   if (this->oscillating_ != nullptr) | ||||||
|  |     this->oscillating_->set_state(this->oscillating); | ||||||
|  |   if (this->direction_ != nullptr) | ||||||
|  |     this->direction_->set_state(this->direction == fan::FanDirection::REVERSE); | ||||||
|  | } | ||||||
|  |  | ||||||
| }  // namespace binary | }  // namespace binary | ||||||
| }  // namespace esphome | }  // namespace esphome | ||||||
|   | |||||||
| @@ -2,28 +2,29 @@ | |||||||
|  |  | ||||||
| #include "esphome/core/component.h" | #include "esphome/core/component.h" | ||||||
| #include "esphome/components/output/binary_output.h" | #include "esphome/components/output/binary_output.h" | ||||||
| #include "esphome/components/fan/fan_state.h" | #include "esphome/components/fan/fan.h" | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace binary { | namespace binary { | ||||||
|  |  | ||||||
| class BinaryFan : public Component { | class BinaryFan : public Component, public fan::Fan { | ||||||
|  public: |  public: | ||||||
|   void set_fan(fan::FanState *fan) { fan_ = fan; } |  | ||||||
|   void set_output(output::BinaryOutput *output) { output_ = output; } |  | ||||||
|   void setup() override; |   void setup() override; | ||||||
|   void loop() override; |  | ||||||
|   void dump_config() override; |   void dump_config() override; | ||||||
|   float get_setup_priority() const override; |  | ||||||
|  |   void set_output(output::BinaryOutput *output) { this->output_ = output; } | ||||||
|   void set_oscillating(output::BinaryOutput *oscillating) { this->oscillating_ = oscillating; } |   void set_oscillating(output::BinaryOutput *oscillating) { this->oscillating_ = oscillating; } | ||||||
|   void set_direction(output::BinaryOutput *direction) { this->direction_ = direction; } |   void set_direction(output::BinaryOutput *direction) { this->direction_ = direction; } | ||||||
|  |  | ||||||
|  |   fan::FanTraits get_traits() override; | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   fan::FanState *fan_; |   void control(const fan::FanCall &call) override; | ||||||
|  |   void write_state_(); | ||||||
|  |  | ||||||
|   output::BinaryOutput *output_; |   output::BinaryOutput *output_; | ||||||
|   output::BinaryOutput *oscillating_{nullptr}; |   output::BinaryOutput *oscillating_{nullptr}; | ||||||
|   output::BinaryOutput *direction_{nullptr}; |   output::BinaryOutput *direction_{nullptr}; | ||||||
|   bool next_update_{true}; |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| }  // namespace binary | }  // namespace binary | ||||||
|   | |||||||
| @@ -65,7 +65,7 @@ void BL0940::update() { | |||||||
| } | } | ||||||
|  |  | ||||||
| void BL0940::setup() { | void BL0940::setup() { | ||||||
|   for (auto i : BL0940_INIT) { |   for (auto *i : BL0940_INIT) { | ||||||
|     this->write_array(i, 6); |     this->write_array(i, 6); | ||||||
|     delay(1); |     delay(1); | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -167,7 +167,7 @@ void BLEClient::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t es | |||||||
|       break; |       break; | ||||||
|     } |     } | ||||||
|     case ESP_GATTC_REG_FOR_NOTIFY_EVT: { |     case ESP_GATTC_REG_FOR_NOTIFY_EVT: { | ||||||
|       auto descr = this->get_config_descriptor(param->reg_for_notify.handle); |       auto *descr = this->get_config_descriptor(param->reg_for_notify.handle); | ||||||
|       if (descr == nullptr) { |       if (descr == nullptr) { | ||||||
|         ESP_LOGW(TAG, "No descriptor found for notify of handle 0x%x", param->reg_for_notify.handle); |         ESP_LOGW(TAG, "No descriptor found for notify of handle 0x%x", param->reg_for_notify.handle); | ||||||
|         break; |         break; | ||||||
| @@ -252,16 +252,17 @@ float BLEClient::parse_char_value(uint8_t *value, uint16_t length) { | |||||||
| } | } | ||||||
|  |  | ||||||
| BLEService *BLEClient::get_service(espbt::ESPBTUUID uuid) { | BLEService *BLEClient::get_service(espbt::ESPBTUUID uuid) { | ||||||
|   for (auto svc : this->services_) |   for (auto *svc : this->services_) { | ||||||
|     if (svc->uuid == uuid) |     if (svc->uuid == uuid) | ||||||
|       return svc; |       return svc; | ||||||
|  |   } | ||||||
|   return nullptr; |   return nullptr; | ||||||
| } | } | ||||||
|  |  | ||||||
| BLEService *BLEClient::get_service(uint16_t uuid) { return this->get_service(espbt::ESPBTUUID::from_uint16(uuid)); } | BLEService *BLEClient::get_service(uint16_t uuid) { return this->get_service(espbt::ESPBTUUID::from_uint16(uuid)); } | ||||||
|  |  | ||||||
| BLECharacteristic *BLEClient::get_characteristic(espbt::ESPBTUUID service, espbt::ESPBTUUID chr) { | BLECharacteristic *BLEClient::get_characteristic(espbt::ESPBTUUID service, espbt::ESPBTUUID chr) { | ||||||
|   auto svc = this->get_service(service); |   auto *svc = this->get_service(service); | ||||||
|   if (svc == nullptr) |   if (svc == nullptr) | ||||||
|     return nullptr; |     return nullptr; | ||||||
|   return svc->get_characteristic(chr); |   return svc->get_characteristic(chr); | ||||||
| @@ -272,19 +273,24 @@ BLECharacteristic *BLEClient::get_characteristic(uint16_t service, uint16_t chr) | |||||||
| } | } | ||||||
|  |  | ||||||
| BLEDescriptor *BLEClient::get_config_descriptor(uint16_t handle) { | BLEDescriptor *BLEClient::get_config_descriptor(uint16_t handle) { | ||||||
|   for (auto &svc : this->services_) |   for (auto &svc : this->services_) { | ||||||
|     for (auto &chr : svc->characteristics) |     for (auto &chr : svc->characteristics) { | ||||||
|       if (chr->handle == handle) |       if (chr->handle == handle) { | ||||||
|         for (auto &desc : chr->descriptors) |         for (auto &desc : chr->descriptors) { | ||||||
|           if (desc->uuid == espbt::ESPBTUUID::from_uint16(0x2902)) |           if (desc->uuid == espbt::ESPBTUUID::from_uint16(0x2902)) | ||||||
|             return desc; |             return desc; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|   return nullptr; |   return nullptr; | ||||||
| } | } | ||||||
|  |  | ||||||
| BLECharacteristic *BLEService::get_characteristic(espbt::ESPBTUUID uuid) { | BLECharacteristic *BLEService::get_characteristic(espbt::ESPBTUUID uuid) { | ||||||
|   for (auto &chr : this->characteristics) |   for (auto &chr : this->characteristics) { | ||||||
|     if (chr->uuid == uuid) |     if (chr->uuid == uuid) | ||||||
|       return chr; |       return chr; | ||||||
|  |   } | ||||||
|   return nullptr; |   return nullptr; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -293,10 +299,10 @@ BLECharacteristic *BLEService::get_characteristic(uint16_t uuid) { | |||||||
| } | } | ||||||
|  |  | ||||||
| BLEDescriptor *BLEClient::get_descriptor(espbt::ESPBTUUID service, espbt::ESPBTUUID chr, espbt::ESPBTUUID descr) { | BLEDescriptor *BLEClient::get_descriptor(espbt::ESPBTUUID service, espbt::ESPBTUUID chr, espbt::ESPBTUUID descr) { | ||||||
|   auto svc = this->get_service(service); |   auto *svc = this->get_service(service); | ||||||
|   if (svc == nullptr) |   if (svc == nullptr) | ||||||
|     return nullptr; |     return nullptr; | ||||||
|   auto ch = svc->get_characteristic(chr); |   auto *ch = svc->get_characteristic(chr); | ||||||
|   if (ch == nullptr) |   if (ch == nullptr) | ||||||
|     return nullptr; |     return nullptr; | ||||||
|   return ch->get_descriptor(descr); |   return ch->get_descriptor(descr); | ||||||
| @@ -379,24 +385,29 @@ void BLECharacteristic::parse_descriptors() { | |||||||
| } | } | ||||||
|  |  | ||||||
| BLEDescriptor *BLECharacteristic::get_descriptor(espbt::ESPBTUUID uuid) { | BLEDescriptor *BLECharacteristic::get_descriptor(espbt::ESPBTUUID uuid) { | ||||||
|   for (auto &desc : this->descriptors) |   for (auto &desc : this->descriptors) { | ||||||
|     if (desc->uuid == uuid) |     if (desc->uuid == uuid) | ||||||
|       return desc; |       return desc; | ||||||
|  |   } | ||||||
|   return nullptr; |   return nullptr; | ||||||
| } | } | ||||||
| BLEDescriptor *BLECharacteristic::get_descriptor(uint16_t uuid) { | BLEDescriptor *BLECharacteristic::get_descriptor(uint16_t uuid) { | ||||||
|   return this->get_descriptor(espbt::ESPBTUUID::from_uint16(uuid)); |   return this->get_descriptor(espbt::ESPBTUUID::from_uint16(uuid)); | ||||||
| } | } | ||||||
|  |  | ||||||
| void BLECharacteristic::write_value(uint8_t *new_val, int16_t new_val_size) { | void BLECharacteristic::write_value(uint8_t *new_val, int16_t new_val_size, esp_gatt_write_type_t write_type) { | ||||||
|   auto client = this->service->client; |   auto *client = this->service->client; | ||||||
|   auto status = esp_ble_gattc_write_char(client->gattc_if, client->conn_id, this->handle, new_val_size, new_val, |   auto status = esp_ble_gattc_write_char(client->gattc_if, client->conn_id, this->handle, new_val_size, new_val, | ||||||
|                                          ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE); |                                          write_type, ESP_GATT_AUTH_REQ_NONE); | ||||||
|   if (status) { |   if (status) { | ||||||
|     ESP_LOGW(TAG, "Error sending write value to BLE gattc server, status=%d", status); |     ESP_LOGW(TAG, "Error sending write value to BLE gattc server, status=%d", status); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void BLECharacteristic::write_value(uint8_t *new_val, int16_t new_val_size) { | ||||||
|  |   write_value(new_val, new_val_size, ESP_GATT_WRITE_TYPE_NO_RSP); | ||||||
|  | } | ||||||
|  |  | ||||||
| }  // namespace ble_client | }  // namespace ble_client | ||||||
| }  // namespace esphome | }  // namespace esphome | ||||||
|  |  | ||||||
|   | |||||||
| @@ -60,6 +60,7 @@ class BLECharacteristic { | |||||||
|   BLEDescriptor *get_descriptor(espbt::ESPBTUUID uuid); |   BLEDescriptor *get_descriptor(espbt::ESPBTUUID uuid); | ||||||
|   BLEDescriptor *get_descriptor(uint16_t uuid); |   BLEDescriptor *get_descriptor(uint16_t uuid); | ||||||
|   void write_value(uint8_t *new_val, int16_t new_val_size); |   void write_value(uint8_t *new_val, int16_t new_val_size); | ||||||
|  |   void write_value(uint8_t *new_val, int16_t new_val_size, esp_gatt_write_type_t write_type); | ||||||
|   BLEService *service; |   BLEService *service; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @@ -126,9 +127,10 @@ class BLEClient : public espbt::ESPBTClient, public Component { | |||||||
|   bool all_nodes_established_() { |   bool all_nodes_established_() { | ||||||
|     if (this->state() != espbt::ClientState::ESTABLISHED) |     if (this->state() != espbt::ClientState::ESTABLISHED) | ||||||
|       return false; |       return false; | ||||||
|     for (auto &node : nodes_) |     for (auto &node : nodes_) { | ||||||
|       if (node->node_state != espbt::ClientState::ESTABLISHED) |       if (node->node_state != espbt::ClientState::ESTABLISHED) | ||||||
|         return false; |         return false; | ||||||
|  |     } | ||||||
|     return true; |     return true; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,13 +1,14 @@ | |||||||
| import esphome.codegen as cg | import esphome.codegen as cg | ||||||
| import esphome.config_validation as cv | import esphome.config_validation as cv | ||||||
| from esphome.components import output, ble_client, esp32_ble_tracker | from esphome.components import ble_client, esp32_ble_tracker, output | ||||||
| from esphome.const import CONF_ID, CONF_SERVICE_UUID | from esphome.const import CONF_ID, CONF_SERVICE_UUID | ||||||
| from .. import ble_client_ns |  | ||||||
|  |  | ||||||
|  | from .. import ble_client_ns | ||||||
|  |  | ||||||
| DEPENDENCIES = ["ble_client"] | DEPENDENCIES = ["ble_client"] | ||||||
|  |  | ||||||
| CONF_CHARACTERISTIC_UUID = "characteristic_uuid" | CONF_CHARACTERISTIC_UUID = "characteristic_uuid" | ||||||
|  | CONF_REQUIRE_RESPONSE = "require_response" | ||||||
|  |  | ||||||
| BLEBinaryOutput = ble_client_ns.class_( | BLEBinaryOutput = ble_client_ns.class_( | ||||||
|     "BLEBinaryOutput", output.BinaryOutput, ble_client.BLEClientNode, cg.Component |     "BLEBinaryOutput", output.BinaryOutput, ble_client.BLEClientNode, cg.Component | ||||||
| @@ -19,6 +20,7 @@ CONFIG_SCHEMA = cv.All( | |||||||
|             cv.Required(CONF_ID): cv.declare_id(BLEBinaryOutput), |             cv.Required(CONF_ID): cv.declare_id(BLEBinaryOutput), | ||||||
|             cv.Required(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid, |             cv.Required(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid, | ||||||
|             cv.Required(CONF_CHARACTERISTIC_UUID): esp32_ble_tracker.bt_uuid, |             cv.Required(CONF_CHARACTERISTIC_UUID): esp32_ble_tracker.bt_uuid, | ||||||
|  |             cv.Optional(CONF_REQUIRE_RESPONSE, default=False): cv.boolean, | ||||||
|         } |         } | ||||||
|     ) |     ) | ||||||
|     .extend(cv.COMPONENT_SCHEMA) |     .extend(cv.COMPONENT_SCHEMA) | ||||||
| @@ -61,7 +63,7 @@ def to_code(config): | |||||||
|             config[CONF_CHARACTERISTIC_UUID] |             config[CONF_CHARACTERISTIC_UUID] | ||||||
|         ) |         ) | ||||||
|         cg.add(var.set_char_uuid128(uuid128)) |         cg.add(var.set_char_uuid128(uuid128)) | ||||||
|  |     cg.add(var.set_require_response(config[CONF_REQUIRE_RESPONSE])) | ||||||
|     yield output.register_output(var, config) |     yield output.register_output(var, config) | ||||||
|     yield ble_client.register_ble_node(var, config) |     yield ble_client.register_ble_node(var, config) | ||||||
|     yield cg.register_component(var, config) |     yield cg.register_component(var, config) | ||||||
|   | |||||||
| @@ -32,7 +32,7 @@ void BLEBinaryOutput::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_i | |||||||
|         break; |         break; | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       auto chr = this->parent()->get_characteristic(this->service_uuid_, this->char_uuid_); |       auto *chr = this->parent()->get_characteristic(this->service_uuid_, this->char_uuid_); | ||||||
|       if (chr == nullptr) { |       if (chr == nullptr) { | ||||||
|         ESP_LOGW(TAG, "[%s] Characteristic not found.", this->char_uuid_.to_string().c_str()); |         ESP_LOGW(TAG, "[%s] Characteristic not found.", this->char_uuid_.to_string().c_str()); | ||||||
|         break; |         break; | ||||||
| @@ -54,7 +54,7 @@ void BLEBinaryOutput::write_state(bool state) { | |||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   auto chr = this->parent()->get_characteristic(this->service_uuid_, this->char_uuid_); |   auto *chr = this->parent()->get_characteristic(this->service_uuid_, this->char_uuid_); | ||||||
|   if (chr == nullptr) { |   if (chr == nullptr) { | ||||||
|     ESP_LOGW(TAG, "[%s] Characteristic not found.  State update can not be written.", |     ESP_LOGW(TAG, "[%s] Characteristic not found.  State update can not be written.", | ||||||
|              this->char_uuid_.to_string().c_str()); |              this->char_uuid_.to_string().c_str()); | ||||||
| @@ -63,7 +63,11 @@ void BLEBinaryOutput::write_state(bool state) { | |||||||
|  |  | ||||||
|   uint8_t state_as_uint = (uint8_t) state; |   uint8_t state_as_uint = (uint8_t) state; | ||||||
|   ESP_LOGV(TAG, "[%s] Write State: %d", this->char_uuid_.to_string().c_str(), state_as_uint); |   ESP_LOGV(TAG, "[%s] Write State: %d", this->char_uuid_.to_string().c_str(), state_as_uint); | ||||||
|   chr->write_value(&state_as_uint, sizeof(state_as_uint)); |   if (this->require_response_) { | ||||||
|  |     chr->write_value(&state_as_uint, sizeof(state_as_uint), ESP_GATT_WRITE_TYPE_RSP); | ||||||
|  |   } else { | ||||||
|  |     chr->write_value(&state_as_uint, sizeof(state_as_uint), ESP_GATT_WRITE_TYPE_NO_RSP); | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| }  // namespace ble_client | }  // namespace ble_client | ||||||
|   | |||||||
| @@ -25,9 +25,11 @@ class BLEBinaryOutput : public output::BinaryOutput, public BLEClientNode, publi | |||||||
|   void set_char_uuid128(uint8_t *uuid) { this->char_uuid_ = espbt::ESPBTUUID::from_raw(uuid); } |   void set_char_uuid128(uint8_t *uuid) { this->char_uuid_ = espbt::ESPBTUUID::from_raw(uuid); } | ||||||
|   void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, |   void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, | ||||||
|                            esp_ble_gattc_cb_param_t *param) override; |                            esp_ble_gattc_cb_param_t *param) override; | ||||||
|  |   void set_require_response(bool response) { this->require_response_ = response; } | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   void write_state(bool state) override; |   void write_state(bool state) override; | ||||||
|  |   bool require_response_; | ||||||
|   espbt::ESPBTUUID service_uuid_; |   espbt::ESPBTUUID service_uuid_; | ||||||
|   espbt::ESPBTUUID char_uuid_; |   espbt::ESPBTUUID char_uuid_; | ||||||
|   espbt::ClientState client_state_; |   espbt::ClientState client_state_; | ||||||
|   | |||||||
| @@ -43,7 +43,7 @@ void BLESensor::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t ga | |||||||
|     } |     } | ||||||
|     case ESP_GATTC_SEARCH_CMPL_EVT: { |     case ESP_GATTC_SEARCH_CMPL_EVT: { | ||||||
|       this->handle = 0; |       this->handle = 0; | ||||||
|       auto chr = this->parent()->get_characteristic(this->service_uuid_, this->char_uuid_); |       auto *chr = this->parent()->get_characteristic(this->service_uuid_, this->char_uuid_); | ||||||
|       if (chr == nullptr) { |       if (chr == nullptr) { | ||||||
|         this->status_set_warning(); |         this->status_set_warning(); | ||||||
|         this->publish_state(NAN); |         this->publish_state(NAN); | ||||||
| @@ -53,7 +53,7 @@ void BLESensor::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t ga | |||||||
|       } |       } | ||||||
|       this->handle = chr->handle; |       this->handle = chr->handle; | ||||||
|       if (this->descr_uuid_.get_uuid().len > 0) { |       if (this->descr_uuid_.get_uuid().len > 0) { | ||||||
|         auto descr = chr->get_descriptor(this->descr_uuid_); |         auto *descr = chr->get_descriptor(this->descr_uuid_); | ||||||
|         if (descr == nullptr) { |         if (descr == nullptr) { | ||||||
|           this->status_set_warning(); |           this->status_set_warning(); | ||||||
|           this->publish_state(NAN); |           this->publish_state(NAN); | ||||||
|   | |||||||
| @@ -1,7 +1,6 @@ | |||||||
| import esphome.codegen as cg | import esphome.codegen as cg | ||||||
| import esphome.config_validation as cv | import esphome.config_validation as cv | ||||||
| from esphome.components import text_sensor, esp32_ble_tracker | from esphome.components import text_sensor, esp32_ble_tracker | ||||||
| from esphome.const import CONF_ID |  | ||||||
|  |  | ||||||
| DEPENDENCIES = ["esp32_ble_tracker"] | DEPENDENCIES = ["esp32_ble_tracker"] | ||||||
|  |  | ||||||
| @@ -14,18 +13,13 @@ BLEScanner = ble_scanner_ns.class_( | |||||||
| ) | ) | ||||||
|  |  | ||||||
| CONFIG_SCHEMA = cv.All( | CONFIG_SCHEMA = cv.All( | ||||||
|     text_sensor.TEXT_SENSOR_SCHEMA.extend( |     text_sensor.text_sensor_schema(klass=BLEScanner) | ||||||
|         { |  | ||||||
|             cv.GenerateID(): cv.declare_id(BLEScanner), |  | ||||||
|         } |  | ||||||
|     ) |  | ||||||
|     .extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA) |     .extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA) | ||||||
|     .extend(cv.COMPONENT_SCHEMA) |     .extend(cv.COMPONENT_SCHEMA) | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  |  | ||||||
| async def to_code(config): | async def to_code(config): | ||||||
|     var = cg.new_Pvariable(config[CONF_ID]) |     var = await text_sensor.new_text_sensor(config) | ||||||
|     await cg.register_component(var, config) |     await cg.register_component(var, config) | ||||||
|     await esp32_ble_tracker.register_ble_device(var, config) |     await esp32_ble_tracker.register_ble_device(var, config) | ||||||
|     await text_sensor.register_text_sensor(var, config) |  | ||||||
|   | |||||||
| @@ -214,9 +214,10 @@ void BME280Component::update() { | |||||||
| float BME280Component::read_temperature_(const uint8_t *data, int32_t *t_fine) { | float BME280Component::read_temperature_(const uint8_t *data, int32_t *t_fine) { | ||||||
|   int32_t adc = ((data[3] & 0xFF) << 16) | ((data[4] & 0xFF) << 8) | (data[5] & 0xFF); |   int32_t adc = ((data[3] & 0xFF) << 16) | ((data[4] & 0xFF) << 8) | (data[5] & 0xFF); | ||||||
|   adc >>= 4; |   adc >>= 4; | ||||||
|   if (adc == 0x80000) |   if (adc == 0x80000) { | ||||||
|     // temperature was disabled |     // temperature was disabled | ||||||
|     return NAN; |     return NAN; | ||||||
|  |   } | ||||||
|  |  | ||||||
|   const int32_t t1 = this->calibration_.t1; |   const int32_t t1 = this->calibration_.t1; | ||||||
|   const int32_t t2 = this->calibration_.t2; |   const int32_t t2 = this->calibration_.t2; | ||||||
| @@ -233,9 +234,10 @@ float BME280Component::read_temperature_(const uint8_t *data, int32_t *t_fine) { | |||||||
| float BME280Component::read_pressure_(const uint8_t *data, int32_t t_fine) { | float BME280Component::read_pressure_(const uint8_t *data, int32_t t_fine) { | ||||||
|   int32_t adc = ((data[0] & 0xFF) << 16) | ((data[1] & 0xFF) << 8) | (data[2] & 0xFF); |   int32_t adc = ((data[0] & 0xFF) << 16) | ((data[1] & 0xFF) << 8) | (data[2] & 0xFF); | ||||||
|   adc >>= 4; |   adc >>= 4; | ||||||
|   if (adc == 0x80000) |   if (adc == 0x80000) { | ||||||
|     // pressure was disabled |     // pressure was disabled | ||||||
|     return NAN; |     return NAN; | ||||||
|  |   } | ||||||
|   const int64_t p1 = this->calibration_.p1; |   const int64_t p1 = this->calibration_.p1; | ||||||
|   const int64_t p2 = this->calibration_.p2; |   const int64_t p2 = this->calibration_.p2; | ||||||
|   const int64_t p3 = this->calibration_.p3; |   const int64_t p3 = this->calibration_.p3; | ||||||
|   | |||||||
| @@ -95,7 +95,7 @@ void BME680Component::setup() { | |||||||
|   this->calibration_.t3 = cal1[3]; |   this->calibration_.t3 = cal1[3]; | ||||||
|  |  | ||||||
|   this->calibration_.h1 = cal2[2] << 4 | (cal2[1] & 0x0F); |   this->calibration_.h1 = cal2[2] << 4 | (cal2[1] & 0x0F); | ||||||
|   this->calibration_.h2 = cal2[0] << 4 | cal2[1]; |   this->calibration_.h2 = cal2[0] << 4 | cal2[1] >> 4; | ||||||
|   this->calibration_.h3 = cal2[3]; |   this->calibration_.h3 = cal2[3]; | ||||||
|   this->calibration_.h4 = cal2[4]; |   this->calibration_.h4 = cal2[4]; | ||||||
|   this->calibration_.h5 = cal2[5]; |   this->calibration_.h5 = cal2[5]; | ||||||
| @@ -420,10 +420,11 @@ float BME680Component::calc_humidity_(uint16_t raw_humidity) { | |||||||
|  |  | ||||||
|   calc_hum = var2 + (var3 + var4 * temp_comp) * var2 * var2; |   calc_hum = var2 + (var3 + var4 * temp_comp) * var2 * var2; | ||||||
|  |  | ||||||
|   if (calc_hum > 100.0f) |   if (calc_hum > 100.0f) { | ||||||
|     calc_hum = 100.0f; |     calc_hum = 100.0f; | ||||||
|   else if (calc_hum < 0.0f) |   } else if (calc_hum < 0.0f) { | ||||||
|     calc_hum = 0.0f; |     calc_hum = 0.0f; | ||||||
|  |   } | ||||||
|  |  | ||||||
|   return calc_hum; |   return calc_hum; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,7 +1,6 @@ | |||||||
| import esphome.codegen as cg | import esphome.codegen as cg | ||||||
| import esphome.config_validation as cv | import esphome.config_validation as cv | ||||||
| from esphome.components import text_sensor | from esphome.components import text_sensor | ||||||
| from esphome.const import CONF_ID, CONF_ICON |  | ||||||
| from . import BME680BSECComponent, CONF_BME680_BSEC_ID | from . import BME680BSECComponent, CONF_BME680_BSEC_ID | ||||||
|  |  | ||||||
| DEPENDENCIES = ["bme680_bsec"] | DEPENDENCIES = ["bme680_bsec"] | ||||||
| @@ -14,11 +13,8 @@ TYPES = [CONF_IAQ_ACCURACY] | |||||||
| CONFIG_SCHEMA = cv.Schema( | CONFIG_SCHEMA = cv.Schema( | ||||||
|     { |     { | ||||||
|         cv.GenerateID(CONF_BME680_BSEC_ID): cv.use_id(BME680BSECComponent), |         cv.GenerateID(CONF_BME680_BSEC_ID): cv.use_id(BME680BSECComponent), | ||||||
|         cv.Optional(CONF_IAQ_ACCURACY): text_sensor.TEXT_SENSOR_SCHEMA.extend( |         cv.Optional(CONF_IAQ_ACCURACY): text_sensor.text_sensor_schema( | ||||||
|             { |             icon=ICON_ACCURACY | ||||||
|                 cv.GenerateID(): cv.declare_id(text_sensor.TextSensor), |  | ||||||
|                 cv.Optional(CONF_ICON, default=ICON_ACCURACY): cv.icon, |  | ||||||
|             } |  | ||||||
|         ), |         ), | ||||||
|     } |     } | ||||||
| ) | ) | ||||||
| @@ -27,8 +23,7 @@ CONFIG_SCHEMA = cv.Schema( | |||||||
| async def setup_conf(config, key, hub): | async def setup_conf(config, key, hub): | ||||||
|     if key in config: |     if key in config: | ||||||
|         conf = config[key] |         conf = config[key] | ||||||
|         sens = cg.new_Pvariable(conf[CONF_ID]) |         sens = await text_sensor.new_text_sensor(conf) | ||||||
|         await text_sensor.register_text_sensor(sens, conf) |  | ||||||
|         cg.add(getattr(hub, f"set_{key}_text_sensor")(sens)) |         cg.add(getattr(hub, f"set_{key}_text_sensor")(sens)) | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -161,9 +161,10 @@ float BMP280Component::read_temperature_(int32_t *t_fine) { | |||||||
|     return NAN; |     return NAN; | ||||||
|   int32_t adc = ((data[0] & 0xFF) << 16) | ((data[1] & 0xFF) << 8) | (data[2] & 0xFF); |   int32_t adc = ((data[0] & 0xFF) << 16) | ((data[1] & 0xFF) << 8) | (data[2] & 0xFF); | ||||||
|   adc >>= 4; |   adc >>= 4; | ||||||
|   if (adc == 0x80000) |   if (adc == 0x80000) { | ||||||
|     // temperature was disabled |     // temperature was disabled | ||||||
|     return NAN; |     return NAN; | ||||||
|  |   } | ||||||
|  |  | ||||||
|   const int32_t t1 = this->calibration_.t1; |   const int32_t t1 = this->calibration_.t1; | ||||||
|   const int32_t t2 = this->calibration_.t2; |   const int32_t t2 = this->calibration_.t2; | ||||||
| @@ -183,9 +184,10 @@ float BMP280Component::read_pressure_(int32_t t_fine) { | |||||||
|     return NAN; |     return NAN; | ||||||
|   int32_t adc = ((data[0] & 0xFF) << 16) | ((data[1] & 0xFF) << 8) | (data[2] & 0xFF); |   int32_t adc = ((data[0] & 0xFF) << 16) | ((data[1] & 0xFF) << 8) | (data[2] & 0xFF); | ||||||
|   adc >>= 4; |   adc >>= 4; | ||||||
|   if (adc == 0x80000) |   if (adc == 0x80000) { | ||||||
|     // pressure was disabled |     // pressure was disabled | ||||||
|     return NAN; |     return NAN; | ||||||
|  |   } | ||||||
|   const int64_t p1 = this->calibration_.p1; |   const int64_t p1 = this->calibration_.p1; | ||||||
|   const int64_t p2 = this->calibration_.p2; |   const int64_t p2 = this->calibration_.p2; | ||||||
|   const int64_t p3 = this->calibration_.p3; |   const int64_t p3 = this->calibration_.p3; | ||||||
|   | |||||||
| @@ -14,10 +14,14 @@ CONF_BIT_RATE = "bit_rate" | |||||||
| CONF_ON_FRAME = "on_frame" | CONF_ON_FRAME = "on_frame" | ||||||
|  |  | ||||||
|  |  | ||||||
| def validate_id(id_value, id_ext): | def validate_id(config): | ||||||
|     if not id_ext: |     if CONF_CAN_ID in config: | ||||||
|         if id_value > 0x7FF: |         id_value = config[CONF_CAN_ID] | ||||||
|             raise cv.Invalid("Standard IDs must be 11 Bit (0x000-0x7ff / 0-2047)") |         id_ext = config[CONF_USE_EXTENDED_ID] | ||||||
|  |         if not id_ext: | ||||||
|  |             if id_value > 0x7FF: | ||||||
|  |                 raise cv.Invalid("Standard IDs must be 11 Bit (0x000-0x7ff / 0-2047)") | ||||||
|  |     return config | ||||||
|  |  | ||||||
|  |  | ||||||
| def validate_raw_data(value): | def validate_raw_data(value): | ||||||
| @@ -67,23 +71,18 @@ CANBUS_SCHEMA = cv.Schema( | |||||||
|         cv.Optional(CONF_ON_FRAME): automation.validate_automation( |         cv.Optional(CONF_ON_FRAME): automation.validate_automation( | ||||||
|             { |             { | ||||||
|                 cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(CanbusTrigger), |                 cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(CanbusTrigger), | ||||||
|                 cv.GenerateID(CONF_CAN_ID): cv.int_range(min=0, max=0x1FFFFFFF), |                 cv.Required(CONF_CAN_ID): cv.int_range(min=0, max=0x1FFFFFFF), | ||||||
|                 cv.Optional(CONF_USE_EXTENDED_ID, default=False): cv.boolean, |                 cv.Optional(CONF_USE_EXTENDED_ID, default=False): cv.boolean, | ||||||
|                 cv.Optional(CONF_ON_FRAME): automation.validate_automation( |             }, | ||||||
|                     { |             validate_id, | ||||||
|                         cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(CanbusTrigger), |  | ||||||
|                         cv.GenerateID(CONF_CAN_ID): cv.int_range(min=0, max=0x1FFFFFFF), |  | ||||||
|                         cv.Optional(CONF_USE_EXTENDED_ID, default=False): cv.boolean, |  | ||||||
|                     } |  | ||||||
|                 ), |  | ||||||
|             } |  | ||||||
|         ), |         ), | ||||||
|     } |     }, | ||||||
| ).extend(cv.COMPONENT_SCHEMA) | ).extend(cv.COMPONENT_SCHEMA) | ||||||
|  |  | ||||||
|  | CANBUS_SCHEMA.add_extra(validate_id) | ||||||
|  |  | ||||||
|  |  | ||||||
| async def setup_canbus_core_(var, config): | async def setup_canbus_core_(var, config): | ||||||
|     validate_id(config[CONF_CAN_ID], config[CONF_USE_EXTENDED_ID]) |  | ||||||
|     await cg.register_component(var, config) |     await cg.register_component(var, config) | ||||||
|     cg.add(var.set_can_id([config[CONF_CAN_ID]])) |     cg.add(var.set_can_id([config[CONF_CAN_ID]])) | ||||||
|     cg.add(var.set_use_extended_id([config[CONF_USE_EXTENDED_ID]])) |     cg.add(var.set_use_extended_id([config[CONF_USE_EXTENDED_ID]])) | ||||||
| @@ -92,7 +91,6 @@ async def setup_canbus_core_(var, config): | |||||||
|     for conf in config.get(CONF_ON_FRAME, []): |     for conf in config.get(CONF_ON_FRAME, []): | ||||||
|         can_id = conf[CONF_CAN_ID] |         can_id = conf[CONF_CAN_ID] | ||||||
|         ext_id = conf[CONF_USE_EXTENDED_ID] |         ext_id = conf[CONF_USE_EXTENDED_ID] | ||||||
|         validate_id(can_id, ext_id) |  | ||||||
|         trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var, can_id, ext_id) |         trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var, can_id, ext_id) | ||||||
|         await cg.register_component(trigger, conf) |         await cg.register_component(trigger, conf) | ||||||
|         await automation.build_automation( |         await automation.build_automation( | ||||||
| @@ -117,11 +115,11 @@ async def register_canbus(var, config): | |||||||
|             cv.Optional(CONF_USE_EXTENDED_ID, default=False): cv.boolean, |             cv.Optional(CONF_USE_EXTENDED_ID, default=False): cv.boolean, | ||||||
|             cv.Required(CONF_DATA): cv.templatable(validate_raw_data), |             cv.Required(CONF_DATA): cv.templatable(validate_raw_data), | ||||||
|         }, |         }, | ||||||
|  |         validate_id, | ||||||
|         key=CONF_DATA, |         key=CONF_DATA, | ||||||
|     ), |     ), | ||||||
| ) | ) | ||||||
| async def canbus_action_to_code(config, action_id, template_arg, args): | async def canbus_action_to_code(config, action_id, template_arg, args): | ||||||
|     validate_id(config[CONF_CAN_ID], config[CONF_USE_EXTENDED_ID]) |  | ||||||
|     var = cg.new_Pvariable(action_id, template_arg) |     var = cg.new_Pvariable(action_id, template_arg) | ||||||
|     await cg.register_parented(var, config[CONF_CANBUS_ID]) |     await cg.register_parented(var, config[CONF_CANBUS_ID]) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -75,7 +75,7 @@ void Canbus::loop() { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     // fire all triggers |     // fire all triggers | ||||||
|     for (auto trigger : this->triggers_) { |     for (auto *trigger : this->triggers_) { | ||||||
|       if ((trigger->can_id_ == can_message.can_id) && (trigger->use_extended_id_ == can_message.use_extended_id)) { |       if ((trigger->can_id_ == can_message.can_id) && (trigger->use_extended_id_ == can_message.use_extended_id)) { | ||||||
|         trigger->trigger(data); |         trigger->trigger(data); | ||||||
|       } |       } | ||||||
|   | |||||||
| @@ -39,14 +39,15 @@ void CCS811Component::setup() { | |||||||
|   // set MEAS_MODE (page 5) |   // set MEAS_MODE (page 5) | ||||||
|   uint8_t meas_mode = 0; |   uint8_t meas_mode = 0; | ||||||
|   uint32_t interval = this->get_update_interval(); |   uint32_t interval = this->get_update_interval(); | ||||||
|   if (interval >= 60 * 1000) |   if (interval >= 60 * 1000) { | ||||||
|     meas_mode = 3 << 4;  // sensor takes a reading every 60 seconds |     meas_mode = 3 << 4;  // sensor takes a reading every 60 seconds | ||||||
|   else if (interval >= 10 * 1000) |   } else if (interval >= 10 * 1000) { | ||||||
|     meas_mode = 2 << 4;  // sensor takes a reading every 10 seconds |     meas_mode = 2 << 4;  // sensor takes a reading every 10 seconds | ||||||
|   else if (interval >= 1 * 1000) |   } else if (interval >= 1 * 1000) { | ||||||
|     meas_mode = 1 << 4;  // sensor takes a reading every second |     meas_mode = 1 << 4;  // sensor takes a reading every second | ||||||
|   else |   } else { | ||||||
|     meas_mode = 4 << 4;  // sensor takes a reading every 250ms |     meas_mode = 4 << 4;  // sensor takes a reading every 250ms | ||||||
|  |   } | ||||||
|  |  | ||||||
|   CHECKED_IO(this->write_byte(0x01, meas_mode)) |   CHECKED_IO(this->write_byte(0x01, meas_mode)) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,7 +2,6 @@ import esphome.codegen as cg | |||||||
| import esphome.config_validation as cv | import esphome.config_validation as cv | ||||||
| from esphome.components import i2c, sensor, text_sensor | from esphome.components import i2c, sensor, text_sensor | ||||||
| from esphome.const import ( | from esphome.const import ( | ||||||
|     CONF_ICON, |  | ||||||
|     CONF_ID, |     CONF_ID, | ||||||
|     ICON_RADIATOR, |     ICON_RADIATOR, | ||||||
|     ICON_RESTART, |     ICON_RESTART, | ||||||
| @@ -47,11 +46,8 @@ CONFIG_SCHEMA = ( | |||||||
|                 device_class=DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS, |                 device_class=DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS, | ||||||
|                 state_class=STATE_CLASS_MEASUREMENT, |                 state_class=STATE_CLASS_MEASUREMENT, | ||||||
|             ), |             ), | ||||||
|             cv.Optional(CONF_VERSION): text_sensor.TEXT_SENSOR_SCHEMA.extend( |             cv.Optional(CONF_VERSION): text_sensor.text_sensor_schema( | ||||||
|                 { |                 icon=ICON_RESTART | ||||||
|                     cv.GenerateID(): cv.declare_id(text_sensor.TextSensor), |  | ||||||
|                     cv.Optional(CONF_ICON, default=ICON_RESTART): cv.icon, |  | ||||||
|                 } |  | ||||||
|             ), |             ), | ||||||
|             cv.Optional(CONF_BASELINE): cv.hex_uint16_t, |             cv.Optional(CONF_BASELINE): cv.hex_uint16_t, | ||||||
|             cv.Optional(CONF_TEMPERATURE): cv.use_id(sensor.Sensor), |             cv.Optional(CONF_TEMPERATURE): cv.use_id(sensor.Sensor), | ||||||
| @@ -74,8 +70,7 @@ async def to_code(config): | |||||||
|     cg.add(var.set_tvoc(sens)) |     cg.add(var.set_tvoc(sens)) | ||||||
|  |  | ||||||
|     if CONF_VERSION in config: |     if CONF_VERSION in config: | ||||||
|         sens = cg.new_Pvariable(config[CONF_VERSION][CONF_ID]) |         sens = await text_sensor.new_text_sensor(config[CONF_VERSION]) | ||||||
|         await text_sensor.register_text_sensor(sens, config[CONF_VERSION]) |  | ||||||
|         cg.add(var.set_version(sens)) |         cg.add(var.set_version(sens)) | ||||||
|  |  | ||||||
|     if CONF_BASELINE in config: |     if CONF_BASELINE in config: | ||||||
|   | |||||||
| @@ -6,8 +6,9 @@ from esphome.const import ( | |||||||
|     CONF_ID, |     CONF_ID, | ||||||
| ) | ) | ||||||
|  |  | ||||||
| CODEOWNERS = ["@asoehlke"] |  | ||||||
| AUTO_LOAD = ["sensor", "voltage_sampler"] | AUTO_LOAD = ["sensor", "voltage_sampler"] | ||||||
|  | CODEOWNERS = ["@asoehlke"] | ||||||
|  | MULTI_CONF = True | ||||||
|  |  | ||||||
| cd74hc4067_ns = cg.esphome_ns.namespace("cd74hc4067") | cd74hc4067_ns = cg.esphome_ns.namespace("cd74hc4067") | ||||||
|  |  | ||||||
|   | |||||||
| @@ -65,7 +65,7 @@ class ClimateTraits { | |||||||
|   ESPDEPRECATED("This method is deprecated, use set_supported_modes() instead", "v1.20") |   ESPDEPRECATED("This method is deprecated, use set_supported_modes() instead", "v1.20") | ||||||
|   void set_supports_dry_mode(bool supports_dry_mode) { set_mode_support_(CLIMATE_MODE_DRY, supports_dry_mode); } |   void set_supports_dry_mode(bool supports_dry_mode) { set_mode_support_(CLIMATE_MODE_DRY, supports_dry_mode); } | ||||||
|   bool supports_mode(ClimateMode mode) const { return supported_modes_.count(mode); } |   bool supports_mode(ClimateMode mode) const { return supported_modes_.count(mode); } | ||||||
|   const std::set<ClimateMode> get_supported_modes() const { return supported_modes_; } |   std::set<ClimateMode> get_supported_modes() const { return supported_modes_; } | ||||||
|  |  | ||||||
|   void set_supports_action(bool supports_action) { supports_action_ = supports_action; } |   void set_supports_action(bool supports_action) { supports_action_ = supports_action; } | ||||||
|   bool get_supports_action() const { return supports_action_; } |   bool get_supports_action() const { return supports_action_; } | ||||||
| @@ -93,7 +93,7 @@ class ClimateTraits { | |||||||
|   void set_supports_fan_mode_diffuse(bool supported) { set_fan_mode_support_(CLIMATE_FAN_DIFFUSE, supported); } |   void set_supports_fan_mode_diffuse(bool supported) { set_fan_mode_support_(CLIMATE_FAN_DIFFUSE, supported); } | ||||||
|   bool supports_fan_mode(ClimateFanMode fan_mode) const { return supported_fan_modes_.count(fan_mode); } |   bool supports_fan_mode(ClimateFanMode fan_mode) const { return supported_fan_modes_.count(fan_mode); } | ||||||
|   bool get_supports_fan_modes() const { return !supported_fan_modes_.empty() || !supported_custom_fan_modes_.empty(); } |   bool get_supports_fan_modes() const { return !supported_fan_modes_.empty() || !supported_custom_fan_modes_.empty(); } | ||||||
|   const std::set<ClimateFanMode> get_supported_fan_modes() const { return supported_fan_modes_; } |   std::set<ClimateFanMode> get_supported_fan_modes() const { return supported_fan_modes_; } | ||||||
|  |  | ||||||
|   void set_supported_custom_fan_modes(std::set<std::string> supported_custom_fan_modes) { |   void set_supported_custom_fan_modes(std::set<std::string> supported_custom_fan_modes) { | ||||||
|     supported_custom_fan_modes_ = std::move(supported_custom_fan_modes); |     supported_custom_fan_modes_ = std::move(supported_custom_fan_modes); | ||||||
| @@ -141,7 +141,7 @@ class ClimateTraits { | |||||||
|   } |   } | ||||||
|   bool supports_swing_mode(ClimateSwingMode swing_mode) const { return supported_swing_modes_.count(swing_mode); } |   bool supports_swing_mode(ClimateSwingMode swing_mode) const { return supported_swing_modes_.count(swing_mode); } | ||||||
|   bool get_supports_swing_modes() const { return !supported_swing_modes_.empty(); } |   bool get_supports_swing_modes() const { return !supported_swing_modes_.empty(); } | ||||||
|   const std::set<ClimateSwingMode> get_supported_swing_modes() { return supported_swing_modes_; } |   std::set<ClimateSwingMode> get_supported_swing_modes() { return supported_swing_modes_; } | ||||||
|  |  | ||||||
|   float get_visual_min_temperature() const { return visual_min_temperature_; } |   float get_visual_min_temperature() const { return visual_min_temperature_; } | ||||||
|   void set_visual_min_temperature(float visual_min_temperature) { visual_min_temperature_ = visual_min_temperature; } |   void set_visual_min_temperature(float visual_min_temperature) { visual_min_temperature_ = visual_min_temperature; } | ||||||
|   | |||||||
| @@ -137,11 +137,11 @@ bool LgIrClimate::on_receive(remote_base::RemoteReceiveData data) { | |||||||
|     this->swing_mode = |     this->swing_mode = | ||||||
|         this->swing_mode == climate::CLIMATE_SWING_OFF ? climate::CLIMATE_SWING_VERTICAL : climate::CLIMATE_SWING_OFF; |         this->swing_mode == climate::CLIMATE_SWING_OFF ? climate::CLIMATE_SWING_VERTICAL : climate::CLIMATE_SWING_OFF; | ||||||
|   } else { |   } else { | ||||||
|     if ((remote_state & COMMAND_MASK) == COMMAND_AUTO) |     if ((remote_state & COMMAND_MASK) == COMMAND_AUTO) { | ||||||
|       this->mode = climate::CLIMATE_MODE_HEAT_COOL; |       this->mode = climate::CLIMATE_MODE_HEAT_COOL; | ||||||
|     else if ((remote_state & COMMAND_MASK) == COMMAND_DRY_FAN) |     } else if ((remote_state & COMMAND_MASK) == COMMAND_DRY_FAN) { | ||||||
|       this->mode = climate::CLIMATE_MODE_DRY; |       this->mode = climate::CLIMATE_MODE_DRY; | ||||||
|     else if ((remote_state & COMMAND_MASK) == COMMAND_HEAT) { |     } else if ((remote_state & COMMAND_MASK) == COMMAND_HEAT) { | ||||||
|       this->mode = climate::CLIMATE_MODE_HEAT; |       this->mode = climate::CLIMATE_MODE_HEAT; | ||||||
|     } else { |     } else { | ||||||
|       this->mode = climate::CLIMATE_MODE_COOL; |       this->mode = climate::CLIMATE_MODE_COOL; | ||||||
| @@ -156,14 +156,15 @@ bool LgIrClimate::on_receive(remote_base::RemoteReceiveData data) { | |||||||
|       this->fan_mode = climate::CLIMATE_FAN_AUTO; |       this->fan_mode = climate::CLIMATE_FAN_AUTO; | ||||||
|     } else if (this->mode == climate::CLIMATE_MODE_COOL || this->mode == climate::CLIMATE_MODE_HEAT || |     } else if (this->mode == climate::CLIMATE_MODE_COOL || this->mode == climate::CLIMATE_MODE_HEAT || | ||||||
|                this->mode == climate::CLIMATE_MODE_DRY) { |                this->mode == climate::CLIMATE_MODE_DRY) { | ||||||
|       if ((remote_state & FAN_MASK) == FAN_AUTO) |       if ((remote_state & FAN_MASK) == FAN_AUTO) { | ||||||
|         this->fan_mode = climate::CLIMATE_FAN_AUTO; |         this->fan_mode = climate::CLIMATE_FAN_AUTO; | ||||||
|       else if ((remote_state & FAN_MASK) == FAN_MIN) |       } else if ((remote_state & FAN_MASK) == FAN_MIN) { | ||||||
|         this->fan_mode = climate::CLIMATE_FAN_LOW; |         this->fan_mode = climate::CLIMATE_FAN_LOW; | ||||||
|       else if ((remote_state & FAN_MASK) == FAN_MED) |       } else if ((remote_state & FAN_MASK) == FAN_MED) { | ||||||
|         this->fan_mode = climate::CLIMATE_FAN_MEDIUM; |         this->fan_mode = climate::CLIMATE_FAN_MEDIUM; | ||||||
|       else if ((remote_state & FAN_MASK) == FAN_MAX) |       } else if ((remote_state & FAN_MASK) == FAN_MAX) { | ||||||
|         this->fan_mode = climate::CLIMATE_FAN_HIGH; |         this->fan_mode = climate::CLIMATE_FAN_HIGH; | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   this->publish_state(); |   this->publish_state(); | ||||||
| @@ -175,7 +176,7 @@ void LgIrClimate::transmit_(uint32_t value) { | |||||||
|   ESP_LOGD(TAG, "Sending climate_lg_ir code: 0x%02X", value); |   ESP_LOGD(TAG, "Sending climate_lg_ir code: 0x%02X", value); | ||||||
|  |  | ||||||
|   auto transmit = this->transmitter_->transmit(); |   auto transmit = this->transmitter_->transmit(); | ||||||
|   auto data = transmit.get_data(); |   auto *data = transmit.get_data(); | ||||||
|  |  | ||||||
|   data->set_carrier_frequency(38000); |   data->set_carrier_frequency(38000); | ||||||
|   data->reserve(2 + BITS * 2u); |   data->reserve(2 + BITS * 2u); | ||||||
|   | |||||||
| @@ -104,7 +104,7 @@ void CoolixClimate::transmit_state() { | |||||||
|   ESP_LOGV(TAG, "Sending coolix code: 0x%06X", remote_state); |   ESP_LOGV(TAG, "Sending coolix code: 0x%06X", remote_state); | ||||||
|  |  | ||||||
|   auto transmit = this->transmitter_->transmit(); |   auto transmit = this->transmitter_->transmit(); | ||||||
|   auto data = transmit.get_data(); |   auto *data = transmit.get_data(); | ||||||
|   remote_base::CoolixProtocol().encode(data, remote_state); |   remote_base::CoolixProtocol().encode(data, remote_state); | ||||||
|   transmit.perform(); |   transmit.perform(); | ||||||
| } | } | ||||||
| @@ -125,34 +125,37 @@ bool CoolixClimate::on_coolix(climate::Climate *parent, remote_base::RemoteRecei | |||||||
|     parent->swing_mode = |     parent->swing_mode = | ||||||
|         parent->swing_mode == climate::CLIMATE_SWING_OFF ? climate::CLIMATE_SWING_VERTICAL : climate::CLIMATE_SWING_OFF; |         parent->swing_mode == climate::CLIMATE_SWING_OFF ? climate::CLIMATE_SWING_VERTICAL : climate::CLIMATE_SWING_OFF; | ||||||
|   } else { |   } else { | ||||||
|     if ((remote_state & COOLIX_MODE_MASK) == COOLIX_HEAT) |     if ((remote_state & COOLIX_MODE_MASK) == COOLIX_HEAT) { | ||||||
|       parent->mode = climate::CLIMATE_MODE_HEAT; |       parent->mode = climate::CLIMATE_MODE_HEAT; | ||||||
|     else if ((remote_state & COOLIX_MODE_MASK) == COOLIX_AUTO) |     } else if ((remote_state & COOLIX_MODE_MASK) == COOLIX_AUTO) { | ||||||
|       parent->mode = climate::CLIMATE_MODE_HEAT_COOL; |       parent->mode = climate::CLIMATE_MODE_HEAT_COOL; | ||||||
|     else if ((remote_state & COOLIX_MODE_MASK) == COOLIX_DRY_FAN) { |     } else if ((remote_state & COOLIX_MODE_MASK) == COOLIX_DRY_FAN) { | ||||||
|       if ((remote_state & COOLIX_FAN_MASK) == COOLIX_FAN_MODE_AUTO_DRY) |       if ((remote_state & COOLIX_FAN_MASK) == COOLIX_FAN_MODE_AUTO_DRY) { | ||||||
|         parent->mode = climate::CLIMATE_MODE_DRY; |         parent->mode = climate::CLIMATE_MODE_DRY; | ||||||
|       else |       } else { | ||||||
|         parent->mode = climate::CLIMATE_MODE_FAN_ONLY; |         parent->mode = climate::CLIMATE_MODE_FAN_ONLY; | ||||||
|  |       } | ||||||
|     } else |     } else | ||||||
|       parent->mode = climate::CLIMATE_MODE_COOL; |       parent->mode = climate::CLIMATE_MODE_COOL; | ||||||
|  |  | ||||||
|     // Fan Speed |     // Fan Speed | ||||||
|     if ((remote_state & COOLIX_FAN_AUTO) == COOLIX_FAN_AUTO || parent->mode == climate::CLIMATE_MODE_HEAT_COOL || |     if ((remote_state & COOLIX_FAN_AUTO) == COOLIX_FAN_AUTO || parent->mode == climate::CLIMATE_MODE_HEAT_COOL || | ||||||
|         parent->mode == climate::CLIMATE_MODE_DRY) |         parent->mode == climate::CLIMATE_MODE_DRY) { | ||||||
|       parent->fan_mode = climate::CLIMATE_FAN_AUTO; |       parent->fan_mode = climate::CLIMATE_FAN_AUTO; | ||||||
|     else if ((remote_state & COOLIX_FAN_MIN) == COOLIX_FAN_MIN) |     } else if ((remote_state & COOLIX_FAN_MIN) == COOLIX_FAN_MIN) { | ||||||
|       parent->fan_mode = climate::CLIMATE_FAN_LOW; |       parent->fan_mode = climate::CLIMATE_FAN_LOW; | ||||||
|     else if ((remote_state & COOLIX_FAN_MED) == COOLIX_FAN_MED) |     } else if ((remote_state & COOLIX_FAN_MED) == COOLIX_FAN_MED) { | ||||||
|       parent->fan_mode = climate::CLIMATE_FAN_MEDIUM; |       parent->fan_mode = climate::CLIMATE_FAN_MEDIUM; | ||||||
|     else if ((remote_state & COOLIX_FAN_MAX) == COOLIX_FAN_MAX) |     } else if ((remote_state & COOLIX_FAN_MAX) == COOLIX_FAN_MAX) { | ||||||
|       parent->fan_mode = climate::CLIMATE_FAN_HIGH; |       parent->fan_mode = climate::CLIMATE_FAN_HIGH; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     // Temperature |     // Temperature | ||||||
|     uint8_t temperature_code = remote_state & COOLIX_TEMP_MASK; |     uint8_t temperature_code = remote_state & COOLIX_TEMP_MASK; | ||||||
|     for (uint8_t i = 0; i < COOLIX_TEMP_RANGE; i++) |     for (uint8_t i = 0; i < COOLIX_TEMP_RANGE; i++) { | ||||||
|       if (COOLIX_TEMP_MAP[i] == temperature_code) |       if (COOLIX_TEMP_MAP[i] == temperature_code) | ||||||
|         parent->target_temperature = i + COOLIX_TEMP_MIN; |         parent->target_temperature = i + COOLIX_TEMP_MIN; | ||||||
|  |     } | ||||||
|   } |   } | ||||||
|   parent->publish_state(); |   parent->publish_state(); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -7,6 +7,7 @@ from esphome.const import ( | |||||||
|     CONF_ID, |     CONF_ID, | ||||||
|     CONF_DEVICE_CLASS, |     CONF_DEVICE_CLASS, | ||||||
|     CONF_STATE, |     CONF_STATE, | ||||||
|  |     CONF_ON_OPEN, | ||||||
|     CONF_POSITION, |     CONF_POSITION, | ||||||
|     CONF_POSITION_COMMAND_TOPIC, |     CONF_POSITION_COMMAND_TOPIC, | ||||||
|     CONF_POSITION_STATE_TOPIC, |     CONF_POSITION_STATE_TOPIC, | ||||||
| @@ -74,7 +75,6 @@ CoverClosedTrigger = cover_ns.class_( | |||||||
|     "CoverClosedTrigger", automation.Trigger.template() |     "CoverClosedTrigger", automation.Trigger.template() | ||||||
| ) | ) | ||||||
|  |  | ||||||
| CONF_ON_OPEN = "on_open" |  | ||||||
| CONF_ON_CLOSED = "on_closed" | CONF_ON_CLOSED = "on_closed" | ||||||
|  |  | ||||||
| COVER_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend( | COVER_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend( | ||||||
|   | |||||||
| @@ -49,8 +49,8 @@ def validate_config(config): | |||||||
|     if current_gain == 0.0 or voltage_gain == 0.0: |     if current_gain == 0.0 or voltage_gain == 0.0: | ||||||
|         raise cv.Invalid("The gains can't be zero") |         raise cv.Invalid("The gains can't be zero") | ||||||
|  |  | ||||||
|     max_energy = (0.25 * 0.25 / 3600 / (2 ** -4)) / (voltage_gain * current_gain) |     max_energy = (0.25 * 0.25 / 3600 / (2**-4)) / (voltage_gain * current_gain) | ||||||
|     min_energy = (0.25 * 0.25 / 3600 / (2 ** 18)) / (voltage_gain * current_gain) |     min_energy = (0.25 * 0.25 / 3600 / (2**18)) / (voltage_gain * current_gain) | ||||||
|     mech_min_energy = (0.25 * 0.25 / 3600 / 7.8) / (voltage_gain * current_gain) |     mech_min_energy = (0.25 * 0.25 / 3600 / 7.8) / (voltage_gain * current_gain) | ||||||
|     if pulse_energy < min_energy or pulse_energy > max_energy: |     if pulse_energy < min_energy or pulse_energy > max_energy: | ||||||
|         raise cv.Invalid( |         raise cv.Invalid( | ||||||
|   | |||||||
| @@ -11,11 +11,7 @@ CONFIG_SCHEMA = cv.Schema( | |||||||
|         cv.GenerateID(): cv.declare_id(CustomTextSensorConstructor), |         cv.GenerateID(): cv.declare_id(CustomTextSensorConstructor), | ||||||
|         cv.Required(CONF_LAMBDA): cv.returning_lambda, |         cv.Required(CONF_LAMBDA): cv.returning_lambda, | ||||||
|         cv.Required(CONF_TEXT_SENSORS): cv.ensure_list( |         cv.Required(CONF_TEXT_SENSORS): cv.ensure_list( | ||||||
|             text_sensor.TEXT_SENSOR_SCHEMA.extend( |             text_sensor.text_sensor_schema() | ||||||
|                 { |  | ||||||
|                     cv.GenerateID(): cv.declare_id(text_sensor.TextSensor), |  | ||||||
|                 } |  | ||||||
|             ) |  | ||||||
|         ), |         ), | ||||||
|     } |     } | ||||||
| ) | ) | ||||||
|   | |||||||
| @@ -23,7 +23,7 @@ void DaikinClimate::transmit_state() { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   auto transmit = this->transmitter_->transmit(); |   auto transmit = this->transmitter_->transmit(); | ||||||
|   auto data = transmit.get_data(); |   auto *data = transmit.get_data(); | ||||||
|   data->set_carrier_frequency(DAIKIN_IR_FREQUENCY); |   data->set_carrier_frequency(DAIKIN_IR_FREQUENCY); | ||||||
|  |  | ||||||
|   data->mark(DAIKIN_HEADER_MARK); |   data->mark(DAIKIN_HEADER_MARK); | ||||||
| @@ -175,14 +175,15 @@ bool DaikinClimate::parse_state_frame_(const uint8_t frame[]) { | |||||||
|   } |   } | ||||||
|   uint8_t fan_mode = frame[8]; |   uint8_t fan_mode = frame[8]; | ||||||
|   uint8_t swing_mode = frame[9]; |   uint8_t swing_mode = frame[9]; | ||||||
|   if (fan_mode & 0xF && swing_mode & 0xF) |   if (fan_mode & 0xF && swing_mode & 0xF) { | ||||||
|     this->swing_mode = climate::CLIMATE_SWING_BOTH; |     this->swing_mode = climate::CLIMATE_SWING_BOTH; | ||||||
|   else if (fan_mode & 0xF) |   } else if (fan_mode & 0xF) { | ||||||
|     this->swing_mode = climate::CLIMATE_SWING_VERTICAL; |     this->swing_mode = climate::CLIMATE_SWING_VERTICAL; | ||||||
|   else if (swing_mode & 0xF) |   } else if (swing_mode & 0xF) { | ||||||
|     this->swing_mode = climate::CLIMATE_SWING_HORIZONTAL; |     this->swing_mode = climate::CLIMATE_SWING_HORIZONTAL; | ||||||
|   else |   } else { | ||||||
|     this->swing_mode = climate::CLIMATE_SWING_OFF; |     this->swing_mode = climate::CLIMATE_SWING_OFF; | ||||||
|  |   } | ||||||
|   switch (fan_mode & 0xF0) { |   switch (fan_mode & 0xF0) { | ||||||
|     case DAIKIN_FAN_1: |     case DAIKIN_FAN_1: | ||||||
|     case DAIKIN_FAN_2: |     case DAIKIN_FAN_2: | ||||||
| @@ -212,9 +213,9 @@ bool DaikinClimate::on_receive(remote_base::RemoteReceiveData data) { | |||||||
|   for (uint8_t pos = 0; pos < DAIKIN_STATE_FRAME_SIZE; pos++) { |   for (uint8_t pos = 0; pos < DAIKIN_STATE_FRAME_SIZE; pos++) { | ||||||
|     uint8_t byte = 0; |     uint8_t byte = 0; | ||||||
|     for (int8_t bit = 0; bit < 8; bit++) { |     for (int8_t bit = 0; bit < 8; bit++) { | ||||||
|       if (data.expect_item(DAIKIN_BIT_MARK, DAIKIN_ONE_SPACE)) |       if (data.expect_item(DAIKIN_BIT_MARK, DAIKIN_ONE_SPACE)) { | ||||||
|         byte |= 1 << bit; |         byte |= 1 << bit; | ||||||
|       else if (!data.expect_item(DAIKIN_BIT_MARK, DAIKIN_ZERO_SPACE)) { |       } else if (!data.expect_item(DAIKIN_BIT_MARK, DAIKIN_ZERO_SPACE)) { | ||||||
|         return false; |         return false; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -52,7 +52,7 @@ void DallasComponent::setup() { | |||||||
|     this->found_sensors_.push_back(address); |     this->found_sensors_.push_back(address); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   for (auto sensor : this->sensors_) { |   for (auto *sensor : this->sensors_) { | ||||||
|     if (sensor->get_index().has_value()) { |     if (sensor->get_index().has_value()) { | ||||||
|       if (*sensor->get_index() >= this->found_sensors_.size()) { |       if (*sensor->get_index() >= this->found_sensors_.size()) { | ||||||
|         this->status_set_error(); |         this->status_set_error(); | ||||||
| @@ -235,7 +235,7 @@ float DallasTemperatureSensor::get_temp_c() { | |||||||
|  |  | ||||||
|   return temp / 128.0f; |   return temp / 128.0f; | ||||||
| } | } | ||||||
| std::string DallasTemperatureSensor::unique_id() { return "dallas-" + str_upper_case(format_hex(this->address_)); } | std::string DallasTemperatureSensor::unique_id() { return "dallas-" + str_lower_case(format_hex(this->address_)); } | ||||||
|  |  | ||||||
| }  // namespace dallas | }  // namespace dallas | ||||||
| }  // namespace esphome | }  // namespace esphome | ||||||
|   | |||||||
| @@ -145,9 +145,10 @@ uint64_t ESPOneWire::search() { | |||||||
|     // read its complement |     // read its complement | ||||||
|     bool cmp_id_bit = this->read_bit(); |     bool cmp_id_bit = this->read_bit(); | ||||||
|  |  | ||||||
|     if (id_bit && cmp_id_bit) |     if (id_bit && cmp_id_bit) { | ||||||
|       // No devices participating in search |       // No devices participating in search | ||||||
|       break; |       break; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     bool branch; |     bool branch; | ||||||
|  |  | ||||||
| @@ -170,12 +171,13 @@ uint64_t ESPOneWire::search() { | |||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (branch) |     if (branch) { | ||||||
|       // set bit |       // set bit | ||||||
|       this->rom_number8_()[rom_byte_number] |= rom_byte_mask; |       this->rom_number8_()[rom_byte_number] |= rom_byte_mask; | ||||||
|     else |     } else { | ||||||
|       // clear bit |       // clear bit | ||||||
|       this->rom_number8_()[rom_byte_number] &= ~rom_byte_mask; |       this->rom_number8_()[rom_byte_number] &= ~rom_byte_mask; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     // choose/announce branch |     // choose/announce branch | ||||||
|     this->write_bit(branch); |     this->write_bit(branch); | ||||||
| @@ -190,9 +192,10 @@ uint64_t ESPOneWire::search() { | |||||||
|  |  | ||||||
|   if (id_bit_number >= 65) { |   if (id_bit_number >= 65) { | ||||||
|     this->last_discrepancy_ = last_zero; |     this->last_discrepancy_ = last_zero; | ||||||
|     if (this->last_discrepancy_ == 0) |     if (this->last_discrepancy_ == 0) { | ||||||
|       // we're at root and have no choices left, so this was the last one. |       // we're at root and have no choices left, so this was the last one. | ||||||
|       this->last_device_flag_ = true; |       this->last_device_flag_ = true; | ||||||
|  |     } | ||||||
|     search_result = true; |     search_result = true; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| import esphome.codegen as cg | import esphome.codegen as cg | ||||||
| import esphome.config_validation as cv | import esphome.config_validation as cv | ||||||
| from esphome.components import text_sensor | from esphome.components import text_sensor | ||||||
| from esphome.const import CONF_ICON, CONF_ID, CONF_STATUS | from esphome.const import CONF_STATUS | ||||||
| from . import DalyBmsComponent, CONF_BMS_DALY_ID | from . import DalyBmsComponent, CONF_BMS_DALY_ID | ||||||
|  |  | ||||||
| ICON_CAR_BATTERY = "mdi:car-battery" | ICON_CAR_BATTERY = "mdi:car-battery" | ||||||
| @@ -14,11 +14,8 @@ CONFIG_SCHEMA = cv.All( | |||||||
|     cv.Schema( |     cv.Schema( | ||||||
|         { |         { | ||||||
|             cv.GenerateID(CONF_BMS_DALY_ID): cv.use_id(DalyBmsComponent), |             cv.GenerateID(CONF_BMS_DALY_ID): cv.use_id(DalyBmsComponent), | ||||||
|             cv.Optional(CONF_STATUS): text_sensor.TEXT_SENSOR_SCHEMA.extend( |             cv.Optional(CONF_STATUS): text_sensor.text_sensor_schema( | ||||||
|                 { |                 icon=ICON_CAR_BATTERY | ||||||
|                     cv.GenerateID(): cv.declare_id(text_sensor.TextSensor), |  | ||||||
|                     cv.Optional(CONF_ICON, default=ICON_CAR_BATTERY): cv.icon, |  | ||||||
|                 } |  | ||||||
|             ), |             ), | ||||||
|         } |         } | ||||||
|     ).extend(cv.COMPONENT_SCHEMA) |     ).extend(cv.COMPONENT_SCHEMA) | ||||||
| @@ -28,8 +25,7 @@ CONFIG_SCHEMA = cv.All( | |||||||
| async def setup_conf(config, key, hub): | async def setup_conf(config, key, hub): | ||||||
|     if key in config: |     if key in config: | ||||||
|         conf = config[key] |         conf = config[key] | ||||||
|         sens = cg.new_Pvariable(conf[CONF_ID]) |         sens = await text_sensor.new_text_sensor(conf) | ||||||
|         await text_sensor.register_text_sensor(sens, conf) |  | ||||||
|         cg.add(getattr(hub, f"set_{key}_text_sensor")(sens)) |         cg.add(getattr(hub, f"set_{key}_text_sensor")(sens)) | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,17 +1,42 @@ | |||||||
| import esphome.config_validation as cv | import esphome.config_validation as cv | ||||||
| import esphome.codegen as cg | import esphome.codegen as cg | ||||||
| from esphome.const import CONF_ID | from esphome.const import ( | ||||||
|  |     CONF_ID, | ||||||
|  |     CONF_DEVICE, | ||||||
|  |     CONF_FREE, | ||||||
|  |     CONF_FRAGMENTATION, | ||||||
|  |     CONF_BLOCK, | ||||||
|  |     CONF_LOOP_TIME, | ||||||
|  | ) | ||||||
|  |  | ||||||
| CODEOWNERS = ["@OttoWinter"] | CODEOWNERS = ["@OttoWinter"] | ||||||
| DEPENDENCIES = ["logger"] | DEPENDENCIES = ["logger"] | ||||||
|  |  | ||||||
|  | CONF_DEBUG_ID = "debug_id" | ||||||
| debug_ns = cg.esphome_ns.namespace("debug") | debug_ns = cg.esphome_ns.namespace("debug") | ||||||
| DebugComponent = debug_ns.class_("DebugComponent", cg.Component) | DebugComponent = debug_ns.class_("DebugComponent", cg.PollingComponent) | ||||||
|  |  | ||||||
|  |  | ||||||
| CONFIG_SCHEMA = cv.Schema( | CONFIG_SCHEMA = cv.Schema( | ||||||
|     { |     { | ||||||
|         cv.GenerateID(): cv.declare_id(DebugComponent), |         cv.GenerateID(): cv.declare_id(DebugComponent), | ||||||
|  |         cv.Optional(CONF_DEVICE): cv.invalid( | ||||||
|  |             "The 'device' option has been moved to the 'debug' text_sensor component" | ||||||
|  |         ), | ||||||
|  |         cv.Optional(CONF_FREE): cv.invalid( | ||||||
|  |             "The 'free' option has been moved to the 'debug' sensor component" | ||||||
|  |         ), | ||||||
|  |         cv.Optional(CONF_BLOCK): cv.invalid( | ||||||
|  |             "The 'block' option has been moved to the 'debug' sensor component" | ||||||
|  |         ), | ||||||
|  |         cv.Optional(CONF_FRAGMENTATION): cv.invalid( | ||||||
|  |             "The 'fragmentation' option has been moved to the 'debug' sensor component" | ||||||
|  |         ), | ||||||
|  |         cv.Optional(CONF_LOOP_TIME): cv.invalid( | ||||||
|  |             "The 'loop_time' option has been moved to the 'debug' sensor component" | ||||||
|  |         ), | ||||||
|     } |     } | ||||||
| ).extend(cv.COMPONENT_SCHEMA) | ).extend(cv.polling_component_schema("60s")) | ||||||
|  |  | ||||||
|  |  | ||||||
| async def to_code(config): | async def to_code(config): | ||||||
|   | |||||||
| @@ -1,21 +1,23 @@ | |||||||
| #include "debug_component.h" | #include "debug_component.h" | ||||||
|  |  | ||||||
|  | #include <algorithm> | ||||||
| #include "esphome/core/log.h" | #include "esphome/core/log.h" | ||||||
|  | #include "esphome/core/hal.h" | ||||||
| #include "esphome/core/helpers.h" | #include "esphome/core/helpers.h" | ||||||
| #include "esphome/core/defines.h" |  | ||||||
| #include "esphome/core/version.h" | #include "esphome/core/version.h" | ||||||
|  |  | ||||||
| #ifdef USE_ESP_IDF | #ifdef USE_ESP32 | ||||||
|  |  | ||||||
| #include <esp_heap_caps.h> | #include <esp_heap_caps.h> | ||||||
| #include <esp_system.h> | #include <esp_system.h> | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #ifdef USE_ESP32 |  | ||||||
| #if ESP_IDF_VERSION_MAJOR >= 4 | #if ESP_IDF_VERSION_MAJOR >= 4 | ||||||
| #include <esp32/rom/rtc.h> | #include <esp32/rom/rtc.h> | ||||||
| #else | #else | ||||||
| #include <rom/rtc.h> | #include <rom/rtc.h> | ||||||
| #endif | #endif | ||||||
| #endif |  | ||||||
|  | #endif  // USE_ESP32 | ||||||
|  |  | ||||||
| #ifdef USE_ARDUINO | #ifdef USE_ARDUINO | ||||||
| #include <Esp.h> | #include <Esp.h> | ||||||
| @@ -26,19 +28,40 @@ namespace debug { | |||||||
|  |  | ||||||
| static const char *const TAG = "debug"; | static const char *const TAG = "debug"; | ||||||
|  |  | ||||||
|  | static uint32_t get_free_heap() { | ||||||
|  | #if defined(USE_ESP8266) | ||||||
|  |   return ESP.getFreeHeap();  // NOLINT(readability-static-accessed-through-instance) | ||||||
|  | #elif defined(USE_ESP32) | ||||||
|  |   return heap_caps_get_free_size(MALLOC_CAP_INTERNAL); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
| void DebugComponent::dump_config() { | void DebugComponent::dump_config() { | ||||||
|  |   std::string device_info; | ||||||
|  |   device_info.reserve(256); | ||||||
|  |  | ||||||
| #ifndef ESPHOME_LOG_HAS_DEBUG | #ifndef ESPHOME_LOG_HAS_DEBUG | ||||||
|   ESP_LOGE(TAG, "Debug Component requires debug log level!"); |   ESP_LOGE(TAG, "Debug Component requires debug log level!"); | ||||||
|   this->status_set_error(); |   this->status_set_error(); | ||||||
|   return; |   return; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  |   ESP_LOGCONFIG(TAG, "Debug component:"); | ||||||
|  | #ifdef USE_TEXT_SENSOR | ||||||
|  |   LOG_TEXT_SENSOR("  ", "Device info", this->device_info_); | ||||||
|  | #endif  // USE_TEXT_SENSOR | ||||||
|  | #ifdef USE_SENSOR | ||||||
|  |   LOG_SENSOR("  ", "Free space on heap", this->free_sensor_); | ||||||
|  |   LOG_SENSOR("  ", "Largest free heap block", this->block_sensor_); | ||||||
|  | #if defined(USE_ESP8266) && ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2) | ||||||
|  |   LOG_SENSOR("  ", "Heap fragmentation", this->fragmentation_sensor_); | ||||||
|  | #endif  // defined(USE_ESP8266) && ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2) | ||||||
|  | #endif  // USE_SENSOR | ||||||
|  |  | ||||||
|   ESP_LOGD(TAG, "ESPHome version %s", ESPHOME_VERSION); |   ESP_LOGD(TAG, "ESPHome version %s", ESPHOME_VERSION); | ||||||
| #ifdef USE_ARDUINO |   device_info += ESPHOME_VERSION; | ||||||
|   this->free_heap_ = ESP.getFreeHeap();  // NOLINT(readability-static-accessed-through-instance) |  | ||||||
| #elif defined(USE_ESP_IDF) |   this->free_heap_ = get_free_heap(); | ||||||
|   this->free_heap_ = heap_caps_get_free_size(MALLOC_CAP_INTERNAL); |  | ||||||
| #endif |  | ||||||
|   ESP_LOGD(TAG, "Free Heap Size: %u bytes", this->free_heap_); |   ESP_LOGD(TAG, "Free Heap Size: %u bytes", this->free_heap_); | ||||||
|  |  | ||||||
| #ifdef USE_ARDUINO | #ifdef USE_ARDUINO | ||||||
| @@ -67,9 +90,12 @@ void DebugComponent::dump_config() { | |||||||
|     default: |     default: | ||||||
|       flash_mode = "UNKNOWN"; |       flash_mode = "UNKNOWN"; | ||||||
|   } |   } | ||||||
|   // NOLINTNEXTLINE(readability-static-accessed-through-instance) |   ESP_LOGD(TAG, "Flash Chip: Size=%ukB Speed=%uMHz Mode=%s", | ||||||
|   ESP_LOGD(TAG, "Flash Chip: Size=%ukB Speed=%uMHz Mode=%s", ESP.getFlashChipSize() / 1024, |            ESP.getFlashChipSize() / 1024,                                                   // NOLINT | ||||||
|            ESP.getFlashChipSpeed() / 1000000, flash_mode); |            ESP.getFlashChipSpeed() / 1000000, flash_mode);                                  // NOLINT | ||||||
|  |   device_info += "|Flash: " + to_string(ESP.getFlashChipSize() / 1024) +                    // NOLINT | ||||||
|  |                  "kB Speed:" + to_string(ESP.getFlashChipSpeed() / 1000000) + "MHz Mode:";  // NOLINT | ||||||
|  |   device_info += flash_mode; | ||||||
| #endif  // USE_ARDUINO | #endif  // USE_ARDUINO | ||||||
|  |  | ||||||
| #ifdef USE_ESP32 | #ifdef USE_ESP32 | ||||||
| @@ -104,10 +130,21 @@ void DebugComponent::dump_config() { | |||||||
|     features += "Other:" + format_hex(info.features); |     features += "Other:" + format_hex(info.features); | ||||||
|   ESP_LOGD(TAG, "Chip: Model=%s, Features=%s Cores=%u, Revision=%u", model, features.c_str(), info.cores, |   ESP_LOGD(TAG, "Chip: Model=%s, Features=%s Cores=%u, Revision=%u", model, features.c_str(), info.cores, | ||||||
|            info.revision); |            info.revision); | ||||||
|  |   device_info += "|Chip: "; | ||||||
|  |   device_info += model; | ||||||
|  |   device_info += " Features:"; | ||||||
|  |   device_info += features; | ||||||
|  |   device_info += " Cores:" + to_string(info.cores); | ||||||
|  |   device_info += " Revision:" + to_string(info.revision); | ||||||
|  |  | ||||||
|   ESP_LOGD(TAG, "ESP-IDF Version: %s", esp_get_idf_version()); |   ESP_LOGD(TAG, "ESP-IDF Version: %s", esp_get_idf_version()); | ||||||
|  |   device_info += "|ESP-IDF: "; | ||||||
|  |   device_info += esp_get_idf_version(); | ||||||
|  |  | ||||||
|   ESP_LOGD(TAG, "EFuse MAC: %s", get_mac_address_pretty().c_str()); |   std::string mac = get_mac_address_pretty(); | ||||||
|  |   ESP_LOGD(TAG, "EFuse MAC: %s", mac.c_str()); | ||||||
|  |   device_info += "|EFuse MAC: "; | ||||||
|  |   device_info += mac; | ||||||
|  |  | ||||||
|   const char *reset_reason; |   const char *reset_reason; | ||||||
|   switch (rtc_get_reset_reason(0)) { |   switch (rtc_get_reset_reason(0)) { | ||||||
| @@ -160,6 +197,8 @@ void DebugComponent::dump_config() { | |||||||
|       reset_reason = "Unknown Reset Reason"; |       reset_reason = "Unknown Reset Reason"; | ||||||
|   } |   } | ||||||
|   ESP_LOGD(TAG, "Reset Reason: %s", reset_reason); |   ESP_LOGD(TAG, "Reset Reason: %s", reset_reason); | ||||||
|  |   device_info += "|Reset: "; | ||||||
|  |   device_info += reset_reason; | ||||||
|  |  | ||||||
|   const char *wakeup_reason; |   const char *wakeup_reason; | ||||||
|   switch (rtc_get_wakeup_cause()) { |   switch (rtc_get_wakeup_cause()) { | ||||||
| @@ -203,6 +242,8 @@ void DebugComponent::dump_config() { | |||||||
|       wakeup_reason = "Unknown"; |       wakeup_reason = "Unknown"; | ||||||
|   } |   } | ||||||
|   ESP_LOGD(TAG, "Wakeup Reason: %s", wakeup_reason); |   ESP_LOGD(TAG, "Wakeup Reason: %s", wakeup_reason); | ||||||
|  |   device_info += "|Wakeup: "; | ||||||
|  |   device_info += wakeup_reason; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #if defined(USE_ESP8266) && !defined(CLANG_TIDY) | #if defined(USE_ESP8266) && !defined(CLANG_TIDY) | ||||||
| @@ -214,20 +255,81 @@ void DebugComponent::dump_config() { | |||||||
|   ESP_LOGD(TAG, "Flash Chip ID=0x%08X", ESP.getFlashChipId()); |   ESP_LOGD(TAG, "Flash Chip ID=0x%08X", ESP.getFlashChipId()); | ||||||
|   ESP_LOGD(TAG, "Reset Reason: %s", ESP.getResetReason().c_str()); |   ESP_LOGD(TAG, "Reset Reason: %s", ESP.getResetReason().c_str()); | ||||||
|   ESP_LOGD(TAG, "Reset Info: %s", ESP.getResetInfo().c_str()); |   ESP_LOGD(TAG, "Reset Info: %s", ESP.getResetInfo().c_str()); | ||||||
|  |  | ||||||
|  |   device_info += "|Chip: 0x" + format_hex(ESP.getChipId()); | ||||||
|  |   device_info += "|SDK: "; | ||||||
|  |   device_info += ESP.getSdkVersion(); | ||||||
|  |   device_info += "|Core: "; | ||||||
|  |   device_info += ESP.getCoreVersion().c_str(); | ||||||
|  |   device_info += "|Boot: "; | ||||||
|  |   device_info += to_string(ESP.getBootVersion()); | ||||||
|  |   device_info += "|Mode: " + to_string(ESP.getBootMode()); | ||||||
|  |   device_info += "|CPU: " + to_string(ESP.getCpuFreqMHz()); | ||||||
|  |   device_info += "|Flash: 0x" + format_hex(ESP.getFlashChipId()); | ||||||
|  |   device_info += "|Reset: "; | ||||||
|  |   device_info += ESP.getResetReason().c_str(); | ||||||
|  |   device_info += "|"; | ||||||
|  |   device_info += ESP.getResetInfo().c_str(); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #ifdef USE_TEXT_SENSOR | ||||||
|  |   if (this->device_info_ != nullptr) { | ||||||
|  |     if (device_info.length() > 255) | ||||||
|  |       device_info.resize(255); | ||||||
|  |     this->device_info_->publish_state(device_info); | ||||||
|  |   } | ||||||
|  | #endif  // USE_TEXT_SENSOR | ||||||
| } | } | ||||||
|  |  | ||||||
| void DebugComponent::loop() { | void DebugComponent::loop() { | ||||||
| #ifdef USE_ARDUINO |   // log when free heap space has halved | ||||||
|   uint32_t new_free_heap = ESP.getFreeHeap();  // NOLINT(readability-static-accessed-through-instance) |   uint32_t new_free_heap = get_free_heap(); | ||||||
| #elif defined(USE_ESP_IDF) |  | ||||||
|   uint32_t new_free_heap = heap_caps_get_free_size(MALLOC_CAP_INTERNAL); |  | ||||||
| #endif |  | ||||||
|   if (new_free_heap < this->free_heap_ / 2) { |   if (new_free_heap < this->free_heap_ / 2) { | ||||||
|     this->free_heap_ = new_free_heap; |     this->free_heap_ = new_free_heap; | ||||||
|     ESP_LOGD(TAG, "Free Heap Size: %u bytes", this->free_heap_); |     ESP_LOGD(TAG, "Free Heap Size: %u bytes", this->free_heap_); | ||||||
|     this->status_momentary_warning("heap", 1000); |     this->status_momentary_warning("heap", 1000); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  | #ifdef USE_SENSOR | ||||||
|  |   // calculate loop time - from last call to this one | ||||||
|  |   if (this->loop_time_sensor_ != nullptr) { | ||||||
|  |     uint32_t now = millis(); | ||||||
|  |     uint32_t loop_time = now - this->last_loop_timetag_; | ||||||
|  |     this->max_loop_time_ = std::max(this->max_loop_time_, loop_time); | ||||||
|  |     this->last_loop_timetag_ = now; | ||||||
|  |   } | ||||||
|  | #endif  // USE_SENSOR | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void DebugComponent::update() { | ||||||
|  | #ifdef USE_SENSOR | ||||||
|  |   if (this->free_sensor_ != nullptr) { | ||||||
|  |     this->free_sensor_->publish_state(get_free_heap()); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (this->block_sensor_ != nullptr) { | ||||||
|  | #if defined(USE_ESP8266) | ||||||
|  |     // NOLINTNEXTLINE(readability-static-accessed-through-instance) | ||||||
|  |     this->block_sensor_->publish_state(ESP.getMaxFreeBlockSize()); | ||||||
|  | #elif defined(USE_ESP32) | ||||||
|  |     this->block_sensor_->publish_state(heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL)); | ||||||
|  | #endif | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | #if defined(USE_ESP8266) && ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2) | ||||||
|  |   if (this->fragmentation_sensor_ != nullptr) { | ||||||
|  |     // NOLINTNEXTLINE(readability-static-accessed-through-instance) | ||||||
|  |     this->fragmentation_sensor_->publish_state(ESP.getHeapFragmentation()); | ||||||
|  |   } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |   if (this->loop_time_sensor_ != nullptr) { | ||||||
|  |     this->loop_time_sensor_->publish_state(this->max_loop_time_); | ||||||
|  |     this->max_loop_time_ = 0; | ||||||
|  |   } | ||||||
|  | #endif  // USE_SENSOR | ||||||
|  | } | ||||||
|  |  | ||||||
| float DebugComponent::get_setup_priority() const { return setup_priority::LATE; } | float DebugComponent::get_setup_priority() const { return setup_priority::LATE; } | ||||||
|  |  | ||||||
| }  // namespace debug | }  // namespace debug | ||||||
|   | |||||||
| @@ -1,18 +1,56 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include "esphome/core/component.h" | #include "esphome/core/component.h" | ||||||
|  | #include "esphome/core/defines.h" | ||||||
|  | #include "esphome/core/macros.h" | ||||||
|  | #include "esphome/core/helpers.h" | ||||||
|  |  | ||||||
|  | #ifdef USE_SENSOR | ||||||
|  | #include "esphome/components/sensor/sensor.h" | ||||||
|  | #endif | ||||||
|  | #ifdef USE_TEXT_SENSOR | ||||||
|  | #include "esphome/components/text_sensor/text_sensor.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace debug { | namespace debug { | ||||||
|  |  | ||||||
| class DebugComponent : public Component { | class DebugComponent : public PollingComponent { | ||||||
|  public: |  public: | ||||||
|   void loop() override; |   void loop() override; | ||||||
|  |   void update() override; | ||||||
|   float get_setup_priority() const override; |   float get_setup_priority() const override; | ||||||
|   void dump_config() override; |   void dump_config() override; | ||||||
|  |  | ||||||
|  | #ifdef USE_TEXT_SENSOR | ||||||
|  |   void set_device_info_sensor(text_sensor::TextSensor *device_info) { device_info_ = device_info; } | ||||||
|  | #endif  // USE_TEXT_SENSOR | ||||||
|  | #ifdef USE_SENSOR | ||||||
|  |   void set_free_sensor(sensor::Sensor *free_sensor) { free_sensor_ = free_sensor; } | ||||||
|  |   void set_block_sensor(sensor::Sensor *block_sensor) { block_sensor_ = block_sensor; } | ||||||
|  | #if defined(USE_ESP8266) && ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2) | ||||||
|  |   void set_fragmentation_sensor(sensor::Sensor *fragmentation_sensor) { fragmentation_sensor_ = fragmentation_sensor; } | ||||||
|  | #endif | ||||||
|  |   void set_loop_time_sensor(sensor::Sensor *loop_time_sensor) { loop_time_sensor_ = loop_time_sensor; } | ||||||
|  | #endif  // USE_SENSOR | ||||||
|  protected: |  protected: | ||||||
|   uint32_t free_heap_{}; |   uint32_t free_heap_{}; | ||||||
|  |  | ||||||
|  | #ifdef USE_SENSOR | ||||||
|  |   uint32_t last_loop_timetag_{0}; | ||||||
|  |   uint32_t max_loop_time_{0}; | ||||||
|  |  | ||||||
|  |   sensor::Sensor *free_sensor_{nullptr}; | ||||||
|  |   sensor::Sensor *block_sensor_{nullptr}; | ||||||
|  | #if defined(USE_ESP8266) && ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2) | ||||||
|  |   sensor::Sensor *fragmentation_sensor_{nullptr}; | ||||||
|  | #endif | ||||||
|  |   sensor::Sensor *loop_time_sensor_{nullptr}; | ||||||
|  | #endif  // USE_SENSOR | ||||||
|  |  | ||||||
|  | #ifdef USE_TEXT_SENSOR | ||||||
|  |   text_sensor::TextSensor *device_info_{nullptr}; | ||||||
|  | #endif  // USE_TEXT_SENSOR | ||||||
| }; | }; | ||||||
|  |  | ||||||
| }  // namespace debug | }  // namespace debug | ||||||
|   | |||||||
							
								
								
									
										49
									
								
								esphome/components/debug/sensor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								esphome/components/debug/sensor.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome.components import sensor | ||||||
|  | from esphome.const import ( | ||||||
|  |     CONF_FREE, | ||||||
|  |     CONF_FRAGMENTATION, | ||||||
|  |     CONF_BLOCK, | ||||||
|  |     CONF_LOOP_TIME, | ||||||
|  |     UNIT_MILLISECOND, | ||||||
|  |     UNIT_PERCENT, | ||||||
|  |     UNIT_BYTES, | ||||||
|  |     ICON_COUNTER, | ||||||
|  |     ICON_TIMER, | ||||||
|  | ) | ||||||
|  | from . import CONF_DEBUG_ID, DebugComponent | ||||||
|  |  | ||||||
|  | DEPENDENCIES = ["debug"] | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = { | ||||||
|  |     cv.GenerateID(CONF_DEBUG_ID): cv.use_id(DebugComponent), | ||||||
|  |     cv.Optional(CONF_FREE): sensor.sensor_schema(UNIT_BYTES, ICON_COUNTER, 0), | ||||||
|  |     cv.Optional(CONF_BLOCK): sensor.sensor_schema(UNIT_BYTES, ICON_COUNTER, 0), | ||||||
|  |     cv.Optional(CONF_FRAGMENTATION): cv.All( | ||||||
|  |         cv.only_on_esp8266, | ||||||
|  |         cv.require_framework_version(esp8266_arduino=cv.Version(2, 5, 2)), | ||||||
|  |         sensor.sensor_schema(UNIT_PERCENT, ICON_COUNTER, 1), | ||||||
|  |     ), | ||||||
|  |     cv.Optional(CONF_LOOP_TIME): sensor.sensor_schema(UNIT_MILLISECOND, ICON_TIMER, 0), | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def to_code(config): | ||||||
|  |     debug_component = await cg.get_variable(config[CONF_DEBUG_ID]) | ||||||
|  |  | ||||||
|  |     if CONF_FREE in config: | ||||||
|  |         sens = await sensor.new_sensor(config[CONF_FREE]) | ||||||
|  |         cg.add(debug_component.set_free_sensor(sens)) | ||||||
|  |  | ||||||
|  |     if CONF_BLOCK in config: | ||||||
|  |         sens = await sensor.new_sensor(config[CONF_BLOCK]) | ||||||
|  |         cg.add(debug_component.set_block_sensor(sens)) | ||||||
|  |  | ||||||
|  |     if CONF_FRAGMENTATION in config: | ||||||
|  |         sens = await sensor.new_sensor(config[CONF_FRAGMENTATION]) | ||||||
|  |         cg.add(debug_component.set_fragmentation_sensor(sens)) | ||||||
|  |  | ||||||
|  |     if CONF_LOOP_TIME in config: | ||||||
|  |         sens = await sensor.new_sensor(config[CONF_LOOP_TIME]) | ||||||
|  |         cg.add(debug_component.set_loop_time_sensor(sens)) | ||||||
							
								
								
									
										24
									
								
								esphome/components/debug/text_sensor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								esphome/components/debug/text_sensor.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | |||||||
|  | from esphome.components import text_sensor | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | import esphome.codegen as cg | ||||||
|  | from esphome.const import CONF_DEVICE | ||||||
|  |  | ||||||
|  | from . import CONF_DEBUG_ID, DebugComponent | ||||||
|  |  | ||||||
|  | DEPENDENCIES = ["debug"] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = cv.Schema( | ||||||
|  |     { | ||||||
|  |         cv.GenerateID(CONF_DEBUG_ID): cv.use_id(DebugComponent), | ||||||
|  |         cv.Optional(CONF_DEVICE): text_sensor.text_sensor_schema(), | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def to_code(config): | ||||||
|  |     debug_component = await cg.get_variable(config[CONF_DEBUG_ID]) | ||||||
|  |  | ||||||
|  |     if CONF_DEVICE in config: | ||||||
|  |         sens = await text_sensor.new_text_sensor(config[CONF_DEVICE]) | ||||||
|  |         cg.add(debug_component.set_device_info_sensor(sens)) | ||||||
| @@ -37,12 +37,10 @@ from esphome.const import ( | |||||||
|     DEVICE_CLASS_TEMPERATURE, |     DEVICE_CLASS_TEMPERATURE, | ||||||
|     ICON_BLUETOOTH, |     ICON_BLUETOOTH, | ||||||
|     ICON_BLUR, |     ICON_BLUR, | ||||||
|     ICON_EMPTY, |  | ||||||
|     ICON_THERMOMETER, |     ICON_THERMOMETER, | ||||||
|     STATE_CLASS_MEASUREMENT, |     STATE_CLASS_MEASUREMENT, | ||||||
|     STATE_CLASS_TOTAL_INCREASING, |     STATE_CLASS_TOTAL_INCREASING, | ||||||
|     UNIT_CELSIUS, |     UNIT_CELSIUS, | ||||||
|     UNIT_EMPTY, |  | ||||||
|     UNIT_PERCENT, |     UNIT_PERCENT, | ||||||
|     UNIT_WATT_HOURS, |     UNIT_WATT_HOURS, | ||||||
| ) | ) | ||||||
| @@ -67,7 +65,7 @@ DemoClimate = demo_ns.class_("DemoClimate", climate.Climate, cg.Component) | |||||||
| DemoClimateType = demo_ns.enum("DemoClimateType", is_class=True) | DemoClimateType = demo_ns.enum("DemoClimateType", is_class=True) | ||||||
| DemoCover = demo_ns.class_("DemoCover", cover.Cover, cg.Component) | DemoCover = demo_ns.class_("DemoCover", cover.Cover, cg.Component) | ||||||
| DemoCoverType = demo_ns.enum("DemoCoverType", is_class=True) | DemoCoverType = demo_ns.enum("DemoCoverType", is_class=True) | ||||||
| DemoFan = demo_ns.class_("DemoFan", cg.Component) | DemoFan = demo_ns.class_("DemoFan", fan.Fan, cg.Component) | ||||||
| DemoFanType = demo_ns.enum("DemoFanType", is_class=True) | DemoFanType = demo_ns.enum("DemoFanType", is_class=True) | ||||||
| DemoLight = demo_ns.class_("DemoLight", light.LightOutput, cg.Component) | DemoLight = demo_ns.class_("DemoLight", light.LightOutput, cg.Component) | ||||||
| DemoLightType = demo_ns.enum("DemoLightType", is_class=True) | DemoLightType = demo_ns.enum("DemoLightType", is_class=True) | ||||||
| @@ -339,7 +337,7 @@ CONFIG_SCHEMA = cv.Schema( | |||||||
|                 }, |                 }, | ||||||
|             ], |             ], | ||||||
|         ): [ |         ): [ | ||||||
|             sensor.sensor_schema(UNIT_EMPTY, ICON_EMPTY, 0) |             sensor.sensor_schema(accuracy_decimals=0) | ||||||
|             .extend(cv.polling_component_schema("60s")) |             .extend(cv.polling_component_schema("60s")) | ||||||
|             .extend( |             .extend( | ||||||
|                 { |                 { | ||||||
| @@ -378,12 +376,8 @@ CONFIG_SCHEMA = cv.Schema( | |||||||
|                 }, |                 }, | ||||||
|             ], |             ], | ||||||
|         ): [ |         ): [ | ||||||
|             text_sensor.TEXT_SENSOR_SCHEMA.extend( |             text_sensor.text_sensor_schema(klass=DemoTextSensor).extend( | ||||||
|                 cv.polling_component_schema("60s") |                 cv.polling_component_schema("60s") | ||||||
|             ).extend( |  | ||||||
|                 { |  | ||||||
|                     cv.GenerateID(): cv.declare_id(DemoTextSensor), |  | ||||||
|                 } |  | ||||||
|             ) |             ) | ||||||
|         ], |         ], | ||||||
|     } |     } | ||||||
| @@ -411,8 +405,7 @@ async def to_code(config): | |||||||
|     for conf in config[CONF_FANS]: |     for conf in config[CONF_FANS]: | ||||||
|         var = cg.new_Pvariable(conf[CONF_OUTPUT_ID]) |         var = cg.new_Pvariable(conf[CONF_OUTPUT_ID]) | ||||||
|         await cg.register_component(var, conf) |         await cg.register_component(var, conf) | ||||||
|         fan_ = await fan.create_fan_state(conf) |         await fan.register_fan(var, conf) | ||||||
|         cg.add(var.set_fan(fan_)) |  | ||||||
|         cg.add(var.set_type(conf[CONF_TYPE])) |         cg.add(var.set_type(conf[CONF_TYPE])) | ||||||
|  |  | ||||||
|     for conf in config[CONF_LIGHTS]: |     for conf in config[CONF_LIGHTS]: | ||||||
| @@ -444,6 +437,5 @@ async def to_code(config): | |||||||
|         await switch.register_switch(var, conf) |         await switch.register_switch(var, conf) | ||||||
|  |  | ||||||
|     for conf in config[CONF_TEXT_SENSORS]: |     for conf in config[CONF_TEXT_SENSORS]: | ||||||
|         var = cg.new_Pvariable(conf[CONF_ID]) |         var = await text_sensor.new_text_sensor(conf) | ||||||
|         await cg.register_component(var, conf) |         await cg.register_component(var, conf) | ||||||
|         await text_sensor.register_text_sensor(var, conf) |  | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include "esphome/core/component.h" | #include "esphome/core/component.h" | ||||||
| #include "esphome/components/fan/fan_state.h" | #include "esphome/components/fan/fan.h" | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace demo { | namespace demo { | ||||||
| @@ -13,11 +13,10 @@ enum class DemoFanType { | |||||||
|   TYPE_4, |   TYPE_4, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| class DemoFan : public Component { | class DemoFan : public fan::Fan, public Component { | ||||||
|  public: |  public: | ||||||
|   void set_type(DemoFanType type) { type_ = type; } |   void set_type(DemoFanType type) { type_ = type; } | ||||||
|   void set_fan(fan::FanState *fan) { fan_ = fan; } |   fan::FanTraits get_traits() override { | ||||||
|   void setup() override { |  | ||||||
|     fan::FanTraits traits{}; |     fan::FanTraits traits{}; | ||||||
|  |  | ||||||
|     // oscillation |     // oscillation | ||||||
| @@ -43,10 +42,23 @@ class DemoFan : public Component { | |||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     this->fan_->set_traits(traits); |     return traits; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   void control(const fan::FanCall &call) override { | ||||||
|  |     if (call.get_state().has_value()) | ||||||
|  |       this->state = *call.get_state(); | ||||||
|  |     if (call.get_oscillating().has_value()) | ||||||
|  |       this->oscillating = *call.get_oscillating(); | ||||||
|  |     if (call.get_speed().has_value()) | ||||||
|  |       this->speed = *call.get_speed(); | ||||||
|  |     if (call.get_direction().has_value()) | ||||||
|  |       this->direction = *call.get_direction(); | ||||||
|  |  | ||||||
|  |     this->publish_state(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   fan::FanState *fan_; |  | ||||||
|   DemoFanType type_; |   DemoFanType type_; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -114,10 +114,11 @@ bool HOT IRAM_ATTR DHT::read_sensor_(float *temperature, float *humidity, bool r | |||||||
|       // Wait for rising edge |       // Wait for rising edge | ||||||
|       while (!this->pin_->digital_read()) { |       while (!this->pin_->digital_read()) { | ||||||
|         if (micros() - start_time > 90) { |         if (micros() - start_time > 90) { | ||||||
|           if (i < 0) |           if (i < 0) { | ||||||
|             error_code = 1; |             error_code = 1; | ||||||
|           else |           } else { | ||||||
|             error_code = 2; |             error_code = 2; | ||||||
|  |           } | ||||||
|           break; |           break; | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
| @@ -130,10 +131,11 @@ bool HOT IRAM_ATTR DHT::read_sensor_(float *temperature, float *humidity, bool r | |||||||
|       // Wait for falling edge |       // Wait for falling edge | ||||||
|       while (this->pin_->digital_read()) { |       while (this->pin_->digital_read()) { | ||||||
|         if ((end_time = micros()) - start_time > 90) { |         if ((end_time = micros()) - start_time > 90) { | ||||||
|           if (i < 0) |           if (i < 0) { | ||||||
|             error_code = 3; |             error_code = 3; | ||||||
|           else |           } else { | ||||||
|             error_code = 4; |             error_code = 4; | ||||||
|  |           } | ||||||
|           break; |           break; | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|   | |||||||
| @@ -176,9 +176,10 @@ void DisplayBuffer::print(int x, int y, Font *font, Color color, TextAlign align | |||||||
|       ESP_LOGW(TAG, "Encountered character without representation in font: '%c'", text[i]); |       ESP_LOGW(TAG, "Encountered character without representation in font: '%c'", text[i]); | ||||||
|       if (!font->get_glyphs().empty()) { |       if (!font->get_glyphs().empty()) { | ||||||
|         uint8_t glyph_width = font->get_glyphs()[0].glyph_data_->width; |         uint8_t glyph_width = font->get_glyphs()[0].glyph_data_->width; | ||||||
|         for (int glyph_x = 0; glyph_x < glyph_width; glyph_x++) |         for (int glyph_x = 0; glyph_x < glyph_width; glyph_x++) { | ||||||
|           for (int glyph_y = 0; glyph_y < height; glyph_y++) |           for (int glyph_y = 0; glyph_y < height; glyph_y++) | ||||||
|             this->draw_pixel_at(glyph_x + x_at, glyph_y + y_start, color); |             this->draw_pixel_at(glyph_x + x_at, glyph_y + y_start, color); | ||||||
|  |         } | ||||||
|         x_at += glyph_width; |         x_at += glyph_width; | ||||||
|       } |       } | ||||||
|  |  | ||||||
| @@ -233,6 +234,14 @@ void DisplayBuffer::image(int x, int y, Image *image, Color color_on, Color colo | |||||||
|         } |         } | ||||||
|       } |       } | ||||||
|       break; |       break; | ||||||
|  |     case IMAGE_TYPE_TRANSPARENT_BINARY: | ||||||
|  |       for (int img_x = 0; img_x < image->get_width(); img_x++) { | ||||||
|  |         for (int img_y = 0; img_y < image->get_height(); img_y++) { | ||||||
|  |           if (image->get_pixel(img_x, img_y)) | ||||||
|  |             this->draw_pixel_at(x + img_x, y + img_y, color_on); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       break; | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -243,6 +252,12 @@ void DisplayBuffer::legend(int x, int y, graph::Graph *graph, Color color_on) { | |||||||
| } | } | ||||||
| #endif  // USE_GRAPH | #endif  // USE_GRAPH | ||||||
|  |  | ||||||
|  | #ifdef USE_QR_CODE | ||||||
|  | void DisplayBuffer::qr_code(int x, int y, qr_code::QrCode *qr_code, Color color_on, int scale) { | ||||||
|  |   qr_code->draw(this, x, y, color_on, scale); | ||||||
|  | } | ||||||
|  | #endif  // USE_QR_CODE | ||||||
|  |  | ||||||
| void DisplayBuffer::get_text_bounds(int x, int y, const char *text, Font *font, TextAlign align, int *x1, int *y1, | void DisplayBuffer::get_text_bounds(int x, int y, const char *text, Font *font, TextAlign align, int *x1, int *y1, | ||||||
|                                     int *width, int *height) { |                                     int *width, int *height) { | ||||||
|   int x_offset, baseline; |   int x_offset, baseline; | ||||||
| @@ -417,10 +432,11 @@ int Font::match_next_glyph(const char *str, int *match_length) { | |||||||
|   int hi = this->glyphs_.size() - 1; |   int hi = this->glyphs_.size() - 1; | ||||||
|   while (lo != hi) { |   while (lo != hi) { | ||||||
|     int mid = (lo + hi + 1) / 2; |     int mid = (lo + hi + 1) / 2; | ||||||
|     if (this->glyphs_[mid].compare_to(str)) |     if (this->glyphs_[mid].compare_to(str)) { | ||||||
|       lo = mid; |       lo = mid; | ||||||
|     else |     } else { | ||||||
|       hi = mid - 1; |       hi = mid - 1; | ||||||
|  |     } | ||||||
|   } |   } | ||||||
|   *match_length = this->glyphs_[lo].match_length(str); |   *match_length = this->glyphs_[lo].match_length(str); | ||||||
|   if (*match_length <= 0) |   if (*match_length <= 0) | ||||||
| @@ -446,10 +462,11 @@ void Font::measure(const char *str, int *width, int *x_offset, int *baseline, in | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     const Glyph &glyph = this->glyphs_[glyph_n]; |     const Glyph &glyph = this->glyphs_[glyph_n]; | ||||||
|     if (!has_char) |     if (!has_char) { | ||||||
|       min_x = glyph.glyph_data_->offset_x; |       min_x = glyph.glyph_data_->offset_x; | ||||||
|     else |     } else { | ||||||
|       min_x = std::min(min_x, x + glyph.glyph_data_->offset_x); |       min_x = std::min(min_x, x + glyph.glyph_data_->offset_x); | ||||||
|  |     } | ||||||
|     x += glyph.glyph_data_->width + glyph.glyph_data_->offset_x; |     x += glyph.glyph_data_->width + glyph.glyph_data_->offset_x; | ||||||
|  |  | ||||||
|     i += match_length; |     i += match_length; | ||||||
|   | |||||||
| @@ -14,6 +14,10 @@ | |||||||
| #include "esphome/components/graph/graph.h" | #include "esphome/components/graph/graph.h" | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #ifdef USE_QR_CODE | ||||||
|  | #include "esphome/components/qr_code/qr_code.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace display { | namespace display { | ||||||
|  |  | ||||||
| @@ -73,7 +77,12 @@ extern const Color COLOR_OFF; | |||||||
| /// Turn the pixel ON. | /// Turn the pixel ON. | ||||||
| extern const Color COLOR_ON; | extern const Color COLOR_ON; | ||||||
|  |  | ||||||
| enum ImageType { IMAGE_TYPE_BINARY = 0, IMAGE_TYPE_GRAYSCALE = 1, IMAGE_TYPE_RGB24 = 2 }; | enum ImageType { | ||||||
|  |   IMAGE_TYPE_BINARY = 0, | ||||||
|  |   IMAGE_TYPE_GRAYSCALE = 1, | ||||||
|  |   IMAGE_TYPE_RGB24 = 2, | ||||||
|  |   IMAGE_TYPE_TRANSPARENT_BINARY = 3, | ||||||
|  | }; | ||||||
|  |  | ||||||
| enum DisplayRotation { | enum DisplayRotation { | ||||||
|   DISPLAY_ROTATION_0_DEGREES = 0, |   DISPLAY_ROTATION_0_DEGREES = 0, | ||||||
| @@ -302,6 +311,17 @@ class DisplayBuffer { | |||||||
|   void legend(int x, int y, graph::Graph *graph, Color color_on = COLOR_ON); |   void legend(int x, int y, graph::Graph *graph, Color color_on = COLOR_ON); | ||||||
| #endif  // USE_GRAPH | #endif  // USE_GRAPH | ||||||
|  |  | ||||||
|  | #ifdef USE_QR_CODE | ||||||
|  |   /** Draw the `qr_code` with the top-left corner at [x,y] to the screen. | ||||||
|  |    * | ||||||
|  |    * @param x The x coordinate of the upper left corner. | ||||||
|  |    * @param y The y coordinate of the upper left corner. | ||||||
|  |    * @param qr_code The qr_code to draw | ||||||
|  |    * @param color_on The color to replace in binary images for the on bits. | ||||||
|  |    */ | ||||||
|  |   void qr_code(int x, int y, qr_code::QrCode *qr_code, Color color_on = COLOR_ON, int scale = 1); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|   /** Get the text bounds of the given string. |   /** Get the text bounds of the given string. | ||||||
|    * |    * | ||||||
|    * @param x The x coordinate to place the string at, can be 0 if only interested in dimensions. |    * @param x The x coordinate to place the string at, can be 0 if only interested in dimensions. | ||||||
| @@ -336,15 +356,15 @@ class DisplayBuffer { | |||||||
|   // Internal method to set display auto clearing. |   // Internal method to set display auto clearing. | ||||||
|   void set_auto_clear(bool auto_clear_enabled) { this->auto_clear_enabled_ = auto_clear_enabled; } |   void set_auto_clear(bool auto_clear_enabled) { this->auto_clear_enabled_ = auto_clear_enabled; } | ||||||
|  |  | ||||||
|  |   virtual int get_height_internal() = 0; | ||||||
|  |   virtual int get_width_internal() = 0; | ||||||
|  |   DisplayRotation get_rotation() const { return this->rotation_; } | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   void vprintf_(int x, int y, Font *font, Color color, TextAlign align, const char *format, va_list arg); |   void vprintf_(int x, int y, Font *font, Color color, TextAlign align, const char *format, va_list arg); | ||||||
|  |  | ||||||
|   virtual void draw_absolute_pixel_internal(int x, int y, Color color) = 0; |   virtual void draw_absolute_pixel_internal(int x, int y, Color color) = 0; | ||||||
|  |  | ||||||
|   virtual int get_height_internal() = 0; |  | ||||||
|  |  | ||||||
|   virtual int get_width_internal() = 0; |  | ||||||
|  |  | ||||||
|   void init_internal_(uint32_t buffer_length); |   void init_internal_(uint32_t buffer_length); | ||||||
|  |  | ||||||
|   void do_update_(); |   void do_update_(); | ||||||
|   | |||||||
| @@ -1,9 +1,7 @@ | |||||||
| import esphome.codegen as cg | import esphome.codegen as cg | ||||||
| import esphome.config_validation as cv | import esphome.config_validation as cv | ||||||
| from esphome.components import text_sensor | from esphome.components import text_sensor | ||||||
| from esphome.const import ( |  | ||||||
|     CONF_ID, |  | ||||||
| ) |  | ||||||
| from . import Dsmr, CONF_DSMR_ID | from . import Dsmr, CONF_DSMR_ID | ||||||
|  |  | ||||||
| AUTO_LOAD = ["dsmr"] | AUTO_LOAD = ["dsmr"] | ||||||
| @@ -11,71 +9,19 @@ AUTO_LOAD = ["dsmr"] | |||||||
| CONFIG_SCHEMA = cv.Schema( | CONFIG_SCHEMA = cv.Schema( | ||||||
|     { |     { | ||||||
|         cv.GenerateID(CONF_DSMR_ID): cv.use_id(Dsmr), |         cv.GenerateID(CONF_DSMR_ID): cv.use_id(Dsmr), | ||||||
|         cv.Optional("identification"): text_sensor.TEXT_SENSOR_SCHEMA.extend( |         cv.Optional("identification"): text_sensor.text_sensor_schema(), | ||||||
|             { |         cv.Optional("p1_version"): text_sensor.text_sensor_schema(), | ||||||
|                 cv.GenerateID(): cv.declare_id(text_sensor.TextSensor), |         cv.Optional("p1_version_be"): text_sensor.text_sensor_schema(), | ||||||
|             } |         cv.Optional("timestamp"): text_sensor.text_sensor_schema(), | ||||||
|         ), |         cv.Optional("electricity_tariff"): text_sensor.text_sensor_schema(), | ||||||
|         cv.Optional("p1_version"): text_sensor.TEXT_SENSOR_SCHEMA.extend( |         cv.Optional("electricity_failure_log"): text_sensor.text_sensor_schema(), | ||||||
|             { |         cv.Optional("message_short"): text_sensor.text_sensor_schema(), | ||||||
|                 cv.GenerateID(): cv.declare_id(text_sensor.TextSensor), |         cv.Optional("message_long"): text_sensor.text_sensor_schema(), | ||||||
|             } |         cv.Optional("gas_equipment_id"): text_sensor.text_sensor_schema(), | ||||||
|         ), |         cv.Optional("thermal_equipment_id"): text_sensor.text_sensor_schema(), | ||||||
|         cv.Optional("p1_version_be"): text_sensor.TEXT_SENSOR_SCHEMA.extend( |         cv.Optional("water_equipment_id"): text_sensor.text_sensor_schema(), | ||||||
|             { |         cv.Optional("sub_equipment_id"): text_sensor.text_sensor_schema(), | ||||||
|                 cv.GenerateID(): cv.declare_id(text_sensor.TextSensor), |         cv.Optional("gas_delivered_text"): text_sensor.text_sensor_schema(), | ||||||
|             } |  | ||||||
|         ), |  | ||||||
|         cv.Optional("timestamp"): text_sensor.TEXT_SENSOR_SCHEMA.extend( |  | ||||||
|             { |  | ||||||
|                 cv.GenerateID(): cv.declare_id(text_sensor.TextSensor), |  | ||||||
|             } |  | ||||||
|         ), |  | ||||||
|         cv.Optional("electricity_tariff"): text_sensor.TEXT_SENSOR_SCHEMA.extend( |  | ||||||
|             { |  | ||||||
|                 cv.GenerateID(): cv.declare_id(text_sensor.TextSensor), |  | ||||||
|             } |  | ||||||
|         ), |  | ||||||
|         cv.Optional("electricity_failure_log"): text_sensor.TEXT_SENSOR_SCHEMA.extend( |  | ||||||
|             { |  | ||||||
|                 cv.GenerateID(): cv.declare_id(text_sensor.TextSensor), |  | ||||||
|             } |  | ||||||
|         ), |  | ||||||
|         cv.Optional("message_short"): text_sensor.TEXT_SENSOR_SCHEMA.extend( |  | ||||||
|             { |  | ||||||
|                 cv.GenerateID(): cv.declare_id(text_sensor.TextSensor), |  | ||||||
|             } |  | ||||||
|         ), |  | ||||||
|         cv.Optional("message_long"): text_sensor.TEXT_SENSOR_SCHEMA.extend( |  | ||||||
|             { |  | ||||||
|                 cv.GenerateID(): cv.declare_id(text_sensor.TextSensor), |  | ||||||
|             } |  | ||||||
|         ), |  | ||||||
|         cv.Optional("gas_equipment_id"): text_sensor.TEXT_SENSOR_SCHEMA.extend( |  | ||||||
|             { |  | ||||||
|                 cv.GenerateID(): cv.declare_id(text_sensor.TextSensor), |  | ||||||
|             } |  | ||||||
|         ), |  | ||||||
|         cv.Optional("thermal_equipment_id"): text_sensor.TEXT_SENSOR_SCHEMA.extend( |  | ||||||
|             { |  | ||||||
|                 cv.GenerateID(): cv.declare_id(text_sensor.TextSensor), |  | ||||||
|             } |  | ||||||
|         ), |  | ||||||
|         cv.Optional("water_equipment_id"): text_sensor.TEXT_SENSOR_SCHEMA.extend( |  | ||||||
|             { |  | ||||||
|                 cv.GenerateID(): cv.declare_id(text_sensor.TextSensor), |  | ||||||
|             } |  | ||||||
|         ), |  | ||||||
|         cv.Optional("sub_equipment_id"): text_sensor.TEXT_SENSOR_SCHEMA.extend( |  | ||||||
|             { |  | ||||||
|                 cv.GenerateID(): cv.declare_id(text_sensor.TextSensor), |  | ||||||
|             } |  | ||||||
|         ), |  | ||||||
|         cv.Optional("gas_delivered_text"): text_sensor.TEXT_SENSOR_SCHEMA.extend( |  | ||||||
|             { |  | ||||||
|                 cv.GenerateID(): cv.declare_id(text_sensor.TextSensor), |  | ||||||
|             } |  | ||||||
|         ), |  | ||||||
|     } |     } | ||||||
| ).extend(cv.COMPONENT_SCHEMA) | ).extend(cv.COMPONENT_SCHEMA) | ||||||
|  |  | ||||||
| @@ -89,8 +35,7 @@ async def to_code(config): | |||||||
|             continue |             continue | ||||||
|         id = conf.get("id") |         id = conf.get("id") | ||||||
|         if id and id.type == text_sensor.TextSensor: |         if id and id.type == text_sensor.TextSensor: | ||||||
|             var = cg.new_Pvariable(conf[CONF_ID]) |             var = await text_sensor.new_text_sensor(conf) | ||||||
|             await text_sensor.register_text_sensor(var, conf) |  | ||||||
|             cg.add(getattr(hub, f"set_{key}")(var)) |             cg.add(getattr(hub, f"set_{key}")(var)) | ||||||
|             text_sensors.append(f"F({key})") |             text_sensors.append(f"F({key})") | ||||||
|  |  | ||||||
|   | |||||||
| @@ -97,7 +97,7 @@ bool E131Component::process_(int universe, const E131Packet &packet) { | |||||||
|  |  | ||||||
|   ESP_LOGV(TAG, "Received E1.31 packet for %d universe, with %d bytes", universe, packet.count); |   ESP_LOGV(TAG, "Received E1.31 packet for %d universe, with %d bytes", universe, packet.count); | ||||||
|  |  | ||||||
|   for (auto light_effect : light_effects_) { |   for (auto *light_effect : light_effects_) { | ||||||
|     handled = light_effect->process_(universe, packet) || handled; |     handled = light_effect->process_(universe, packet) || handled; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -33,11 +33,9 @@ class E131Component : public esphome::Component { | |||||||
|   void loop() override; |   void loop() override; | ||||||
|   float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } |   float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } | ||||||
|  |  | ||||||
|  public: |  | ||||||
|   void add_effect(E131AddressableLightEffect *light_effect); |   void add_effect(E131AddressableLightEffect *light_effect); | ||||||
|   void remove_effect(E131AddressableLightEffect *light_effect); |   void remove_effect(E131AddressableLightEffect *light_effect); | ||||||
|  |  | ||||||
|  public: |  | ||||||
|   void set_method(E131ListenMethod listen_method) { this->listen_method_ = listen_method; } |   void set_method(E131ListenMethod listen_method) { this->listen_method_ = listen_method; } | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
| @@ -47,7 +45,6 @@ class E131Component : public esphome::Component { | |||||||
|   void join_(int universe); |   void join_(int universe); | ||||||
|   void leave_(int universe); |   void leave_(int universe); | ||||||
|  |  | ||||||
|  protected: |  | ||||||
|   E131ListenMethod listen_method_{E131_MULTICAST}; |   E131ListenMethod listen_method_{E131_MULTICAST}; | ||||||
|   std::unique_ptr<UDP> udp_; |   std::unique_ptr<UDP> udp_; | ||||||
|   std::set<E131AddressableLightEffect *> light_effects_; |   std::set<E131AddressableLightEffect *> light_effects_; | ||||||
|   | |||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user