Merge branch 'beta' into bump-2023.4.0

This commit is contained in:
Jesse Hills 2023-04-20 14:06:52 +12:00
commit f668d5617f
No known key found for this signature in database
GPG key ID: BEAAE804EFD8E83A
230 changed files with 4277 additions and 1404 deletions

View file

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

View file

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

View file

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

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

View file

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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,20 @@ void APIServer::on_shutdown() {
delay(10); delay(10);
} }
#ifdef USE_VOICE_ASSISTANT
bool APIServer::start_voice_assistant() {
bool result = false;
for (auto &c : this->clients_) {
result |= c->request_voice_assistant(true);
}
return result;
}
void APIServer::stop_voice_assistant() {
for (auto &c : this->clients_) {
c->request_voice_assistant(false);
}
}
#endif
} // namespace api } // namespace api
} // namespace esphome } // namespace esphome

View file

@ -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
bool start_voice_assistant();
void stop_voice_assistant();
#endif
bool is_connected() const; bool is_connected() const;
struct HomeAssistantStateSubscription { struct HomeAssistantStateSubscription {

View file

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

View file

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

View file

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

View file

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

View file

@ -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() {

View file

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

View file

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

View file

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

View file

@ -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)
), ),
} }
), ),

View file

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

View file

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

View file

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

View file

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

View file

@ -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();

View file

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

View file

@ -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");

View file

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

View file

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

View file

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

View file

@ -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();

View file

@ -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_{};

View file

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

View file

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

View file

@ -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();

View file

@ -1,15 +1,11 @@
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
import esphome.final_validate as fv
from esphome.components import logger
from esphome.const import ( from esphome.const import (
CONF_BLOCK, CONF_BLOCK,
CONF_DEVICE, CONF_DEVICE,
CONF_FRAGMENTATION, CONF_FRAGMENTATION,
CONF_FREE, CONF_FREE,
CONF_ID, CONF_ID,
CONF_LEVEL,
CONF_LOGGER,
CONF_LOOP_TIME, CONF_LOOP_TIME,
) )
@ -43,18 +39,6 @@ CONFIG_SCHEMA = cv.Schema(
).extend(cv.polling_component_schema("60s")) ).extend(cv.polling_component_schema("60s"))
def _final_validate(_):
logger_conf = fv.full_config.get()[CONF_LOGGER]
severity = logger.LOG_LEVEL_SEVERITY.index(logger_conf[CONF_LEVEL])
if severity < logger.LOG_LEVEL_SEVERITY.index("DEBUG"):
raise cv.Invalid(
"The debug component requires the logger to be at least at DEBUG level"
)
FINAL_VALIDATE_SCHEMA = _final_validate
async def to_code(config): async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID]) var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config) await cg.register_component(var, config)

View file

@ -37,6 +37,10 @@ static uint32_t get_free_heap() {
} }
void DebugComponent::dump_config() { void DebugComponent::dump_config() {
#ifndef ESPHOME_LOG_HAS_DEBUG
return; // Can't log below if debug logging is disabled
#endif
std::string device_info; std::string device_info;
std::string reset_reason; std::string reset_reason;
device_info.reserve(256); device_info.reserve(256);

View file

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

View file

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

View file

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

View file

@ -163,7 +163,7 @@ RECOMMENDED_ARDUINO_FRAMEWORK_VERSION = cv.Version(2, 0, 5)
# The platformio/espressif32 version to use for arduino frameworks # The platformio/espressif32 version to use for arduino frameworks
# - https://github.com/platformio/platform-espressif32/releases # - https://github.com/platformio/platform-espressif32/releases
# - https://api.registry.platformio.org/v3/packages/platformio/platform/espressif32 # - https://api.registry.platformio.org/v3/packages/platformio/platform/espressif32
ARDUINO_PLATFORM_VERSION = cv.Version(5, 2, 0) ARDUINO_PLATFORM_VERSION = cv.Version(5, 3, 0)
# The default/recommended esp-idf framework version # The default/recommended esp-idf framework version
# - https://github.com/espressif/esp-idf/releases # - https://github.com/espressif/esp-idf/releases

View file

@ -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); }

View file

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

View file

@ -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);
} }

View file

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

View file

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

View file

@ -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_; }

View file

@ -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);
} }
} }

View file

@ -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)
), ),
} }
), ),

View file

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

View file

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

View file

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

View file

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

View file

