mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	Merge branch 'dev' into bump-2023.4.0b1
This commit is contained in:
		| @@ -4,53 +4,60 @@ | |||||||
|   "postCreateCommand": [ |   "postCreateCommand": [ | ||||||
|     "script/devcontainer-post-create" |     "script/devcontainer-post-create" | ||||||
|   ], |   ], | ||||||
|  |   "containerEnv": { | ||||||
|  |     "DEVCONTAINER": "1" | ||||||
|  |   }, | ||||||
|   "runArgs": [ |   "runArgs": [ | ||||||
|     "--privileged", |     "--privileged", | ||||||
|     "-e", |     "-e", | ||||||
|     "ESPHOME_DASHBOARD_USE_PING=1" |     "ESPHOME_DASHBOARD_USE_PING=1" | ||||||
|   ], |   ], | ||||||
|   "appPort": 6052, |   "appPort": 6052, | ||||||
|   "extensions": [ |   "customizations": { | ||||||
|     // python |     "vscode": { | ||||||
|     "ms-python.python", |       "extensions": [ | ||||||
|     "visualstudioexptteam.vscodeintellicode", |         // python | ||||||
|     // yaml |         "ms-python.python", | ||||||
|     "redhat.vscode-yaml", |         "visualstudioexptteam.vscodeintellicode", | ||||||
|     // cpp |         // yaml | ||||||
|     "ms-vscode.cpptools", |         "redhat.vscode-yaml", | ||||||
|     // editorconfig |         // cpp | ||||||
|     "editorconfig.editorconfig", |         "ms-vscode.cpptools", | ||||||
|   ], |         // editorconfig | ||||||
|   "settings": { |         "editorconfig.editorconfig", | ||||||
|     "python.languageServer": "Pylance", |       ], | ||||||
|     "python.pythonPath": "/usr/bin/python3", |       "settings": { | ||||||
|     "python.linting.pylintEnabled": true, |         "python.languageServer": "Pylance", | ||||||
|     "python.linting.enabled": true, |         "python.pythonPath": "/usr/bin/python3", | ||||||
|     "python.formatting.provider": "black", |         "python.linting.pylintEnabled": true, | ||||||
|     "editor.formatOnPaste": false, |         "python.linting.enabled": true, | ||||||
|     "editor.formatOnSave": true, |         "python.formatting.provider": "black", | ||||||
|     "editor.formatOnType": true, |         "editor.formatOnPaste": false, | ||||||
|     "files.trimTrailingWhitespace": true, |         "editor.formatOnSave": true, | ||||||
|     "terminal.integrated.defaultProfile.linux": "bash", |         "editor.formatOnType": true, | ||||||
|     "yaml.customTags": [ |         "files.trimTrailingWhitespace": true, | ||||||
|       "!secret scalar", |         "terminal.integrated.defaultProfile.linux": "bash", | ||||||
|       "!lambda scalar", |         "yaml.customTags": [ | ||||||
|       "!include_dir_named scalar", |           "!secret scalar", | ||||||
|       "!include_dir_list scalar", |           "!lambda scalar", | ||||||
|       "!include_dir_merge_list scalar", |           "!include_dir_named scalar", | ||||||
|       "!include_dir_merge_named scalar" |           "!include_dir_list scalar", | ||||||
|     ], |           "!include_dir_merge_list scalar", | ||||||
|     "files.exclude": { |           "!include_dir_merge_named scalar" | ||||||
|       "**/.git": true, |         ], | ||||||
|       "**/.DS_Store": true, |         "files.exclude": { | ||||||
|       "**/*.pyc": { |           "**/.git": true, | ||||||
|         "when": "$(basename).py" |           "**/.DS_Store": true, | ||||||
|       }, |           "**/*.pyc": { | ||||||
|       "**/__pycache__": true |             "when": "$(basename).py" | ||||||
|     }, |           }, | ||||||
|     "files.associations": { |           "**/__pycache__": true | ||||||
|       "**/.vscode/*.json": "jsonc" |         }, | ||||||
|     }, |         "files.associations": { | ||||||
|     "C_Cpp.clang_format_path": "/usr/bin/clang-format-11", |           "**/.vscode/*.json": "jsonc" | ||||||
|  |         }, | ||||||
|  |         "C_Cpp.clang_format_path": "/usr/bin/clang-format-13" | ||||||
|  |       } | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							| @@ -41,6 +41,10 @@ jobs: | |||||||
|             file: tests/test3.yaml |             file: tests/test3.yaml | ||||||
|             name: Test tests/test3.yaml |             name: Test tests/test3.yaml | ||||||
|             pio_cache_key: test3 |             pio_cache_key: test3 | ||||||
|  |           - id: test | ||||||
|  |             file: tests/test3.1.yaml | ||||||
|  |             name: Test tests/test3.1.yaml | ||||||
|  |             pio_cache_key: test3.1 | ||||||
|           - id: test |           - id: test | ||||||
|             file: tests/test4.yaml |             file: tests/test4.yaml | ||||||
|             name: Test tests/test4.yaml |             name: Test tests/test4.yaml | ||||||
| @@ -129,7 +133,7 @@ jobs: | |||||||
|       - name: Install clang tools |       - name: Install clang tools | ||||||
|         run: | |         run: | | ||||||
|           sudo apt-get install \ |           sudo apt-get install \ | ||||||
|               clang-format-11 \ |               clang-format-13 \ | ||||||
|               clang-tidy-11 |               clang-tidy-11 | ||||||
|         if: matrix.id == 'clang-tidy' || matrix.id == 'clang-format' |         if: matrix.id == 'clang-tidy' || matrix.id == 'clang-format' | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										4
									
								
								.github/workflows/stale.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/stale.yml
									
									
									
									
										vendored
									
									
								
							| @@ -18,7 +18,7 @@ jobs: | |||||||
|   stale: |   stale: | ||||||
|     runs-on: ubuntu-latest |     runs-on: ubuntu-latest | ||||||
|     steps: |     steps: | ||||||
|       - uses: actions/stale@v7 |       - uses: actions/stale@v8 | ||||||
|         with: |         with: | ||||||
|           days-before-pr-stale: 90 |           days-before-pr-stale: 90 | ||||||
|           days-before-pr-close: 7 |           days-before-pr-close: 7 | ||||||
| @@ -38,7 +38,7 @@ jobs: | |||||||
|   close-issues: |   close-issues: | ||||||
|     runs-on: ubuntu-latest |     runs-on: ubuntu-latest | ||||||
|     steps: |     steps: | ||||||
|       - uses: actions/stale@v7 |       - uses: actions/stale@v8 | ||||||
|         with: |         with: | ||||||
|           days-before-pr-stale: -1 |           days-before-pr-stale: -1 | ||||||
|           days-before-pr-close: -1 |           days-before-pr-close: -1 | ||||||
|   | |||||||
							
								
								
									
										60
									
								
								.github/workflows/sync-device-classes.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								.github/workflows/sync-device-classes.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | |||||||
|  | --- | ||||||
|  | name: Synchronise Device Classes from Home Assistant | ||||||
|  |  | ||||||
|  | on: | ||||||
|  |   workflow_dispatch: | ||||||
|  |   schedule: | ||||||
|  |     - cron: '45 6 * * *' | ||||||
|  |  | ||||||
|  | permissions: | ||||||
|  |   contents: write | ||||||
|  |   pull-requests: write | ||||||
|  |  | ||||||
|  | jobs: | ||||||
|  |   sync: | ||||||
|  |     name: Sync Device Classes | ||||||
|  |     runs-on: ubuntu-latest | ||||||
|  |     steps: | ||||||
|  |       - name: Checkout | ||||||
|  |         uses: actions/checkout@v3 | ||||||
|  |  | ||||||
|  |       - name: Checkout Home Assistant | ||||||
|  |         uses: actions/checkout@v3 | ||||||
|  |         with: | ||||||
|  |           repository: home-assistant/core | ||||||
|  |           path: lib/home-assistant | ||||||
|  |  | ||||||
|  |       - name: Setup Python | ||||||
|  |         uses: actions/setup-python@v4 | ||||||
|  |         with: | ||||||
|  |           python-version: 3.11 | ||||||
|  |  | ||||||
|  |       - name: Install Home Assistant | ||||||
|  |         run: | | ||||||
|  |           python -m pip install --upgrade pip | ||||||
|  |           pip install -e lib/home-assistant | ||||||
|  |  | ||||||
|  |       - name: Sync | ||||||
|  |         run: | | ||||||
|  |           python ./script/sync-device_class.py | ||||||
|  |  | ||||||
|  |       - name: Get PR template | ||||||
|  |         id: pr-template-body | ||||||
|  |         run: | | ||||||
|  |           body=$(cat .github/PULL_REQUEST_TEMPLATE.md) | ||||||
|  |           delimiter="$(openssl rand -hex 8)" | ||||||
|  |           echo "body<<$delimiter" >> $GITHUB_OUTPUT | ||||||
|  |           echo "$body" >> $GITHUB_OUTPUT | ||||||
|  |           echo "$delimiter" >> $GITHUB_OUTPUT | ||||||
|  |  | ||||||
|  |       - name: Commit changes | ||||||
|  |         uses: peter-evans/create-pull-request@v4 | ||||||
|  |         with: | ||||||
|  |           commit-message: "Synchronise Device Classes from Home Assistant" | ||||||
|  |           committer: esphomebot <esphome@nabucasa.com> | ||||||
|  |           author: esphomebot <esphome@nabucasa.com> | ||||||
|  |           branch: sync/device-classes/ | ||||||
|  |           branch-suffix: timestamp | ||||||
|  |           delete-branch: true | ||||||
|  |           title: "Synchronise Device Classes from Home Assistant" | ||||||
|  |           body: ${{ steps.pr-template-body.outputs.body }} | ||||||
| @@ -2,8 +2,8 @@ | |||||||
| # See https://pre-commit.com for more information | # See https://pre-commit.com for more information | ||||||
| # 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/psf/black | ||||||
|     rev: 23.1.0 |     rev: 23.3.0 | ||||||
|     hooks: |     hooks: | ||||||
|       - id: black |       - id: black | ||||||
|         args: |         args: | ||||||
|   | |||||||
							
								
								
									
										15
									
								
								.vscode/tasks.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										15
									
								
								.vscode/tasks.json
									
									
									
									
										vendored
									
									
								
							| @@ -2,15 +2,24 @@ | |||||||
|   "version": "2.0.0", |   "version": "2.0.0", | ||||||
|   "tasks": [ |   "tasks": [ | ||||||
|     { |     { | ||||||
|       "label": "run", |       "label": "Run Dashboard", | ||||||
|       "type": "shell", |       "type": "shell", | ||||||
|       "command": "python3 -m esphome dashboard config/", |       "command": "${command:python.interpreterPath}", | ||||||
|  |       "args": [ | ||||||
|  |         "-m", | ||||||
|  |         "esphome", | ||||||
|  |         "dashboard", | ||||||
|  |         "config/" | ||||||
|  |       ], | ||||||
|       "problemMatcher": [] |       "problemMatcher": [] | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|       "label": "clang-tidy", |       "label": "clang-tidy", | ||||||
|       "type": "shell", |       "type": "shell", | ||||||
|       "command": "./script/clang-tidy", |       "command": "${command:python.interpreterPath}", | ||||||
|  |       "args": [ | ||||||
|  |         "./script/clang-tidy" | ||||||
|  |       ], | ||||||
|       "problemMatcher": [ |       "problemMatcher": [ | ||||||
|         { |         { | ||||||
|           "owner": "clang-tidy", |           "owner": "clang-tidy", | ||||||
|   | |||||||
| @@ -111,6 +111,8 @@ esphome/components/hte501/* @Stock-M | |||||||
| esphome/components/hydreon_rgxx/* @functionpointer | esphome/components/hydreon_rgxx/* @functionpointer | ||||||
| esphome/components/i2c/* @esphome/core | esphome/components/i2c/* @esphome/core | ||||||
| esphome/components/i2s_audio/* @jesserockz | esphome/components/i2s_audio/* @jesserockz | ||||||
|  | esphome/components/i2s_audio/media_player/* @jesserockz | ||||||
|  | esphome/components/i2s_audio/microphone/* @jesserockz | ||||||
| esphome/components/ili9xxx/* @nielsnl68 | esphome/components/ili9xxx/* @nielsnl68 | ||||||
| esphome/components/improv_base/* @esphome/core | esphome/components/improv_base/* @esphome/core | ||||||
| esphome/components/improv_serial/* @esphome/core | esphome/components/improv_serial/* @esphome/core | ||||||
| @@ -154,11 +156,13 @@ esphome/components/mcp9808/* @k7hpn | |||||||
| esphome/components/md5/* @esphome/core | esphome/components/md5/* @esphome/core | ||||||
| esphome/components/mdns/* @esphome/core | esphome/components/mdns/* @esphome/core | ||||||
| esphome/components/media_player/* @jesserockz | esphome/components/media_player/* @jesserockz | ||||||
|  | esphome/components/microphone/* @jesserockz | ||||||
| esphome/components/mics_4514/* @jesserockz | esphome/components/mics_4514/* @jesserockz | ||||||
| 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/mlx90393/* @functionpointer | ||||||
|  | esphome/components/mmc5603/* @benhoff | ||||||
| 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 | ||||||
| @@ -286,6 +290,7 @@ esphome/components/ufire_ise/* @pvizeli | |||||||
| esphome/components/ultrasonic/* @OttoWinter | esphome/components/ultrasonic/* @OttoWinter | ||||||
| esphome/components/vbus/* @ssieb | esphome/components/vbus/* @ssieb | ||||||
| esphome/components/version/* @esphome/core | esphome/components/version/* @esphome/core | ||||||
|  | esphome/components/voice_assistant/* @jesserockz | ||||||
| esphome/components/wake_on_lan/* @willwill2will54 | 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 | ||||||
|   | |||||||
| @@ -135,7 +135,7 @@ RUN \ | |||||||
|     apt-get update \ |     apt-get update \ | ||||||
|     # Use pinned versions so that we get updates with build caching |     # Use pinned versions so that we get updates with build caching | ||||||
|     && apt-get install -y --no-install-recommends \ |     && apt-get install -y --no-install-recommends \ | ||||||
|         clang-format-11=1:11.0.1-2 \ |         clang-format-13=1:13.0.1-6~deb11u1 \ | ||||||
|         clang-tidy-11=1:11.0.1-2 \ |         clang-tidy-11=1:11.0.1-2 \ | ||||||
|         patch=2.7.6-7 \ |         patch=2.7.6-7 \ | ||||||
|         software-properties-common=0.96.20.2-2.1 \ |         software-properties-common=0.96.20.2-2.1 \ | ||||||
|   | |||||||
| @@ -152,6 +152,8 @@ def run_miniterm(config, port): | |||||||
|         _LOGGER.error("Could not connect to serial port %s", port) |         _LOGGER.error("Could not connect to serial port %s", port) | ||||||
|         return 1 |         return 1 | ||||||
|  |  | ||||||
|  |     return 0 | ||||||
|  |  | ||||||
|  |  | ||||||
| def wrap_to_code(name, comp): | def wrap_to_code(name, comp): | ||||||
|     coro = coroutine(comp.to_code) |     coro = coroutine(comp.to_code) | ||||||
|   | |||||||
| @@ -65,7 +65,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_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_, |         esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_, | ||||||
|                                  packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE); |                                  packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE); | ||||||
|   | |||||||
| @@ -76,8 +76,6 @@ async def to_code(config): | |||||||
|         pos = 0 |         pos = 0 | ||||||
|         for frameIndex in range(frames): |         for frameIndex in range(frames): | ||||||
|             image.seek(frameIndex) |             image.seek(frameIndex) | ||||||
|             if CONF_RESIZE in config: |  | ||||||
|                 image.thumbnail(config[CONF_RESIZE]) |  | ||||||
|             frame = image.convert("RGB") |             frame = image.convert("RGB") | ||||||
|             if CONF_RESIZE in config: |             if CONF_RESIZE in config: | ||||||
|                 frame = frame.resize([width, height]) |                 frame = frame.resize([width, height]) | ||||||
|   | |||||||
| @@ -53,6 +53,9 @@ service APIConnection { | |||||||
|   rpc bluetooth_gatt_write_descriptor(BluetoothGATTWriteDescriptorRequest) returns (void) {} |   rpc bluetooth_gatt_write_descriptor(BluetoothGATTWriteDescriptorRequest) returns (void) {} | ||||||
|   rpc bluetooth_gatt_notify(BluetoothGATTNotifyRequest) returns (void) {} |   rpc bluetooth_gatt_notify(BluetoothGATTNotifyRequest) returns (void) {} | ||||||
|   rpc subscribe_bluetooth_connections_free(SubscribeBluetoothConnectionsFreeRequest) returns (BluetoothConnectionsFreeResponse) {} |   rpc subscribe_bluetooth_connections_free(SubscribeBluetoothConnectionsFreeRequest) returns (BluetoothConnectionsFreeResponse) {} | ||||||
|  |   rpc unsubscribe_bluetooth_le_advertisements(UnsubscribeBluetoothLEAdvertisementsRequest) returns (void) {} | ||||||
|  |  | ||||||
|  |   rpc subscribe_voice_assistant(SubscribeVoiceAssistantRequest) returns (void) {} | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -208,6 +211,8 @@ message DeviceInfoResponse { | |||||||
|   string manufacturer = 12; |   string manufacturer = 12; | ||||||
|  |  | ||||||
|   string friendly_name = 13; |   string friendly_name = 13; | ||||||
|  |  | ||||||
|  |   uint32 voice_assistant_version = 14; | ||||||
| } | } | ||||||
|  |  | ||||||
| message ListEntitiesRequest { | message ListEntitiesRequest { | ||||||
| @@ -1125,6 +1130,7 @@ message MediaPlayerCommandRequest { | |||||||
| message SubscribeBluetoothLEAdvertisementsRequest { | message SubscribeBluetoothLEAdvertisementsRequest { | ||||||
|   option (id) = 66; |   option (id) = 66; | ||||||
|   option (source) = SOURCE_CLIENT; |   option (source) = SOURCE_CLIENT; | ||||||
|  |   option (ifdef) = "USE_BLUETOOTH_PROXY"; | ||||||
| } | } | ||||||
|  |  | ||||||
| message BluetoothServiceData { | message BluetoothServiceData { | ||||||
| @@ -1156,6 +1162,7 @@ enum BluetoothDeviceRequestType { | |||||||
|   BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR = 3; |   BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR = 3; | ||||||
|   BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE = 4; |   BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE = 4; | ||||||
|   BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE = 5; |   BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE = 5; | ||||||
|  |   BLUETOOTH_DEVICE_REQUEST_TYPE_CLEAR_CACHE = 6; | ||||||
| } | } | ||||||
|  |  | ||||||
| message BluetoothDeviceRequest { | message BluetoothDeviceRequest { | ||||||
| @@ -1359,3 +1366,71 @@ message BluetoothDeviceUnpairingResponse { | |||||||
|   bool success = 2; |   bool success = 2; | ||||||
|   int32 error = 3; |   int32 error = 3; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | message UnsubscribeBluetoothLEAdvertisementsRequest { | ||||||
|  |   option (id) = 87; | ||||||
|  |   option (source) = SOURCE_CLIENT; | ||||||
|  |   option (ifdef) = "USE_BLUETOOTH_PROXY"; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | message BluetoothDeviceClearCacheResponse { | ||||||
|  |   option (id) = 88; | ||||||
|  |   option (source) = SOURCE_SERVER; | ||||||
|  |   option (ifdef) = "USE_BLUETOOTH_PROXY"; | ||||||
|  |  | ||||||
|  |   uint64 address = 1; | ||||||
|  |   bool success = 2; | ||||||
|  |   int32 error = 3; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ==================== PUSH TO TALK ==================== | ||||||
|  | message SubscribeVoiceAssistantRequest { | ||||||
|  |   option (id) = 89; | ||||||
|  |   option (source) = SOURCE_CLIENT; | ||||||
|  |   option (ifdef) = "USE_VOICE_ASSISTANT"; | ||||||
|  |  | ||||||
|  |   bool subscribe = 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | message VoiceAssistantRequest { | ||||||
|  |   option (id) = 90; | ||||||
|  |   option (source) = SOURCE_SERVER; | ||||||
|  |   option (ifdef) = "USE_VOICE_ASSISTANT"; | ||||||
|  |  | ||||||
|  |   bool start = 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | message VoiceAssistantResponse { | ||||||
|  |   option (id) = 91; | ||||||
|  |   option (source) = SOURCE_CLIENT; | ||||||
|  |   option (ifdef) = "USE_VOICE_ASSISTANT"; | ||||||
|  |  | ||||||
|  |   uint32 port = 1; | ||||||
|  |   bool error = 2; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | enum VoiceAssistantEvent { | ||||||
|  |   VOICE_ASSISTANT_ERROR = 0; | ||||||
|  |   VOICE_ASSISTANT_RUN_START = 1; | ||||||
|  |   VOICE_ASSISTANT_RUN_END = 2; | ||||||
|  |   VOICE_ASSISTANT_STT_START = 3; | ||||||
|  |   VOICE_ASSISTANT_STT_END = 4; | ||||||
|  |   VOICE_ASSISTANT_INTENT_START = 5; | ||||||
|  |   VOICE_ASSISTANT_INTENT_END = 6; | ||||||
|  |   VOICE_ASSISTANT_TTS_START = 7; | ||||||
|  |   VOICE_ASSISTANT_TTS_END = 8; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | message VoiceAssistantEventData { | ||||||
|  |   string name = 1; | ||||||
|  |   string value = 2; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | message VoiceAssistantEventResponse { | ||||||
|  |   option (id) = 92; | ||||||
|  |   option (source) = SOURCE_CLIENT; | ||||||
|  |   option (ifdef) = "USE_VOICE_ASSISTANT"; | ||||||
|  |  | ||||||
|  |   VoiceAssistantEvent event_type = 1; | ||||||
|  |   repeated VoiceAssistantEventData data = 2; | ||||||
|  | } | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
| #include "api_connection.h" | #include "api_connection.h" | ||||||
| #include <cerrno> | #include <cerrno> | ||||||
|  | #include <cinttypes> | ||||||
| #include "esphome/components/network/util.h" | #include "esphome/components/network/util.h" | ||||||
| #include "esphome/core/entity_base.h" | #include "esphome/core/entity_base.h" | ||||||
| #include "esphome/core/hal.h" | #include "esphome/core/hal.h" | ||||||
| @@ -15,6 +16,9 @@ | |||||||
| #ifdef USE_BLUETOOTH_PROXY | #ifdef USE_BLUETOOTH_PROXY | ||||||
| #include "esphome/components/bluetooth_proxy/bluetooth_proxy.h" | #include "esphome/components/bluetooth_proxy/bluetooth_proxy.h" | ||||||
| #endif | #endif | ||||||
|  | #ifdef USE_VOICE_ASSISTANT | ||||||
|  | #include "esphome/components/voice_assistant/voice_assistant.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace api { | namespace api { | ||||||
| @@ -180,7 +184,8 @@ bool APIConnection::send_binary_sensor_info(binary_sensor::BinarySensor *binary_ | |||||||
|   ListEntitiesBinarySensorResponse msg; |   ListEntitiesBinarySensorResponse msg; | ||||||
|   msg.object_id = binary_sensor->get_object_id(); |   msg.object_id = binary_sensor->get_object_id(); | ||||||
|   msg.key = binary_sensor->get_object_id_hash(); |   msg.key = binary_sensor->get_object_id_hash(); | ||||||
|   msg.name = binary_sensor->get_name(); |   if (binary_sensor->has_own_name()) | ||||||
|  |     msg.name = binary_sensor->get_name(); | ||||||
|   msg.unique_id = get_default_unique_id("binary_sensor", binary_sensor); |   msg.unique_id = get_default_unique_id("binary_sensor", binary_sensor); | ||||||
|   msg.device_class = binary_sensor->get_device_class(); |   msg.device_class = binary_sensor->get_device_class(); | ||||||
|   msg.is_status_binary_sensor = binary_sensor->is_status_binary_sensor(); |   msg.is_status_binary_sensor = binary_sensor->is_status_binary_sensor(); | ||||||
| @@ -212,7 +217,8 @@ bool APIConnection::send_cover_info(cover::Cover *cover) { | |||||||
|   ListEntitiesCoverResponse msg; |   ListEntitiesCoverResponse msg; | ||||||
|   msg.key = cover->get_object_id_hash(); |   msg.key = cover->get_object_id_hash(); | ||||||
|   msg.object_id = cover->get_object_id(); |   msg.object_id = cover->get_object_id(); | ||||||
|   msg.name = cover->get_name(); |   if (cover->has_own_name()) | ||||||
|  |     msg.name = cover->get_name(); | ||||||
|   msg.unique_id = get_default_unique_id("cover", cover); |   msg.unique_id = get_default_unique_id("cover", cover); | ||||||
|   msg.assumed_state = traits.get_is_assumed_state(); |   msg.assumed_state = traits.get_is_assumed_state(); | ||||||
|   msg.supports_position = traits.get_supports_position(); |   msg.supports_position = traits.get_supports_position(); | ||||||
| @@ -275,7 +281,8 @@ bool APIConnection::send_fan_info(fan::Fan *fan) { | |||||||
|   ListEntitiesFanResponse msg; |   ListEntitiesFanResponse msg; | ||||||
|   msg.key = fan->get_object_id_hash(); |   msg.key = fan->get_object_id_hash(); | ||||||
|   msg.object_id = fan->get_object_id(); |   msg.object_id = fan->get_object_id(); | ||||||
|   msg.name = fan->get_name(); |   if (fan->has_own_name()) | ||||||
|  |     msg.name = fan->get_name(); | ||||||
|   msg.unique_id = get_default_unique_id("fan", fan); |   msg.unique_id = get_default_unique_id("fan", fan); | ||||||
|   msg.supports_oscillation = traits.supports_oscillation(); |   msg.supports_oscillation = traits.supports_oscillation(); | ||||||
|   msg.supports_speed = traits.supports_speed(); |   msg.supports_speed = traits.supports_speed(); | ||||||
| @@ -337,7 +344,8 @@ bool APIConnection::send_light_info(light::LightState *light) { | |||||||
|   ListEntitiesLightResponse msg; |   ListEntitiesLightResponse msg; | ||||||
|   msg.key = light->get_object_id_hash(); |   msg.key = light->get_object_id_hash(); | ||||||
|   msg.object_id = light->get_object_id(); |   msg.object_id = light->get_object_id(); | ||||||
|   msg.name = light->get_name(); |   if (light->has_own_name()) | ||||||
|  |     msg.name = light->get_name(); | ||||||
|   msg.unique_id = get_default_unique_id("light", light); |   msg.unique_id = get_default_unique_id("light", light); | ||||||
|  |  | ||||||
|   msg.disabled_by_default = light->is_disabled_by_default(); |   msg.disabled_by_default = light->is_disabled_by_default(); | ||||||
| @@ -418,7 +426,8 @@ bool APIConnection::send_sensor_info(sensor::Sensor *sensor) { | |||||||
|   ListEntitiesSensorResponse msg; |   ListEntitiesSensorResponse msg; | ||||||
|   msg.key = sensor->get_object_id_hash(); |   msg.key = sensor->get_object_id_hash(); | ||||||
|   msg.object_id = sensor->get_object_id(); |   msg.object_id = sensor->get_object_id(); | ||||||
|   msg.name = sensor->get_name(); |   if (sensor->has_own_name()) | ||||||
|  |     msg.name = sensor->get_name(); | ||||||
|   msg.unique_id = sensor->unique_id(); |   msg.unique_id = sensor->unique_id(); | ||||||
|   if (msg.unique_id.empty()) |   if (msg.unique_id.empty()) | ||||||
|     msg.unique_id = get_default_unique_id("sensor", sensor); |     msg.unique_id = get_default_unique_id("sensor", sensor); | ||||||
| @@ -448,7 +457,8 @@ bool APIConnection::send_switch_info(switch_::Switch *a_switch) { | |||||||
|   ListEntitiesSwitchResponse msg; |   ListEntitiesSwitchResponse msg; | ||||||
|   msg.key = a_switch->get_object_id_hash(); |   msg.key = a_switch->get_object_id_hash(); | ||||||
|   msg.object_id = a_switch->get_object_id(); |   msg.object_id = a_switch->get_object_id(); | ||||||
|   msg.name = a_switch->get_name(); |   if (a_switch->has_own_name()) | ||||||
|  |     msg.name = a_switch->get_name(); | ||||||
|   msg.unique_id = get_default_unique_id("switch", a_switch); |   msg.unique_id = get_default_unique_id("switch", a_switch); | ||||||
|   msg.icon = a_switch->get_icon(); |   msg.icon = a_switch->get_icon(); | ||||||
|   msg.assumed_state = a_switch->assumed_state(); |   msg.assumed_state = a_switch->assumed_state(); | ||||||
| @@ -533,7 +543,8 @@ bool APIConnection::send_climate_info(climate::Climate *climate) { | |||||||
|   ListEntitiesClimateResponse msg; |   ListEntitiesClimateResponse msg; | ||||||
|   msg.key = climate->get_object_id_hash(); |   msg.key = climate->get_object_id_hash(); | ||||||
|   msg.object_id = climate->get_object_id(); |   msg.object_id = climate->get_object_id(); | ||||||
|   msg.name = climate->get_name(); |   if (climate->has_own_name()) | ||||||
|  |     msg.name = climate->get_name(); | ||||||
|   msg.unique_id = get_default_unique_id("climate", climate); |   msg.unique_id = get_default_unique_id("climate", climate); | ||||||
|  |  | ||||||
|   msg.disabled_by_default = climate->is_disabled_by_default(); |   msg.disabled_by_default = climate->is_disabled_by_default(); | ||||||
| @@ -611,7 +622,8 @@ bool APIConnection::send_number_info(number::Number *number) { | |||||||
|   ListEntitiesNumberResponse msg; |   ListEntitiesNumberResponse msg; | ||||||
|   msg.key = number->get_object_id_hash(); |   msg.key = number->get_object_id_hash(); | ||||||
|   msg.object_id = number->get_object_id(); |   msg.object_id = number->get_object_id(); | ||||||
|   msg.name = number->get_name(); |   if (number->has_own_name()) | ||||||
|  |     msg.name = number->get_name(); | ||||||
|   msg.unique_id = get_default_unique_id("number", number); |   msg.unique_id = get_default_unique_id("number", number); | ||||||
|   msg.icon = number->get_icon(); |   msg.icon = number->get_icon(); | ||||||
|   msg.disabled_by_default = number->is_disabled_by_default(); |   msg.disabled_by_default = number->is_disabled_by_default(); | ||||||
| @@ -652,7 +664,8 @@ bool APIConnection::send_select_info(select::Select *select) { | |||||||
|   ListEntitiesSelectResponse msg; |   ListEntitiesSelectResponse msg; | ||||||
|   msg.key = select->get_object_id_hash(); |   msg.key = select->get_object_id_hash(); | ||||||
|   msg.object_id = select->get_object_id(); |   msg.object_id = select->get_object_id(); | ||||||
|   msg.name = select->get_name(); |   if (select->has_own_name()) | ||||||
|  |     msg.name = select->get_name(); | ||||||
|   msg.unique_id = get_default_unique_id("select", select); |   msg.unique_id = get_default_unique_id("select", select); | ||||||
|   msg.icon = select->get_icon(); |   msg.icon = select->get_icon(); | ||||||
|   msg.disabled_by_default = select->is_disabled_by_default(); |   msg.disabled_by_default = select->is_disabled_by_default(); | ||||||
| @@ -679,7 +692,8 @@ bool APIConnection::send_button_info(button::Button *button) { | |||||||
|   ListEntitiesButtonResponse msg; |   ListEntitiesButtonResponse msg; | ||||||
|   msg.key = button->get_object_id_hash(); |   msg.key = button->get_object_id_hash(); | ||||||
|   msg.object_id = button->get_object_id(); |   msg.object_id = button->get_object_id(); | ||||||
|   msg.name = button->get_name(); |   if (button->has_own_name()) | ||||||
|  |     msg.name = button->get_name(); | ||||||
|   msg.unique_id = get_default_unique_id("button", button); |   msg.unique_id = get_default_unique_id("button", button); | ||||||
|   msg.icon = button->get_icon(); |   msg.icon = button->get_icon(); | ||||||
|   msg.disabled_by_default = button->is_disabled_by_default(); |   msg.disabled_by_default = button->is_disabled_by_default(); | ||||||
| @@ -710,7 +724,8 @@ bool APIConnection::send_lock_info(lock::Lock *a_lock) { | |||||||
|   ListEntitiesLockResponse msg; |   ListEntitiesLockResponse msg; | ||||||
|   msg.key = a_lock->get_object_id_hash(); |   msg.key = a_lock->get_object_id_hash(); | ||||||
|   msg.object_id = a_lock->get_object_id(); |   msg.object_id = a_lock->get_object_id(); | ||||||
|   msg.name = a_lock->get_name(); |   if (a_lock->has_own_name()) | ||||||
|  |     msg.name = a_lock->get_name(); | ||||||
|   msg.unique_id = get_default_unique_id("lock", a_lock); |   msg.unique_id = get_default_unique_id("lock", a_lock); | ||||||
|   msg.icon = a_lock->get_icon(); |   msg.icon = a_lock->get_icon(); | ||||||
|   msg.assumed_state = a_lock->traits.get_assumed_state(); |   msg.assumed_state = a_lock->traits.get_assumed_state(); | ||||||
| @@ -755,7 +770,8 @@ bool APIConnection::send_media_player_info(media_player::MediaPlayer *media_play | |||||||
|   ListEntitiesMediaPlayerResponse msg; |   ListEntitiesMediaPlayerResponse msg; | ||||||
|   msg.key = media_player->get_object_id_hash(); |   msg.key = media_player->get_object_id_hash(); | ||||||
|   msg.object_id = media_player->get_object_id(); |   msg.object_id = media_player->get_object_id(); | ||||||
|   msg.name = media_player->get_name(); |   if (media_player->has_own_name()) | ||||||
|  |     msg.name = media_player->get_name(); | ||||||
|   msg.unique_id = get_default_unique_id("media_player", media_player); |   msg.unique_id = get_default_unique_id("media_player", media_player); | ||||||
|   msg.icon = media_player->get_icon(); |   msg.icon = media_player->get_icon(); | ||||||
|   msg.disabled_by_default = media_player->is_disabled_by_default(); |   msg.disabled_by_default = media_player->is_disabled_by_default(); | ||||||
| @@ -799,7 +815,8 @@ bool APIConnection::send_camera_info(esp32_camera::ESP32Camera *camera) { | |||||||
|   ListEntitiesCameraResponse msg; |   ListEntitiesCameraResponse msg; | ||||||
|   msg.key = camera->get_object_id_hash(); |   msg.key = camera->get_object_id_hash(); | ||||||
|   msg.object_id = camera->get_object_id(); |   msg.object_id = camera->get_object_id(); | ||||||
|   msg.name = camera->get_name(); |   if (camera->has_own_name()) | ||||||
|  |     msg.name = camera->get_name(); | ||||||
|   msg.unique_id = get_default_unique_id("camera", camera); |   msg.unique_id = get_default_unique_id("camera", camera); | ||||||
|   msg.disabled_by_default = camera->is_disabled_by_default(); |   msg.disabled_by_default = camera->is_disabled_by_default(); | ||||||
|   msg.icon = camera->get_icon(); |   msg.icon = camera->get_icon(); | ||||||
| @@ -879,6 +896,30 @@ BluetoothConnectionsFreeResponse APIConnection::subscribe_bluetooth_connections_ | |||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #ifdef USE_VOICE_ASSISTANT | ||||||
|  | bool APIConnection::request_voice_assistant(bool start) { | ||||||
|  |   if (!this->voice_assistant_subscription_) | ||||||
|  |     return false; | ||||||
|  |   VoiceAssistantRequest msg; | ||||||
|  |   msg.start = start; | ||||||
|  |   return this->send_voice_assistant_request(msg); | ||||||
|  | } | ||||||
|  | void APIConnection::on_voice_assistant_response(const VoiceAssistantResponse &msg) { | ||||||
|  |   if (voice_assistant::global_voice_assistant != nullptr) { | ||||||
|  |     struct sockaddr_storage storage; | ||||||
|  |     socklen_t len = sizeof(storage); | ||||||
|  |     this->helper_->getpeername((struct sockaddr *) &storage, &len); | ||||||
|  |     voice_assistant::global_voice_assistant->start(&storage, msg.port); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | void APIConnection::on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) { | ||||||
|  |   if (voice_assistant::global_voice_assistant != nullptr) { | ||||||
|  |     voice_assistant::global_voice_assistant->on_event(msg); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #endif | ||||||
|  |  | ||||||
| bool APIConnection::send_log_message(int level, const char *tag, const char *line) { | bool APIConnection::send_log_message(int level, const char *tag, const char *line) { | ||||||
|   if (this->log_subscription_ < level) |   if (this->log_subscription_ < level) | ||||||
|     return false; |     return false; | ||||||
| @@ -898,7 +939,7 @@ HelloResponse APIConnection::hello(const HelloRequest &msg) { | |||||||
|   this->helper_->set_log_info(client_info_); |   this->helper_->set_log_info(client_info_); | ||||||
|   this->client_api_version_major_ = msg.api_version_major; |   this->client_api_version_major_ = msg.api_version_major; | ||||||
|   this->client_api_version_minor_ = msg.api_version_minor; |   this->client_api_version_minor_ = msg.api_version_minor; | ||||||
|   ESP_LOGV(TAG, "Hello from client: '%s' | API Version %d.%d", this->client_info_.c_str(), |   ESP_LOGV(TAG, "Hello from client: '%s' | API Version %" PRIu32 ".%" PRIu32, this->client_info_.c_str(), | ||||||
|            this->client_api_version_major_, this->client_api_version_minor_); |            this->client_api_version_major_, this->client_api_version_minor_); | ||||||
|  |  | ||||||
|   HelloResponse resp; |   HelloResponse resp; | ||||||
| @@ -953,7 +994,12 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) { | |||||||
|   resp.webserver_port = USE_WEBSERVER_PORT; |   resp.webserver_port = USE_WEBSERVER_PORT; | ||||||
| #endif | #endif | ||||||
| #ifdef USE_BLUETOOTH_PROXY | #ifdef USE_BLUETOOTH_PROXY | ||||||
|   resp.bluetooth_proxy_version = bluetooth_proxy::global_bluetooth_proxy->has_active() ? 4 : 1; |   resp.bluetooth_proxy_version = bluetooth_proxy::global_bluetooth_proxy->has_active() | ||||||
|  |                                      ? bluetooth_proxy::ACTIVE_CONNECTIONS_VERSION | ||||||
|  |                                      : bluetooth_proxy::PASSIVE_ONLY_VERSION; | ||||||
|  | #endif | ||||||
|  | #ifdef USE_VOICE_ASSISTANT | ||||||
|  |   resp.voice_assistant_version = 1; | ||||||
| #endif | #endif | ||||||
|   return resp; |   return resp; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ | |||||||
| #include "api_server.h" | #include "api_server.h" | ||||||
| #include "esphome/core/application.h" | #include "esphome/core/application.h" | ||||||
| #include "esphome/core/component.h" | #include "esphome/core/component.h" | ||||||
|  | #include "esphome/core/defines.h" | ||||||
|  |  | ||||||
| #include <vector> | #include <vector> | ||||||
|  |  | ||||||
| @@ -97,6 +98,12 @@ class APIConnection : public APIServerConnection { | |||||||
|     this->send_homeassistant_service_response(call); |     this->send_homeassistant_service_response(call); | ||||||
|   } |   } | ||||||
| #ifdef USE_BLUETOOTH_PROXY | #ifdef USE_BLUETOOTH_PROXY | ||||||
|  |   void subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) override { | ||||||
|  |     this->bluetooth_le_advertisement_subscription_ = true; | ||||||
|  |   } | ||||||
|  |   void unsubscribe_bluetooth_le_advertisements(const UnsubscribeBluetoothLEAdvertisementsRequest &msg) override { | ||||||
|  |     this->bluetooth_le_advertisement_subscription_ = false; | ||||||
|  |   } | ||||||
|   bool send_bluetooth_le_advertisement(const BluetoothLEAdvertisementResponse &msg); |   bool send_bluetooth_le_advertisement(const BluetoothLEAdvertisementResponse &msg); | ||||||
|  |  | ||||||
|   void bluetooth_device_request(const BluetoothDeviceRequest &msg) override; |   void bluetooth_device_request(const BluetoothDeviceRequest &msg) override; | ||||||
| @@ -117,6 +124,15 @@ class APIConnection : public APIServerConnection { | |||||||
|   } |   } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #ifdef USE_VOICE_ASSISTANT | ||||||
|  |   void subscribe_voice_assistant(const SubscribeVoiceAssistantRequest &msg) override { | ||||||
|  |     this->voice_assistant_subscription_ = msg.subscribe; | ||||||
|  |   } | ||||||
|  |   bool request_voice_assistant(bool start); | ||||||
|  |   void on_voice_assistant_response(const VoiceAssistantResponse &msg) override; | ||||||
|  |   void on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) override; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|   void on_disconnect_response(const DisconnectResponse &value) override; |   void on_disconnect_response(const DisconnectResponse &value) override; | ||||||
|   void on_ping_response(const PingResponse &value) override { |   void on_ping_response(const PingResponse &value) override { | ||||||
|     // we initiated ping |     // we initiated ping | ||||||
| @@ -150,9 +166,7 @@ class APIConnection : public APIServerConnection { | |||||||
|     return {}; |     return {}; | ||||||
|   } |   } | ||||||
|   void execute_service(const ExecuteServiceRequest &msg) override; |   void execute_service(const ExecuteServiceRequest &msg) override; | ||||||
|   void subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) override { |  | ||||||
|     this->bluetooth_le_advertisement_subscription_ = true; |  | ||||||
|   } |  | ||||||
|   bool is_authenticated() override { return this->connection_state_ == ConnectionState::AUTHENTICATED; } |   bool is_authenticated() override { return this->connection_state_ == ConnectionState::AUTHENTICATED; } | ||||||
|   bool is_connection_setup() override { |   bool is_connection_setup() override { | ||||||
|     return this->connection_state_ == ConnectionState ::CONNECTED || this->is_authenticated(); |     return this->connection_state_ == ConnectionState ::CONNECTED || this->is_authenticated(); | ||||||
| @@ -197,7 +211,12 @@ class APIConnection : public APIServerConnection { | |||||||
|   uint32_t last_traffic_; |   uint32_t last_traffic_; | ||||||
|   bool sent_ping_{false}; |   bool sent_ping_{false}; | ||||||
|   bool service_call_subscription_{false}; |   bool service_call_subscription_{false}; | ||||||
|  | #ifdef USE_BLUETOOTH_PROXY | ||||||
|   bool bluetooth_le_advertisement_subscription_{false}; |   bool bluetooth_le_advertisement_subscription_{false}; | ||||||
|  | #endif | ||||||
|  | #ifdef USE_VOICE_ASSISTANT | ||||||
|  |   bool voice_assistant_subscription_{false}; | ||||||
|  | #endif | ||||||
|   bool next_close_ = false; |   bool next_close_ = false; | ||||||
|   APIServer *parent_; |   APIServer *parent_; | ||||||
|   InitialStateIterator initial_state_iterator_; |   InitialStateIterator initial_state_iterator_; | ||||||
|   | |||||||
| @@ -295,7 +295,7 @@ APIError APINoiseFrameHelper::state_action_() { | |||||||
|     if (aerr != APIError::OK) |     if (aerr != APIError::OK) | ||||||
|       return aerr; |       return aerr; | ||||||
|     // ignore contents, may be used in future for flags |     // ignore contents, may be used in future for flags | ||||||
|     prologue_.push_back((uint8_t)(frame.msg.size() >> 8)); |     prologue_.push_back((uint8_t) (frame.msg.size() >> 8)); | ||||||
|     prologue_.push_back((uint8_t) frame.msg.size()); |     prologue_.push_back((uint8_t) frame.msg.size()); | ||||||
|     prologue_.insert(prologue_.end(), frame.msg.begin(), frame.msg.end()); |     prologue_.insert(prologue_.end(), frame.msg.begin(), frame.msg.end()); | ||||||
|  |  | ||||||
| @@ -492,9 +492,9 @@ APIError APINoiseFrameHelper::write_packet(uint16_t type, const uint8_t *payload | |||||||
|   // tmpbuf[1], tmpbuf[2] to be set later |   // tmpbuf[1], tmpbuf[2] to be set later | ||||||
|   const uint8_t msg_offset = 3; |   const uint8_t msg_offset = 3; | ||||||
|   const uint8_t payload_offset = msg_offset + 4; |   const uint8_t payload_offset = msg_offset + 4; | ||||||
|   tmpbuf[msg_offset + 0] = (uint8_t)(type >> 8);  // type |   tmpbuf[msg_offset + 0] = (uint8_t) (type >> 8);  // type | ||||||
|   tmpbuf[msg_offset + 1] = (uint8_t) type; |   tmpbuf[msg_offset + 1] = (uint8_t) type; | ||||||
|   tmpbuf[msg_offset + 2] = (uint8_t)(payload_len >> 8);  // data_len |   tmpbuf[msg_offset + 2] = (uint8_t) (payload_len >> 8);  // data_len | ||||||
|   tmpbuf[msg_offset + 3] = (uint8_t) payload_len; |   tmpbuf[msg_offset + 3] = (uint8_t) payload_len; | ||||||
|   // copy data |   // copy data | ||||||
|   std::copy(payload, payload + payload_len, &tmpbuf[payload_offset]); |   std::copy(payload, payload + payload_len, &tmpbuf[payload_offset]); | ||||||
| @@ -512,7 +512,7 @@ APIError APINoiseFrameHelper::write_packet(uint16_t type, const uint8_t *payload | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   size_t total_len = 3 + mbuf.size; |   size_t total_len = 3 + mbuf.size; | ||||||
|   tmpbuf[1] = (uint8_t)(mbuf.size >> 8); |   tmpbuf[1] = (uint8_t) (mbuf.size >> 8); | ||||||
|   tmpbuf[2] = (uint8_t) mbuf.size; |   tmpbuf[2] = (uint8_t) mbuf.size; | ||||||
|  |  | ||||||
|   struct iovec iov; |   struct iovec iov; | ||||||
| @@ -610,7 +610,7 @@ APIError APINoiseFrameHelper::write_raw_(const struct iovec *iov, int iovcnt) { | |||||||
| APIError APINoiseFrameHelper::write_frame_(const uint8_t *data, size_t len) { | APIError APINoiseFrameHelper::write_frame_(const uint8_t *data, size_t len) { | ||||||
|   uint8_t header[3]; |   uint8_t header[3]; | ||||||
|   header[0] = 0x01;  // indicator |   header[0] = 0x01;  // indicator | ||||||
|   header[1] = (uint8_t)(len >> 8); |   header[1] = (uint8_t) (len >> 8); | ||||||
|   header[2] = (uint8_t) len; |   header[2] = (uint8_t) len; | ||||||
|  |  | ||||||
|   struct iovec iov[2]; |   struct iovec iov[2]; | ||||||
|   | |||||||
| @@ -10,8 +10,8 @@ | |||||||
| #include "noise/protocol.h" | #include "noise/protocol.h" | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #include "esphome/components/socket/socket.h" |  | ||||||
| #include "api_noise_context.h" | #include "api_noise_context.h" | ||||||
|  | #include "esphome/components/socket/socket.h" | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace api { | namespace api { | ||||||
| @@ -67,6 +67,7 @@ class APIFrameHelper { | |||||||
|   virtual bool can_write_without_blocking() = 0; |   virtual bool can_write_without_blocking() = 0; | ||||||
|   virtual APIError write_packet(uint16_t type, const uint8_t *data, size_t len) = 0; |   virtual APIError write_packet(uint16_t type, const uint8_t *data, size_t len) = 0; | ||||||
|   virtual std::string getpeername() = 0; |   virtual std::string getpeername() = 0; | ||||||
|  |   virtual int getpeername(struct sockaddr *addr, socklen_t *addrlen) = 0; | ||||||
|   virtual APIError close() = 0; |   virtual APIError close() = 0; | ||||||
|   virtual APIError shutdown(int how) = 0; |   virtual APIError shutdown(int how) = 0; | ||||||
|   // Give this helper a name for logging |   // Give this helper a name for logging | ||||||
| @@ -84,7 +85,10 @@ class APINoiseFrameHelper : public APIFrameHelper { | |||||||
|   APIError read_packet(ReadPacketBuffer *buffer) override; |   APIError read_packet(ReadPacketBuffer *buffer) override; | ||||||
|   bool can_write_without_blocking() override; |   bool can_write_without_blocking() override; | ||||||
|   APIError write_packet(uint16_t type, const uint8_t *payload, size_t len) override; |   APIError write_packet(uint16_t type, const uint8_t *payload, size_t len) override; | ||||||
|   std::string getpeername() override { return socket_->getpeername(); } |   std::string getpeername() override { return this->socket_->getpeername(); } | ||||||
|  |   int getpeername(struct sockaddr *addr, socklen_t *addrlen) override { | ||||||
|  |     return this->socket_->getpeername(addr, addrlen); | ||||||
|  |   } | ||||||
|   APIError close() override; |   APIError close() override; | ||||||
|   APIError shutdown(int how) override; |   APIError shutdown(int how) override; | ||||||
|   // Give this helper a name for logging |   // Give this helper a name for logging | ||||||
| @@ -144,7 +148,10 @@ class APIPlaintextFrameHelper : public APIFrameHelper { | |||||||
|   APIError read_packet(ReadPacketBuffer *buffer) override; |   APIError read_packet(ReadPacketBuffer *buffer) override; | ||||||
|   bool can_write_without_blocking() override; |   bool can_write_without_blocking() override; | ||||||
|   APIError write_packet(uint16_t type, const uint8_t *payload, size_t len) override; |   APIError write_packet(uint16_t type, const uint8_t *payload, size_t len) override; | ||||||
|   std::string getpeername() override { return socket_->getpeername(); } |   std::string getpeername() override { return this->socket_->getpeername(); } | ||||||
|  |   int getpeername(struct sockaddr *addr, socklen_t *addrlen) override { | ||||||
|  |     return this->socket_->getpeername(addr, addrlen); | ||||||
|  |   } | ||||||
|   APIError close() override; |   APIError close() override; | ||||||
|   APIError shutdown(int how) override; |   APIError shutdown(int how) override; | ||||||
|   // Give this helper a name for logging |   // Give this helper a name for logging | ||||||
|   | |||||||
| @@ -400,6 +400,34 @@ const char *proto_enum_to_string<enums::BluetoothDeviceRequestType>(enums::Bluet | |||||||
|       return "BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE"; |       return "BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE"; | ||||||
|     case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE: |     case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE: | ||||||
|       return "BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE"; |       return "BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE"; | ||||||
|  |     case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CLEAR_CACHE: | ||||||
|  |       return "BLUETOOTH_DEVICE_REQUEST_TYPE_CLEAR_CACHE"; | ||||||
|  |     default: | ||||||
|  |       return "UNKNOWN"; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|  | template<> const char *proto_enum_to_string<enums::VoiceAssistantEvent>(enums::VoiceAssistantEvent value) { | ||||||
|  |   switch (value) { | ||||||
|  |     case enums::VOICE_ASSISTANT_ERROR: | ||||||
|  |       return "VOICE_ASSISTANT_ERROR"; | ||||||
|  |     case enums::VOICE_ASSISTANT_RUN_START: | ||||||
|  |       return "VOICE_ASSISTANT_RUN_START"; | ||||||
|  |     case enums::VOICE_ASSISTANT_RUN_END: | ||||||
|  |       return "VOICE_ASSISTANT_RUN_END"; | ||||||
|  |     case enums::VOICE_ASSISTANT_STT_START: | ||||||
|  |       return "VOICE_ASSISTANT_STT_START"; | ||||||
|  |     case enums::VOICE_ASSISTANT_STT_END: | ||||||
|  |       return "VOICE_ASSISTANT_STT_END"; | ||||||
|  |     case enums::VOICE_ASSISTANT_INTENT_START: | ||||||
|  |       return "VOICE_ASSISTANT_INTENT_START"; | ||||||
|  |     case enums::VOICE_ASSISTANT_INTENT_END: | ||||||
|  |       return "VOICE_ASSISTANT_INTENT_END"; | ||||||
|  |     case enums::VOICE_ASSISTANT_TTS_START: | ||||||
|  |       return "VOICE_ASSISTANT_TTS_START"; | ||||||
|  |     case enums::VOICE_ASSISTANT_TTS_END: | ||||||
|  |       return "VOICE_ASSISTANT_TTS_END"; | ||||||
|     default: |     default: | ||||||
|       return "UNKNOWN"; |       return "UNKNOWN"; | ||||||
|   } |   } | ||||||
| @@ -592,6 +620,10 @@ bool DeviceInfoResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { | |||||||
|       this->bluetooth_proxy_version = value.as_uint32(); |       this->bluetooth_proxy_version = value.as_uint32(); | ||||||
|       return true; |       return true; | ||||||
|     } |     } | ||||||
|  |     case 14: { | ||||||
|  |       this->voice_assistant_version = value.as_uint32(); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|     default: |     default: | ||||||
|       return false; |       return false; | ||||||
|   } |   } | ||||||
| @@ -652,6 +684,7 @@ void DeviceInfoResponse::encode(ProtoWriteBuffer buffer) const { | |||||||
|   buffer.encode_uint32(11, this->bluetooth_proxy_version); |   buffer.encode_uint32(11, this->bluetooth_proxy_version); | ||||||
|   buffer.encode_string(12, this->manufacturer); |   buffer.encode_string(12, this->manufacturer); | ||||||
|   buffer.encode_string(13, this->friendly_name); |   buffer.encode_string(13, this->friendly_name); | ||||||
|  |   buffer.encode_uint32(14, this->voice_assistant_version); | ||||||
| } | } | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
| void DeviceInfoResponse::dump_to(std::string &out) const { | void DeviceInfoResponse::dump_to(std::string &out) const { | ||||||
| @@ -710,6 +743,11 @@ void DeviceInfoResponse::dump_to(std::string &out) const { | |||||||
|   out.append("  friendly_name: "); |   out.append("  friendly_name: "); | ||||||
|   out.append("'").append(this->friendly_name).append("'"); |   out.append("'").append(this->friendly_name).append("'"); | ||||||
|   out.append("\n"); |   out.append("\n"); | ||||||
|  |  | ||||||
|  |   out.append("  voice_assistant_version: "); | ||||||
|  |   sprintf(buffer, "%u", this->voice_assistant_version); | ||||||
|  |   out.append(buffer); | ||||||
|  |   out.append("\n"); | ||||||
|   out.append("}"); |   out.append("}"); | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| @@ -6060,6 +6098,204 @@ void BluetoothDeviceUnpairingResponse::dump_to(std::string &out) const { | |||||||
|   out.append("}"); |   out.append("}"); | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | void UnsubscribeBluetoothLEAdvertisementsRequest::encode(ProtoWriteBuffer buffer) const {} | ||||||
|  | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|  | void UnsubscribeBluetoothLEAdvertisementsRequest::dump_to(std::string &out) const { | ||||||
|  |   out.append("UnsubscribeBluetoothLEAdvertisementsRequest {}"); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | bool BluetoothDeviceClearCacheResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { | ||||||
|  |   switch (field_id) { | ||||||
|  |     case 1: { | ||||||
|  |       this->address = value.as_uint64(); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |     case 2: { | ||||||
|  |       this->success = value.as_bool(); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |     case 3: { | ||||||
|  |       this->error = value.as_int32(); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |     default: | ||||||
|  |       return false; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | void BluetoothDeviceClearCacheResponse::encode(ProtoWriteBuffer buffer) const { | ||||||
|  |   buffer.encode_uint64(1, this->address); | ||||||
|  |   buffer.encode_bool(2, this->success); | ||||||
|  |   buffer.encode_int32(3, this->error); | ||||||
|  | } | ||||||
|  | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|  | void BluetoothDeviceClearCacheResponse::dump_to(std::string &out) const { | ||||||
|  |   __attribute__((unused)) char buffer[64]; | ||||||
|  |   out.append("BluetoothDeviceClearCacheResponse {\n"); | ||||||
|  |   out.append("  address: "); | ||||||
|  |   sprintf(buffer, "%llu", this->address); | ||||||
|  |   out.append(buffer); | ||||||
|  |   out.append("\n"); | ||||||
|  |  | ||||||
|  |   out.append("  success: "); | ||||||
|  |   out.append(YESNO(this->success)); | ||||||
|  |   out.append("\n"); | ||||||
|  |  | ||||||
|  |   out.append("  error: "); | ||||||
|  |   sprintf(buffer, "%d", this->error); | ||||||
|  |   out.append(buffer); | ||||||
|  |   out.append("\n"); | ||||||
|  |   out.append("}"); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | bool SubscribeVoiceAssistantRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { | ||||||
|  |   switch (field_id) { | ||||||
|  |     case 1: { | ||||||
|  |       this->subscribe = value.as_bool(); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |     default: | ||||||
|  |       return false; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | void SubscribeVoiceAssistantRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_bool(1, this->subscribe); } | ||||||
|  | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|  | void SubscribeVoiceAssistantRequest::dump_to(std::string &out) const { | ||||||
|  |   __attribute__((unused)) char buffer[64]; | ||||||
|  |   out.append("SubscribeVoiceAssistantRequest {\n"); | ||||||
|  |   out.append("  subscribe: "); | ||||||
|  |   out.append(YESNO(this->subscribe)); | ||||||
|  |   out.append("\n"); | ||||||
|  |   out.append("}"); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | bool VoiceAssistantRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { | ||||||
|  |   switch (field_id) { | ||||||
|  |     case 1: { | ||||||
|  |       this->start = value.as_bool(); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |     default: | ||||||
|  |       return false; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | void VoiceAssistantRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_bool(1, this->start); } | ||||||
|  | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|  | void VoiceAssistantRequest::dump_to(std::string &out) const { | ||||||
|  |   __attribute__((unused)) char buffer[64]; | ||||||
|  |   out.append("VoiceAssistantRequest {\n"); | ||||||
|  |   out.append("  start: "); | ||||||
|  |   out.append(YESNO(this->start)); | ||||||
|  |   out.append("\n"); | ||||||
|  |   out.append("}"); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | bool VoiceAssistantResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { | ||||||
|  |   switch (field_id) { | ||||||
|  |     case 1: { | ||||||
|  |       this->port = value.as_uint32(); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |     case 2: { | ||||||
|  |       this->error = value.as_bool(); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |     default: | ||||||
|  |       return false; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | void VoiceAssistantResponse::encode(ProtoWriteBuffer buffer) const { | ||||||
|  |   buffer.encode_uint32(1, this->port); | ||||||
|  |   buffer.encode_bool(2, this->error); | ||||||
|  | } | ||||||
|  | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|  | void VoiceAssistantResponse::dump_to(std::string &out) const { | ||||||
|  |   __attribute__((unused)) char buffer[64]; | ||||||
|  |   out.append("VoiceAssistantResponse {\n"); | ||||||
|  |   out.append("  port: "); | ||||||
|  |   sprintf(buffer, "%u", this->port); | ||||||
|  |   out.append(buffer); | ||||||
|  |   out.append("\n"); | ||||||
|  |  | ||||||
|  |   out.append("  error: "); | ||||||
|  |   out.append(YESNO(this->error)); | ||||||
|  |   out.append("\n"); | ||||||
|  |   out.append("}"); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | bool VoiceAssistantEventData::decode_length(uint32_t field_id, ProtoLengthDelimited value) { | ||||||
|  |   switch (field_id) { | ||||||
|  |     case 1: { | ||||||
|  |       this->name = value.as_string(); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |     case 2: { | ||||||
|  |       this->value = value.as_string(); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |     default: | ||||||
|  |       return false; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | void VoiceAssistantEventData::encode(ProtoWriteBuffer buffer) const { | ||||||
|  |   buffer.encode_string(1, this->name); | ||||||
|  |   buffer.encode_string(2, this->value); | ||||||
|  | } | ||||||
|  | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|  | void VoiceAssistantEventData::dump_to(std::string &out) const { | ||||||
|  |   __attribute__((unused)) char buffer[64]; | ||||||
|  |   out.append("VoiceAssistantEventData {\n"); | ||||||
|  |   out.append("  name: "); | ||||||
|  |   out.append("'").append(this->name).append("'"); | ||||||
|  |   out.append("\n"); | ||||||
|  |  | ||||||
|  |   out.append("  value: "); | ||||||
|  |   out.append("'").append(this->value).append("'"); | ||||||
|  |   out.append("\n"); | ||||||
|  |   out.append("}"); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | bool VoiceAssistantEventResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { | ||||||
|  |   switch (field_id) { | ||||||
|  |     case 1: { | ||||||
|  |       this->event_type = value.as_enum<enums::VoiceAssistantEvent>(); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |     default: | ||||||
|  |       return false; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | bool VoiceAssistantEventResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) { | ||||||
|  |   switch (field_id) { | ||||||
|  |     case 2: { | ||||||
|  |       this->data.push_back(value.as_message<VoiceAssistantEventData>()); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |     default: | ||||||
|  |       return false; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | void VoiceAssistantEventResponse::encode(ProtoWriteBuffer buffer) const { | ||||||
|  |   buffer.encode_enum<enums::VoiceAssistantEvent>(1, this->event_type); | ||||||
|  |   for (auto &it : this->data) { | ||||||
|  |     buffer.encode_message<VoiceAssistantEventData>(2, it, true); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|  | void VoiceAssistantEventResponse::dump_to(std::string &out) const { | ||||||
|  |   __attribute__((unused)) char buffer[64]; | ||||||
|  |   out.append("VoiceAssistantEventResponse {\n"); | ||||||
|  |   out.append("  event_type: "); | ||||||
|  |   out.append(proto_enum_to_string<enums::VoiceAssistantEvent>(this->event_type)); | ||||||
|  |   out.append("\n"); | ||||||
|  |  | ||||||
|  |   for (const auto &it : this->data) { | ||||||
|  |     out.append("  data: "); | ||||||
|  |     it.dump_to(out); | ||||||
|  |     out.append("\n"); | ||||||
|  |   } | ||||||
|  |   out.append("}"); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
| }  // namespace api | }  // namespace api | ||||||
| }  // namespace esphome | }  // namespace esphome | ||||||
|   | |||||||
| @@ -163,6 +163,18 @@ enum BluetoothDeviceRequestType : uint32_t { | |||||||
|   BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR = 3, |   BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR = 3, | ||||||
|   BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE = 4, |   BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE = 4, | ||||||
|   BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE = 5, |   BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE = 5, | ||||||
|  |   BLUETOOTH_DEVICE_REQUEST_TYPE_CLEAR_CACHE = 6, | ||||||
|  | }; | ||||||
|  | enum VoiceAssistantEvent : uint32_t { | ||||||
|  |   VOICE_ASSISTANT_ERROR = 0, | ||||||
|  |   VOICE_ASSISTANT_RUN_START = 1, | ||||||
|  |   VOICE_ASSISTANT_RUN_END = 2, | ||||||
|  |   VOICE_ASSISTANT_STT_START = 3, | ||||||
|  |   VOICE_ASSISTANT_STT_END = 4, | ||||||
|  |   VOICE_ASSISTANT_INTENT_START = 5, | ||||||
|  |   VOICE_ASSISTANT_INTENT_END = 6, | ||||||
|  |   VOICE_ASSISTANT_TTS_START = 7, | ||||||
|  |   VOICE_ASSISTANT_TTS_END = 8, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| }  // namespace enums | }  // namespace enums | ||||||
| @@ -278,6 +290,7 @@ class DeviceInfoResponse : public ProtoMessage { | |||||||
|   uint32_t bluetooth_proxy_version{0}; |   uint32_t bluetooth_proxy_version{0}; | ||||||
|   std::string manufacturer{}; |   std::string manufacturer{}; | ||||||
|   std::string friendly_name{}; |   std::string friendly_name{}; | ||||||
|  |   uint32_t voice_assistant_version{0}; | ||||||
|   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; | ||||||
| @@ -1554,6 +1567,87 @@ class BluetoothDeviceUnpairingResponse : public ProtoMessage { | |||||||
|  protected: |  protected: | ||||||
|   bool decode_varint(uint32_t field_id, ProtoVarInt value) override; |   bool decode_varint(uint32_t field_id, ProtoVarInt value) override; | ||||||
| }; | }; | ||||||
|  | class UnsubscribeBluetoothLEAdvertisementsRequest : public ProtoMessage { | ||||||
|  |  public: | ||||||
|  |   void encode(ProtoWriteBuffer buffer) const override; | ||||||
|  | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|  |   void dump_to(std::string &out) const override; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  | }; | ||||||
|  | class BluetoothDeviceClearCacheResponse : public ProtoMessage { | ||||||
|  |  public: | ||||||
|  |   uint64_t address{0}; | ||||||
|  |   bool success{false}; | ||||||
|  |   int32_t error{0}; | ||||||
|  |   void encode(ProtoWriteBuffer buffer) const override; | ||||||
|  | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|  |   void dump_to(std::string &out) const override; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   bool decode_varint(uint32_t field_id, ProtoVarInt value) override; | ||||||
|  | }; | ||||||
|  | class SubscribeVoiceAssistantRequest : public ProtoMessage { | ||||||
|  |  public: | ||||||
|  |   bool subscribe{false}; | ||||||
|  |   void encode(ProtoWriteBuffer buffer) const override; | ||||||
|  | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|  |   void dump_to(std::string &out) const override; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   bool decode_varint(uint32_t field_id, ProtoVarInt value) override; | ||||||
|  | }; | ||||||
|  | class VoiceAssistantRequest : public ProtoMessage { | ||||||
|  |  public: | ||||||
|  |   bool start{false}; | ||||||
|  |   void encode(ProtoWriteBuffer buffer) const override; | ||||||
|  | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|  |   void dump_to(std::string &out) const override; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   bool decode_varint(uint32_t field_id, ProtoVarInt value) override; | ||||||
|  | }; | ||||||
|  | class VoiceAssistantResponse : public ProtoMessage { | ||||||
|  |  public: | ||||||
|  |   uint32_t port{0}; | ||||||
|  |   bool error{false}; | ||||||
|  |   void encode(ProtoWriteBuffer buffer) const override; | ||||||
|  | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|  |   void dump_to(std::string &out) const override; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   bool decode_varint(uint32_t field_id, ProtoVarInt value) override; | ||||||
|  | }; | ||||||
|  | class VoiceAssistantEventData : public ProtoMessage { | ||||||
|  |  public: | ||||||
|  |   std::string name{}; | ||||||
|  |   std::string value{}; | ||||||
|  |   void encode(ProtoWriteBuffer buffer) const override; | ||||||
|  | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|  |   void dump_to(std::string &out) const override; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; | ||||||
|  | }; | ||||||
|  | class VoiceAssistantEventResponse : public ProtoMessage { | ||||||
|  |  public: | ||||||
|  |   enums::VoiceAssistantEvent event_type{}; | ||||||
|  |   std::vector<VoiceAssistantEventData> data{}; | ||||||
|  |   void encode(ProtoWriteBuffer buffer) const override; | ||||||
|  | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|  |   void dump_to(std::string &out) const override; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; | ||||||
|  |   bool decode_varint(uint32_t field_id, ProtoVarInt value) override; | ||||||
|  | }; | ||||||
|  |  | ||||||
| }  // namespace api | }  // namespace api | ||||||
| }  // namespace esphome | }  // namespace esphome | ||||||
|   | |||||||
| @@ -329,6 +329,8 @@ bool APIServerConnectionBase::send_media_player_state_response(const MediaPlayer | |||||||
| #ifdef USE_MEDIA_PLAYER | #ifdef USE_MEDIA_PLAYER | ||||||
| #endif | #endif | ||||||
| #ifdef USE_BLUETOOTH_PROXY | #ifdef USE_BLUETOOTH_PROXY | ||||||
|  | #endif | ||||||
|  | #ifdef USE_BLUETOOTH_PROXY | ||||||
| bool APIServerConnectionBase::send_bluetooth_le_advertisement_response(const BluetoothLEAdvertisementResponse &msg) { | bool APIServerConnectionBase::send_bluetooth_le_advertisement_response(const BluetoothLEAdvertisementResponse &msg) { | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|   ESP_LOGVV(TAG, "send_bluetooth_le_advertisement_response: %s", msg.dump().c_str()); |   ESP_LOGVV(TAG, "send_bluetooth_le_advertisement_response: %s", msg.dump().c_str()); | ||||||
| @@ -441,6 +443,30 @@ bool APIServerConnectionBase::send_bluetooth_device_unpairing_response(const Blu | |||||||
|   return this->send_message_<BluetoothDeviceUnpairingResponse>(msg, 86); |   return this->send_message_<BluetoothDeviceUnpairingResponse>(msg, 86); | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | #ifdef USE_BLUETOOTH_PROXY | ||||||
|  | #endif | ||||||
|  | #ifdef USE_BLUETOOTH_PROXY | ||||||
|  | bool APIServerConnectionBase::send_bluetooth_device_clear_cache_response(const BluetoothDeviceClearCacheResponse &msg) { | ||||||
|  | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|  |   ESP_LOGVV(TAG, "send_bluetooth_device_clear_cache_response: %s", msg.dump().c_str()); | ||||||
|  | #endif | ||||||
|  |   return this->send_message_<BluetoothDeviceClearCacheResponse>(msg, 88); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | #ifdef USE_VOICE_ASSISTANT | ||||||
|  | #endif | ||||||
|  | #ifdef USE_VOICE_ASSISTANT | ||||||
|  | bool APIServerConnectionBase::send_voice_assistant_request(const VoiceAssistantRequest &msg) { | ||||||
|  | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|  |   ESP_LOGVV(TAG, "send_voice_assistant_request: %s", msg.dump().c_str()); | ||||||
|  | #endif | ||||||
|  |   return this->send_message_<VoiceAssistantRequest>(msg, 90); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | #ifdef USE_VOICE_ASSISTANT | ||||||
|  | #endif | ||||||
|  | #ifdef USE_VOICE_ASSISTANT | ||||||
|  | #endif | ||||||
| bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) { | bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) { | ||||||
|   switch (msg_type) { |   switch (msg_type) { | ||||||
|     case 1: { |     case 1: { | ||||||
| @@ -709,12 +735,14 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, | |||||||
|       break; |       break; | ||||||
|     } |     } | ||||||
|     case 66: { |     case 66: { | ||||||
|  | #ifdef USE_BLUETOOTH_PROXY | ||||||
|       SubscribeBluetoothLEAdvertisementsRequest msg; |       SubscribeBluetoothLEAdvertisementsRequest msg; | ||||||
|       msg.decode(msg_data, msg_size); |       msg.decode(msg_data, msg_size); | ||||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|       ESP_LOGVV(TAG, "on_subscribe_bluetooth_le_advertisements_request: %s", msg.dump().c_str()); |       ESP_LOGVV(TAG, "on_subscribe_bluetooth_le_advertisements_request: %s", msg.dump().c_str()); | ||||||
| #endif | #endif | ||||||
|       this->on_subscribe_bluetooth_le_advertisements_request(msg); |       this->on_subscribe_bluetooth_le_advertisements_request(msg); | ||||||
|  | #endif | ||||||
|       break; |       break; | ||||||
|     } |     } | ||||||
|     case 68: { |     case 68: { | ||||||
| @@ -802,6 +830,50 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, | |||||||
|       ESP_LOGVV(TAG, "on_subscribe_bluetooth_connections_free_request: %s", msg.dump().c_str()); |       ESP_LOGVV(TAG, "on_subscribe_bluetooth_connections_free_request: %s", msg.dump().c_str()); | ||||||
| #endif | #endif | ||||||
|       this->on_subscribe_bluetooth_connections_free_request(msg); |       this->on_subscribe_bluetooth_connections_free_request(msg); | ||||||
|  | #endif | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |     case 87: { | ||||||
|  | #ifdef USE_BLUETOOTH_PROXY | ||||||
|  |       UnsubscribeBluetoothLEAdvertisementsRequest msg; | ||||||
|  |       msg.decode(msg_data, msg_size); | ||||||
|  | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|  |       ESP_LOGVV(TAG, "on_unsubscribe_bluetooth_le_advertisements_request: %s", msg.dump().c_str()); | ||||||
|  | #endif | ||||||
|  |       this->on_unsubscribe_bluetooth_le_advertisements_request(msg); | ||||||
|  | #endif | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |     case 89: { | ||||||
|  | #ifdef USE_VOICE_ASSISTANT | ||||||
|  |       SubscribeVoiceAssistantRequest msg; | ||||||
|  |       msg.decode(msg_data, msg_size); | ||||||
|  | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|  |       ESP_LOGVV(TAG, "on_subscribe_voice_assistant_request: %s", msg.dump().c_str()); | ||||||
|  | #endif | ||||||
|  |       this->on_subscribe_voice_assistant_request(msg); | ||||||
|  | #endif | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |     case 91: { | ||||||
|  | #ifdef USE_VOICE_ASSISTANT | ||||||
|  |       VoiceAssistantResponse msg; | ||||||
|  |       msg.decode(msg_data, msg_size); | ||||||
|  | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|  |       ESP_LOGVV(TAG, "on_voice_assistant_response: %s", msg.dump().c_str()); | ||||||
|  | #endif | ||||||
|  |       this->on_voice_assistant_response(msg); | ||||||
|  | #endif | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |     case 92: { | ||||||
|  | #ifdef USE_VOICE_ASSISTANT | ||||||
|  |       VoiceAssistantEventResponse msg; | ||||||
|  |       msg.decode(msg_data, msg_size); | ||||||
|  | #ifdef HAS_PROTO_MESSAGE_DUMP | ||||||
|  |       ESP_LOGVV(TAG, "on_voice_assistant_event_response: %s", msg.dump().c_str()); | ||||||
|  | #endif | ||||||
|  |       this->on_voice_assistant_event_response(msg); | ||||||
| #endif | #endif | ||||||
|       break; |       break; | ||||||
|     } |     } | ||||||
| @@ -1065,6 +1137,7 @@ void APIServerConnection::on_media_player_command_request(const MediaPlayerComma | |||||||
|   this->media_player_command(msg); |   this->media_player_command(msg); | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | #ifdef USE_BLUETOOTH_PROXY | ||||||
| void APIServerConnection::on_subscribe_bluetooth_le_advertisements_request( | void APIServerConnection::on_subscribe_bluetooth_le_advertisements_request( | ||||||
|     const SubscribeBluetoothLEAdvertisementsRequest &msg) { |     const SubscribeBluetoothLEAdvertisementsRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (!this->is_connection_setup()) { | ||||||
| @@ -1077,6 +1150,7 @@ void APIServerConnection::on_subscribe_bluetooth_le_advertisements_request( | |||||||
|   } |   } | ||||||
|   this->subscribe_bluetooth_le_advertisements(msg); |   this->subscribe_bluetooth_le_advertisements(msg); | ||||||
| } | } | ||||||
|  | #endif | ||||||
| #ifdef USE_BLUETOOTH_PROXY | #ifdef USE_BLUETOOTH_PROXY | ||||||
| void APIServerConnection::on_bluetooth_device_request(const BluetoothDeviceRequest &msg) { | void APIServerConnection::on_bluetooth_device_request(const BluetoothDeviceRequest &msg) { | ||||||
|   if (!this->is_connection_setup()) { |   if (!this->is_connection_setup()) { | ||||||
| @@ -1185,6 +1259,33 @@ void APIServerConnection::on_subscribe_bluetooth_connections_free_request( | |||||||
|   } |   } | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | #ifdef USE_BLUETOOTH_PROXY | ||||||
|  | void APIServerConnection::on_unsubscribe_bluetooth_le_advertisements_request( | ||||||
|  |     const UnsubscribeBluetoothLEAdvertisementsRequest &msg) { | ||||||
|  |   if (!this->is_connection_setup()) { | ||||||
|  |     this->on_no_setup_connection(); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   if (!this->is_authenticated()) { | ||||||
|  |     this->on_unauthenticated_access(); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   this->unsubscribe_bluetooth_le_advertisements(msg); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | #ifdef USE_VOICE_ASSISTANT | ||||||
|  | void APIServerConnection::on_subscribe_voice_assistant_request(const SubscribeVoiceAssistantRequest &msg) { | ||||||
|  |   if (!this->is_connection_setup()) { | ||||||
|  |     this->on_no_setup_connection(); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   if (!this->is_authenticated()) { | ||||||
|  |     this->on_unauthenticated_access(); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   this->subscribe_voice_assistant(msg); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
| }  // namespace api | }  // namespace api | ||||||
| }  // namespace esphome | }  // namespace esphome | ||||||
|   | |||||||
| @@ -154,8 +154,10 @@ class APIServerConnectionBase : public ProtoService { | |||||||
| #ifdef USE_MEDIA_PLAYER | #ifdef USE_MEDIA_PLAYER | ||||||
|   virtual void on_media_player_command_request(const MediaPlayerCommandRequest &value){}; |   virtual void on_media_player_command_request(const MediaPlayerCommandRequest &value){}; | ||||||
| #endif | #endif | ||||||
|  | #ifdef USE_BLUETOOTH_PROXY | ||||||
|   virtual void on_subscribe_bluetooth_le_advertisements_request( |   virtual void on_subscribe_bluetooth_le_advertisements_request( | ||||||
|       const SubscribeBluetoothLEAdvertisementsRequest &value){}; |       const SubscribeBluetoothLEAdvertisementsRequest &value){}; | ||||||
|  | #endif | ||||||
| #ifdef USE_BLUETOOTH_PROXY | #ifdef USE_BLUETOOTH_PROXY | ||||||
|   bool send_bluetooth_le_advertisement_response(const BluetoothLEAdvertisementResponse &msg); |   bool send_bluetooth_le_advertisement_response(const BluetoothLEAdvertisementResponse &msg); | ||||||
| #endif | #endif | ||||||
| @@ -215,6 +217,25 @@ class APIServerConnectionBase : public ProtoService { | |||||||
| #endif | #endif | ||||||
| #ifdef USE_BLUETOOTH_PROXY | #ifdef USE_BLUETOOTH_PROXY | ||||||
|   bool send_bluetooth_device_unpairing_response(const BluetoothDeviceUnpairingResponse &msg); |   bool send_bluetooth_device_unpairing_response(const BluetoothDeviceUnpairingResponse &msg); | ||||||
|  | #endif | ||||||
|  | #ifdef USE_BLUETOOTH_PROXY | ||||||
|  |   virtual void on_unsubscribe_bluetooth_le_advertisements_request( | ||||||
|  |       const UnsubscribeBluetoothLEAdvertisementsRequest &value){}; | ||||||
|  | #endif | ||||||
|  | #ifdef USE_BLUETOOTH_PROXY | ||||||
|  |   bool send_bluetooth_device_clear_cache_response(const BluetoothDeviceClearCacheResponse &msg); | ||||||
|  | #endif | ||||||
|  | #ifdef USE_VOICE_ASSISTANT | ||||||
|  |   virtual void on_subscribe_voice_assistant_request(const SubscribeVoiceAssistantRequest &value){}; | ||||||
|  | #endif | ||||||
|  | #ifdef USE_VOICE_ASSISTANT | ||||||
|  |   bool send_voice_assistant_request(const VoiceAssistantRequest &msg); | ||||||
|  | #endif | ||||||
|  | #ifdef USE_VOICE_ASSISTANT | ||||||
|  |   virtual void on_voice_assistant_response(const VoiceAssistantResponse &value){}; | ||||||
|  | #endif | ||||||
|  | #ifdef USE_VOICE_ASSISTANT | ||||||
|  |   virtual void on_voice_assistant_event_response(const VoiceAssistantEventResponse &value){}; | ||||||
| #endif | #endif | ||||||
|  protected: |  protected: | ||||||
|   bool read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) override; |   bool read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) override; | ||||||
| @@ -267,7 +288,9 @@ class APIServerConnection : public APIServerConnectionBase { | |||||||
| #ifdef USE_MEDIA_PLAYER | #ifdef USE_MEDIA_PLAYER | ||||||
|   virtual void media_player_command(const MediaPlayerCommandRequest &msg) = 0; |   virtual void media_player_command(const MediaPlayerCommandRequest &msg) = 0; | ||||||
| #endif | #endif | ||||||
|  | #ifdef USE_BLUETOOTH_PROXY | ||||||
|   virtual void subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) = 0; |   virtual void subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) = 0; | ||||||
|  | #endif | ||||||
| #ifdef USE_BLUETOOTH_PROXY | #ifdef USE_BLUETOOTH_PROXY | ||||||
|   virtual void bluetooth_device_request(const BluetoothDeviceRequest &msg) = 0; |   virtual void bluetooth_device_request(const BluetoothDeviceRequest &msg) = 0; | ||||||
| #endif | #endif | ||||||
| @@ -292,6 +315,12 @@ class APIServerConnection : public APIServerConnectionBase { | |||||||
| #ifdef USE_BLUETOOTH_PROXY | #ifdef USE_BLUETOOTH_PROXY | ||||||
|   virtual BluetoothConnectionsFreeResponse subscribe_bluetooth_connections_free( |   virtual BluetoothConnectionsFreeResponse subscribe_bluetooth_connections_free( | ||||||
|       const SubscribeBluetoothConnectionsFreeRequest &msg) = 0; |       const SubscribeBluetoothConnectionsFreeRequest &msg) = 0; | ||||||
|  | #endif | ||||||
|  | #ifdef USE_BLUETOOTH_PROXY | ||||||
|  |   virtual void unsubscribe_bluetooth_le_advertisements(const UnsubscribeBluetoothLEAdvertisementsRequest &msg) = 0; | ||||||
|  | #endif | ||||||
|  | #ifdef USE_VOICE_ASSISTANT | ||||||
|  |   virtual void subscribe_voice_assistant(const SubscribeVoiceAssistantRequest &msg) = 0; | ||||||
| #endif | #endif | ||||||
|  protected: |  protected: | ||||||
|   void on_hello_request(const HelloRequest &msg) override; |   void on_hello_request(const HelloRequest &msg) override; | ||||||
| @@ -339,7 +368,9 @@ class APIServerConnection : public APIServerConnectionBase { | |||||||
| #ifdef USE_MEDIA_PLAYER | #ifdef USE_MEDIA_PLAYER | ||||||
|   void on_media_player_command_request(const MediaPlayerCommandRequest &msg) override; |   void on_media_player_command_request(const MediaPlayerCommandRequest &msg) override; | ||||||
| #endif | #endif | ||||||
|  | #ifdef USE_BLUETOOTH_PROXY | ||||||
|   void on_subscribe_bluetooth_le_advertisements_request(const SubscribeBluetoothLEAdvertisementsRequest &msg) override; |   void on_subscribe_bluetooth_le_advertisements_request(const SubscribeBluetoothLEAdvertisementsRequest &msg) override; | ||||||
|  | #endif | ||||||
| #ifdef USE_BLUETOOTH_PROXY | #ifdef USE_BLUETOOTH_PROXY | ||||||
|   void on_bluetooth_device_request(const BluetoothDeviceRequest &msg) override; |   void on_bluetooth_device_request(const BluetoothDeviceRequest &msg) override; | ||||||
| #endif | #endif | ||||||
| @@ -364,6 +395,13 @@ class APIServerConnection : public APIServerConnectionBase { | |||||||
| #ifdef USE_BLUETOOTH_PROXY | #ifdef USE_BLUETOOTH_PROXY | ||||||
|   void on_subscribe_bluetooth_connections_free_request(const SubscribeBluetoothConnectionsFreeRequest &msg) override; |   void on_subscribe_bluetooth_connections_free_request(const SubscribeBluetoothConnectionsFreeRequest &msg) override; | ||||||
| #endif | #endif | ||||||
|  | #ifdef USE_BLUETOOTH_PROXY | ||||||
|  |   void on_unsubscribe_bluetooth_le_advertisements_request( | ||||||
|  |       const UnsubscribeBluetoothLEAdvertisementsRequest &msg) override; | ||||||
|  | #endif | ||||||
|  | #ifdef USE_VOICE_ASSISTANT | ||||||
|  |   void on_subscribe_voice_assistant_request(const SubscribeVoiceAssistantRequest &msg) override; | ||||||
|  | #endif | ||||||
| }; | }; | ||||||
|  |  | ||||||
| }  // namespace api | }  // namespace api | ||||||
|   | |||||||
| @@ -45,7 +45,7 @@ void APIServer::setup() { | |||||||
|  |  | ||||||
|   struct sockaddr_storage server; |   struct sockaddr_storage server; | ||||||
|  |  | ||||||
|   socklen_t sl = socket::set_sockaddr_any((struct sockaddr *) &server, sizeof(server), htons(this->port_)); |   socklen_t sl = socket::set_sockaddr_any((struct sockaddr *) &server, sizeof(server), this->port_); | ||||||
|   if (sl == 0) { |   if (sl == 0) { | ||||||
|     ESP_LOGW(TAG, "Socket unable to set sockaddr: errno %d", errno); |     ESP_LOGW(TAG, "Socket unable to set sockaddr: errno %d", errno); | ||||||
|     this->mark_failed(); |     this->mark_failed(); | ||||||
| @@ -331,6 +331,17 @@ void APIServer::send_bluetooth_device_unpairing(uint64_t address, bool success, | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void APIServer::send_bluetooth_device_clear_cache(uint64_t address, bool success, esp_err_t error) { | ||||||
|  |   BluetoothDeviceClearCacheResponse call; | ||||||
|  |   call.address = address; | ||||||
|  |   call.success = success; | ||||||
|  |   call.error = error; | ||||||
|  |  | ||||||
|  |   for (auto &client : this->clients_) { | ||||||
|  |     client->send_bluetooth_device_clear_cache_response(call); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
| void APIServer::send_bluetooth_connections_free(uint8_t free, uint8_t limit) { | void APIServer::send_bluetooth_connections_free(uint8_t free, uint8_t limit) { | ||||||
|   BluetoothConnectionsFreeResponse call; |   BluetoothConnectionsFreeResponse call; | ||||||
|   call.free = free; |   call.free = free; | ||||||
| @@ -416,5 +427,18 @@ void APIServer::on_shutdown() { | |||||||
|   delay(10); |   delay(10); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #ifdef USE_VOICE_ASSISTANT | ||||||
|  | void APIServer::start_voice_assistant() { | ||||||
|  |   for (auto &c : this->clients_) { | ||||||
|  |     c->request_voice_assistant(true); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | void APIServer::stop_voice_assistant() { | ||||||
|  |   for (auto &c : this->clients_) { | ||||||
|  |     c->request_voice_assistant(false); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
| }  // namespace api | }  // namespace api | ||||||
| }  // namespace esphome | }  // namespace esphome | ||||||
|   | |||||||
| @@ -80,6 +80,7 @@ class APIServer : public Component, public Controller { | |||||||
|   void send_bluetooth_device_connection(uint64_t address, bool connected, uint16_t mtu = 0, esp_err_t error = ESP_OK); |   void send_bluetooth_device_connection(uint64_t address, bool connected, uint16_t mtu = 0, esp_err_t error = ESP_OK); | ||||||
|   void send_bluetooth_device_pairing(uint64_t address, bool paired, esp_err_t error = ESP_OK); |   void send_bluetooth_device_pairing(uint64_t address, bool paired, esp_err_t error = ESP_OK); | ||||||
|   void send_bluetooth_device_unpairing(uint64_t address, bool success, esp_err_t error = ESP_OK); |   void send_bluetooth_device_unpairing(uint64_t address, bool success, esp_err_t error = ESP_OK); | ||||||
|  |   void send_bluetooth_device_clear_cache(uint64_t address, bool success, esp_err_t error = ESP_OK); | ||||||
|   void send_bluetooth_connections_free(uint8_t free, uint8_t limit); |   void send_bluetooth_connections_free(uint8_t free, uint8_t limit); | ||||||
|   void send_bluetooth_gatt_read_response(const BluetoothGATTReadResponse &call); |   void send_bluetooth_gatt_read_response(const BluetoothGATTReadResponse &call); | ||||||
|   void send_bluetooth_gatt_write_response(const BluetoothGATTWriteResponse &call); |   void send_bluetooth_gatt_write_response(const BluetoothGATTWriteResponse &call); | ||||||
| @@ -94,6 +95,11 @@ class APIServer : public Component, public Controller { | |||||||
|   void request_time(); |   void request_time(); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #ifdef USE_VOICE_ASSISTANT | ||||||
|  |   void start_voice_assistant(); | ||||||
|  |   void stop_voice_assistant(); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|   bool is_connected() const; |   bool is_connected() const; | ||||||
|  |  | ||||||
|   struct HomeAssistantStateSubscription { |   struct HomeAssistantStateSubscription { | ||||||
|   | |||||||
| @@ -1,4 +1,5 @@ | |||||||
| #include "proto.h" | #include "proto.h" | ||||||
|  | #include <cinttypes> | ||||||
| #include "esphome/core/log.h" | #include "esphome/core/log.h" | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| @@ -13,7 +14,7 @@ void ProtoMessage::decode(const uint8_t *buffer, size_t length) { | |||||||
|     uint32_t consumed; |     uint32_t consumed; | ||||||
|     auto res = ProtoVarInt::parse(&buffer[i], length - i, &consumed); |     auto res = ProtoVarInt::parse(&buffer[i], length - i, &consumed); | ||||||
|     if (!res.has_value()) { |     if (!res.has_value()) { | ||||||
|       ESP_LOGV(TAG, "Invalid field start at %u", i); |       ESP_LOGV(TAG, "Invalid field start at %" PRIu32, i); | ||||||
|       break; |       break; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -25,12 +26,12 @@ void ProtoMessage::decode(const uint8_t *buffer, size_t length) { | |||||||
|       case 0: {  // VarInt |       case 0: {  // VarInt | ||||||
|         res = ProtoVarInt::parse(&buffer[i], length - i, &consumed); |         res = ProtoVarInt::parse(&buffer[i], length - i, &consumed); | ||||||
|         if (!res.has_value()) { |         if (!res.has_value()) { | ||||||
|           ESP_LOGV(TAG, "Invalid VarInt at %u", i); |           ESP_LOGV(TAG, "Invalid VarInt at %" PRIu32, i); | ||||||
|           error = true; |           error = true; | ||||||
|           break; |           break; | ||||||
|         } |         } | ||||||
|         if (!this->decode_varint(field_id, *res)) { |         if (!this->decode_varint(field_id, *res)) { | ||||||
|           ESP_LOGV(TAG, "Cannot decode VarInt field %u with value %u!", field_id, res->as_uint32()); |           ESP_LOGV(TAG, "Cannot decode VarInt field %" PRIu32 " with value %" PRIu32 "!", field_id, res->as_uint32()); | ||||||
|         } |         } | ||||||
|         i += consumed; |         i += consumed; | ||||||
|         break; |         break; | ||||||
| @@ -38,38 +39,38 @@ void ProtoMessage::decode(const uint8_t *buffer, size_t length) { | |||||||
|       case 2: {  // Length-delimited |       case 2: {  // Length-delimited | ||||||
|         res = ProtoVarInt::parse(&buffer[i], length - i, &consumed); |         res = ProtoVarInt::parse(&buffer[i], length - i, &consumed); | ||||||
|         if (!res.has_value()) { |         if (!res.has_value()) { | ||||||
|           ESP_LOGV(TAG, "Invalid Length Delimited at %u", i); |           ESP_LOGV(TAG, "Invalid Length Delimited at %" PRIu32, i); | ||||||
|           error = true; |           error = true; | ||||||
|           break; |           break; | ||||||
|         } |         } | ||||||
|         uint32_t field_length = res->as_uint32(); |         uint32_t field_length = res->as_uint32(); | ||||||
|         i += consumed; |         i += consumed; | ||||||
|         if (field_length > length - i) { |         if (field_length > length - i) { | ||||||
|           ESP_LOGV(TAG, "Out-of-bounds Length Delimited at %u", i); |           ESP_LOGV(TAG, "Out-of-bounds Length Delimited at %" PRIu32, i); | ||||||
|           error = true; |           error = true; | ||||||
|           break; |           break; | ||||||
|         } |         } | ||||||
|         if (!this->decode_length(field_id, ProtoLengthDelimited(&buffer[i], field_length))) { |         if (!this->decode_length(field_id, ProtoLengthDelimited(&buffer[i], field_length))) { | ||||||
|           ESP_LOGV(TAG, "Cannot decode Length Delimited field %u!", field_id); |           ESP_LOGV(TAG, "Cannot decode Length Delimited field %" PRIu32 "!", field_id); | ||||||
|         } |         } | ||||||
|         i += field_length; |         i += field_length; | ||||||
|         break; |         break; | ||||||
|       } |       } | ||||||
|       case 5: {  // 32-bit |       case 5: {  // 32-bit | ||||||
|         if (length - i < 4) { |         if (length - i < 4) { | ||||||
|           ESP_LOGV(TAG, "Out-of-bounds Fixed32-bit at %u", i); |           ESP_LOGV(TAG, "Out-of-bounds Fixed32-bit at %" PRIu32, i); | ||||||
|           error = true; |           error = true; | ||||||
|           break; |           break; | ||||||
|         } |         } | ||||||
|         uint32_t val = encode_uint32(buffer[i + 3], buffer[i + 2], buffer[i + 1], buffer[i]); |         uint32_t val = encode_uint32(buffer[i + 3], buffer[i + 2], buffer[i + 1], buffer[i]); | ||||||
|         if (!this->decode_32bit(field_id, Proto32Bit(val))) { |         if (!this->decode_32bit(field_id, Proto32Bit(val))) { | ||||||
|           ESP_LOGV(TAG, "Cannot decode 32-bit field %u with value %u!", field_id, val); |           ESP_LOGV(TAG, "Cannot decode 32-bit field %" PRIu32 " with value %" PRIu32 "!", field_id, val); | ||||||
|         } |         } | ||||||
|         i += 4; |         i += 4; | ||||||
|         break; |         break; | ||||||
|       } |       } | ||||||
|       default: |       default: | ||||||
|         ESP_LOGV(TAG, "Invalid field type at %u", i); |         ESP_LOGV(TAG, "Invalid field type at %" PRIu32, i); | ||||||
|         error = true; |         error = true; | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -12,7 +12,6 @@ from esphome.const import ( | |||||||
|     CONF_CAPACITANCE, |     CONF_CAPACITANCE, | ||||||
| ) | ) | ||||||
|  |  | ||||||
| AUTO_LOAD = ["sensor", "binary_sensor"] |  | ||||||
| MULTI_CONF = True | MULTI_CONF = True | ||||||
|  |  | ||||||
| CONF_AS3935_ID = "as3935_id" | CONF_AS3935_ID = "as3935_id" | ||||||
|   | |||||||
| @@ -26,9 +26,13 @@ void AS3935Component::setup() { | |||||||
| void AS3935Component::dump_config() { | void AS3935Component::dump_config() { | ||||||
|   ESP_LOGCONFIG(TAG, "AS3935:"); |   ESP_LOGCONFIG(TAG, "AS3935:"); | ||||||
|   LOG_PIN("  Interrupt Pin: ", this->irq_pin_); |   LOG_PIN("  Interrupt Pin: ", this->irq_pin_); | ||||||
|  | #ifdef USE_BINARY_SENSOR | ||||||
|   LOG_BINARY_SENSOR("  ", "Thunder alert", this->thunder_alert_binary_sensor_); |   LOG_BINARY_SENSOR("  ", "Thunder alert", this->thunder_alert_binary_sensor_); | ||||||
|  | #endif | ||||||
|  | #ifdef USE_SENSOR | ||||||
|   LOG_SENSOR("  ", "Distance", this->distance_sensor_); |   LOG_SENSOR("  ", "Distance", this->distance_sensor_); | ||||||
|   LOG_SENSOR("  ", "Lightning energy", this->energy_sensor_); |   LOG_SENSOR("  ", "Lightning energy", this->energy_sensor_); | ||||||
|  | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
| float AS3935Component::get_setup_priority() const { return setup_priority::DATA; } | float AS3935Component::get_setup_priority() const { return setup_priority::DATA; } | ||||||
| @@ -44,16 +48,22 @@ void AS3935Component::loop() { | |||||||
|     ESP_LOGI(TAG, "Disturber was detected - try increasing the spike rejection value!"); |     ESP_LOGI(TAG, "Disturber was detected - try increasing the spike rejection value!"); | ||||||
|   } else if (int_value == LIGHTNING_INT) { |   } else if (int_value == LIGHTNING_INT) { | ||||||
|     ESP_LOGI(TAG, "Lightning has been detected!"); |     ESP_LOGI(TAG, "Lightning has been detected!"); | ||||||
|     if (this->thunder_alert_binary_sensor_ != nullptr) | #ifdef USE_BINARY_SENSOR | ||||||
|  |     if (this->thunder_alert_binary_sensor_ != nullptr) { | ||||||
|       this->thunder_alert_binary_sensor_->publish_state(true); |       this->thunder_alert_binary_sensor_->publish_state(true); | ||||||
|  |       this->set_timeout(10, [this]() { this->thunder_alert_binary_sensor_->publish_state(false); }); | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  | #ifdef USE_SENSOR | ||||||
|     uint8_t distance = this->get_distance_to_storm_(); |     uint8_t distance = this->get_distance_to_storm_(); | ||||||
|     if (this->distance_sensor_ != nullptr) |     if (this->distance_sensor_ != nullptr) | ||||||
|       this->distance_sensor_->publish_state(distance); |       this->distance_sensor_->publish_state(distance); | ||||||
|  |  | ||||||
|     uint32_t energy = this->get_lightning_energy_(); |     uint32_t energy = this->get_lightning_energy_(); | ||||||
|     if (this->energy_sensor_ != nullptr) |     if (this->energy_sensor_ != nullptr) | ||||||
|       this->energy_sensor_->publish_state(energy); |       this->energy_sensor_->publish_state(energy); | ||||||
|  | #endif | ||||||
|   } |   } | ||||||
|   this->thunder_alert_binary_sensor_->publish_state(false); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void AS3935Component::write_indoor(bool indoor) { | void AS3935Component::write_indoor(bool indoor) { | ||||||
|   | |||||||
| @@ -1,9 +1,14 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include "esphome/core/component.h" | #include "esphome/core/component.h" | ||||||
|  | #include "esphome/core/defines.h" | ||||||
| #include "esphome/core/hal.h" | #include "esphome/core/hal.h" | ||||||
|  | #ifdef USE_SENSOR | ||||||
| #include "esphome/components/sensor/sensor.h" | #include "esphome/components/sensor/sensor.h" | ||||||
|  | #endif | ||||||
|  | #ifdef USE_BINARY_SENSOR | ||||||
| #include "esphome/components/binary_sensor/binary_sensor.h" | #include "esphome/components/binary_sensor/binary_sensor.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace as3935 { | namespace as3935 { | ||||||
| @@ -52,6 +57,15 @@ enum AS3935Values { | |||||||
| }; | }; | ||||||
|  |  | ||||||
| class AS3935Component : public Component { | class AS3935Component : public Component { | ||||||
|  | #ifdef USE_SENSOR | ||||||
|  |   SUB_SENSOR(distance) | ||||||
|  |   SUB_SENSOR(energy) | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #ifdef USE_BINARY_SENSOR | ||||||
|  |   SUB_BINARY_SENSOR(thunder_alert) | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  public: |  public: | ||||||
|   void setup() override; |   void setup() override; | ||||||
|   void dump_config() override; |   void dump_config() override; | ||||||
| @@ -59,11 +73,7 @@ class AS3935Component : public Component { | |||||||
|   void loop() override; |   void loop() override; | ||||||
|  |  | ||||||
|   void set_irq_pin(GPIOPin *irq_pin) { irq_pin_ = irq_pin; } |   void set_irq_pin(GPIOPin *irq_pin) { irq_pin_ = irq_pin; } | ||||||
|   void set_distance_sensor(sensor::Sensor *distance_sensor) { distance_sensor_ = distance_sensor; } |  | ||||||
|   void set_energy_sensor(sensor::Sensor *energy_sensor) { energy_sensor_ = energy_sensor; } |  | ||||||
|   void set_thunder_alert_binary_sensor(binary_sensor::BinarySensor *thunder_alert_binary_sensor) { |  | ||||||
|     thunder_alert_binary_sensor_ = thunder_alert_binary_sensor; |  | ||||||
|   } |  | ||||||
|   void set_indoor(bool indoor) { indoor_ = indoor; } |   void set_indoor(bool indoor) { indoor_ = indoor; } | ||||||
|   void write_indoor(bool indoor); |   void write_indoor(bool indoor); | ||||||
|   void set_noise_level(uint8_t noise_level) { noise_level_ = noise_level; } |   void set_noise_level(uint8_t noise_level) { noise_level_ = noise_level; } | ||||||
| @@ -92,9 +102,6 @@ class AS3935Component : public Component { | |||||||
|  |  | ||||||
|   virtual void write_register(uint8_t reg, uint8_t mask, uint8_t bits, uint8_t start_position) = 0; |   virtual void write_register(uint8_t reg, uint8_t mask, uint8_t bits, uint8_t start_position) = 0; | ||||||
|  |  | ||||||
|   sensor::Sensor *distance_sensor_{nullptr}; |  | ||||||
|   sensor::Sensor *energy_sensor_{nullptr}; |  | ||||||
|   binary_sensor::BinarySensor *thunder_alert_binary_sensor_{nullptr}; |  | ||||||
|   GPIOPin *irq_pin_; |   GPIOPin *irq_pin_; | ||||||
|  |  | ||||||
|   bool indoor_; |   bool indoor_; | ||||||
|   | |||||||
| @@ -116,7 +116,7 @@ class BedJetHub : public esphome::ble_client::BLEClientNode, public PollingCompo | |||||||
|   void update() override; |   void update() override; | ||||||
|   void dump_config() override; |   void dump_config() override; | ||||||
|   void setup() override { this->codec_ = make_unique<BedjetCodec>(); } |   void setup() override { this->codec_ = make_unique<BedjetCodec>(); } | ||||||
|   float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } |   float get_setup_priority() const override { return setup_priority::BLUETOOTH; } | ||||||
|  |  | ||||||
|   /** @return The BedJet's configured name, or the MAC address if not discovered yet. */ |   /** @return The BedJet's configured name, or the MAC address if not discovered yet. */ | ||||||
|   std::string get_name() { |   std::string get_name() { | ||||||
|   | |||||||
| @@ -41,16 +41,13 @@ void BinarySensor::send_state_internal(bool state, bool is_initial) { | |||||||
|     this->state_callback_.call(state); |     this->state_callback_.call(state); | ||||||
|   } |   } | ||||||
| } | } | ||||||
| std::string BinarySensor::device_class() { return ""; } |  | ||||||
| BinarySensor::BinarySensor() : state(false) {} | BinarySensor::BinarySensor() : state(false) {} | ||||||
| void BinarySensor::set_device_class(const std::string &device_class) { this->device_class_ = device_class; } | void BinarySensor::set_device_class(const std::string &device_class) { this->device_class_ = device_class; } | ||||||
| std::string BinarySensor::get_device_class() { | std::string BinarySensor::get_device_class() { | ||||||
|   if (this->device_class_.has_value()) |   if (this->device_class_.has_value()) | ||||||
|     return *this->device_class_; |     return *this->device_class_; | ||||||
| #pragma GCC diagnostic push |   return ""; | ||||||
| #pragma GCC diagnostic ignored "-Wdeprecated-declarations" |  | ||||||
|   return this->device_class(); |  | ||||||
| #pragma GCC diagnostic pop |  | ||||||
| } | } | ||||||
| void BinarySensor::add_filter(Filter *filter) { | void BinarySensor::add_filter(Filter *filter) { | ||||||
|   filter->parent_ = this; |   filter->parent_ = this; | ||||||
|   | |||||||
| @@ -80,14 +80,6 @@ class BinarySensor : public EntityBase { | |||||||
|  |  | ||||||
|   virtual bool is_status_binary_sensor() const; |   virtual bool is_status_binary_sensor() const; | ||||||
|  |  | ||||||
|   // ========== OVERRIDE METHODS ========== |  | ||||||
|   // (You'll only need this when creating your own custom binary sensor) |  | ||||||
|   /** Override this to set the default device class. |  | ||||||
|    * |  | ||||||
|    * @deprecated This method is deprecated, set the property during config validation instead. (2022.1) |  | ||||||
|    */ |  | ||||||
|   virtual std::string device_class(); |  | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   CallbackManager<void(bool)> state_callback_{}; |   CallbackManager<void(bool)> state_callback_{}; | ||||||
|   optional<std::string> device_class_{};  ///< Stores the override of the device class |   optional<std::string> device_class_{};  ///< Stores the override of the device class | ||||||
|   | |||||||
| @@ -30,7 +30,7 @@ void BinarySensorMap::process_group_() { | |||||||
|     if (bs.binary_sensor->state) { |     if (bs.binary_sensor->state) { | ||||||
|       num_active_sensors++; |       num_active_sensors++; | ||||||
|       total_current_value += bs.sensor_value; |       total_current_value += bs.sensor_value; | ||||||
|       mask |= 1 << i; |       mask |= 1ULL << i; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   // check if the sensor map was touched |   // check if the sensor map was touched | ||||||
| @@ -38,12 +38,11 @@ void BinarySensorMap::process_group_() { | |||||||
|     // did the bit_mask change or is it a new sensor touch |     // did the bit_mask change or is it a new sensor touch | ||||||
|     if (this->last_mask_ != mask) { |     if (this->last_mask_ != mask) { | ||||||
|       float publish_value = total_current_value / num_active_sensors; |       float publish_value = total_current_value / num_active_sensors; | ||||||
|       ESP_LOGD(TAG, "'%s' - Publishing %.2f", this->name_.c_str(), publish_value); |  | ||||||
|       this->publish_state(publish_value); |       this->publish_state(publish_value); | ||||||
|     } |     } | ||||||
|   } else if (this->last_mask_ != 0ULL) { |   } else if (this->last_mask_ != 0ULL) { | ||||||
|     // is this a new sensor release |     // is this a new sensor release | ||||||
|     ESP_LOGD(TAG, "'%s' - No binary sensor active, publishing NAN", this->name_.c_str()); |     ESP_LOGV(TAG, "'%s' - No binary sensor active, publishing NAN", this->name_.c_str()); | ||||||
|     this->publish_state(NAN); |     this->publish_state(NAN); | ||||||
|   } |   } | ||||||
|   this->last_mask_ = mask; |   this->last_mask_ = mask; | ||||||
| @@ -52,28 +51,22 @@ void BinarySensorMap::process_group_() { | |||||||
| void BinarySensorMap::process_sum_() { | void BinarySensorMap::process_sum_() { | ||||||
|   float total_current_value = 0.0; |   float total_current_value = 0.0; | ||||||
|   uint64_t mask = 0x00; |   uint64_t mask = 0x00; | ||||||
|   // check all binary_sensors for its state. when active add its value to total_current_value. |   // - check all binary_sensor states | ||||||
|   // create a bitmask for the binary_sensor status on all channels |   // - if active, add its value to total_current_value | ||||||
|  |   // - creates a bitmask for the binary_sensor status on all channels | ||||||
|   for (size_t i = 0; i < this->channels_.size(); i++) { |   for (size_t i = 0; i < this->channels_.size(); i++) { | ||||||
|     auto bs = this->channels_[i]; |     auto bs = this->channels_[i]; | ||||||
|     if (bs.binary_sensor->state) { |     if (bs.binary_sensor->state) { | ||||||
|       total_current_value += bs.sensor_value; |       total_current_value += bs.sensor_value; | ||||||
|       mask |= 1 << i; |       mask |= 1ULL << i; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   // check if the sensor map was touched |  | ||||||
|   if (mask != 0ULL) { |   // update state only if the binary sensor states have changed or if no state has ever been sent on boot | ||||||
|     // did the bit_mask change or is it a new sensor touch |   if ((this->last_mask_ != mask) || (!this->has_state())) { | ||||||
|     if (this->last_mask_ != mask) { |     this->publish_state(total_current_value); | ||||||
|       float publish_value = total_current_value; |  | ||||||
|       ESP_LOGD(TAG, "'%s' - Publishing %.2f", this->name_.c_str(), publish_value); |  | ||||||
|       this->publish_state(publish_value); |  | ||||||
|     } |  | ||||||
|   } else if (this->last_mask_ != 0ULL) { |  | ||||||
|     // is this a new sensor release |  | ||||||
|     ESP_LOGD(TAG, "'%s' - No binary sensor active, publishing 0", this->name_.c_str()); |  | ||||||
|     this->publish_state(0.0); |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   this->last_mask_ = mask; |   this->last_mask_ = mask; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -39,7 +39,7 @@ CONFIG_SCHEMA = cv.typed_schema( | |||||||
|         ).extend( |         ).extend( | ||||||
|             { |             { | ||||||
|                 cv.Required(CONF_CHANNELS): cv.All( |                 cv.Required(CONF_CHANNELS): cv.All( | ||||||
|                     cv.ensure_list(entry), cv.Length(min=1) |                     cv.ensure_list(entry), cv.Length(min=1, max=64) | ||||||
|                 ), |                 ), | ||||||
|             } |             } | ||||||
|         ), |         ), | ||||||
| @@ -50,7 +50,7 @@ CONFIG_SCHEMA = cv.typed_schema( | |||||||
|         ).extend( |         ).extend( | ||||||
|             { |             { | ||||||
|                 cv.Required(CONF_CHANNELS): cv.All( |                 cv.Required(CONF_CHANNELS): cv.All( | ||||||
|                     cv.ensure_list(entry), cv.Length(min=1) |                     cv.ensure_list(entry), cv.Length(min=1, max=64) | ||||||
|                 ), |                 ), | ||||||
|             } |             } | ||||||
|         ), |         ), | ||||||
|   | |||||||
| @@ -306,6 +306,13 @@ void BluetoothProxy::bluetooth_device_request(const api::BluetoothDeviceRequest | |||||||
|       api::global_api_server->send_bluetooth_device_unpairing(msg.address, ret == ESP_OK, ret); |       api::global_api_server->send_bluetooth_device_unpairing(msg.address, ret == ESP_OK, ret); | ||||||
|       break; |       break; | ||||||
|     } |     } | ||||||
|  |     case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CLEAR_CACHE: { | ||||||
|  |       esp_bd_addr_t address; | ||||||
|  |       uint64_to_bd_addr(msg.address, address); | ||||||
|  |       esp_err_t ret = esp_ble_gattc_cache_clean(address); | ||||||
|  |       api::global_api_server->send_bluetooth_device_clear_cache(msg.address, ret == ESP_OK, ret); | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -68,6 +68,14 @@ class BluetoothProxy : public esp32_ble_tracker::ESPBTDeviceListener, public Com | |||||||
|  |  | ||||||
| extern BluetoothProxy *global_bluetooth_proxy;  // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) | extern BluetoothProxy *global_bluetooth_proxy;  // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) | ||||||
|  |  | ||||||
|  | // Version 1: Initial version without active connections | ||||||
|  | // Version 2: Support for active connections | ||||||
|  | // Version 3: New connection API | ||||||
|  | // Version 4: Pairing support | ||||||
|  | // Version 5: Cache clear support | ||||||
|  | static const uint32_t ACTIVE_CONNECTIONS_VERSION = 5; | ||||||
|  | static const uint32_t PASSIVE_ONLY_VERSION = 1; | ||||||
|  |  | ||||||
| }  // namespace bluetooth_proxy | }  // namespace bluetooth_proxy | ||||||
| }  // namespace esphome | }  // namespace esphome | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| #include "bme680.h" | #include "bme680.h" | ||||||
| #include "esphome/core/log.h" |  | ||||||
| #include "esphome/core/hal.h" | #include "esphome/core/hal.h" | ||||||
|  | #include "esphome/core/log.h" | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace bme680 { | namespace bme680 { | ||||||
| @@ -275,8 +275,8 @@ uint8_t BME680Component::calc_heater_resistance_(uint16_t temperature) { | |||||||
|   var3 = var1 + (var2 / 2); |   var3 = var1 + (var2 / 2); | ||||||
|   var4 = (var3 / (res_heat_range + 4)); |   var4 = (var3 / (res_heat_range + 4)); | ||||||
|   var5 = (131 * res_heat_val) + 65536; |   var5 = (131 * res_heat_val) + 65536; | ||||||
|   heatr_res_x100 = (int32_t)(((var4 / var5) - 250) * 34); |   heatr_res_x100 = (int32_t) (((var4 / var5) - 250) * 34); | ||||||
|   heatr_res = (uint8_t)((heatr_res_x100 + 50) / 100); |   heatr_res = (uint8_t) ((heatr_res_x100 + 50) / 100); | ||||||
|  |  | ||||||
|   return heatr_res; |   return heatr_res; | ||||||
| } | } | ||||||
| @@ -316,7 +316,7 @@ void BME680Component::read_data_() { | |||||||
|   uint32_t raw_temperature = (uint32_t(data[5]) << 12) | (uint32_t(data[6]) << 4) | (uint32_t(data[7]) >> 4); |   uint32_t raw_temperature = (uint32_t(data[5]) << 12) | (uint32_t(data[6]) << 4) | (uint32_t(data[7]) >> 4); | ||||||
|   uint32_t raw_pressure = (uint32_t(data[2]) << 12) | (uint32_t(data[3]) << 4) | (uint32_t(data[4]) >> 4); |   uint32_t raw_pressure = (uint32_t(data[2]) << 12) | (uint32_t(data[3]) << 4) | (uint32_t(data[4]) >> 4); | ||||||
|   uint32_t raw_humidity = (uint32_t(data[8]) << 8) | uint32_t(data[9]); |   uint32_t raw_humidity = (uint32_t(data[8]) << 8) | uint32_t(data[9]); | ||||||
|   uint16_t raw_gas = (uint16_t)((uint32_t) data[13] * 4 | (((uint32_t) data[14]) / 64)); |   uint16_t raw_gas = (uint16_t) ((uint32_t) data[13] * 4 | (((uint32_t) data[14]) / 64)); | ||||||
|   uint8_t gas_range = data[14] & 0x0F; |   uint8_t gas_range = data[14] & 0x0F; | ||||||
|  |  | ||||||
|   float temperature = this->calc_temperature_(raw_temperature); |   float temperature = this->calc_temperature_(raw_temperature); | ||||||
|   | |||||||
| @@ -1,6 +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 i2c | from esphome.components import i2c, esp32 | ||||||
| from esphome.const import CONF_ID | from esphome.const import CONF_ID | ||||||
|  |  | ||||||
| CODEOWNERS = ["@trvrnrth"] | CODEOWNERS = ["@trvrnrth"] | ||||||
| @@ -32,22 +32,31 @@ BME680BSECComponent = bme680_bsec_ns.class_( | |||||||
|     "BME680BSECComponent", cg.Component, i2c.I2CDevice |     "BME680BSECComponent", cg.Component, i2c.I2CDevice | ||||||
| ) | ) | ||||||
|  |  | ||||||
| CONFIG_SCHEMA = cv.Schema( | CONFIG_SCHEMA = cv.All( | ||||||
|     { |     cv.Schema( | ||||||
|         cv.GenerateID(): cv.declare_id(BME680BSECComponent), |         { | ||||||
|         cv.Optional(CONF_TEMPERATURE_OFFSET, default=0): cv.temperature, |             cv.GenerateID(): cv.declare_id(BME680BSECComponent), | ||||||
|         cv.Optional(CONF_IAQ_MODE, default="STATIC"): cv.enum( |             cv.Optional(CONF_TEMPERATURE_OFFSET, default=0): cv.temperature, | ||||||
|             IAQ_MODE_OPTIONS, upper=True |             cv.Optional(CONF_IAQ_MODE, default="STATIC"): cv.enum( | ||||||
|         ), |                 IAQ_MODE_OPTIONS, upper=True | ||||||
|         cv.Optional(CONF_SAMPLE_RATE, default="LP"): cv.enum( |             ), | ||||||
|             SAMPLE_RATE_OPTIONS, upper=True |             cv.Optional(CONF_SAMPLE_RATE, default="LP"): cv.enum( | ||||||
|         ), |                 SAMPLE_RATE_OPTIONS, upper=True | ||||||
|         cv.Optional( |             ), | ||||||
|             CONF_STATE_SAVE_INTERVAL, default="6hours" |             cv.Optional( | ||||||
|         ): cv.positive_time_period_minutes, |                 CONF_STATE_SAVE_INTERVAL, default="6hours" | ||||||
|     }, |             ): cv.positive_time_period_minutes, | ||||||
|  |         } | ||||||
|  |     ).extend(i2c.i2c_device_schema(0x76)), | ||||||
|     cv.only_with_arduino, |     cv.only_with_arduino, | ||||||
| ).extend(i2c.i2c_device_schema(0x76)) |     cv.Any( | ||||||
|  |         cv.only_on_esp8266, | ||||||
|  |         cv.All( | ||||||
|  |             cv.only_on_esp32, | ||||||
|  |             esp32.only_on_variant(supported=[esp32.const.VARIANT_ESP32]), | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
| async def to_code(config): | async def to_code(config): | ||||||
|   | |||||||
| @@ -6,9 +6,6 @@ namespace button { | |||||||
|  |  | ||||||
| static const char *const TAG = "button"; | static const char *const TAG = "button"; | ||||||
|  |  | ||||||
| Button::Button(const std::string &name) : EntityBase(name) {} |  | ||||||
| Button::Button() : Button("") {} |  | ||||||
|  |  | ||||||
| void Button::press() { | void Button::press() { | ||||||
|   ESP_LOGD(TAG, "'%s' Pressed.", this->get_name().c_str()); |   ESP_LOGD(TAG, "'%s' Pressed.", this->get_name().c_str()); | ||||||
|   this->press_action(); |   this->press_action(); | ||||||
|   | |||||||
| @@ -28,9 +28,6 @@ namespace button { | |||||||
|  */ |  */ | ||||||
| class Button : public EntityBase { | class Button : public EntityBase { | ||||||
|  public: |  public: | ||||||
|   explicit Button(); |  | ||||||
|   explicit Button(const std::string &name); |  | ||||||
|  |  | ||||||
|   /** Press this button. This is called by the front-end. |   /** Press this button. This is called by the front-end. | ||||||
|    * |    * | ||||||
|    * For implementing buttons, please override press_action. |    * For implementing buttons, please override press_action. | ||||||
|   | |||||||
| @@ -145,8 +145,8 @@ void CCS811Component::send_env_data_() { | |||||||
|   // https://github.com/adafruit/Adafruit_CCS811/blob/0990f5c620354d8bc087c4706bec091d8e6e5dfd/Adafruit_CCS811.cpp#L135-L142 |   // https://github.com/adafruit/Adafruit_CCS811/blob/0990f5c620354d8bc087c4706bec091d8e6e5dfd/Adafruit_CCS811.cpp#L135-L142 | ||||||
|   uint16_t hum_conv = static_cast<uint16_t>(lroundf(humidity * 512.0f + 0.5f)); |   uint16_t hum_conv = static_cast<uint16_t>(lroundf(humidity * 512.0f + 0.5f)); | ||||||
|   uint16_t temp_conv = static_cast<uint16_t>(lroundf(temperature * 512.0f + 0.5f)); |   uint16_t temp_conv = static_cast<uint16_t>(lroundf(temperature * 512.0f + 0.5f)); | ||||||
|   this->write_bytes(0x05, {(uint8_t)((hum_conv >> 8) & 0xff), (uint8_t)((hum_conv & 0xff)), |   this->write_bytes(0x05, {(uint8_t) ((hum_conv >> 8) & 0xff), (uint8_t) ((hum_conv & 0xff)), | ||||||
|                            (uint8_t)((temp_conv >> 8) & 0xff), (uint8_t)((temp_conv & 0xff))}); |                            (uint8_t) ((temp_conv >> 8) & 0xff), (uint8_t) ((temp_conv & 0xff))}); | ||||||
| } | } | ||||||
| void CCS811Component::dump_config() { | void CCS811Component::dump_config() { | ||||||
|   ESP_LOGCONFIG(TAG, "CCS811"); |   ESP_LOGCONFIG(TAG, "CCS811"); | ||||||
|   | |||||||
| @@ -324,6 +324,10 @@ async def setup_climate_core_(var, config): | |||||||
|         trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) |         trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) | ||||||
|         await automation.build_automation(trigger, [], conf) |         await automation.build_automation(trigger, [], conf) | ||||||
|  |  | ||||||
|  |     for conf in config.get(CONF_ON_CONTROL, []): | ||||||
|  |         trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) | ||||||
|  |         await automation.build_automation(trigger, [], conf) | ||||||
|  |  | ||||||
|  |  | ||||||
| async def register_climate(var, config): | async def register_climate(var, config): | ||||||
|     if not CORE.has_id(config[CONF_ID]): |     if not CORE.has_id(config[CONF_ID]): | ||||||
|   | |||||||
| @@ -453,12 +453,7 @@ void Climate::set_visual_temperature_step_override(float target, float current) | |||||||
|   this->visual_target_temperature_step_override_ = target; |   this->visual_target_temperature_step_override_ = target; | ||||||
|   this->visual_current_temperature_step_override_ = current; |   this->visual_current_temperature_step_override_ = current; | ||||||
| } | } | ||||||
| #pragma GCC diagnostic push |  | ||||||
| #pragma GCC diagnostic ignored "-Wdeprecated-declarations" |  | ||||||
| Climate::Climate(const std::string &name) : EntityBase(name) {} |  | ||||||
| #pragma GCC diagnostic pop |  | ||||||
|  |  | ||||||
| Climate::Climate() : Climate("") {} |  | ||||||
| ClimateCall Climate::make_call() { return ClimateCall(this); } | ClimateCall Climate::make_call() { return ClimateCall(this); } | ||||||
|  |  | ||||||
| ClimateCall ClimateDeviceRestoreState::to_call(Climate *climate) { | ClimateCall ClimateDeviceRestoreState::to_call(Climate *climate) { | ||||||
|   | |||||||
| @@ -166,11 +166,6 @@ struct ClimateDeviceRestoreState { | |||||||
|  */ |  */ | ||||||
| class Climate : public EntityBase { | class Climate : public EntityBase { | ||||||
|  public: |  public: | ||||||
|   /// Construct a climate device with empty name (will be set later). |  | ||||||
|   Climate(); |  | ||||||
|   /// Construct a climate device with a name. |  | ||||||
|   Climate(const std::string &name); |  | ||||||
|  |  | ||||||
|   /// The active mode of the climate device. |   /// The active mode of the climate device. | ||||||
|   ClimateMode mode{CLIMATE_MODE_OFF}; |   ClimateMode mode{CLIMATE_MODE_OFF}; | ||||||
|   /// The active state of the climate device. |   /// The active state of the climate device. | ||||||
|   | |||||||
| @@ -14,12 +14,15 @@ from .. import copy_ns | |||||||
| CopySelect = copy_ns.class_("CopySelect", select.Select, cg.Component) | CopySelect = copy_ns.class_("CopySelect", select.Select, cg.Component) | ||||||
|  |  | ||||||
|  |  | ||||||
| CONFIG_SCHEMA = select.SELECT_SCHEMA.extend( | CONFIG_SCHEMA = ( | ||||||
|     { |     select.select_schema(CopySelect) | ||||||
|         cv.GenerateID(): cv.declare_id(CopySelect), |     .extend( | ||||||
|         cv.Required(CONF_SOURCE_ID): cv.use_id(select.Select), |         { | ||||||
|     } |             cv.Required(CONF_SOURCE_ID): cv.use_id(select.Select), | ||||||
| ).extend(cv.COMPONENT_SCHEMA) |         } | ||||||
|  |     ) | ||||||
|  |     .extend(cv.COMPONENT_SCHEMA) | ||||||
|  | ) | ||||||
|  |  | ||||||
| FINAL_VALIDATE_SCHEMA = cv.All( | FINAL_VALIDATE_SCHEMA = cv.All( | ||||||
|     inherit_property_from(CONF_ICON, CONF_SOURCE_ID), |     inherit_property_from(CONF_ICON, CONF_SOURCE_ID), | ||||||
|   | |||||||
| @@ -31,7 +31,7 @@ const char *cover_operation_to_str(CoverOperation op) { | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| Cover::Cover(const std::string &name) : EntityBase(name), position{COVER_OPEN} {} | Cover::Cover() : position{COVER_OPEN} {} | ||||||
|  |  | ||||||
| CoverCall::CoverCall(Cover *parent) : parent_(parent) {} | CoverCall::CoverCall(Cover *parent) : parent_(parent) {} | ||||||
| CoverCall &CoverCall::set_command(const char *command) { | CoverCall &CoverCall::set_command(const char *command) { | ||||||
| @@ -204,18 +204,13 @@ optional<CoverRestoreState> Cover::restore_state_() { | |||||||
|     return {}; |     return {}; | ||||||
|   return recovered; |   return recovered; | ||||||
| } | } | ||||||
| Cover::Cover() : Cover("") {} |  | ||||||
| std::string Cover::get_device_class() { | std::string Cover::get_device_class() { | ||||||
|   if (this->device_class_override_.has_value()) |   if (this->device_class_override_.has_value()) | ||||||
|     return *this->device_class_override_; |     return *this->device_class_override_; | ||||||
| #pragma GCC diagnostic push |   return ""; | ||||||
| #pragma GCC diagnostic ignored "-Wdeprecated-declarations" |  | ||||||
|   return this->device_class(); |  | ||||||
| #pragma GCC diagnostic pop |  | ||||||
| } | } | ||||||
| bool Cover::is_fully_open() const { return this->position == COVER_OPEN; } | bool Cover::is_fully_open() const { return this->position == COVER_OPEN; } | ||||||
| bool Cover::is_fully_closed() const { return this->position == COVER_CLOSED; } | bool Cover::is_fully_closed() const { return this->position == COVER_CLOSED; } | ||||||
| std::string Cover::device_class() { return ""; } |  | ||||||
|  |  | ||||||
| CoverCall CoverRestoreState::to_call(Cover *cover) { | CoverCall CoverRestoreState::to_call(Cover *cover) { | ||||||
|   auto call = cover->make_call(); |   auto call = cover->make_call(); | ||||||
|   | |||||||
| @@ -111,7 +111,6 @@ const char *cover_operation_to_str(CoverOperation op); | |||||||
| class Cover : public EntityBase { | class Cover : public EntityBase { | ||||||
|  public: |  public: | ||||||
|   explicit Cover(); |   explicit Cover(); | ||||||
|   explicit Cover(const std::string &name); |  | ||||||
|  |  | ||||||
|   /// The current operation of the cover (idle, opening, closing). |   /// The current operation of the cover (idle, opening, closing). | ||||||
|   CoverOperation current_operation{COVER_OPERATION_IDLE}; |   CoverOperation current_operation{COVER_OPERATION_IDLE}; | ||||||
| @@ -170,12 +169,6 @@ class Cover : public EntityBase { | |||||||
|  |  | ||||||
|   virtual void control(const CoverCall &call) = 0; |   virtual void control(const CoverCall &call) = 0; | ||||||
|  |  | ||||||
|   /** Override this to set the default device class. |  | ||||||
|    * |  | ||||||
|    * @deprecated This method is deprecated, set the property during config validation instead. (2022.1) |  | ||||||
|    */ |  | ||||||
|   virtual std::string device_class(); |  | ||||||
|  |  | ||||||
|   optional<CoverRestoreState> restore_state_(); |   optional<CoverRestoreState> restore_state_(); | ||||||
|  |  | ||||||
|   CallbackManager<void()> state_callback_{}; |   CallbackManager<void()> state_callback_{}; | ||||||
|   | |||||||
| @@ -305,7 +305,7 @@ bool CS5460AComponent::check_status_() { | |||||||
|       voltage_sensor_->publish_state(raw_voltage * voltage_multiplier_); |       voltage_sensor_->publish_state(raw_voltage * voltage_multiplier_); | ||||||
|  |  | ||||||
|     if (power_sensor_ != nullptr && raw_energy != prev_raw_energy_) { |     if (power_sensor_ != nullptr && raw_energy != prev_raw_energy_) { | ||||||
|       int32_t raw = (int32_t)(raw_energy << 8) >> 8; /* Sign-extend */ |       int32_t raw = (int32_t) (raw_energy << 8) >> 8; /* Sign-extend */ | ||||||
|       power_sensor_->publish_state(raw * power_multiplier_); |       power_sensor_->publish_state(raw * power_multiplier_); | ||||||
|       prev_raw_energy_ = raw_energy; |       prev_raw_energy_ = raw_energy; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -33,7 +33,10 @@ void CTClampSensor::update() { | |||||||
|  |  | ||||||
|     const float rms_ac_dc_squared = this->sample_squared_sum_ / this->num_samples_; |     const float rms_ac_dc_squared = this->sample_squared_sum_ / this->num_samples_; | ||||||
|     const float rms_dc = this->sample_sum_ / this->num_samples_; |     const float rms_dc = this->sample_sum_ / this->num_samples_; | ||||||
|     const float rms_ac = std::sqrt(rms_ac_dc_squared - rms_dc * rms_dc); |     const float rms_ac_squared = rms_ac_dc_squared - rms_dc * rms_dc; | ||||||
|  |     float rms_ac = 0; | ||||||
|  |     if (rms_ac_squared > 0) | ||||||
|  |       rms_ac = std::sqrt(rms_ac_squared); | ||||||
|     ESP_LOGD(TAG, "'%s' - Raw AC Value: %.3fA after %d different samples (%d SPS)", this->name_.c_str(), rms_ac, |     ESP_LOGD(TAG, "'%s' - Raw AC Value: %.3fA after %d different samples (%d SPS)", this->name_.c_str(), rms_ac, | ||||||
|              this->num_samples_, 1000 * this->num_samples_ / this->sample_duration_); |              this->num_samples_, 1000 * this->num_samples_ / this->sample_duration_); | ||||||
|     this->publish_state(rms_ac); |     this->publish_state(rms_ac); | ||||||
|   | |||||||
| @@ -61,8 +61,8 @@ void DalyBmsComponent::request_data_(uint8_t data_id) { | |||||||
|   request_message[9] = 0x00;     //     | |   request_message[9] = 0x00;     //     | | ||||||
|   request_message[10] = 0x00;    //     | |   request_message[10] = 0x00;    //     | | ||||||
|   request_message[11] = 0x00;    // Empty Data |   request_message[11] = 0x00;    // Empty Data | ||||||
|   request_message[12] = (uint8_t)(request_message[0] + request_message[1] + request_message[2] + |   request_message[12] = (uint8_t) (request_message[0] + request_message[1] + request_message[2] + | ||||||
|                                   request_message[3]);  // Checksum (Lower byte of the other bytes sum) |                                    request_message[3]);  // Checksum (Lower byte of the other bytes sum) | ||||||
|  |  | ||||||
|   this->write_array(request_message, sizeof(request_message)); |   this->write_array(request_message, sizeof(request_message)); | ||||||
|   this->flush(); |   this->flush(); | ||||||
|   | |||||||
| @@ -19,7 +19,7 @@ void DFPlayer::play_folder(uint16_t folder, uint16_t file) { | |||||||
| } | } | ||||||
|  |  | ||||||
| void DFPlayer::send_cmd_(uint8_t cmd, uint16_t argument) { | void DFPlayer::send_cmd_(uint8_t cmd, uint16_t argument) { | ||||||
|   uint8_t buffer[10]{0x7e, 0xff, 0x06, cmd, 0x01, (uint8_t)(argument >> 8), (uint8_t) argument, 0x00, 0x00, 0xef}; |   uint8_t buffer[10]{0x7e, 0xff, 0x06, cmd, 0x01, (uint8_t) (argument >> 8), (uint8_t) argument, 0x00, 0x00, 0xef}; | ||||||
|   uint16_t checksum = 0; |   uint16_t checksum = 0; | ||||||
|   for (uint8_t i = 1; i < 7; i++) |   for (uint8_t i = 1; i < 7; i++) | ||||||
|     checksum += buffer[i]; |     checksum += buffer[i]; | ||||||
|   | |||||||
| @@ -664,7 +664,7 @@ bool Animation::get_pixel(int x, int y) const { | |||||||
|     return false; |     return false; | ||||||
|   const uint32_t width_8 = ((this->width_ + 7u) / 8u) * 8u; |   const uint32_t width_8 = ((this->width_ + 7u) / 8u) * 8u; | ||||||
|   const uint32_t frame_index = this->height_ * width_8 * this->current_frame_; |   const uint32_t frame_index = this->height_ * width_8 * this->current_frame_; | ||||||
|   if (frame_index >= (uint32_t)(this->width_ * this->height_ * this->animation_frame_count_)) |   if (frame_index >= (uint32_t) (this->width_ * this->height_ * this->animation_frame_count_)) | ||||||
|     return false; |     return false; | ||||||
|   const uint32_t pos = x + y * width_8 + frame_index; |   const uint32_t pos = x + y * width_8 + frame_index; | ||||||
|   return progmem_read_byte(this->data_start_ + (pos / 8u)) & (0x80 >> (pos % 8u)); |   return progmem_read_byte(this->data_start_ + (pos / 8u)) & (0x80 >> (pos % 8u)); | ||||||
| @@ -673,7 +673,7 @@ Color Animation::get_color_pixel(int x, int y) const { | |||||||
|   if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) |   if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) | ||||||
|     return Color::BLACK; |     return Color::BLACK; | ||||||
|   const uint32_t frame_index = this->width_ * this->height_ * this->current_frame_; |   const uint32_t frame_index = this->width_ * this->height_ * this->current_frame_; | ||||||
|   if (frame_index >= (uint32_t)(this->width_ * this->height_ * this->animation_frame_count_)) |   if (frame_index >= (uint32_t) (this->width_ * this->height_ * this->animation_frame_count_)) | ||||||
|     return Color::BLACK; |     return Color::BLACK; | ||||||
|   const uint32_t pos = (x + y * this->width_ + frame_index) * 3; |   const uint32_t pos = (x + y * this->width_ + frame_index) * 3; | ||||||
|   const uint32_t color32 = (progmem_read_byte(this->data_start_ + pos + 2) << 0) | |   const uint32_t color32 = (progmem_read_byte(this->data_start_ + pos + 2) << 0) | | ||||||
| @@ -685,7 +685,7 @@ Color Animation::get_rgb565_pixel(int x, int y) const { | |||||||
|   if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) |   if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) | ||||||
|     return Color::BLACK; |     return Color::BLACK; | ||||||
|   const uint32_t frame_index = this->width_ * this->height_ * this->current_frame_; |   const uint32_t frame_index = this->width_ * this->height_ * this->current_frame_; | ||||||
|   if (frame_index >= (uint32_t)(this->width_ * this->height_ * this->animation_frame_count_)) |   if (frame_index >= (uint32_t) (this->width_ * this->height_ * this->animation_frame_count_)) | ||||||
|     return Color::BLACK; |     return Color::BLACK; | ||||||
|   const uint32_t pos = (x + y * this->width_ + frame_index) * 2; |   const uint32_t pos = (x + y * this->width_ + frame_index) * 2; | ||||||
|   uint16_t rgb565 = |   uint16_t rgb565 = | ||||||
| @@ -699,7 +699,7 @@ Color Animation::get_grayscale_pixel(int x, int y) const { | |||||||
|   if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) |   if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) | ||||||
|     return Color::BLACK; |     return Color::BLACK; | ||||||
|   const uint32_t frame_index = this->width_ * this->height_ * this->current_frame_; |   const uint32_t frame_index = this->width_ * this->height_ * this->current_frame_; | ||||||
|   if (frame_index >= (uint32_t)(this->width_ * this->height_ * this->animation_frame_count_)) |   if (frame_index >= (uint32_t) (this->width_ * this->height_ * this->animation_frame_count_)) | ||||||
|     return Color::BLACK; |     return Color::BLACK; | ||||||
|   const uint32_t pos = (x + y * this->width_ + frame_index); |   const uint32_t pos = (x + y * this->width_ + frame_index); | ||||||
|   const uint8_t gray = progmem_read_byte(this->data_start_ + pos); |   const uint8_t gray = progmem_read_byte(this->data_start_ + pos); | ||||||
|   | |||||||
| @@ -168,7 +168,7 @@ void ENS210Component::update() { | |||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|     // Pack bytes for humidity |     // Pack bytes for humidity | ||||||
|     h_val_data = (uint32_t)((uint32_t) data[5] << 16 | (uint32_t) data[4] << 8 | (uint32_t) data[3]); |     h_val_data = (uint32_t) ((uint32_t) data[5] << 16 | (uint32_t) data[4] << 8 | (uint32_t) data[3]); | ||||||
|     // Extract humidity data and update the status |     // Extract humidity data and update the status | ||||||
|     extract_measurement_(h_val_data, &humidity_data, &humidity_status); |     extract_measurement_(h_val_data, &humidity_data, &humidity_status); | ||||||
|  |  | ||||||
| @@ -183,7 +183,7 @@ void ENS210Component::update() { | |||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|     // Pack bytes for temperature |     // Pack bytes for temperature | ||||||
|     t_val_data = (uint32_t)((uint32_t) data[2] << 16 | (uint32_t) data[1] << 8 | (uint32_t) data[0]); |     t_val_data = (uint32_t) ((uint32_t) data[2] << 16 | (uint32_t) data[1] << 8 | (uint32_t) data[0]); | ||||||
|     // Extract temperature data and update the status |     // Extract temperature data and update the status | ||||||
|     extract_measurement_(t_val_data, &temperature_data, &temperature_status); |     extract_measurement_(t_val_data, &temperature_data, &temperature_status); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -23,7 +23,7 @@ void loop(); | |||||||
| namespace esphome { | namespace esphome { | ||||||
|  |  | ||||||
| void IRAM_ATTR HOT yield() { vPortYield(); } | void IRAM_ATTR HOT yield() { vPortYield(); } | ||||||
| uint32_t IRAM_ATTR HOT millis() { return (uint32_t)(esp_timer_get_time() / 1000ULL); } | uint32_t IRAM_ATTR HOT millis() { return (uint32_t) (esp_timer_get_time() / 1000ULL); } | ||||||
| void IRAM_ATTR HOT delay(uint32_t ms) { vTaskDelay(ms / portTICK_PERIOD_MS); } | void IRAM_ATTR HOT delay(uint32_t ms) { vTaskDelay(ms / portTICK_PERIOD_MS); } | ||||||
| uint32_t IRAM_ATTR HOT micros() { return (uint32_t) esp_timer_get_time(); } | uint32_t IRAM_ATTR HOT micros() { return (uint32_t) esp_timer_get_time(); } | ||||||
| void IRAM_ATTR HOT delayMicroseconds(uint32_t us) { delay_microseconds_safe(us); } | void IRAM_ATTR HOT delayMicroseconds(uint32_t us) { delay_microseconds_safe(us); } | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ | |||||||
|  |  | ||||||
| #include "gpio.h" | #include "gpio.h" | ||||||
| #include "esphome/core/log.h" | #include "esphome/core/log.h" | ||||||
|  | #include <cinttypes> | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace esp32 { | namespace esp32 { | ||||||
| @@ -74,7 +75,7 @@ void ESP32InternalGPIOPin::attach_interrupt(void (*func)(void *), void *arg, gpi | |||||||
|  |  | ||||||
| std::string ESP32InternalGPIOPin::dump_summary() const { | std::string ESP32InternalGPIOPin::dump_summary() const { | ||||||
|   char buffer[32]; |   char buffer[32]; | ||||||
|   snprintf(buffer, sizeof(buffer), "GPIO%u", static_cast<uint32_t>(pin_)); |   snprintf(buffer, sizeof(buffer), "GPIO%" PRIu32, static_cast<uint32_t>(pin_)); | ||||||
|   return buffer; |   return buffer; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ | |||||||
| #include "esphome/core/log.h" | #include "esphome/core/log.h" | ||||||
| #include <nvs_flash.h> | #include <nvs_flash.h> | ||||||
| #include <cstring> | #include <cstring> | ||||||
|  | #include <cinttypes> | ||||||
| #include <vector> | #include <vector> | ||||||
| #include <string> | #include <string> | ||||||
|  |  | ||||||
| @@ -101,7 +102,7 @@ class ESP32Preferences : public ESPPreferences { | |||||||
|     pref->nvs_handle = nvs_handle; |     pref->nvs_handle = nvs_handle; | ||||||
|  |  | ||||||
|     uint32_t keyval = type; |     uint32_t keyval = type; | ||||||
|     pref->key = str_sprintf("%u", keyval); |     pref->key = str_sprintf("%" PRIu32, keyval); | ||||||
|  |  | ||||||
|     return ESPPreferenceObject(pref); |     return ESPPreferenceObject(pref); | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ | |||||||
|  |  | ||||||
| #include <esp_bt.h> | #include <esp_bt.h> | ||||||
| #include <esp_bt_main.h> | #include <esp_bt_main.h> | ||||||
|  | #include <esp_bt_device.h> | ||||||
| #include <esp_gap_ble_api.h> | #include <esp_gap_ble_api.h> | ||||||
| #include <freertos/FreeRTOS.h> | #include <freertos/FreeRTOS.h> | ||||||
| #include <freertos/FreeRTOSConfig.h> | #include <freertos/FreeRTOSConfig.h> | ||||||
| @@ -211,7 +212,16 @@ void ESP32BLE::real_gattc_event_handler_(esp_gattc_cb_event_t event, esp_gatt_if | |||||||
|  |  | ||||||
| float ESP32BLE::get_setup_priority() const { return setup_priority::BLUETOOTH; } | float ESP32BLE::get_setup_priority() const { return setup_priority::BLUETOOTH; } | ||||||
|  |  | ||||||
| void ESP32BLE::dump_config() { ESP_LOGCONFIG(TAG, "ESP32 BLE:"); } | void ESP32BLE::dump_config() { | ||||||
|  |   const uint8_t *mac_address = esp_bt_dev_get_address(); | ||||||
|  |   if (mac_address) { | ||||||
|  |     ESP_LOGCONFIG(TAG, "ESP32 BLE:"); | ||||||
|  |     ESP_LOGCONFIG(TAG, "  MAC address: %02X:%02X:%02X:%02X:%02X:%02X", mac_address[0], mac_address[1], mac_address[2], | ||||||
|  |                   mac_address[3], mac_address[4], mac_address[5]); | ||||||
|  |   } else { | ||||||
|  |     ESP_LOGCONFIG(TAG, "ESP32 BLE: bluetooth stack is not enabled"); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
| ESP32BLE *global_ble = nullptr;  // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) | ESP32BLE *global_ble = nullptr;  // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -316,18 +316,18 @@ float BLEClientBase::parse_char_value(uint8_t *value, uint16_t length) { | |||||||
|     case 0xD:  // int12. |     case 0xD:  // int12. | ||||||
|     case 0xE:  // int16. |     case 0xE:  // int16. | ||||||
|       if (length > 2) { |       if (length > 2) { | ||||||
|         return (float) ((int16_t)(value[1] << 8) + (int16_t) value[2]); |         return (float) ((int16_t) (value[1] << 8) + (int16_t) value[2]); | ||||||
|       } |       } | ||||||
|       // fall through |       // fall through | ||||||
|     case 0xF:  // int24. |     case 0xF:  // int24. | ||||||
|       if (length > 3) { |       if (length > 3) { | ||||||
|         return (float) ((int32_t)(value[1] << 16) + (int32_t)(value[2] << 8) + (int32_t)(value[3])); |         return (float) ((int32_t) (value[1] << 16) + (int32_t) (value[2] << 8) + (int32_t) (value[3])); | ||||||
|       } |       } | ||||||
|       // fall through |       // fall through | ||||||
|     case 0x10:  // int32. |     case 0x10:  // int32. | ||||||
|       if (length > 4) { |       if (length > 4) { | ||||||
|         return (float) ((int32_t)(value[1] << 24) + (int32_t)(value[2] << 16) + (int32_t)(value[3] << 8) + |         return (float) ((int32_t) (value[1] << 24) + (int32_t) (value[2] << 16) + (int32_t) (value[3] << 8) + | ||||||
|                         (int32_t)(value[4])); |                         (int32_t) (value[4])); | ||||||
|       } |       } | ||||||
|   } |   } | ||||||
|   ESP_LOGW(TAG, "[%d] [%s] Cannot parse characteristic value of type 0x%x length %d", this->connection_index_, |   ESP_LOGW(TAG, "[%d] [%s] Cannot parse characteristic value of type 0x%x length %d", this->connection_index_, | ||||||
|   | |||||||
| @@ -45,10 +45,11 @@ class BLEClientBase : public espbt::ESPBTClient, public Component { | |||||||
|       memset(this->remote_bda_, 0, sizeof(this->remote_bda_)); |       memset(this->remote_bda_, 0, sizeof(this->remote_bda_)); | ||||||
|       this->address_str_ = ""; |       this->address_str_ = ""; | ||||||
|     } else { |     } else { | ||||||
|       this->address_str_ = str_snprintf("%02X:%02X:%02X:%02X:%02X:%02X", 17, (uint8_t)(this->address_ >> 40) & 0xff, |       this->address_str_ = | ||||||
|                                         (uint8_t)(this->address_ >> 32) & 0xff, (uint8_t)(this->address_ >> 24) & 0xff, |           str_snprintf("%02X:%02X:%02X:%02X:%02X:%02X", 17, (uint8_t) (this->address_ >> 40) & 0xff, | ||||||
|                                         (uint8_t)(this->address_ >> 16) & 0xff, (uint8_t)(this->address_ >> 8) & 0xff, |                        (uint8_t) (this->address_ >> 32) & 0xff, (uint8_t) (this->address_ >> 24) & 0xff, | ||||||
|                                         (uint8_t)(this->address_ >> 0) & 0xff); |                        (uint8_t) (this->address_ >> 16) & 0xff, (uint8_t) (this->address_ >> 8) & 0xff, | ||||||
|  |                        (uint8_t) (this->address_ >> 0) & 0xff); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   std::string address_str() const { return this->address_str_; } |   std::string address_str() const { return this->address_str_; } | ||||||
|   | |||||||
| @@ -148,44 +148,44 @@ bool BLECharacteristic::is_failed() { | |||||||
|  |  | ||||||
| void BLECharacteristic::set_broadcast_property(bool value) { | void BLECharacteristic::set_broadcast_property(bool value) { | ||||||
|   if (value) { |   if (value) { | ||||||
|     this->properties_ = (esp_gatt_char_prop_t)(this->properties_ | ESP_GATT_CHAR_PROP_BIT_BROADCAST); |     this->properties_ = (esp_gatt_char_prop_t) (this->properties_ | ESP_GATT_CHAR_PROP_BIT_BROADCAST); | ||||||
|   } else { |   } else { | ||||||
|     this->properties_ = (esp_gatt_char_prop_t)(this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_BROADCAST); |     this->properties_ = (esp_gatt_char_prop_t) (this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_BROADCAST); | ||||||
|   } |   } | ||||||
| } | } | ||||||
| void BLECharacteristic::set_indicate_property(bool value) { | void BLECharacteristic::set_indicate_property(bool value) { | ||||||
|   if (value) { |   if (value) { | ||||||
|     this->properties_ = (esp_gatt_char_prop_t)(this->properties_ | ESP_GATT_CHAR_PROP_BIT_INDICATE); |     this->properties_ = (esp_gatt_char_prop_t) (this->properties_ | ESP_GATT_CHAR_PROP_BIT_INDICATE); | ||||||
|   } else { |   } else { | ||||||
|     this->properties_ = (esp_gatt_char_prop_t)(this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_INDICATE); |     this->properties_ = (esp_gatt_char_prop_t) (this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_INDICATE); | ||||||
|   } |   } | ||||||
| } | } | ||||||
| void BLECharacteristic::set_notify_property(bool value) { | void BLECharacteristic::set_notify_property(bool value) { | ||||||
|   if (value) { |   if (value) { | ||||||
|     this->properties_ = (esp_gatt_char_prop_t)(this->properties_ | ESP_GATT_CHAR_PROP_BIT_NOTIFY); |     this->properties_ = (esp_gatt_char_prop_t) (this->properties_ | ESP_GATT_CHAR_PROP_BIT_NOTIFY); | ||||||
|   } else { |   } else { | ||||||
|     this->properties_ = (esp_gatt_char_prop_t)(this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_NOTIFY); |     this->properties_ = (esp_gatt_char_prop_t) (this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_NOTIFY); | ||||||
|   } |   } | ||||||
| } | } | ||||||
| void BLECharacteristic::set_read_property(bool value) { | void BLECharacteristic::set_read_property(bool value) { | ||||||
|   if (value) { |   if (value) { | ||||||
|     this->properties_ = (esp_gatt_char_prop_t)(this->properties_ | ESP_GATT_CHAR_PROP_BIT_READ); |     this->properties_ = (esp_gatt_char_prop_t) (this->properties_ | ESP_GATT_CHAR_PROP_BIT_READ); | ||||||
|   } else { |   } else { | ||||||
|     this->properties_ = (esp_gatt_char_prop_t)(this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_READ); |     this->properties_ = (esp_gatt_char_prop_t) (this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_READ); | ||||||
|   } |   } | ||||||
| } | } | ||||||
| void BLECharacteristic::set_write_property(bool value) { | void BLECharacteristic::set_write_property(bool value) { | ||||||
|   if (value) { |   if (value) { | ||||||
|     this->properties_ = (esp_gatt_char_prop_t)(this->properties_ | ESP_GATT_CHAR_PROP_BIT_WRITE); |     this->properties_ = (esp_gatt_char_prop_t) (this->properties_ | ESP_GATT_CHAR_PROP_BIT_WRITE); | ||||||
|   } else { |   } else { | ||||||
|     this->properties_ = (esp_gatt_char_prop_t)(this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_WRITE); |     this->properties_ = (esp_gatt_char_prop_t) (this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_WRITE); | ||||||
|   } |   } | ||||||
| } | } | ||||||
| void BLECharacteristic::set_write_no_response_property(bool value) { | void BLECharacteristic::set_write_no_response_property(bool value) { | ||||||
|   if (value) { |   if (value) { | ||||||
|     this->properties_ = (esp_gatt_char_prop_t)(this->properties_ | ESP_GATT_CHAR_PROP_BIT_WRITE_NR); |     this->properties_ = (esp_gatt_char_prop_t) (this->properties_ | ESP_GATT_CHAR_PROP_BIT_WRITE_NR); | ||||||
|   } else { |   } else { | ||||||
|     this->properties_ = (esp_gatt_char_prop_t)(this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_WRITE_NR); |     this->properties_ = (esp_gatt_char_prop_t) (this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_WRITE_NR); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -55,6 +55,22 @@ FRAME_SIZES = { | |||||||
|     "SXGA": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1280X1024, |     "SXGA": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1280X1024, | ||||||
|     "1600X1200": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1600X1200, |     "1600X1200": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1600X1200, | ||||||
|     "UXGA": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1600X1200, |     "UXGA": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1600X1200, | ||||||
|  |     "1920X1080": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1920X1080, | ||||||
|  |     "FHD": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1920X1080, | ||||||
|  |     "720X1280": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_720X1280, | ||||||
|  |     "PHD": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_720X1280, | ||||||
|  |     "864X1536": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_864X1536, | ||||||
|  |     "P3MP": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_864X1536, | ||||||
|  |     "2048X1536": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_2048X1536, | ||||||
|  |     "QXGA": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_2048X1536, | ||||||
|  |     "2560X1440": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_2560X1440, | ||||||
|  |     "QHD": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_2560X1440, | ||||||
|  |     "2560X1600": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_2560X1600, | ||||||
|  |     "WQXGA": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_2560X1600, | ||||||
|  |     "1080X1920": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1080X1920, | ||||||
|  |     "PFHD": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1080X1920, | ||||||
|  |     "2560X1920": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_2560X1920, | ||||||
|  |     "QSXGA": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_2560X1920, | ||||||
| } | } | ||||||
| ESP32GainControlMode = esp32_camera_ns.enum("ESP32GainControlMode") | ESP32GainControlMode = esp32_camera_ns.enum("ESP32GainControlMode") | ||||||
| ENUM_GAIN_CONTROL_MODE = { | ENUM_GAIN_CONTROL_MODE = { | ||||||
| @@ -140,7 +156,7 @@ CONFIG_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend( | |||||||
|             { |             { | ||||||
|                 cv.Required(CONF_PIN): pins.internal_gpio_input_pin_number, |                 cv.Required(CONF_PIN): pins.internal_gpio_input_pin_number, | ||||||
|                 cv.Optional(CONF_FREQUENCY, default="20MHz"): cv.All( |                 cv.Optional(CONF_FREQUENCY, default="20MHz"): cv.All( | ||||||
|                     cv.frequency, cv.one_of(20e6, 10e6) |                     cv.frequency, cv.Range(min=8e6, max=20e6) | ||||||
|                 ), |                 ), | ||||||
|             } |             } | ||||||
|         ), |         ), | ||||||
|   | |||||||
| @@ -91,6 +91,30 @@ void ESP32Camera::dump_config() { | |||||||
|     case FRAMESIZE_UXGA: |     case FRAMESIZE_UXGA: | ||||||
|       ESP_LOGCONFIG(TAG, "  Resolution: 1600x1200 (UXGA)"); |       ESP_LOGCONFIG(TAG, "  Resolution: 1600x1200 (UXGA)"); | ||||||
|       break; |       break; | ||||||
|  |     case FRAMESIZE_FHD: | ||||||
|  |       ESP_LOGCONFIG(TAG, "  Resolution: 1920x1080 (FHD)"); | ||||||
|  |       break; | ||||||
|  |     case FRAMESIZE_P_HD: | ||||||
|  |       ESP_LOGCONFIG(TAG, "  Resolution: 720x1280 (P_HD)"); | ||||||
|  |       break; | ||||||
|  |     case FRAMESIZE_P_3MP: | ||||||
|  |       ESP_LOGCONFIG(TAG, "  Resolution: 864x1536 (P_3MP)"); | ||||||
|  |       break; | ||||||
|  |     case FRAMESIZE_QXGA: | ||||||
|  |       ESP_LOGCONFIG(TAG, "  Resolution: 2048x1536 (QXGA)"); | ||||||
|  |       break; | ||||||
|  |     case FRAMESIZE_QHD: | ||||||
|  |       ESP_LOGCONFIG(TAG, "  Resolution: 2560x1440 (QHD)"); | ||||||
|  |       break; | ||||||
|  |     case FRAMESIZE_WQXGA: | ||||||
|  |       ESP_LOGCONFIG(TAG, "  Resolution: 2560x1600 (WQXGA)"); | ||||||
|  |       break; | ||||||
|  |     case FRAMESIZE_P_FHD: | ||||||
|  |       ESP_LOGCONFIG(TAG, "  Resolution: 1080x1920 (P_FHD)"); | ||||||
|  |       break; | ||||||
|  |     case FRAMESIZE_QSXGA: | ||||||
|  |       ESP_LOGCONFIG(TAG, "  Resolution: 2560x1920 (QSXGA)"); | ||||||
|  |       break; | ||||||
|     default: |     default: | ||||||
|       break; |       break; | ||||||
|   } |   } | ||||||
| @@ -178,7 +202,7 @@ void ESP32Camera::loop() { | |||||||
| float ESP32Camera::get_setup_priority() const { return setup_priority::DATA; } | float ESP32Camera::get_setup_priority() const { return setup_priority::DATA; } | ||||||
|  |  | ||||||
| /* ---------------- constructors ---------------- */ | /* ---------------- constructors ---------------- */ | ||||||
| ESP32Camera::ESP32Camera(const std::string &name) : EntityBase(name) { | ESP32Camera::ESP32Camera() { | ||||||
|   this->config_.pin_pwdn = -1; |   this->config_.pin_pwdn = -1; | ||||||
|   this->config_.pin_reset = -1; |   this->config_.pin_reset = -1; | ||||||
|   this->config_.pin_xclk = -1; |   this->config_.pin_xclk = -1; | ||||||
| @@ -191,7 +215,6 @@ ESP32Camera::ESP32Camera(const std::string &name) : EntityBase(name) { | |||||||
|  |  | ||||||
|   global_esp32_camera = this; |   global_esp32_camera = this; | ||||||
| } | } | ||||||
| ESP32Camera::ESP32Camera() : ESP32Camera("") {} |  | ||||||
|  |  | ||||||
| /* ---------------- setters ---------------- */ | /* ---------------- setters ---------------- */ | ||||||
| /* set pin assignment */ | /* set pin assignment */ | ||||||
| @@ -257,6 +280,30 @@ void ESP32Camera::set_frame_size(ESP32CameraFrameSize size) { | |||||||
|     case ESP32_CAMERA_SIZE_1600X1200: |     case ESP32_CAMERA_SIZE_1600X1200: | ||||||
|       this->config_.frame_size = FRAMESIZE_UXGA; |       this->config_.frame_size = FRAMESIZE_UXGA; | ||||||
|       break; |       break; | ||||||
|  |     case ESP32_CAMERA_SIZE_1920X1080: | ||||||
|  |       this->config_.frame_size = FRAMESIZE_FHD; | ||||||
|  |       break; | ||||||
|  |     case ESP32_CAMERA_SIZE_720X1280: | ||||||
|  |       this->config_.frame_size = FRAMESIZE_P_HD; | ||||||
|  |       break; | ||||||
|  |     case ESP32_CAMERA_SIZE_864X1536: | ||||||
|  |       this->config_.frame_size = FRAMESIZE_P_3MP; | ||||||
|  |       break; | ||||||
|  |     case ESP32_CAMERA_SIZE_2048X1536: | ||||||
|  |       this->config_.frame_size = FRAMESIZE_QXGA; | ||||||
|  |       break; | ||||||
|  |     case ESP32_CAMERA_SIZE_2560X1440: | ||||||
|  |       this->config_.frame_size = FRAMESIZE_QHD; | ||||||
|  |       break; | ||||||
|  |     case ESP32_CAMERA_SIZE_2560X1600: | ||||||
|  |       this->config_.frame_size = FRAMESIZE_WQXGA; | ||||||
|  |       break; | ||||||
|  |     case ESP32_CAMERA_SIZE_1080X1920: | ||||||
|  |       this->config_.frame_size = FRAMESIZE_P_FHD; | ||||||
|  |       break; | ||||||
|  |     case ESP32_CAMERA_SIZE_2560X1920: | ||||||
|  |       this->config_.frame_size = FRAMESIZE_QSXGA; | ||||||
|  |       break; | ||||||
|   } |   } | ||||||
| } | } | ||||||
| void ESP32Camera::set_jpeg_quality(uint8_t quality) { this->config_.jpeg_quality = quality; } | void ESP32Camera::set_jpeg_quality(uint8_t quality) { this->config_.jpeg_quality = quality; } | ||||||
|   | |||||||
| @@ -29,6 +29,14 @@ enum ESP32CameraFrameSize { | |||||||
|   ESP32_CAMERA_SIZE_1024X768,   // XGA |   ESP32_CAMERA_SIZE_1024X768,   // XGA | ||||||
|   ESP32_CAMERA_SIZE_1280X1024,  // SXGA |   ESP32_CAMERA_SIZE_1280X1024,  // SXGA | ||||||
|   ESP32_CAMERA_SIZE_1600X1200,  // UXGA |   ESP32_CAMERA_SIZE_1600X1200,  // UXGA | ||||||
|  |   ESP32_CAMERA_SIZE_1920X1080,  // FHD | ||||||
|  |   ESP32_CAMERA_SIZE_720X1280,   // PHD | ||||||
|  |   ESP32_CAMERA_SIZE_864X1536,   // P3MP | ||||||
|  |   ESP32_CAMERA_SIZE_2048X1536,  // QXGA | ||||||
|  |   ESP32_CAMERA_SIZE_2560X1440,  // QHD | ||||||
|  |   ESP32_CAMERA_SIZE_2560X1600,  // WQXGA | ||||||
|  |   ESP32_CAMERA_SIZE_1080X1920,  // PFHD | ||||||
|  |   ESP32_CAMERA_SIZE_2560X1920,  // QSXGA | ||||||
| }; | }; | ||||||
|  |  | ||||||
| enum ESP32AgcGainCeiling { | enum ESP32AgcGainCeiling { | ||||||
| @@ -95,7 +103,6 @@ class CameraImageReader { | |||||||
| /* ---------------- ESP32Camera class ---------------- */ | /* ---------------- ESP32Camera class ---------------- */ | ||||||
| class ESP32Camera : public Component, public EntityBase { | class ESP32Camera : public Component, public EntityBase { | ||||||
|  public: |  public: | ||||||
|   ESP32Camera(const std::string &name); |  | ||||||
|   ESP32Camera(); |   ESP32Camera(); | ||||||
|  |  | ||||||
|   /* setters */ |   /* setters */ | ||||||
|   | |||||||
| @@ -22,20 +22,12 @@ ESP32ImprovComponent = esp32_improv_ns.class_( | |||||||
| ) | ) | ||||||
|  |  | ||||||
|  |  | ||||||
| def validate_none_(value): |  | ||||||
|     if value in ("none", "None"): |  | ||||||
|         return None |  | ||||||
|     if cv.boolean(value) is False: |  | ||||||
|         return None |  | ||||||
|     raise cv.Invalid("Must be none") |  | ||||||
|  |  | ||||||
|  |  | ||||||
| CONFIG_SCHEMA = cv.Schema( | CONFIG_SCHEMA = cv.Schema( | ||||||
|     { |     { | ||||||
|         cv.GenerateID(): cv.declare_id(ESP32ImprovComponent), |         cv.GenerateID(): cv.declare_id(ESP32ImprovComponent), | ||||||
|         cv.GenerateID(CONF_BLE_SERVER_ID): cv.use_id(esp32_ble_server.BLEServer), |         cv.GenerateID(CONF_BLE_SERVER_ID): cv.use_id(esp32_ble_server.BLEServer), | ||||||
|         cv.Required(CONF_AUTHORIZER): cv.Any( |         cv.Required(CONF_AUTHORIZER): cv.Any( | ||||||
|             validate_none_, cv.use_id(binary_sensor.BinarySensor) |             cv.none, cv.use_id(binary_sensor.BinarySensor) | ||||||
|         ), |         ), | ||||||
|         cv.Optional(CONF_STATUS_INDICATOR): cv.use_id(output.BinaryOutput), |         cv.Optional(CONF_STATUS_INDICATOR): cv.use_id(output.BinaryOutput), | ||||||
|         cv.Optional( |         cv.Optional( | ||||||
|   | |||||||
| @@ -34,6 +34,7 @@ ETHERNET_TYPES = { | |||||||
|     "DP83848": EthernetType.ETHERNET_TYPE_DP83848, |     "DP83848": EthernetType.ETHERNET_TYPE_DP83848, | ||||||
|     "IP101": EthernetType.ETHERNET_TYPE_IP101, |     "IP101": EthernetType.ETHERNET_TYPE_IP101, | ||||||
|     "JL1101": EthernetType.ETHERNET_TYPE_JL1101, |     "JL1101": EthernetType.ETHERNET_TYPE_JL1101, | ||||||
|  |     "KSZ8081": EthernetType.ETHERNET_TYPE_KSZ8081, | ||||||
| } | } | ||||||
|  |  | ||||||
| emac_rmii_clock_mode_t = cg.global_ns.enum("emac_rmii_clock_mode_t") | emac_rmii_clock_mode_t = cg.global_ns.enum("emac_rmii_clock_mode_t") | ||||||
|   | |||||||
| @@ -74,6 +74,10 @@ void EthernetComponent::setup() { | |||||||
|       phy = esp_eth_phy_new_jl1101(&phy_config); |       phy = esp_eth_phy_new_jl1101(&phy_config); | ||||||
|       break; |       break; | ||||||
|     } |     } | ||||||
|  |     case ETHERNET_TYPE_KSZ8081: { | ||||||
|  |       phy = esp_eth_phy_new_ksz8081(&phy_config); | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|     default: { |     default: { | ||||||
|       this->mark_failed(); |       this->mark_failed(); | ||||||
|       return; |       return; | ||||||
| @@ -140,7 +144,7 @@ void EthernetComponent::loop() { | |||||||
| } | } | ||||||
|  |  | ||||||
| void EthernetComponent::dump_config() { | void EthernetComponent::dump_config() { | ||||||
|   std::string eth_type; |   const char *eth_type; | ||||||
|   switch (this->type_) { |   switch (this->type_) { | ||||||
|     case ETHERNET_TYPE_LAN8720: |     case ETHERNET_TYPE_LAN8720: | ||||||
|       eth_type = "LAN8720"; |       eth_type = "LAN8720"; | ||||||
| @@ -158,6 +162,14 @@ void EthernetComponent::dump_config() { | |||||||
|       eth_type = "IP101"; |       eth_type = "IP101"; | ||||||
|       break; |       break; | ||||||
|  |  | ||||||
|  |     case ETHERNET_TYPE_JL1101: | ||||||
|  |       eth_type = "JL1101"; | ||||||
|  |       break; | ||||||
|  |  | ||||||
|  |     case ETHERNET_TYPE_KSZ8081: | ||||||
|  |       eth_type = "KSZ8081"; | ||||||
|  |       break; | ||||||
|  |  | ||||||
|     default: |     default: | ||||||
|       eth_type = "Unknown"; |       eth_type = "Unknown"; | ||||||
|       break; |       break; | ||||||
| @@ -170,7 +182,8 @@ void EthernetComponent::dump_config() { | |||||||
|   } |   } | ||||||
|   ESP_LOGCONFIG(TAG, "  MDC Pin: %u", this->mdc_pin_); |   ESP_LOGCONFIG(TAG, "  MDC Pin: %u", this->mdc_pin_); | ||||||
|   ESP_LOGCONFIG(TAG, "  MDIO Pin: %u", this->mdio_pin_); |   ESP_LOGCONFIG(TAG, "  MDIO Pin: %u", this->mdio_pin_); | ||||||
|   ESP_LOGCONFIG(TAG, "  Type: %s", eth_type.c_str()); |   ESP_LOGCONFIG(TAG, "  Type: %s", eth_type); | ||||||
|  |   ESP_LOGCONFIG(TAG, "  PHY addr: %u", this->phy_addr_); | ||||||
| } | } | ||||||
|  |  | ||||||
| float EthernetComponent::get_setup_priority() const { return setup_priority::WIFI; } | float EthernetComponent::get_setup_priority() const { return setup_priority::WIFI; } | ||||||
| @@ -255,14 +268,22 @@ void EthernetComponent::start_connect_() { | |||||||
|   if (this->manual_ip_.has_value()) { |   if (this->manual_ip_.has_value()) { | ||||||
|     if (uint32_t(this->manual_ip_->dns1) != 0) { |     if (uint32_t(this->manual_ip_->dns1) != 0) { | ||||||
|       ip_addr_t d; |       ip_addr_t d; | ||||||
|  | #if LWIP_IPV6 | ||||||
|       d.type = IPADDR_TYPE_V4; |       d.type = IPADDR_TYPE_V4; | ||||||
|       d.u_addr.ip4.addr = static_cast<uint32_t>(this->manual_ip_->dns1); |       d.u_addr.ip4.addr = static_cast<uint32_t>(this->manual_ip_->dns1); | ||||||
|  | #else | ||||||
|  |       d.addr = static_cast<uint32_t>(this->manual_ip_->dns1); | ||||||
|  | #endif | ||||||
|       dns_setserver(0, &d); |       dns_setserver(0, &d); | ||||||
|     } |     } | ||||||
|     if (uint32_t(this->manual_ip_->dns1) != 0) { |     if (uint32_t(this->manual_ip_->dns1) != 0) { | ||||||
|       ip_addr_t d; |       ip_addr_t d; | ||||||
|  | #if LWIP_IPV6 | ||||||
|       d.type = IPADDR_TYPE_V4; |       d.type = IPADDR_TYPE_V4; | ||||||
|       d.u_addr.ip4.addr = static_cast<uint32_t>(this->manual_ip_->dns2); |       d.u_addr.ip4.addr = static_cast<uint32_t>(this->manual_ip_->dns2); | ||||||
|  | #else | ||||||
|  |       d.addr = static_cast<uint32_t>(this->manual_ip_->dns2); | ||||||
|  | #endif | ||||||
|       dns_setserver(1, &d); |       dns_setserver(1, &d); | ||||||
|     } |     } | ||||||
|   } else { |   } else { | ||||||
| @@ -289,8 +310,13 @@ void EthernetComponent::dump_connect_params_() { | |||||||
|   const ip_addr_t *dns_ip1 = dns_getserver(0); |   const ip_addr_t *dns_ip1 = dns_getserver(0); | ||||||
|   const ip_addr_t *dns_ip2 = dns_getserver(1); |   const ip_addr_t *dns_ip2 = dns_getserver(1); | ||||||
|  |  | ||||||
|  | #if LWIP_IPV6 | ||||||
|   ESP_LOGCONFIG(TAG, "  DNS1: %s", network::IPAddress(dns_ip1->u_addr.ip4.addr).str().c_str()); |   ESP_LOGCONFIG(TAG, "  DNS1: %s", network::IPAddress(dns_ip1->u_addr.ip4.addr).str().c_str()); | ||||||
|   ESP_LOGCONFIG(TAG, "  DNS2: %s", network::IPAddress(dns_ip2->u_addr.ip4.addr).str().c_str()); |   ESP_LOGCONFIG(TAG, "  DNS2: %s", network::IPAddress(dns_ip2->u_addr.ip4.addr).str().c_str()); | ||||||
|  | #else | ||||||
|  |   ESP_LOGCONFIG(TAG, "  DNS1: %s", network::IPAddress(dns_ip1->addr).str().c_str()); | ||||||
|  |   ESP_LOGCONFIG(TAG, "  DNS2: %s", network::IPAddress(dns_ip2->addr).str().c_str()); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|   esp_err_t err; |   esp_err_t err; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -14,11 +14,13 @@ namespace esphome { | |||||||
| namespace ethernet { | namespace ethernet { | ||||||
|  |  | ||||||
| enum EthernetType { | enum EthernetType { | ||||||
|   ETHERNET_TYPE_LAN8720 = 0, |   ETHERNET_TYPE_UNKNOWN = 0, | ||||||
|  |   ETHERNET_TYPE_LAN8720, | ||||||
|   ETHERNET_TYPE_RTL8201, |   ETHERNET_TYPE_RTL8201, | ||||||
|   ETHERNET_TYPE_DP83848, |   ETHERNET_TYPE_DP83848, | ||||||
|   ETHERNET_TYPE_IP101, |   ETHERNET_TYPE_IP101, | ||||||
|   ETHERNET_TYPE_JL1101, |   ETHERNET_TYPE_JL1101, | ||||||
|  |   ETHERNET_TYPE_KSZ8081, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| struct ManualIP { | struct ManualIP { | ||||||
| @@ -69,7 +71,7 @@ class EthernetComponent : public Component { | |||||||
|   int power_pin_{-1}; |   int power_pin_{-1}; | ||||||
|   uint8_t mdc_pin_{23}; |   uint8_t mdc_pin_{23}; | ||||||
|   uint8_t mdio_pin_{18}; |   uint8_t mdio_pin_{18}; | ||||||
|   EthernetType type_{ETHERNET_TYPE_LAN8720}; |   EthernetType type_{ETHERNET_TYPE_UNKNOWN}; | ||||||
|   emac_rmii_clock_mode_t clk_mode_{EMAC_CLK_EXT_IN}; |   emac_rmii_clock_mode_t clk_mode_{EMAC_CLK_EXT_IN}; | ||||||
|   emac_rmii_clock_gpio_t clk_gpio_{EMAC_CLK_IN_GPIO}; |   emac_rmii_clock_gpio_t clk_gpio_{EMAC_CLK_IN_GPIO}; | ||||||
|   optional<ManualIP> manual_ip_{}; |   optional<ManualIP> manual_ip_{}; | ||||||
|   | |||||||
| @@ -12,14 +12,14 @@ static const char *const TAG = "ezo.sensor"; | |||||||
|  |  | ||||||
| enum EzoCommandType : uint8_t { | enum EzoCommandType : uint8_t { | ||||||
|   EZO_READ = 0, |   EZO_READ = 0, | ||||||
|   EZO_LED = 1, |   EZO_LED, | ||||||
|   EZO_DEVICE_INFORMATION = 2, |   EZO_DEVICE_INFORMATION, | ||||||
|   EZO_SLOPE = 3, |   EZO_SLOPE, | ||||||
|   EZO_CALIBRATION, |   EZO_CALIBRATION, | ||||||
|   EZO_SLEEP = 4, |   EZO_SLEEP, | ||||||
|   EZO_I2C = 5, |   EZO_I2C, | ||||||
|   EZO_T = 6, |   EZO_T, | ||||||
|   EZO_CUSTOM = 7 |   EZO_CUSTOM | ||||||
| }; | }; | ||||||
|  |  | ||||||
| enum EzoCalibrationType : uint8_t { EZO_CAL_LOW = 0, EZO_CAL_MID = 1, EZO_CAL_HIGH = 2 }; | enum EzoCalibrationType : uint8_t { EZO_CAL_LOW = 0, EZO_CAL_MID = 1, EZO_CAL_HIGH = 2 }; | ||||||
|   | |||||||
| @@ -63,7 +63,7 @@ FanIsOffCondition = fan_ns.class_("FanIsOffCondition", automation.Condition.temp | |||||||
| FAN_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend( | FAN_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend( | ||||||
|     { |     { | ||||||
|         cv.GenerateID(): cv.declare_id(Fan), |         cv.GenerateID(): cv.declare_id(Fan), | ||||||
|         cv.Optional(CONF_RESTORE_MODE, default="RESTORE_DEFAULT_OFF"): cv.enum( |         cv.Optional(CONF_RESTORE_MODE, default="ALWAYS_OFF"): cv.enum( | ||||||
|             RESTORE_MODES, upper=True, space="_" |             RESTORE_MODES, upper=True, space="_" | ||||||
|         ), |         ), | ||||||
|         cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTFanComponent), |         cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTFanComponent), | ||||||
|   | |||||||
| @@ -80,9 +80,6 @@ void FanRestoreState::apply(Fan &fan) { | |||||||
|   fan.publish_state(); |   fan.publish_state(); | ||||||
| } | } | ||||||
|  |  | ||||||
| Fan::Fan() : EntityBase("") {} |  | ||||||
| Fan::Fan(const std::string &name) : EntityBase(name) {} |  | ||||||
|  |  | ||||||
| FanCall Fan::turn_on() { return this->make_call().set_state(true); } | FanCall Fan::turn_on() { return this->make_call().set_state(true); } | ||||||
| FanCall Fan::turn_off() { return this->make_call().set_state(false); } | FanCall Fan::turn_off() { return this->make_call().set_state(false); } | ||||||
| FanCall Fan::toggle() { return this->make_call().set_state(!this->state); } | FanCall Fan::toggle() { return this->make_call().set_state(!this->state); } | ||||||
|   | |||||||
| @@ -99,10 +99,6 @@ struct FanRestoreState { | |||||||
|  |  | ||||||
| class Fan : public EntityBase { | class Fan : public EntityBase { | ||||||
|  public: |  public: | ||||||
|   Fan(); |  | ||||||
|   /// Construct the fan with name. |  | ||||||
|   explicit Fan(const std::string &name); |  | ||||||
|  |  | ||||||
|   /// The current on/off state of the fan. |   /// The current on/off state of the fan. | ||||||
|   bool state{false}; |   bool state{false}; | ||||||
|   /// The current oscillation state of the fan. |   /// The current oscillation state of the fan. | ||||||
|   | |||||||
| @@ -15,7 +15,6 @@ enum ESPDEPRECATED("LegacyFanDirection members are deprecated, use FanDirection | |||||||
| class ESPDEPRECATED("FanState is deprecated, use Fan instead.", "2022.2") FanState : public Fan, public Component { | class ESPDEPRECATED("FanState is deprecated, use Fan instead.", "2022.2") FanState : public Fan, public Component { | ||||||
|  public: |  public: | ||||||
|   FanState() = default; |   FanState() = default; | ||||||
|   explicit FanState(const std::string &name) : Fan(name) {} |  | ||||||
|  |  | ||||||
|   /// Get the traits of this fan. |   /// Get the traits of this fan. | ||||||
|   FanTraits get_traits() override { return this->traits_; } |   FanTraits get_traits() override { return this->traits_; } | ||||||
|   | |||||||
| @@ -95,7 +95,7 @@ void FingerprintGrowComponent::scan_and_match_() { | |||||||
|   } |   } | ||||||
|   if (this->scan_image_(1) == OK) { |   if (this->scan_image_(1) == OK) { | ||||||
|     this->waiting_removal_ = true; |     this->waiting_removal_ = true; | ||||||
|     this->data_ = {SEARCH, 0x01, 0x00, 0x00, (uint8_t)(this->capacity_ >> 8), (uint8_t)(this->capacity_ & 0xFF)}; |     this->data_ = {SEARCH, 0x01, 0x00, 0x00, (uint8_t) (this->capacity_ >> 8), (uint8_t) (this->capacity_ & 0xFF)}; | ||||||
|     switch (this->send_command_()) { |     switch (this->send_command_()) { | ||||||
|       case OK: { |       case OK: { | ||||||
|         ESP_LOGD(TAG, "Fingerprint matched"); |         ESP_LOGD(TAG, "Fingerprint matched"); | ||||||
| @@ -171,7 +171,7 @@ uint8_t FingerprintGrowComponent::save_fingerprint_() { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   ESP_LOGI(TAG, "Storing model"); |   ESP_LOGI(TAG, "Storing model"); | ||||||
|   this->data_ = {STORE, 0x01, (uint8_t)(this->enrollment_slot_ >> 8), (uint8_t)(this->enrollment_slot_ & 0xFF)}; |   this->data_ = {STORE, 0x01, (uint8_t) (this->enrollment_slot_ >> 8), (uint8_t) (this->enrollment_slot_ & 0xFF)}; | ||||||
|   switch (this->send_command_()) { |   switch (this->send_command_()) { | ||||||
|     case OK: |     case OK: | ||||||
|       ESP_LOGI(TAG, "Stored model"); |       ESP_LOGI(TAG, "Stored model"); | ||||||
| @@ -188,8 +188,8 @@ uint8_t FingerprintGrowComponent::save_fingerprint_() { | |||||||
|  |  | ||||||
| bool FingerprintGrowComponent::check_password_() { | bool FingerprintGrowComponent::check_password_() { | ||||||
|   ESP_LOGD(TAG, "Checking password"); |   ESP_LOGD(TAG, "Checking password"); | ||||||
|   this->data_ = {VERIFY_PASSWORD, (uint8_t)(this->password_ >> 24), (uint8_t)(this->password_ >> 16), |   this->data_ = {VERIFY_PASSWORD, (uint8_t) (this->password_ >> 24), (uint8_t) (this->password_ >> 16), | ||||||
|                  (uint8_t)(this->password_ >> 8), (uint8_t)(this->password_ & 0xFF)}; |                  (uint8_t) (this->password_ >> 8), (uint8_t) (this->password_ & 0xFF)}; | ||||||
|   switch (this->send_command_()) { |   switch (this->send_command_()) { | ||||||
|     case OK: |     case OK: | ||||||
|       ESP_LOGD(TAG, "Password verified"); |       ESP_LOGD(TAG, "Password verified"); | ||||||
| @@ -203,8 +203,8 @@ bool FingerprintGrowComponent::check_password_() { | |||||||
|  |  | ||||||
| bool FingerprintGrowComponent::set_password_() { | bool FingerprintGrowComponent::set_password_() { | ||||||
|   ESP_LOGI(TAG, "Setting new password: %d", this->new_password_); |   ESP_LOGI(TAG, "Setting new password: %d", this->new_password_); | ||||||
|   this->data_ = {SET_PASSWORD, (uint8_t)(this->new_password_ >> 24), (uint8_t)(this->new_password_ >> 16), |   this->data_ = {SET_PASSWORD, (uint8_t) (this->new_password_ >> 24), (uint8_t) (this->new_password_ >> 16), | ||||||
|                  (uint8_t)(this->new_password_ >> 8), (uint8_t)(this->new_password_ & 0xFF)}; |                  (uint8_t) (this->new_password_ >> 8), (uint8_t) (this->new_password_ & 0xFF)}; | ||||||
|   if (this->send_command_() == OK) { |   if (this->send_command_() == OK) { | ||||||
|     ESP_LOGI(TAG, "New password successfully set"); |     ESP_LOGI(TAG, "New password successfully set"); | ||||||
|     ESP_LOGI(TAG, "Define the new password in your configuration and reflash now"); |     ESP_LOGI(TAG, "Define the new password in your configuration and reflash now"); | ||||||
| @@ -250,7 +250,7 @@ void FingerprintGrowComponent::get_fingerprint_count_() { | |||||||
|  |  | ||||||
| void FingerprintGrowComponent::delete_fingerprint(uint16_t finger_id) { | void FingerprintGrowComponent::delete_fingerprint(uint16_t finger_id) { | ||||||
|   ESP_LOGI(TAG, "Deleting fingerprint in slot %d", finger_id); |   ESP_LOGI(TAG, "Deleting fingerprint in slot %d", finger_id); | ||||||
|   this->data_ = {DELETE, (uint8_t)(finger_id >> 8), (uint8_t)(finger_id & 0xFF), 0x00, 0x01}; |   this->data_ = {DELETE, (uint8_t) (finger_id >> 8), (uint8_t) (finger_id & 0xFF), 0x00, 0x01}; | ||||||
|   switch (this->send_command_()) { |   switch (this->send_command_()) { | ||||||
|     case OK: |     case OK: | ||||||
|       ESP_LOGI(TAG, "Deleted fingerprint"); |       ESP_LOGI(TAG, "Deleted fingerprint"); | ||||||
| @@ -320,8 +320,8 @@ void FingerprintGrowComponent::aura_led_control(uint8_t state, uint8_t speed, ui | |||||||
| } | } | ||||||
|  |  | ||||||
| uint8_t FingerprintGrowComponent::send_command_() { | uint8_t FingerprintGrowComponent::send_command_() { | ||||||
|   this->write((uint8_t)(START_CODE >> 8)); |   this->write((uint8_t) (START_CODE >> 8)); | ||||||
|   this->write((uint8_t)(START_CODE & 0xFF)); |   this->write((uint8_t) (START_CODE & 0xFF)); | ||||||
|   this->write(this->address_[0]); |   this->write(this->address_[0]); | ||||||
|   this->write(this->address_[1]); |   this->write(this->address_[1]); | ||||||
|   this->write(this->address_[2]); |   this->write(this->address_[2]); | ||||||
| @@ -329,8 +329,8 @@ uint8_t FingerprintGrowComponent::send_command_() { | |||||||
|   this->write(COMMAND); |   this->write(COMMAND); | ||||||
|  |  | ||||||
|   uint16_t wire_length = this->data_.size() + 2; |   uint16_t wire_length = this->data_.size() + 2; | ||||||
|   this->write((uint8_t)(wire_length >> 8)); |   this->write((uint8_t) (wire_length >> 8)); | ||||||
|   this->write((uint8_t)(wire_length & 0xFF)); |   this->write((uint8_t) (wire_length & 0xFF)); | ||||||
|  |  | ||||||
|   uint16_t sum = ((wire_length) >> 8) + ((wire_length) &0xFF) + COMMAND; |   uint16_t sum = ((wire_length) >> 8) + ((wire_length) &0xFF) + COMMAND; | ||||||
|   for (auto data : this->data_) { |   for (auto data : this->data_) { | ||||||
| @@ -338,8 +338,8 @@ uint8_t FingerprintGrowComponent::send_command_() { | |||||||
|     sum += data; |     sum += data; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   this->write((uint8_t)(sum >> 8)); |   this->write((uint8_t) (sum >> 8)); | ||||||
|   this->write((uint8_t)(sum & 0xFF)); |   this->write((uint8_t) (sum & 0xFF)); | ||||||
|  |  | ||||||
|   this->data_.clear(); |   this->data_.clear(); | ||||||
|  |  | ||||||
| @@ -354,11 +354,11 @@ uint8_t FingerprintGrowComponent::send_command_() { | |||||||
|     byte = this->read(); |     byte = this->read(); | ||||||
|     switch (idx) { |     switch (idx) { | ||||||
|       case 0: |       case 0: | ||||||
|         if (byte != (uint8_t)(START_CODE >> 8)) |         if (byte != (uint8_t) (START_CODE >> 8)) | ||||||
|           continue; |           continue; | ||||||
|         break; |         break; | ||||||
|       case 1: |       case 1: | ||||||
|         if (byte != (uint8_t)(START_CODE & 0xFF)) { |         if (byte != (uint8_t) (START_CODE & 0xFF)) { | ||||||
|           idx = 0; |           idx = 0; | ||||||
|           continue; |           continue; | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -91,10 +91,10 @@ class FingerprintGrowComponent : public PollingComponent, public uart::UARTDevic | |||||||
|   void dump_config() override; |   void dump_config() override; | ||||||
|  |  | ||||||
|   void set_address(uint32_t address) { |   void set_address(uint32_t address) { | ||||||
|     this->address_[0] = (uint8_t)(address >> 24); |     this->address_[0] = (uint8_t) (address >> 24); | ||||||
|     this->address_[1] = (uint8_t)(address >> 16); |     this->address_[1] = (uint8_t) (address >> 16); | ||||||
|     this->address_[2] = (uint8_t)(address >> 8); |     this->address_[2] = (uint8_t) (address >> 8); | ||||||
|     this->address_[3] = (uint8_t)(address & 0xFF); |     this->address_[3] = (uint8_t) (address & 0xFF); | ||||||
|   } |   } | ||||||
|   void set_sensing_pin(GPIOPin *sensing_pin) { this->sensing_pin_ = sensing_pin; } |   void set_sensing_pin(GPIOPin *sensing_pin) { this->sensing_pin_ = sensing_pin; } | ||||||
|   void set_password(uint32_t password) { this->password_ = password; } |   void set_password(uint32_t password) { this->password_ = password; } | ||||||
|   | |||||||
| @@ -122,11 +122,18 @@ void Graph::draw(DisplayBuffer *buff, uint16_t x_offset, uint16_t y_offset, Colo | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   // Adjust limits to nice y_per_div boundaries |   // Adjust limits to nice y_per_div boundaries | ||||||
|   int yn = int(ymin / y_per_div); |   int yn = 0; | ||||||
|   int ym = int(ymax / y_per_div) + int(1 * (fmodf(ymax, y_per_div) != 0)); |   int ym = 1; | ||||||
|   ymin = yn * y_per_div; |   if (!std::isnan(ymin) && !std::isnan(ymax)) { | ||||||
|   ymax = ym * y_per_div; |     yn = (int) floorf(ymin / y_per_div); | ||||||
|   yrange = ymax - ymin; |     ym = (int) ceilf(ymax / y_per_div); | ||||||
|  |     if (yn == ym) { | ||||||
|  |       ym++; | ||||||
|  |     } | ||||||
|  |     ymin = yn * y_per_div; | ||||||
|  |     ymax = ym * y_per_div; | ||||||
|  |     yrange = ymax - ymin; | ||||||
|  |   } | ||||||
|  |  | ||||||
|   /// Draw grid |   /// Draw grid | ||||||
|   if (!std::isnan(this->gridspacing_y_)) { |   if (!std::isnan(this->gridspacing_y_)) { | ||||||
|   | |||||||
| @@ -12,7 +12,7 @@ void set_bits(uint8_t *const dst, const uint8_t offset, const uint8_t nbits, con | |||||||
|   uint8_t mask = UINT8_MAX >> (8 - ((nbits > 8) ? 8 : nbits)); |   uint8_t mask = UINT8_MAX >> (8 - ((nbits > 8) ? 8 : nbits)); | ||||||
|   // Calculate the mask & clear the space for the data. |   // Calculate the mask & clear the space for the data. | ||||||
|   // Clear the destination bits. |   // Clear the destination bits. | ||||||
|   *dst &= ~(uint8_t)(mask << offset); |   *dst &= ~(uint8_t) (mask << offset); | ||||||
|   // Merge in the data. |   // Merge in the data. | ||||||
|   *dst |= ((data & mask) << offset); |   *dst |= ((data & mask) << offset); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -12,7 +12,7 @@ void set_bits(uint8_t *const dst, const uint8_t offset, const uint8_t nbits, con | |||||||
|   uint8_t mask = UINT8_MAX >> (8 - ((nbits > 8) ? 8 : nbits)); |   uint8_t mask = UINT8_MAX >> (8 - ((nbits > 8) ? 8 : nbits)); | ||||||
|   // Calculate the mask & clear the space for the data. |   // Calculate the mask & clear the space for the data. | ||||||
|   // Clear the destination bits. |   // Clear the destination bits. | ||||||
|   *dst &= ~(uint8_t)(mask << offset); |   *dst &= ~(uint8_t) (mask << offset); | ||||||
|   // Merge in the data. |   // Merge in the data. | ||||||
|   *dst |= ((data & mask) << offset); |   *dst |= ((data & mask) << offset); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -35,9 +35,9 @@ uint8_t HONEYWELLABPSensor::readsensor_() { | |||||||
|   // if device is normal and there is new data, bitmask and save the raw data |   // if device is normal and there is new data, bitmask and save the raw data | ||||||
|   if (status_ == 0) { |   if (status_ == 0) { | ||||||
|     // 14 - bit pressure is the last 6 bits of byte 0 (high bits) & all of byte 1 (lowest 8 bits) |     // 14 - bit pressure is the last 6 bits of byte 0 (high bits) & all of byte 1 (lowest 8 bits) | ||||||
|     pressure_count_ = ((uint16_t)(buf_[0]) << 8 & 0x3F00) | ((uint16_t)(buf_[1]) & 0xFF); |     pressure_count_ = ((uint16_t) (buf_[0]) << 8 & 0x3F00) | ((uint16_t) (buf_[1]) & 0xFF); | ||||||
|     // 11 - bit temperature is all of byte 2 (lowest 8 bits) and the first three bits of byte 3 |     // 11 - bit temperature is all of byte 2 (lowest 8 bits) and the first three bits of byte 3 | ||||||
|     temperature_count_ = (((uint16_t)(buf_[2]) << 3) & 0x7F8) | (((uint16_t)(buf_[3]) >> 5) & 0x7); |     temperature_count_ = (((uint16_t) (buf_[2]) << 3) & 0x7F8) | (((uint16_t) (buf_[3]) >> 5) & 0x7); | ||||||
|     ESP_LOGV(TAG, "Sensor pressure_count_ %d", pressure_count_); |     ESP_LOGV(TAG, "Sensor pressure_count_ %d", pressure_count_); | ||||||
|     ESP_LOGV(TAG, "Sensor temperature_count_ %d", temperature_count_); |     ESP_LOGV(TAG, "Sensor temperature_count_ %d", temperature_count_); | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ | |||||||
| #include "esphome/core/log.h" | #include "esphome/core/log.h" | ||||||
| #include "esphome/core/helpers.h" | #include "esphome/core/helpers.h" | ||||||
| #include <cstring> | #include <cstring> | ||||||
|  | #include <cinttypes> | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace i2c { | namespace i2c { | ||||||
| @@ -47,7 +48,7 @@ void IDFI2CBus::dump_config() { | |||||||
|   ESP_LOGCONFIG(TAG, "I2C Bus:"); |   ESP_LOGCONFIG(TAG, "I2C Bus:"); | ||||||
|   ESP_LOGCONFIG(TAG, "  SDA Pin: GPIO%u", this->sda_pin_); |   ESP_LOGCONFIG(TAG, "  SDA Pin: GPIO%u", this->sda_pin_); | ||||||
|   ESP_LOGCONFIG(TAG, "  SCL Pin: GPIO%u", this->scl_pin_); |   ESP_LOGCONFIG(TAG, "  SCL Pin: GPIO%u", this->scl_pin_); | ||||||
|   ESP_LOGCONFIG(TAG, "  Frequency: %u Hz", this->frequency_); |   ESP_LOGCONFIG(TAG, "  Frequency: %" PRIu32 " Hz", this->frequency_); | ||||||
|   switch (this->recovery_result_) { |   switch (this->recovery_result_) { | ||||||
|     case RECOVERY_COMPLETED: |     case RECOVERY_COMPLETED: | ||||||
|       ESP_LOGCONFIG(TAG, "  Recovery: bus successfully recovered"); |       ESP_LOGCONFIG(TAG, "  Recovery: bus successfully recovered"); | ||||||
|   | |||||||
| @@ -0,0 +1,70 @@ | |||||||
|  | import esphome.config_validation as cv | ||||||
|  | import esphome.final_validate as fv | ||||||
|  | import esphome.codegen as cg | ||||||
|  |  | ||||||
|  | from esphome import pins | ||||||
|  | from esphome.const import CONF_ID | ||||||
|  | from esphome.components.esp32 import get_esp32_variant | ||||||
|  | from esphome.components.esp32.const import ( | ||||||
|  |     VARIANT_ESP32, | ||||||
|  |     VARIANT_ESP32S2, | ||||||
|  |     VARIANT_ESP32S3, | ||||||
|  |     VARIANT_ESP32C3, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | CODEOWNERS = ["@jesserockz"] | ||||||
|  | DEPENDENCIES = ["esp32"] | ||||||
|  | MULTI_CONF = True | ||||||
|  |  | ||||||
|  | CONF_I2S_DOUT_PIN = "i2s_dout_pin" | ||||||
|  | CONF_I2S_DIN_PIN = "i2s_din_pin" | ||||||
|  | CONF_I2S_BCLK_PIN = "i2s_bclk_pin" | ||||||
|  | CONF_I2S_LRCLK_PIN = "i2s_lrclk_pin" | ||||||
|  |  | ||||||
|  | CONF_I2S_AUDIO = "i2s_audio" | ||||||
|  | CONF_I2S_AUDIO_ID = "i2s_audio_id" | ||||||
|  |  | ||||||
|  | i2s_audio_ns = cg.esphome_ns.namespace("i2s_audio") | ||||||
|  | I2SAudioComponent = i2s_audio_ns.class_("I2SAudioComponent", cg.Component) | ||||||
|  | I2SAudioIn = i2s_audio_ns.class_("I2SAudioIn", cg.Parented.template(I2SAudioComponent)) | ||||||
|  | I2SAudioOut = i2s_audio_ns.class_( | ||||||
|  |     "I2SAudioOut", cg.Parented.template(I2SAudioComponent) | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | # https://github.com/espressif/esp-idf/blob/master/components/soc/{variant}/include/soc/soc_caps.h | ||||||
|  | I2S_PORTS = { | ||||||
|  |     VARIANT_ESP32: 2, | ||||||
|  |     VARIANT_ESP32S2: 1, | ||||||
|  |     VARIANT_ESP32S3: 2, | ||||||
|  |     VARIANT_ESP32C3: 1, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = cv.Schema( | ||||||
|  |     { | ||||||
|  |         cv.GenerateID(): cv.declare_id(I2SAudioComponent), | ||||||
|  |         cv.Required(CONF_I2S_BCLK_PIN): pins.internal_gpio_output_pin_number, | ||||||
|  |         cv.Required(CONF_I2S_LRCLK_PIN): pins.internal_gpio_output_pin_number, | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def _final_validate(_): | ||||||
|  |     i2s_audio_configs = fv.full_config.get()[CONF_I2S_AUDIO] | ||||||
|  |     variant = get_esp32_variant() | ||||||
|  |     if variant not in I2S_PORTS: | ||||||
|  |         raise cv.Invalid(f"Unsupported variant {variant}") | ||||||
|  |     if len(i2s_audio_configs) > I2S_PORTS[variant]: | ||||||
|  |         raise cv.Invalid( | ||||||
|  |             f"Only {I2S_PORTS[variant]} I2S audio ports are supported on {variant}" | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | FINAL_VALIDATE_SCHEMA = _final_validate | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def to_code(config): | ||||||
|  |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|  |     await cg.register_component(var, config) | ||||||
|  |  | ||||||
|  |     cg.add(var.set_bclk_pin(config[CONF_I2S_BCLK_PIN])) | ||||||
|  |     cg.add(var.set_lrclk_pin(config[CONF_I2S_LRCLK_PIN])) | ||||||
|   | |||||||
							
								
								
									
										30
									
								
								esphome/components/i2s_audio/i2s_audio.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								esphome/components/i2s_audio/i2s_audio.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | |||||||
|  | #include "i2s_audio.h" | ||||||
|  |  | ||||||
|  | #ifdef USE_ESP32 | ||||||
|  |  | ||||||
|  | #include "esphome/core/log.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace i2s_audio { | ||||||
|  |  | ||||||
|  | static const char *const TAG = "i2s_audio"; | ||||||
|  |  | ||||||
|  | void I2SAudioComponent::setup() { | ||||||
|  |   static i2s_port_t next_port_num = I2S_NUM_0; | ||||||
|  |  | ||||||
|  |   if (next_port_num >= I2S_NUM_MAX) { | ||||||
|  |     ESP_LOGE(TAG, "Too many I2S Audio components!"); | ||||||
|  |     this->mark_failed(); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   this->port_ = next_port_num; | ||||||
|  |   next_port_num = (i2s_port_t) (next_port_num + 1); | ||||||
|  |  | ||||||
|  |   ESP_LOGCONFIG(TAG, "Setting up I2S Audio..."); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace i2s_audio | ||||||
|  | }  // namespace esphome | ||||||
|  |  | ||||||
|  | #endif  // USE_ESP32 | ||||||
							
								
								
									
										64
									
								
								esphome/components/i2s_audio/i2s_audio.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								esphome/components/i2s_audio/i2s_audio.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #ifdef USE_ESP32 | ||||||
|  |  | ||||||
|  | #include <driver/i2s.h> | ||||||
|  | #include "esphome/core/component.h" | ||||||
|  | #include "esphome/core/helpers.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace i2s_audio { | ||||||
|  |  | ||||||
|  | class I2SAudioComponent; | ||||||
|  |  | ||||||
|  | class I2SAudioIn : public Parented<I2SAudioComponent> {}; | ||||||
|  |  | ||||||
|  | class I2SAudioOut : public Parented<I2SAudioComponent> {}; | ||||||
|  |  | ||||||
|  | class I2SAudioComponent : public Component { | ||||||
|  |  public: | ||||||
|  |   void setup() override; | ||||||
|  |  | ||||||
|  |   void register_audio_in(I2SAudioIn *in) { | ||||||
|  |     this->audio_in_ = in; | ||||||
|  |     in->set_parent(this); | ||||||
|  |   } | ||||||
|  |   void register_audio_out(I2SAudioOut *out) { | ||||||
|  |     this->audio_out_ = out; | ||||||
|  |     out->set_parent(this); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   i2s_pin_config_t get_pin_config() const { | ||||||
|  |     return { | ||||||
|  |         .mck_io_num = I2S_PIN_NO_CHANGE, | ||||||
|  |         .bck_io_num = this->bclk_pin_, | ||||||
|  |         .ws_io_num = this->lrclk_pin_, | ||||||
|  |         .data_out_num = I2S_PIN_NO_CHANGE, | ||||||
|  |         .data_in_num = I2S_PIN_NO_CHANGE, | ||||||
|  |     }; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void set_bclk_pin(uint8_t pin) { this->bclk_pin_ = pin; } | ||||||
|  |   void set_lrclk_pin(uint8_t pin) { this->lrclk_pin_ = pin; } | ||||||
|  |  | ||||||
|  |   void lock() { this->lock_.lock(); } | ||||||
|  |   bool try_lock() { return this->lock_.try_lock(); } | ||||||
|  |   void unlock() { this->lock_.unlock(); } | ||||||
|  |  | ||||||
|  |   i2s_port_t get_port() const { return this->port_; } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   Mutex lock_; | ||||||
|  |  | ||||||
|  |   I2SAudioIn *audio_in_{nullptr}; | ||||||
|  |   I2SAudioOut *audio_out_{nullptr}; | ||||||
|  |  | ||||||
|  |   uint8_t bclk_pin_; | ||||||
|  |   uint8_t lrclk_pin_; | ||||||
|  |   i2s_port_t port_{}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace i2s_audio | ||||||
|  | }  // namespace esphome | ||||||
|  |  | ||||||
|  | #endif  // USE_ESP32 | ||||||
| @@ -5,22 +5,25 @@ import esphome.config_validation as cv | |||||||
| from esphome import pins | from esphome import pins | ||||||
| 
 | 
 | ||||||
| from esphome.const import CONF_ID, CONF_MODE | from esphome.const import CONF_ID, CONF_MODE | ||||||
| from esphome.core import CORE | 
 | ||||||
|  | from .. import ( | ||||||
|  |     i2s_audio_ns, | ||||||
|  |     I2SAudioComponent, | ||||||
|  |     I2SAudioOut, | ||||||
|  |     CONF_I2S_AUDIO_ID, | ||||||
|  |     CONF_I2S_DOUT_PIN, | ||||||
|  | ) | ||||||
| 
 | 
 | ||||||
| CODEOWNERS = ["@jesserockz"] | CODEOWNERS = ["@jesserockz"] | ||||||
| DEPENDENCIES = ["esp32"] | DEPENDENCIES = ["i2s_audio"] | ||||||
| 
 |  | ||||||
| i2s_audio_ns = cg.esphome_ns.namespace("i2s_audio") |  | ||||||
| 
 | 
 | ||||||
| I2SAudioMediaPlayer = i2s_audio_ns.class_( | I2SAudioMediaPlayer = i2s_audio_ns.class_( | ||||||
|     "I2SAudioMediaPlayer", cg.Component, media_player.MediaPlayer |     "I2SAudioMediaPlayer", cg.Component, media_player.MediaPlayer, I2SAudioOut | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| i2s_dac_mode_t = cg.global_ns.enum("i2s_dac_mode_t") | i2s_dac_mode_t = cg.global_ns.enum("i2s_dac_mode_t") | ||||||
| 
 | 
 | ||||||
| CONF_I2S_DOUT_PIN = "i2s_dout_pin" | 
 | ||||||
| CONF_I2S_BCLK_PIN = "i2s_bclk_pin" |  | ||||||
| CONF_I2S_LRCLK_PIN = "i2s_lrclk_pin" |  | ||||||
| CONF_MUTE_PIN = "mute_pin" | CONF_MUTE_PIN = "mute_pin" | ||||||
| CONF_AUDIO_ID = "audio_id" | CONF_AUDIO_ID = "audio_id" | ||||||
| CONF_DAC_TYPE = "dac_type" | CONF_DAC_TYPE = "dac_type" | ||||||
| @@ -48,34 +51,26 @@ def validate_esp32_variant(config): | |||||||
| CONFIG_SCHEMA = cv.All( | CONFIG_SCHEMA = cv.All( | ||||||
|     cv.typed_schema( |     cv.typed_schema( | ||||||
|         { |         { | ||||||
|             "internal": cv.Schema( |             "internal": media_player.MEDIA_PLAYER_SCHEMA.extend( | ||||||
|                 { |                 { | ||||||
|                     cv.GenerateID(): cv.declare_id(I2SAudioMediaPlayer), |                     cv.GenerateID(): cv.declare_id(I2SAudioMediaPlayer), | ||||||
|  |                     cv.GenerateID(CONF_I2S_AUDIO_ID): cv.use_id(I2SAudioComponent), | ||||||
|                     cv.Required(CONF_MODE): cv.enum(INTERNAL_DAC_OPTIONS, lower=True), |                     cv.Required(CONF_MODE): cv.enum(INTERNAL_DAC_OPTIONS, lower=True), | ||||||
|                 } |                 } | ||||||
|             ) |             ).extend(cv.COMPONENT_SCHEMA), | ||||||
|             .extend(media_player.MEDIA_PLAYER_SCHEMA) |             "external": media_player.MEDIA_PLAYER_SCHEMA.extend( | ||||||
|             .extend(cv.COMPONENT_SCHEMA), |  | ||||||
|             "external": cv.Schema( |  | ||||||
|                 { |                 { | ||||||
|                     cv.GenerateID(): cv.declare_id(I2SAudioMediaPlayer), |                     cv.GenerateID(): cv.declare_id(I2SAudioMediaPlayer), | ||||||
|  |                     cv.GenerateID(CONF_I2S_AUDIO_ID): cv.use_id(I2SAudioComponent), | ||||||
|                     cv.Required( |                     cv.Required( | ||||||
|                         CONF_I2S_DOUT_PIN |                         CONF_I2S_DOUT_PIN | ||||||
|                     ): pins.internal_gpio_output_pin_number, |                     ): pins.internal_gpio_output_pin_number, | ||||||
|                     cv.Required( |  | ||||||
|                         CONF_I2S_BCLK_PIN |  | ||||||
|                     ): pins.internal_gpio_output_pin_number, |  | ||||||
|                     cv.Required( |  | ||||||
|                         CONF_I2S_LRCLK_PIN |  | ||||||
|                     ): pins.internal_gpio_output_pin_number, |  | ||||||
|                     cv.Optional(CONF_MUTE_PIN): pins.gpio_output_pin_schema, |                     cv.Optional(CONF_MUTE_PIN): pins.gpio_output_pin_schema, | ||||||
|                     cv.Optional(CONF_MODE, default="mono"): cv.one_of( |                     cv.Optional(CONF_MODE, default="mono"): cv.one_of( | ||||||
|                         *EXTERNAL_DAC_OPTIONS, lower=True |                         *EXTERNAL_DAC_OPTIONS, lower=True | ||||||
|                     ), |                     ), | ||||||
|                 } |                 } | ||||||
|             ) |             ).extend(cv.COMPONENT_SCHEMA), | ||||||
|             .extend(media_player.MEDIA_PLAYER_SCHEMA) |  | ||||||
|             .extend(cv.COMPONENT_SCHEMA), |  | ||||||
|         }, |         }, | ||||||
|         key=CONF_DAC_TYPE, |         key=CONF_DAC_TYPE, | ||||||
|     ), |     ), | ||||||
| @@ -89,19 +84,19 @@ async def to_code(config): | |||||||
|     await cg.register_component(var, config) |     await cg.register_component(var, config) | ||||||
|     await media_player.register_media_player(var, config) |     await media_player.register_media_player(var, config) | ||||||
| 
 | 
 | ||||||
|  |     parent = await cg.get_variable(config[CONF_I2S_AUDIO_ID]) | ||||||
|  |     cg.add(parent.register_audio_out(var)) | ||||||
|  | 
 | ||||||
|     if config[CONF_DAC_TYPE] == "internal": |     if config[CONF_DAC_TYPE] == "internal": | ||||||
|         cg.add(var.set_internal_dac_mode(config[CONF_MODE])) |         cg.add(var.set_internal_dac_mode(config[CONF_MODE])) | ||||||
|     else: |     else: | ||||||
|         cg.add(var.set_dout_pin(config[CONF_I2S_DOUT_PIN])) |         cg.add(var.set_dout_pin(config[CONF_I2S_DOUT_PIN])) | ||||||
|         cg.add(var.set_bclk_pin(config[CONF_I2S_BCLK_PIN])) |  | ||||||
|         cg.add(var.set_lrclk_pin(config[CONF_I2S_LRCLK_PIN])) |  | ||||||
|         if CONF_MUTE_PIN in config: |         if CONF_MUTE_PIN in config: | ||||||
|             pin = await cg.gpio_pin_expression(config[CONF_MUTE_PIN]) |             pin = await cg.gpio_pin_expression(config[CONF_MUTE_PIN]) | ||||||
|             cg.add(var.set_mute_pin(pin)) |             cg.add(var.set_mute_pin(pin)) | ||||||
|         cg.add(var.set_external_dac_channels(2 if config[CONF_MODE] == "stereo" else 1)) |         cg.add(var.set_external_dac_channels(2 if config[CONF_MODE] == "stereo" else 1)) | ||||||
| 
 | 
 | ||||||
|     if CORE.is_esp32: |     cg.add_library("WiFiClientSecure", None) | ||||||
|         cg.add_library("WiFiClientSecure", None) |     cg.add_library("HTTPClient", None) | ||||||
|         cg.add_library("HTTPClient", None) |     cg.add_library("esphome/ESP32-audioI2S", "2.0.6") | ||||||
|         cg.add_library("esphome/ESP32-audioI2S", "2.0.6") |     cg.add_build_flag("-DAUDIO_NO_SD_FS") | ||||||
|         cg.add_build_flag("-DAUDIO_NO_SD_FS") |  | ||||||
| @@ -11,11 +11,19 @@ static const char *const TAG = "audio"; | |||||||
| 
 | 
 | ||||||
| void I2SAudioMediaPlayer::control(const media_player::MediaPlayerCall &call) { | void I2SAudioMediaPlayer::control(const media_player::MediaPlayerCall &call) { | ||||||
|   if (call.get_media_url().has_value()) { |   if (call.get_media_url().has_value()) { | ||||||
|     if (this->audio_->isRunning()) |     this->current_url_ = call.get_media_url(); | ||||||
|       this->audio_->stopSong(); | 
 | ||||||
|     this->high_freq_.start(); |     if (this->state == media_player::MEDIA_PLAYER_STATE_PLAYING && this->audio_ != nullptr) { | ||||||
|     this->audio_->connecttohost(call.get_media_url().value().c_str()); |       if (this->audio_->isRunning()) { | ||||||
|     this->state = media_player::MEDIA_PLAYER_STATE_PLAYING; |         this->audio_->stopSong(); | ||||||
|  |       } | ||||||
|  |       this->audio_->connecttohost(this->current_url_.value().c_str()); | ||||||
|  |     } else { | ||||||
|  |       this->start(); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   if (this->i2s_state_ != I2S_STATE_RUNNING) { | ||||||
|  |     return; | ||||||
|   } |   } | ||||||
|   if (call.get_volume().has_value()) { |   if (call.get_volume().has_value()) { | ||||||
|     this->volume = call.get_volume().value(); |     this->volume = call.get_volume().value(); | ||||||
| @@ -35,7 +43,7 @@ void I2SAudioMediaPlayer::control(const media_player::MediaPlayerCall &call) { | |||||||
|         this->state = media_player::MEDIA_PLAYER_STATE_PAUSED; |         this->state = media_player::MEDIA_PLAYER_STATE_PAUSED; | ||||||
|         break; |         break; | ||||||
|       case media_player::MEDIA_PLAYER_COMMAND_STOP: |       case media_player::MEDIA_PLAYER_COMMAND_STOP: | ||||||
|         this->stop_(); |         this->stop(); | ||||||
|         break; |         break; | ||||||
|       case media_player::MEDIA_PLAYER_COMMAND_MUTE: |       case media_player::MEDIA_PLAYER_COMMAND_MUTE: | ||||||
|         this->mute_(); |         this->mute_(); | ||||||
| @@ -94,22 +102,51 @@ void I2SAudioMediaPlayer::set_volume_(float volume, bool publish) { | |||||||
|     this->volume = volume; |     this->volume = volume; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void I2SAudioMediaPlayer::stop_() { | void I2SAudioMediaPlayer::setup() { | ||||||
|   if (this->audio_->isRunning()) |   ESP_LOGCONFIG(TAG, "Setting up Audio..."); | ||||||
|     this->audio_->stopSong(); |  | ||||||
|   this->high_freq_.stop(); |  | ||||||
|   this->state = media_player::MEDIA_PLAYER_STATE_IDLE; |   this->state = media_player::MEDIA_PLAYER_STATE_IDLE; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void I2SAudioMediaPlayer::setup() { | void I2SAudioMediaPlayer::loop() { | ||||||
|   ESP_LOGCONFIG(TAG, "Setting up Audio..."); |   switch (this->i2s_state_) { | ||||||
|  |     case I2S_STATE_STARTING: | ||||||
|  |       this->start_(); | ||||||
|  |       break; | ||||||
|  |     case I2S_STATE_RUNNING: | ||||||
|  |       this->play_(); | ||||||
|  |       break; | ||||||
|  |     case I2S_STATE_STOPPING: | ||||||
|  |       this->stop_(); | ||||||
|  |       break; | ||||||
|  |     case I2S_STATE_STOPPED: | ||||||
|  |       break; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void I2SAudioMediaPlayer::play_() { | ||||||
|  |   this->audio_->loop(); | ||||||
|  |   if (this->state == media_player::MEDIA_PLAYER_STATE_PLAYING && !this->audio_->isRunning()) { | ||||||
|  |     this->stop(); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void I2SAudioMediaPlayer::start() { this->i2s_state_ = I2S_STATE_STARTING; } | ||||||
|  | void I2SAudioMediaPlayer::start_() { | ||||||
|  |   if (this->parent_->try_lock()) { | ||||||
|  |     return;  // Waiting for another i2s to return lock
 | ||||||
|  |   } | ||||||
|  | 
 | ||||||
| #if SOC_I2S_SUPPORTS_DAC | #if SOC_I2S_SUPPORTS_DAC | ||||||
|   if (this->internal_dac_mode_ != I2S_DAC_CHANNEL_DISABLE) { |   if (this->internal_dac_mode_ != I2S_DAC_CHANNEL_DISABLE) { | ||||||
|     this->audio_ = make_unique<Audio>(true, this->internal_dac_mode_); |     this->audio_ = make_unique<Audio>(true, this->internal_dac_mode_, this->parent_->get_port()); | ||||||
|   } else { |   } else { | ||||||
| #endif | #endif | ||||||
|     this->audio_ = make_unique<Audio>(false); |     this->audio_ = make_unique<Audio>(false, I2S_DAC_CHANNEL_BOTH_EN, this->parent_->get_port()); | ||||||
|     this->audio_->setPinout(this->bclk_pin_, this->lrclk_pin_, this->dout_pin_); | 
 | ||||||
|  |     i2s_pin_config_t pin_config = this->parent_->get_pin_config(); | ||||||
|  |     pin_config.data_out_num = this->dout_pin_; | ||||||
|  |     i2s_set_pin(this->parent_->get_port(), &pin_config); | ||||||
|  | 
 | ||||||
|     this->audio_->forceMono(this->external_dac_channels_ == 1); |     this->audio_->forceMono(this->external_dac_channels_ == 1); | ||||||
|     if (this->mute_pin_ != nullptr) { |     if (this->mute_pin_ != nullptr) { | ||||||
|       this->mute_pin_->setup(); |       this->mute_pin_->setup(); | ||||||
| @@ -118,16 +155,30 @@ void I2SAudioMediaPlayer::setup() { | |||||||
| #if SOC_I2S_SUPPORTS_DAC | #if SOC_I2S_SUPPORTS_DAC | ||||||
|   } |   } | ||||||
| #endif | #endif | ||||||
|   this->state = media_player::MEDIA_PLAYER_STATE_IDLE; |   this->i2s_state_ = I2S_STATE_RUNNING; | ||||||
| } |   this->high_freq_.start(); | ||||||
| 
 |   if (this->current_url_.has_value()) { | ||||||
| void I2SAudioMediaPlayer::loop() { |     this->audio_->connecttohost(this->current_url_.value().c_str()); | ||||||
|   this->audio_->loop(); |     this->state = media_player::MEDIA_PLAYER_STATE_PLAYING; | ||||||
|   if (this->state == media_player::MEDIA_PLAYER_STATE_PLAYING && !this->audio_->isRunning()) { |  | ||||||
|     this->stop_(); |  | ||||||
|     this->publish_state(); |     this->publish_state(); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | void I2SAudioMediaPlayer::stop() { this->i2s_state_ = I2S_STATE_STOPPING; } | ||||||
|  | void I2SAudioMediaPlayer::stop_() { | ||||||
|  |   if (this->audio_->isRunning()) { | ||||||
|  |     this->audio_->stopSong(); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   this->audio_ = nullptr; | ||||||
|  |   this->current_url_ = {}; | ||||||
|  |   this->parent_->unlock(); | ||||||
|  |   this->i2s_state_ = I2S_STATE_STOPPED; | ||||||
|  | 
 | ||||||
|  |   this->high_freq_.stop(); | ||||||
|  |   this->state = media_player::MEDIA_PLAYER_STATE_IDLE; | ||||||
|  |   this->publish_state(); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| media_player::MediaPlayerTraits I2SAudioMediaPlayer::get_traits() { | media_player::MediaPlayerTraits I2SAudioMediaPlayer::get_traits() { | ||||||
|   auto traits = media_player::MediaPlayerTraits(); |   auto traits = media_player::MediaPlayerTraits(); | ||||||
| @@ -2,6 +2,10 @@ | |||||||
| 
 | 
 | ||||||
| #ifdef USE_ESP32_FRAMEWORK_ARDUINO | #ifdef USE_ESP32_FRAMEWORK_ARDUINO | ||||||
| 
 | 
 | ||||||
|  | #include "../i2s_audio.h" | ||||||
|  | 
 | ||||||
|  | #include <driver/i2s.h> | ||||||
|  | 
 | ||||||
| #include "esphome/components/media_player/media_player.h" | #include "esphome/components/media_player/media_player.h" | ||||||
| #include "esphome/core/component.h" | #include "esphome/core/component.h" | ||||||
| #include "esphome/core/gpio.h" | #include "esphome/core/gpio.h" | ||||||
| @@ -12,7 +16,14 @@ | |||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace i2s_audio { | namespace i2s_audio { | ||||||
| 
 | 
 | ||||||
| class I2SAudioMediaPlayer : public Component, public media_player::MediaPlayer { | enum I2SState : uint8_t { | ||||||
|  |   I2S_STATE_STOPPED = 0, | ||||||
|  |   I2S_STATE_STARTING, | ||||||
|  |   I2S_STATE_RUNNING, | ||||||
|  |   I2S_STATE_STOPPING, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | class I2SAudioMediaPlayer : public Component, public media_player::MediaPlayer, public I2SAudioOut { | ||||||
|  public: |  public: | ||||||
|   void setup() override; |   void setup() override; | ||||||
|   float get_setup_priority() const override { return esphome::setup_priority::LATE; } |   float get_setup_priority() const override { return esphome::setup_priority::LATE; } | ||||||
| @@ -22,8 +33,6 @@ class I2SAudioMediaPlayer : public Component, public media_player::MediaPlayer { | |||||||
|   void dump_config() override; |   void dump_config() override; | ||||||
| 
 | 
 | ||||||
|   void set_dout_pin(uint8_t pin) { this->dout_pin_ = pin; } |   void set_dout_pin(uint8_t pin) { this->dout_pin_ = pin; } | ||||||
|   void set_bclk_pin(uint8_t pin) { this->bclk_pin_ = pin; } |  | ||||||
|   void set_lrclk_pin(uint8_t pin) { this->lrclk_pin_ = pin; } |  | ||||||
|   void set_mute_pin(GPIOPin *mute_pin) { this->mute_pin_ = mute_pin; } |   void set_mute_pin(GPIOPin *mute_pin) { this->mute_pin_ = mute_pin; } | ||||||
| #if SOC_I2S_SUPPORTS_DAC | #if SOC_I2S_SUPPORTS_DAC | ||||||
|   void set_internal_dac_mode(i2s_dac_mode_t mode) { this->internal_dac_mode_ = mode; } |   void set_internal_dac_mode(i2s_dac_mode_t mode) { this->internal_dac_mode_ = mode; } | ||||||
| @@ -34,20 +43,24 @@ class I2SAudioMediaPlayer : public Component, public media_player::MediaPlayer { | |||||||
| 
 | 
 | ||||||
|   bool is_muted() const override { return this->muted_; } |   bool is_muted() const override { return this->muted_; } | ||||||
| 
 | 
 | ||||||
|  |   void start(); | ||||||
|  |   void stop(); | ||||||
|  | 
 | ||||||
|  protected: |  protected: | ||||||
|   void control(const media_player::MediaPlayerCall &call) override; |   void control(const media_player::MediaPlayerCall &call) override; | ||||||
| 
 | 
 | ||||||
|   void mute_(); |   void mute_(); | ||||||
|   void unmute_(); |   void unmute_(); | ||||||
|   void set_volume_(float volume, bool publish = true); |   void set_volume_(float volume, bool publish = true); | ||||||
|   void stop_(); |  | ||||||
| 
 | 
 | ||||||
|  |   void start_(); | ||||||
|  |   void stop_(); | ||||||
|  |   void play_(); | ||||||
|  | 
 | ||||||
|  |   I2SState i2s_state_{I2S_STATE_STOPPED}; | ||||||
|   std::unique_ptr<Audio> audio_; |   std::unique_ptr<Audio> audio_; | ||||||
| 
 | 
 | ||||||
|   uint8_t dout_pin_{0}; |   uint8_t dout_pin_{0}; | ||||||
|   uint8_t din_pin_{0}; |  | ||||||
|   uint8_t bclk_pin_; |  | ||||||
|   uint8_t lrclk_pin_; |  | ||||||
| 
 | 
 | ||||||
|   GPIOPin *mute_pin_{nullptr}; |   GPIOPin *mute_pin_{nullptr}; | ||||||
|   bool muted_{false}; |   bool muted_{false}; | ||||||
| @@ -59,6 +72,8 @@ class I2SAudioMediaPlayer : public Component, public media_player::MediaPlayer { | |||||||
|   uint8_t external_dac_channels_; |   uint8_t external_dac_channels_; | ||||||
| 
 | 
 | ||||||
|   HighFrequencyLoopRequester high_freq_; |   HighFrequencyLoopRequester high_freq_; | ||||||
|  | 
 | ||||||
|  |   optional<std::string> current_url_{}; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| }  // namespace i2s_audio
 | }  // namespace i2s_audio
 | ||||||
							
								
								
									
										41
									
								
								esphome/components/i2s_audio/microphone/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								esphome/components/i2s_audio/microphone/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | |||||||
|  | import esphome.config_validation as cv | ||||||
|  | import esphome.codegen as cg | ||||||
|  |  | ||||||
|  | from esphome import pins | ||||||
|  | from esphome.const import CONF_ID | ||||||
|  | from esphome.components import microphone | ||||||
|  |  | ||||||
|  | from .. import ( | ||||||
|  |     i2s_audio_ns, | ||||||
|  |     I2SAudioComponent, | ||||||
|  |     I2SAudioIn, | ||||||
|  |     CONF_I2S_AUDIO_ID, | ||||||
|  |     CONF_I2S_DIN_PIN, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | CODEOWNERS = ["@jesserockz"] | ||||||
|  | DEPENDENCIES = ["i2s_audio"] | ||||||
|  |  | ||||||
|  | I2SAudioMicrophone = i2s_audio_ns.class_( | ||||||
|  |     "I2SAudioMicrophone", I2SAudioIn, microphone.Microphone, cg.Component | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = microphone.MICROPHONE_SCHEMA.extend( | ||||||
|  |     { | ||||||
|  |         cv.GenerateID(): cv.declare_id(I2SAudioMicrophone), | ||||||
|  |         cv.GenerateID(CONF_I2S_AUDIO_ID): cv.use_id(I2SAudioComponent), | ||||||
|  |         cv.Required(CONF_I2S_DIN_PIN): pins.internal_gpio_input_pin_number, | ||||||
|  |     } | ||||||
|  | ).extend(cv.COMPONENT_SCHEMA) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def to_code(config): | ||||||
|  |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|  |     await cg.register_component(var, config) | ||||||
|  |  | ||||||
|  |     parent = await cg.get_variable(config[CONF_I2S_AUDIO_ID]) | ||||||
|  |     cg.add(parent.register_audio_in(var)) | ||||||
|  |  | ||||||
|  |     cg.add(var.set_din_pin(config[CONF_I2S_DIN_PIN])) | ||||||
|  |  | ||||||
|  |     await microphone.register_microphone(var, config) | ||||||
							
								
								
									
										101
									
								
								esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,101 @@ | |||||||
|  | #include "i2s_audio_microphone.h" | ||||||
|  |  | ||||||
|  | #ifdef USE_ESP32 | ||||||
|  |  | ||||||
|  | #include <driver/i2s.h> | ||||||
|  |  | ||||||
|  | #include "esphome/core/hal.h" | ||||||
|  | #include "esphome/core/log.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace i2s_audio { | ||||||
|  |  | ||||||
|  | static const size_t BUFFER_SIZE = 512; | ||||||
|  |  | ||||||
|  | static const char *const TAG = "i2s_audio.microphone"; | ||||||
|  |  | ||||||
|  | void I2SAudioMicrophone::setup() { | ||||||
|  |   ESP_LOGCONFIG(TAG, "Setting up I2S Audio Microphone..."); | ||||||
|  |   this->buffer_.resize(BUFFER_SIZE); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void I2SAudioMicrophone::start() { this->state_ = microphone::STATE_STARTING; } | ||||||
|  | void I2SAudioMicrophone::start_() { | ||||||
|  |   if (!this->parent_->try_lock()) { | ||||||
|  |     return;  // Waiting for another i2s to return lock | ||||||
|  |   } | ||||||
|  |   i2s_driver_config_t config = { | ||||||
|  |       .mode = (i2s_mode_t) (I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM), | ||||||
|  |       .sample_rate = 16000, | ||||||
|  |       .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, | ||||||
|  |       .channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT, | ||||||
|  |       .communication_format = I2S_COMM_FORMAT_STAND_I2S, | ||||||
|  |       .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, | ||||||
|  |       .dma_buf_count = 4, | ||||||
|  |       .dma_buf_len = 256, | ||||||
|  |       .use_apll = false, | ||||||
|  |       .tx_desc_auto_clear = false, | ||||||
|  |       .fixed_mclk = 0, | ||||||
|  |       .mclk_multiple = I2S_MCLK_MULTIPLE_DEFAULT, | ||||||
|  |       .bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT, | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   i2s_driver_install(this->parent_->get_port(), &config, 0, nullptr); | ||||||
|  |  | ||||||
|  |   i2s_pin_config_t pin_config = this->parent_->get_pin_config(); | ||||||
|  |   pin_config.data_in_num = this->din_pin_; | ||||||
|  |  | ||||||
|  |   i2s_set_pin(this->parent_->get_port(), &pin_config); | ||||||
|  |   this->state_ = microphone::STATE_RUNNING; | ||||||
|  |   this->high_freq_.start(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void I2SAudioMicrophone::stop() { | ||||||
|  |   if (this->state_ == microphone::STATE_STOPPED) | ||||||
|  |     return; | ||||||
|  |   this->state_ = microphone::STATE_STOPPING; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void I2SAudioMicrophone::stop_() { | ||||||
|  |   i2s_stop(this->parent_->get_port()); | ||||||
|  |   i2s_driver_uninstall(this->parent_->get_port()); | ||||||
|  |   this->parent_->unlock(); | ||||||
|  |   this->state_ = microphone::STATE_STOPPED; | ||||||
|  |   this->high_freq_.stop(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void I2SAudioMicrophone::read_() { | ||||||
|  |   size_t bytes_read = 0; | ||||||
|  |   esp_err_t err = | ||||||
|  |       i2s_read(this->parent_->get_port(), this->buffer_.data(), BUFFER_SIZE, &bytes_read, (100 / portTICK_PERIOD_MS)); | ||||||
|  |   if (err != ESP_OK) { | ||||||
|  |     ESP_LOGW(TAG, "Error reading from I2S microphone: %s", esp_err_to_name(err)); | ||||||
|  |     this->status_set_warning(); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   this->status_clear_warning(); | ||||||
|  |  | ||||||
|  |   this->data_callbacks_.call(this->buffer_); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void I2SAudioMicrophone::loop() { | ||||||
|  |   switch (this->state_) { | ||||||
|  |     case microphone::STATE_STOPPED: | ||||||
|  |       break; | ||||||
|  |     case microphone::STATE_STARTING: | ||||||
|  |       this->start_(); | ||||||
|  |       break; | ||||||
|  |     case microphone::STATE_RUNNING: | ||||||
|  |       this->read_(); | ||||||
|  |       break; | ||||||
|  |     case microphone::STATE_STOPPING: | ||||||
|  |       this->stop_(); | ||||||
|  |       break; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace i2s_audio | ||||||
|  | }  // namespace esphome | ||||||
|  |  | ||||||
|  | #endif  // USE_ESP32 | ||||||
| @@ -0,0 +1,37 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #ifdef USE_ESP32 | ||||||
|  |  | ||||||
|  | #include "../i2s_audio.h" | ||||||
|  |  | ||||||
|  | #include "esphome/components/microphone/microphone.h" | ||||||
|  | #include "esphome/core/component.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace i2s_audio { | ||||||
|  |  | ||||||
|  | class I2SAudioMicrophone : public I2SAudioIn, public microphone::Microphone, public Component { | ||||||
|  |  public: | ||||||
|  |   void setup() override; | ||||||
|  |   void start() override; | ||||||
|  |   void stop() override; | ||||||
|  |  | ||||||
|  |   void loop() override; | ||||||
|  |  | ||||||
|  |   void set_din_pin(uint8_t pin) { this->din_pin_ = pin; } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   void start_(); | ||||||
|  |   void stop_(); | ||||||
|  |   void read_(); | ||||||
|  |  | ||||||
|  |   uint8_t din_pin_{0}; | ||||||
|  |   std::vector<uint8_t> buffer_; | ||||||
|  |  | ||||||
|  |   HighFrequencyLoopRequester high_freq_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace i2s_audio | ||||||
|  | }  // namespace esphome | ||||||
|  |  | ||||||
|  | #endif  // USE_ESP32 | ||||||
| @@ -1,8 +1,8 @@ | |||||||
| #include "ili9xxx_display.h" | #include "ili9xxx_display.h" | ||||||
| #include "esphome/core/log.h" |  | ||||||
| #include "esphome/core/application.h" | #include "esphome/core/application.h" | ||||||
| #include "esphome/core/helpers.h" |  | ||||||
| #include "esphome/core/hal.h" | #include "esphome/core/hal.h" | ||||||
|  | #include "esphome/core/helpers.h" | ||||||
|  | #include "esphome/core/log.h" | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace ili9xxx { | namespace ili9xxx { | ||||||
| @@ -85,7 +85,7 @@ void ILI9XXXDisplay::fill(Color color) { | |||||||
|     case BITS_16: |     case BITS_16: | ||||||
|       new_color = display::ColorUtil::color_to_565(color); |       new_color = display::ColorUtil::color_to_565(color); | ||||||
|       for (uint32_t i = 0; i < this->get_buffer_length_() * 2; i = i + 2) { |       for (uint32_t i = 0; i < this->get_buffer_length_() * 2; i = i + 2) { | ||||||
|         this->buffer_[i] = (uint8_t)(new_color >> 8); |         this->buffer_[i] = (uint8_t) (new_color >> 8); | ||||||
|         this->buffer_[i + 1] = (uint8_t) new_color; |         this->buffer_[i + 1] = (uint8_t) new_color; | ||||||
|       } |       } | ||||||
|       return; |       return; | ||||||
| @@ -111,8 +111,8 @@ void HOT ILI9XXXDisplay::draw_absolute_pixel_internal(int x, int y, Color color) | |||||||
|     case BITS_16: |     case BITS_16: | ||||||
|       pos = pos * 2; |       pos = pos * 2; | ||||||
|       new_color = display::ColorUtil::color_to_565(color, display::ColorOrder::COLOR_ORDER_RGB); |       new_color = display::ColorUtil::color_to_565(color, display::ColorOrder::COLOR_ORDER_RGB); | ||||||
|       if (this->buffer_[pos] != (uint8_t)(new_color >> 8)) { |       if (this->buffer_[pos] != (uint8_t) (new_color >> 8)) { | ||||||
|         this->buffer_[pos] = (uint8_t)(new_color >> 8); |         this->buffer_[pos] = (uint8_t) (new_color >> 8); | ||||||
|         updated = true; |         updated = true; | ||||||
|       } |       } | ||||||
|       pos = pos + 1; |       pos = pos + 1; | ||||||
| @@ -192,9 +192,9 @@ void ILI9XXXDisplay::display_() { | |||||||
|  |  | ||||||
|           uint8_t pass_buff[3]; |           uint8_t pass_buff[3]; | ||||||
|  |  | ||||||
|           pass_buff[2] = (uint8_t)((red / 32.0) * 64) << 2; |           pass_buff[2] = (uint8_t) ((red / 32.0) * 64) << 2; | ||||||
|           pass_buff[1] = (uint8_t) green << 2; |           pass_buff[1] = (uint8_t) green << 2; | ||||||
|           pass_buff[0] = (uint8_t)((blue / 32.0) * 64) << 2; |           pass_buff[0] = (uint8_t) ((blue / 32.0) * 64) << 2; | ||||||
|  |  | ||||||
|           this->write_array(pass_buff, sizeof(pass_buff)); |           this->write_array(pass_buff, sizeof(pass_buff)); | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -21,7 +21,7 @@ std::string ImprovBase::get_formatted_next_url_() { | |||||||
|   // Ip address |   // Ip address | ||||||
|   pos = this->next_url_.find("{{ip_address}}"); |   pos = this->next_url_.find("{{ip_address}}"); | ||||||
|   if (pos != std::string::npos) { |   if (pos != std::string::npos) { | ||||||
|     std::string ip = network::IPAddress(network::get_ip_address()).str(); |     std::string ip = network::get_ip_address().str(); | ||||||
|     copy.replace(pos, 14, ip); |     copy.replace(pos, 14, ip); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -73,7 +73,7 @@ void parse_json(const std::string &data, const json_parse_t &f) { | |||||||
|   const size_t free_heap = rp2040.getFreeHeap(); |   const size_t free_heap = rp2040.getFreeHeap(); | ||||||
| #endif | #endif | ||||||
|   bool pass = false; |   bool pass = false; | ||||||
|   size_t request_size = std::min(free_heap, (size_t)(data.size() * 1.5)); |   size_t request_size = std::min(free_heap, (size_t) (data.size() * 1.5)); | ||||||
|   do { |   do { | ||||||
|     DynamicJsonDocument json_document(request_size); |     DynamicJsonDocument json_document(request_size); | ||||||
|     if (json_document.capacity() == 0) { |     if (json_document.capacity() == 0) { | ||||||
|   | |||||||
| @@ -17,7 +17,7 @@ void GPIOLCDDisplay::setup() { | |||||||
|   this->enable_pin_->setup();  // OUTPUT |   this->enable_pin_->setup();  // OUTPUT | ||||||
|   this->enable_pin_->digital_write(false); |   this->enable_pin_->digital_write(false); | ||||||
|  |  | ||||||
|   for (uint8_t i = 0; i < (uint8_t)(this->is_four_bit_mode() ? 4u : 8u); i++) { |   for (uint8_t i = 0; i < (uint8_t) (this->is_four_bit_mode() ? 4u : 8u); i++) { | ||||||
|     this->data_pins_[i]->setup();  // OUTPUT |     this->data_pins_[i]->setup();  // OUTPUT | ||||||
|     this->data_pins_[i]->digital_write(false); |     this->data_pins_[i]->digital_write(false); | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -118,7 +118,7 @@ class LD2410Component : public Component, public uart::UARTDevice { | |||||||
| #endif | #endif | ||||||
|  |  | ||||||
|   std::vector<uint8_t> rx_buffer_; |   std::vector<uint8_t> rx_buffer_; | ||||||
|   int two_byte_to_int_(char firstbyte, char secondbyte) { return (int16_t)(secondbyte << 8) + firstbyte; } |   int two_byte_to_int_(char firstbyte, char secondbyte) { return (int16_t) (secondbyte << 8) + firstbyte; } | ||||||
|   void send_command_(uint8_t command_str, uint8_t *command_value, int command_value_len); |   void send_command_(uint8_t command_str, uint8_t *command_value, int command_value_len); | ||||||
|  |  | ||||||
|   void set_max_distances_timeout_(uint8_t max_moving_distance_range, uint8_t max_still_distance_range, |   void set_max_distances_timeout_(uint8_t max_moving_distance_range, uint8_t max_still_distance_range, | ||||||
|   | |||||||
| @@ -60,7 +60,7 @@ LIGHT_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).ex | |||||||
|     { |     { | ||||||
|         cv.GenerateID(): cv.declare_id(LightState), |         cv.GenerateID(): cv.declare_id(LightState), | ||||||
|         cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTJSONLightComponent), |         cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTJSONLightComponent), | ||||||
|         cv.Optional(CONF_RESTORE_MODE, default="restore_default_off"): cv.enum( |         cv.Optional(CONF_RESTORE_MODE, default="ALWAYS_OFF"): cv.enum( | ||||||
|             RESTORE_MODES, upper=True, space="_" |             RESTORE_MODES, upper=True, space="_" | ||||||
|         ), |         ), | ||||||
|         cv.Optional(CONF_ON_TURN_ON): auto.validate_automation( |         cv.Optional(CONF_ON_TURN_ON): auto.validate_automation( | ||||||
|   | |||||||
| @@ -52,25 +52,26 @@ enum class ColorMode : uint8_t { | |||||||
|   /// Only on/off control. |   /// Only on/off control. | ||||||
|   ON_OFF = (uint8_t) ColorCapability::ON_OFF, |   ON_OFF = (uint8_t) ColorCapability::ON_OFF, | ||||||
|   /// Dimmable light. |   /// Dimmable light. | ||||||
|   BRIGHTNESS = (uint8_t)(ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS), |   BRIGHTNESS = (uint8_t) (ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS), | ||||||
|   /// White output only (use only if the light also has another color mode such as RGB). |   /// White output only (use only if the light also has another color mode such as RGB). | ||||||
|   WHITE = (uint8_t)(ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::WHITE), |   WHITE = (uint8_t) (ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::WHITE), | ||||||
|   /// Controllable color temperature output. |   /// Controllable color temperature output. | ||||||
|   COLOR_TEMPERATURE = |   COLOR_TEMPERATURE = | ||||||
|       (uint8_t)(ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::COLOR_TEMPERATURE), |       (uint8_t) (ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::COLOR_TEMPERATURE), | ||||||
|   /// Cold and warm white output with individually controllable brightness. |   /// Cold and warm white output with individually controllable brightness. | ||||||
|   COLD_WARM_WHITE = (uint8_t)(ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::COLD_WARM_WHITE), |   COLD_WARM_WHITE = | ||||||
|  |       (uint8_t) (ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::COLD_WARM_WHITE), | ||||||
|   /// RGB color output. |   /// RGB color output. | ||||||
|   RGB = (uint8_t)(ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::RGB), |   RGB = (uint8_t) (ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::RGB), | ||||||
|   /// RGB color output and a separate white output. |   /// RGB color output and a separate white output. | ||||||
|   RGB_WHITE = |   RGB_WHITE = | ||||||
|       (uint8_t)(ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::RGB | ColorCapability::WHITE), |       (uint8_t) (ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::RGB | ColorCapability::WHITE), | ||||||
|   /// RGB color output and a separate white output with controllable color temperature. |   /// RGB color output and a separate white output with controllable color temperature. | ||||||
|   RGB_COLOR_TEMPERATURE = (uint8_t)(ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::RGB | |   RGB_COLOR_TEMPERATURE = (uint8_t) (ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::RGB | | ||||||
|                                     ColorCapability::WHITE | ColorCapability::COLOR_TEMPERATURE), |                                      ColorCapability::WHITE | ColorCapability::COLOR_TEMPERATURE), | ||||||
|   /// RGB color output, and separate cold and warm white outputs. |   /// RGB color output, and separate cold and warm white outputs. | ||||||
|   RGB_COLD_WARM_WHITE = (uint8_t)(ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::RGB | |   RGB_COLD_WARM_WHITE = (uint8_t) (ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::RGB | | ||||||
|                                   ColorCapability::COLD_WARM_WHITE), |                                    ColorCapability::COLD_WARM_WHITE), | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /// Helper class to allow bitwise operations on ColorMode with ColorCapability | /// Helper class to allow bitwise operations on ColorMode with ColorCapability | ||||||
|   | |||||||
| @@ -8,7 +8,6 @@ namespace light { | |||||||
|  |  | ||||||
| static const char *const TAG = "light"; | static const char *const TAG = "light"; | ||||||
|  |  | ||||||
| LightState::LightState(const std::string &name, LightOutput *output) : EntityBase(name), output_(output) {} |  | ||||||
| LightState::LightState(LightOutput *output) : output_(output) {} | LightState::LightState(LightOutput *output) : output_(output) {} | ||||||
|  |  | ||||||
| LightTraits LightState::get_traits() { return this->output_->get_traits(); } | LightTraits LightState::get_traits() { return this->output_->get_traits(); } | ||||||
|   | |||||||
| @@ -33,9 +33,6 @@ enum LightRestoreMode { | |||||||
|  */ |  */ | ||||||
| class LightState : public EntityBase, public Component { | class LightState : public EntityBase, public Component { | ||||||
|  public: |  public: | ||||||
|   /// Construct this LightState using the provided traits and name. |  | ||||||
|   LightState(const std::string &name, LightOutput *output); |  | ||||||
|  |  | ||||||
|   LightState(LightOutput *output); |   LightState(LightOutput *output); | ||||||
|  |  | ||||||
|   LightTraits get_traits(); |   LightTraits get_traits(); | ||||||
|   | |||||||
| @@ -113,8 +113,8 @@ void LilygoT547Touchscreen::loop() { | |||||||
|       if (tp.state == 0x06) |       if (tp.state == 0x06) | ||||||
|         tp.state = 0x07; |         tp.state = 0x07; | ||||||
|  |  | ||||||
|       uint16_t y = (uint16_t)((buffer[i * 5 + 1 + offset] << 4) | ((buffer[i * 5 + 3 + offset] >> 4) & 0x0F)); |       uint16_t y = (uint16_t) ((buffer[i * 5 + 1 + offset] << 4) | ((buffer[i * 5 + 3 + offset] >> 4) & 0x0F)); | ||||||
|       uint16_t x = (uint16_t)((buffer[i * 5 + 2 + offset] << 4) | (buffer[i * 5 + 3 + offset] & 0x0F)); |       uint16_t x = (uint16_t) ((buffer[i * 5 + 2 + offset] << 4) | (buffer[i * 5 + 3 + offset] & 0x0F)); | ||||||
|  |  | ||||||
|       switch (this->rotation_) { |       switch (this->rotation_) { | ||||||
|         case ROTATE_0_DEGREES: |         case ROTATE_0_DEGREES: | ||||||
| @@ -142,8 +142,8 @@ void LilygoT547Touchscreen::loop() { | |||||||
|     tp.id = (buffer[0] >> 4) & 0x0F; |     tp.id = (buffer[0] >> 4) & 0x0F; | ||||||
|     tp.state = 0x06; |     tp.state = 0x06; | ||||||
|  |  | ||||||
|     uint16_t y = (uint16_t)((buffer[0 * 5 + 1] << 4) | ((buffer[0 * 5 + 3] >> 4) & 0x0F)); |     uint16_t y = (uint16_t) ((buffer[0 * 5 + 1] << 4) | ((buffer[0 * 5 + 3] >> 4) & 0x0F)); | ||||||
|     uint16_t x = (uint16_t)((buffer[0 * 5 + 2] << 4) | (buffer[0 * 5 + 3] & 0x0F)); |     uint16_t x = (uint16_t) ((buffer[0 * 5 + 2] << 4) | (buffer[0 * 5 + 3] & 0x0F)); | ||||||
|  |  | ||||||
|     switch (this->rotation_) { |     switch (this->rotation_) { | ||||||
|       case ROTATE_0_DEGREES: |       case ROTATE_0_DEGREES: | ||||||
|   | |||||||
| @@ -24,8 +24,7 @@ const char *lock_state_to_string(LockState state) { | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| Lock::Lock(const std::string &name) : EntityBase(name), state(LOCK_STATE_NONE) {} | Lock::Lock() : state(LOCK_STATE_NONE) {} | ||||||
| Lock::Lock() : Lock("") {} |  | ||||||
| LockCall Lock::make_call() { return LockCall(this); } | LockCall Lock::make_call() { return LockCall(this); } | ||||||
|  |  | ||||||
| void Lock::lock() { | void Lock::lock() { | ||||||
|   | |||||||
| @@ -103,7 +103,6 @@ class LockCall { | |||||||
| class Lock : public EntityBase { | class Lock : public EntityBase { | ||||||
|  public: |  public: | ||||||
|   explicit Lock(); |   explicit Lock(); | ||||||
|   explicit Lock(const std::string &name); |  | ||||||
|  |  | ||||||
|   /** Make a lock device control call, this is used to control the lock device, see the LockCall description |   /** Make a lock device control call, this is used to control the lock device, see the LockCall description | ||||||
|    * for more info. |    * for more info. | ||||||
|   | |||||||
| @@ -1,4 +1,5 @@ | |||||||
| #include "logger.h" | #include "logger.h" | ||||||
|  | #include <cinttypes> | ||||||
|  |  | ||||||
| #ifdef USE_ESP_IDF | #ifdef USE_ESP_IDF | ||||||
| #include <driver/uart.h> | #include <driver/uart.h> | ||||||
| @@ -292,7 +293,7 @@ const char *const UART_SELECTIONS[] = {"UART0", "UART1", "USB_CDC"}; | |||||||
| void Logger::dump_config() { | void Logger::dump_config() { | ||||||
|   ESP_LOGCONFIG(TAG, "Logger:"); |   ESP_LOGCONFIG(TAG, "Logger:"); | ||||||
|   ESP_LOGCONFIG(TAG, "  Level: %s", LOG_LEVELS[ESPHOME_LOG_LEVEL]); |   ESP_LOGCONFIG(TAG, "  Level: %s", LOG_LEVELS[ESPHOME_LOG_LEVEL]); | ||||||
|   ESP_LOGCONFIG(TAG, "  Log Baud Rate: %u", this->baud_rate_); |   ESP_LOGCONFIG(TAG, "  Log Baud Rate: %" PRIu32, this->baud_rate_); | ||||||
|   ESP_LOGCONFIG(TAG, "  Hardware UART: %s", UART_SELECTIONS[this->uart_]); |   ESP_LOGCONFIG(TAG, "  Hardware UART: %s", UART_SELECTIONS[this->uart_]); | ||||||
|   for (auto &it : this->log_levels_) { |   for (auto &it : this->log_levels_) { | ||||||
|     ESP_LOGCONFIG(TAG, "  Level for '%s': %s", it.tag.c_str(), LOG_LEVELS[it.level]); |     ESP_LOGCONFIG(TAG, "  Level for '%s': %s", it.tag.c_str(), LOG_LEVELS[it.level]); | ||||||
|   | |||||||
| @@ -7,6 +7,7 @@ CODEOWNERS = ["@rspaargaren"] | |||||||
| DEPENDENCIES = ["spi"] | DEPENDENCIES = ["spi"] | ||||||
|  |  | ||||||
| CONF_ROTATE_CHIP = "rotate_chip" | CONF_ROTATE_CHIP = "rotate_chip" | ||||||
|  | CONF_FLIP_X = "flip_x" | ||||||
| CONF_SCROLL_SPEED = "scroll_speed" | CONF_SCROLL_SPEED = "scroll_speed" | ||||||
| CONF_SCROLL_DWELL = "scroll_dwell" | CONF_SCROLL_DWELL = "scroll_dwell" | ||||||
| CONF_SCROLL_DELAY = "scroll_delay" | CONF_SCROLL_DELAY = "scroll_delay" | ||||||
| @@ -67,6 +68,7 @@ CONFIG_SCHEMA = ( | |||||||
|                 CONF_SCROLL_DWELL, default="1000ms" |                 CONF_SCROLL_DWELL, default="1000ms" | ||||||
|             ): cv.positive_time_period_milliseconds, |             ): cv.positive_time_period_milliseconds, | ||||||
|             cv.Optional(CONF_REVERSE_ENABLE, default=False): cv.boolean, |             cv.Optional(CONF_REVERSE_ENABLE, default=False): cv.boolean, | ||||||
|  |             cv.Optional(CONF_FLIP_X, default=False): cv.boolean, | ||||||
|         } |         } | ||||||
|     ) |     ) | ||||||
|     .extend(cv.polling_component_schema("500ms")) |     .extend(cv.polling_component_schema("500ms")) | ||||||
| @@ -91,6 +93,7 @@ async def to_code(config): | |||||||
|     cg.add(var.set_scroll(config[CONF_SCROLL_ENABLE])) |     cg.add(var.set_scroll(config[CONF_SCROLL_ENABLE])) | ||||||
|     cg.add(var.set_scroll_mode(config[CONF_SCROLL_MODE])) |     cg.add(var.set_scroll_mode(config[CONF_SCROLL_MODE])) | ||||||
|     cg.add(var.set_reverse(config[CONF_REVERSE_ENABLE])) |     cg.add(var.set_reverse(config[CONF_REVERSE_ENABLE])) | ||||||
|  |     cg.add(var.set_flip_x([CONF_FLIP_X])) | ||||||
|  |  | ||||||
|     if CONF_LAMBDA in config: |     if CONF_LAMBDA in config: | ||||||
|         lambda_ = await cg.process_lambda( |         lambda_ = await cg.process_lambda( | ||||||
|   | |||||||
| @@ -261,13 +261,21 @@ void MAX7219Component::send64pixels(uint8_t chip, const uint8_t pixels[8]) { | |||||||
|     if (this->orientation_ == 0) { |     if (this->orientation_ == 0) { | ||||||
|       for (uint8_t i = 0; i < 8; i++) { |       for (uint8_t i = 0; i < 8; i++) { | ||||||
|         // run this loop 8 times for all the pixels[8] received |         // run this loop 8 times for all the pixels[8] received | ||||||
|         b |= ((pixels[i] >> col) & 1) << (7 - i);  // change the column bits into row bits |         if (this->flip_x_) { | ||||||
|  |           b |= ((pixels[i] >> col) & 1) << i;  // change the column bits into row bits | ||||||
|  |         } else { | ||||||
|  |           b |= ((pixels[i] >> col) & 1) << (7 - i);  // change the column bits into row bits | ||||||
|  |         } | ||||||
|       } |       } | ||||||
|     } else if (this->orientation_ == 1) { |     } else if (this->orientation_ == 1) { | ||||||
|       b = pixels[col]; |       b = pixels[col]; | ||||||
|     } else if (this->orientation_ == 2) { |     } else if (this->orientation_ == 2) { | ||||||
|       for (uint8_t i = 0; i < 8; i++) { |       for (uint8_t i = 0; i < 8; i++) { | ||||||
|         b |= ((pixels[i] >> (7 - col)) & 1) << i; |         if (this->flip_x_) { | ||||||
|  |           b |= ((pixels[i] >> (7 - col)) & 1) << (7 - i); | ||||||
|  |         } else { | ||||||
|  |           b |= ((pixels[i] >> (7 - col)) & 1) << i; | ||||||
|  |         } | ||||||
|       } |       } | ||||||
|     } else { |     } else { | ||||||
|       b = pixels[7 - col]; |       b = pixels[7 - col]; | ||||||
|   | |||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user