@ -26,8 +26,10 @@ EthernetComponent::EthernetComponent() { global_eth_component = this; }
void EthernetComponent::setup() { void EthernetComponent::setup() {
ESP_LOGCONFIG(TAG, "Setting up Ethernet..."); ESP_LOGCONFIG(TAG, "Setting up Ethernet...");
// Delay here to allow power to stabilise before Ethernet is initialised. if (esp_reset_reason() != ESP_RST_DEEPSLEEP) {
delay(300); // NOLINT // Delay here to allow power to stabilise before Ethernet is initialized.
delay(300); // NOLINT
}
esp_err_t err; esp_err_t err;
err = esp_netif_init(); err = esp_netif_init();
@ -52,26 +54,29 @@ void EthernetComponent::setup() {
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config); esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config);
esp_eth_phy_t *phy;
switch (this->type_) { switch (this->type_) {
case ETHERNET_TYPE_LAN8720: { case ETHERNET_TYPE_LAN8720: {
phy = esp_eth_phy_new_lan87xx(&phy_config); this->phy_ = esp_eth_phy_new_lan87xx(&phy_config);
break; break;
} }
case ETHERNET_TYPE_RTL8201: { case ETHERNET_TYPE_RTL8201: {
phy = esp_eth_phy_new_rtl8201(&phy_config); this->phy_ = esp_eth_phy_new_rtl8201(&phy_config);
break; break;
} }
case ETHERNET_TYPE_DP83848: { case ETHERNET_TYPE_DP83848: {
phy = esp_eth_phy_new_dp83848(&phy_config); this->phy_ = esp_eth_phy_new_dp83848(&phy_config);
break; break;
} }
case ETHERNET_TYPE_IP101: { case ETHERNET_TYPE_IP101: {
phy = esp_eth_phy_new_ip101(&phy_config); this->phy_ = esp_eth_phy_new_ip101(&phy_config);
break; break;
} }
case ETHERNET_TYPE_JL1101: { case ETHERNET_TYPE_JL1101: {
phy = esp_eth_phy_new_jl1101(&phy_config); this->phy_ = esp_eth_phy_new_jl1101(&phy_config);
break;
}
case ETHERNET_TYPE_KSZ8081: {
this->phy_ = esp_eth_phy_new_ksz8081(&phy_config);
break; break;
} }
default: { default: {
@ -80,7 +85,7 @@ void EthernetComponent::setup() {
} }
} }
esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy); esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, this->phy_);
this->eth_handle_ = nullptr; this->eth_handle_ = nullptr;
err = esp_eth_driver_install(&eth_config, &this->eth_handle_); err = esp_eth_driver_install(&eth_config, &this->eth_handle_);
ESPHL_ERROR_CHECK(err, "ETH driver install error"); ESPHL_ERROR_CHECK(err, "ETH driver install error");
@ -140,7 +145,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 +163,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 +183,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 +269,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_->dns2) != 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 +311,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;
@ -330,6 +357,21 @@ std::string EthernetComponent::get_use_address() const {
void EthernetComponent::set_use_address(const std::string &use_address) { this->use_address_ = use_address; } void EthernetComponent::set_use_address(const std::string &use_address) { this->use_address_ = use_address; }
bool EthernetComponent::powerdown() {
ESP_LOGI(TAG, "Powering down ethernet PHY");
if (this->phy_ == nullptr) {
ESP_LOGE(TAG, "Ethernet PHY not assigned");
return false;
}
this->connected_ = false;
this->started_ = false;
if (this->phy_->pwrctl(this->phy_, false) != ESP_OK) {
ESP_LOGE(TAG, "Error powering down ethernet PHY");
return false;
}
return true;
}
} // namespace ethernet } // namespace ethernet
} // namespace esphome } // namespace esphome

View file

@ -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 {
@ -43,6 +45,7 @@ class EthernetComponent : public Component {
void dump_config() override; void dump_config() override;
float get_setup_priority() const override; float get_setup_priority() const override;
bool can_proceed() override; bool can_proceed() override;
void on_shutdown() override { powerdown(); }
bool is_connected(); bool is_connected();
void set_phy_addr(uint8_t phy_addr); void set_phy_addr(uint8_t phy_addr);
@ -56,6 +59,7 @@ class EthernetComponent : public Component {
network::IPAddress get_ip_address(); network::IPAddress get_ip_address();
std::string get_use_address() const; std::string get_use_address() const;
void set_use_address(const std::string &use_address); void set_use_address(const std::string &use_address);
bool powerdown();
protected: protected:
static void eth_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data); static void eth_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data);
@ -69,7 +73,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_{};
@ -80,6 +84,7 @@ class EthernetComponent : public Component {
uint32_t connect_begin_; uint32_t connect_begin_;
esp_netif_t *eth_netif_{nullptr}; esp_netif_t *eth_netif_{nullptr};
esp_eth_handle_t eth_handle_; esp_eth_handle_t eth_handle_;
esp_eth_phy_t *phy_{nullptr};
}; };
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)

View file

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

View file

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

View file

@ -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); }

View file

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

View file

@ -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_; }

View file

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

View file

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

View file

@ -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_)) {

View file

@ -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);
} }

View file

@ -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);
} }

View file

@ -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_);
} }

View file

@ -154,18 +154,25 @@ ErrorCode ArduinoI2CBus::writev(uint8_t address, WriteBuffer *buffers, size_t cn
} }
} }
uint8_t status = wire_->endTransmission(stop); uint8_t status = wire_->endTransmission(stop);
if (status == 0) { switch (status) {
return ERROR_OK; case 0:
} else if (status == 1) { return ERROR_OK;
// transmit buffer not large enough case 1:
ESP_LOGVV(TAG, "TX failed: buffer not large enough"); // transmit buffer not large enough
return ERROR_UNKNOWN; ESP_LOGVV(TAG, "TX failed: buffer not large enough");
} else if (status == 2 || status == 3) { return ERROR_UNKNOWN;
ESP_LOGVV(TAG, "TX failed: not acknowledged"); case 2:
return ERROR_NOT_ACKNOWLEDGED; case 3:
ESP_LOGVV(TAG, "TX failed: not acknowledged");
return ERROR_NOT_ACKNOWLEDGED;
case 5:
ESP_LOGVV(TAG, "TX failed: timeout");
return ERROR_UNKNOWN;
case 4:
default:
ESP_LOGVV(TAG, "TX failed: unknown error %u", status);
return ERROR_UNKNOWN;
} }
ESP_LOGVV(TAG, "TX failed: unknown error %u", status);
return ERROR_UNKNOWN;
} }
/// Perform I2C bus recovery, see: /// Perform I2C bus recovery, see:

View file

@ -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");

View file

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

View 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

View 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

View file

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

View file

@ -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();

View file

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

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

View 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

View file

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

View file

@ -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));
} }

View file

@ -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);
} }

View file

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

View file

@ -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);
} }

View file

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

View file

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

View file

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

View file

@ -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(); }

View file

@ -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();

View file

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

View file

@ -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() {

View file

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

View file

@ -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]);

Some files were not shown because too many files have changed in this diff Show more