Merge pull request #8389 from esphome/bump-2025.3.0b1

2025.3.0b1
This commit is contained in:
Keith Burzinski
2025-03-12 03:40:31 -05:00
committed by GitHub
186 changed files with 7254 additions and 1185 deletions
+3 -6
View File
@@ -31,7 +31,7 @@
"ms-python.python",
"ms-python.pylint",
"ms-python.flake8",
"ms-python.black-formatter",
"charliermarsh.ruff",
"visualstudioexptteam.vscodeintellicode",
// yaml
"redhat.vscode-yaml",
@@ -49,14 +49,11 @@
"flake8.args": [
"--config=${workspaceFolder}/.flake8"
],
"black-formatter.args": [
"--config",
"${workspaceFolder}/pyproject.toml"
],
"ruff.configuration": "${workspaceFolder}/pyproject.toml",
"[python]": {
// VS will say "Value is not accepted" before building the devcontainer, but the warning
// should go away after build is completed.
"editor.defaultFormatter": "ms-python.black-formatter"
"editor.defaultFormatter": "charliermarsh.ruff"
},
"editor.formatOnPaste": false,
"editor.formatOnSave": true,
+2 -2
View File
@@ -46,7 +46,7 @@ runs:
- name: Build and push to ghcr by digest
id: build-ghcr
uses: docker/build-push-action@v6.13.0
uses: docker/build-push-action@v6.15.0
env:
DOCKER_BUILD_SUMMARY: false
DOCKER_BUILD_RECORD_UPLOAD: false
@@ -72,7 +72,7 @@ runs:
- name: Build and push to dockerhub by digest
id: build-dockerhub
uses: docker/build-push-action@v6.13.0
uses: docker/build-push-action@v6.15.0
env:
DOCKER_BUILD_SUMMARY: false
DOCKER_BUILD_RECORD_UPLOAD: false
+1 -1
View File
@@ -22,7 +22,7 @@ runs:
python-version: ${{ inputs.python-version }}
- name: Restore Python virtual environment
id: cache-venv
uses: actions/cache/restore@v4.2.0
uses: actions/cache/restore@v4.2.2
with:
path: venv
# yamllint disable-line rule:line-length
+4 -6
View File
@@ -33,11 +33,11 @@ concurrency:
jobs:
check-docker:
name: Build docker containers
runs-on: ubuntu-latest
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
arch: [amd64, aarch64]
os: ["ubuntu-latest", "ubuntu-24.04-arm"]
build_type: ["ha-addon", "docker", "lint"]
steps:
- uses: actions/checkout@v4.1.7
@@ -46,9 +46,7 @@ jobs:
with:
python-version: "3.9"
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.9.0
- name: Set up QEMU
uses: docker/setup-qemu-action@v3.4.0
uses: docker/setup-buildx-action@v3.10.0
- name: Set TAG
run: |
@@ -58,6 +56,6 @@ jobs:
run: |
docker/build.py \
--tag "${TAG}" \
--arch "${{ matrix.arch }}" \
--arch "${{ matrix.os == 'ubuntu-24.04-arm' && 'aarch64' || 'amd64' }}" \
--build-type "${{ matrix.build_type }}" \
build
+9 -9
View File
@@ -47,7 +47,7 @@ jobs:
python-version: ${{ env.DEFAULT_PYTHON }}
- name: Restore Python virtual environment
id: cache-venv
uses: actions/cache@v4.2.0
uses: actions/cache@v4.2.2
with:
path: venv
# yamllint disable-line rule:line-length
@@ -61,8 +61,8 @@ jobs:
pip install -r requirements.txt -r requirements_optional.txt -r requirements_test.txt
pip install -e .
black:
name: Check black
ruff:
name: Check ruff
runs-on: ubuntu-24.04
needs:
- common
@@ -74,10 +74,10 @@ jobs:
with:
python-version: ${{ env.DEFAULT_PYTHON }}
cache-key: ${{ needs.common.outputs.cache-key }}
- name: Run black
- name: Run Ruff
run: |
. venv/bin/activate
black --verbose esphome tests
ruff format esphome tests
- name: Suggested changes
run: script/ci-suggest-changes
if: always()
@@ -255,7 +255,7 @@ jobs:
runs-on: ubuntu-24.04
needs:
- common
- black
- ruff
- ci-custom
- clang-format
- flake8
@@ -303,14 +303,14 @@ jobs:
- name: Cache platformio
if: github.ref == 'refs/heads/dev'
uses: actions/cache@v4.2.0
uses: actions/cache@v4.2.2
with:
path: ~/.platformio
key: platformio-${{ matrix.pio_cache_key }}
- name: Cache platformio
if: github.ref != 'refs/heads/dev'
uses: actions/cache/restore@v4.2.0
uses: actions/cache/restore@v4.2.2
with:
path: ~/.platformio
key: platformio-${{ matrix.pio_cache_key }}
@@ -482,7 +482,7 @@ jobs:
runs-on: ubuntu-24.04
needs:
- common
- black
- ruff
- ci-custom
- clang-format
- flake8
+2 -2
View File
@@ -1,11 +1,11 @@
{
"problemMatcher": [
{
"owner": "black",
"owner": "ruff",
"severity": "error",
"pattern": [
{
"regexp": "^(.*): (Please format this file with the black formatter)",
"regexp": "^(.*): (Please format this file with the ruff formatter)",
"file": 1,
"message": 2
}
+5 -5
View File
@@ -89,10 +89,10 @@ jobs:
python-version: "3.9"
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.9.0
uses: docker/setup-buildx-action@v3.10.0
- name: Set up QEMU
if: matrix.platform != 'linux/amd64'
uses: docker/setup-qemu-action@v3.4.0
uses: docker/setup-qemu-action@v3.6.0
- name: Log in to docker hub
uses: docker/login-action@v3.3.0
@@ -140,7 +140,7 @@ jobs:
echo name=$(cat /tmp/platform) >> $GITHUB_OUTPUT
- name: Upload digests
uses: actions/upload-artifact@v4.6.0
uses: actions/upload-artifact@v4.6.1
with:
name: digests-${{ steps.sanitize.outputs.name }}
path: /tmp/digests
@@ -176,14 +176,14 @@ jobs:
- uses: actions/checkout@v4.1.7
- name: Download digests
uses: actions/download-artifact@v4.1.8
uses: actions/download-artifact@v4.1.9
with:
pattern: digests-*
path: /tmp/digests
merge-multiple: true
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.9.0
uses: docker/setup-buildx-action@v3.10.0
- name: Log in to docker hub
if: matrix.registry == 'dockerhub'
+1 -1
View File
@@ -36,7 +36,7 @@ jobs:
python ./script/sync-device_class.py
- name: Commit changes
uses: peter-evans/create-pull-request@v7.0.6
uses: peter-evans/create-pull-request@v7.0.7
with:
commit-message: "Synchronise Device Classes from Home Assistant"
committer: esphomebot <esphome@nabucasa.com>
+1 -1
View File
@@ -4,7 +4,7 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.5.4
rev: v0.9.2
hooks:
# Run the linter.
- id: ruff
+4
View File
@@ -93,6 +93,7 @@ esphome/components/captive_portal/* @OttoWinter
esphome/components/ccs811/* @habbie
esphome/components/cd74hc4067/* @asoehlke
esphome/components/ch422g/* @clydebarrow @jesterret
esphome/components/chsc6x/* @kkosik20
esphome/components/climate/* @esphome/core
esphome/components/climate_ir/* @glmnet
esphome/components/color_temperature/* @jesserockz
@@ -234,6 +235,7 @@ esphome/components/kuntze/* @ssieb
esphome/components/lcd_menu/* @numo68
esphome/components/ld2410/* @regevbr @sebcaps
esphome/components/ld2420/* @descipher
esphome/components/ld2450/* @hareeshmu
esphome/components/ledc/* @OttoWinter
esphome/components/libretiny/* @kuba2k2
esphome/components/libretiny_pwm/* @kuba2k2
@@ -297,6 +299,7 @@ esphome/components/mopeka_std_check/* @Fabian-Schmidt
esphome/components/mpl3115a2/* @kbickar
esphome/components/mpu6886/* @fabaff
esphome/components/ms8607/* @e28eta
esphome/components/msa3xx/* @latonita
esphome/components/nau7802/* @cujomalainey
esphome/components/network/* @esphome/core
esphome/components/nextion/* @edwardtfn @senexcrenshaw
@@ -445,6 +448,7 @@ esphome/components/tmp102/* @timsavage
esphome/components/tmp1075/* @sybrenstuvel
esphome/components/tmp117/* @Azimath
esphome/components/tof10120/* @wstrzalka
esphome/components/tormatic/* @ti-mo
esphome/components/toshiba/* @kbx81
esphome/components/touchscreen/* @jesserockz @nielsnl68
esphome/components/tsl2591/* @wjcarpenter
@@ -23,10 +23,6 @@ if bashio::config.true 'streamer_mode'; then
export ESPHOME_STREAMER_MODE=true
fi
if bashio::config.true 'status_use_ping'; then
export ESPHOME_DASHBOARD_USE_PING=true
fi
if bashio::config.has_value 'relative_url'; then
export ESPHOME_DASHBOARD_RELATIVE_URL=$(bashio::config 'relative_url')
fi
+9 -1
View File
@@ -2,6 +2,7 @@
import argparse
from datetime import datetime
import functools
import importlib
import logging
import os
import re
@@ -66,7 +67,7 @@ def choose_prompt(options, purpose: str = None):
return options[0][1]
safe_print(
f'Found multiple options{f" for {purpose}" if purpose else ""}, please choose one:'
f"Found multiple options{f' for {purpose}' if purpose else ''}, please choose one:"
)
for i, (desc, _) in enumerate(options):
safe_print(f" [{i + 1}] {desc}")
@@ -336,6 +337,13 @@ def check_permissions(port):
def upload_program(config, args, host):
try:
module = importlib.import_module("esphome.components." + CORE.target_platform)
if getattr(module, "upload_program")(config, args, host):
return 0
except AttributeError:
pass
if get_port_type(host) == "SERIAL":
check_permissions(host)
if CORE.target_platform in (PLATFORM_ESP32, PLATFORM_ESP8266):
+3
View File
@@ -227,6 +227,9 @@ message DeviceInfoResponse {
uint32 voice_assistant_feature_flags = 17;
string suggested_area = 16;
// The Bluetooth mac address of the device. For example "AC:BC:32:89:0E:AA"
string bluetooth_mac_address = 18;
}
message ListEntitiesRequest {
File diff suppressed because it is too large Load Diff
+117 -25
View File
@@ -14,6 +14,46 @@
namespace esphome {
namespace api {
using send_message_t = bool(APIConnection *, void *);
/*
This class holds a pointer to the source component that wants to publish a message, and a pointer to a function that
will lazily publish that message. The two pointers allow dedup in the deferred queue if multiple publishes for the
same component are backed up, and take up only 8 bytes of memory. The entry in the deferred queue (a std::vector) is
the DeferredMessage instance itself (not a pointer to one elsewhere in heap) so still only 8 bytes per entry. Even
100 backed up messages (you'd have to have at least 100 sensors publishing because of dedup) would take up only 0.8
kB.
*/
class DeferredMessageQueue {
struct DeferredMessage {
friend class DeferredMessageQueue;
protected:
void *source_;
send_message_t *send_message_;
public:
DeferredMessage(void *source, send_message_t *send_message) : source_(source), send_message_(send_message) {}
bool operator==(const DeferredMessage &test) const {
return (source_ == test.source_ && send_message_ == test.send_message_);
}
} __attribute__((packed));
protected:
// vector is used very specifically for its zero memory overhead even though items are popped from the front (memory
// footprint is more important than speed here)
std::vector<DeferredMessage> deferred_queue_;
APIConnection *api_connection_;
// helper for allowing only unique entries in the queue
void dmq_push_back_with_dedup_(void *source, send_message_t *send_message);
public:
DeferredMessageQueue(APIConnection *api_connection) : api_connection_(api_connection) {}
void process_queue();
void defer(void *source, send_message_t *send_message);
};
class APIConnection : public APIServerConnection {
public:
APIConnection(std::unique_ptr<socket::Socket> socket, APIServer *parent);
@@ -28,96 +68,140 @@ class APIConnection : public APIServerConnection {
}
#ifdef USE_BINARY_SENSOR
bool send_binary_sensor_state(binary_sensor::BinarySensor *binary_sensor, bool state);
bool send_binary_sensor_info(binary_sensor::BinarySensor *binary_sensor);
void send_binary_sensor_info(binary_sensor::BinarySensor *binary_sensor);
static bool try_send_binary_sensor_state(APIConnection *api, void *v_binary_sensor);
static bool try_send_binary_sensor_state(APIConnection *api, binary_sensor::BinarySensor *binary_sensor, bool state);
static bool try_send_binary_sensor_info(APIConnection *api, void *v_binary_sensor);
#endif
#ifdef USE_COVER
bool send_cover_state(cover::Cover *cover);
bool send_cover_info(cover::Cover *cover);
void send_cover_info(cover::Cover *cover);
static bool try_send_cover_state(APIConnection *api, void *v_cover);
static bool try_send_cover_info(APIConnection *api, void *v_cover);
void cover_command(const CoverCommandRequest &msg) override;
#endif
#ifdef USE_FAN
bool send_fan_state(fan::Fan *fan);
bool send_fan_info(fan::Fan *fan);
void send_fan_info(fan::Fan *fan);
static bool try_send_fan_state(APIConnection *api, void *v_fan);
static bool try_send_fan_info(APIConnection *api, void *v_fan);
void fan_command(const FanCommandRequest &msg) override;
#endif
#ifdef USE_LIGHT
bool send_light_state(light::LightState *light);
bool send_light_info(light::LightState *light);
void send_light_info(light::LightState *light);
static bool try_send_light_state(APIConnection *api, void *v_light);
static bool try_send_light_info(APIConnection *api, void *v_light);
void light_command(const LightCommandRequest &msg) override;
#endif
#ifdef USE_SENSOR
bool send_sensor_state(sensor::Sensor *sensor, float state);
bool send_sensor_info(sensor::Sensor *sensor);
void send_sensor_info(sensor::Sensor *sensor);
static bool try_send_sensor_state(APIConnection *api, void *v_sensor);
static bool try_send_sensor_state(APIConnection *api, sensor::Sensor *sensor, float state);
static bool try_send_sensor_info(APIConnection *api, void *v_sensor);
#endif
#ifdef USE_SWITCH
bool send_switch_state(switch_::Switch *a_switch, bool state);
bool send_switch_info(switch_::Switch *a_switch);
void send_switch_info(switch_::Switch *a_switch);
static bool try_send_switch_state(APIConnection *api, void *v_a_switch);
static bool try_send_switch_state(APIConnection *api, switch_::Switch *a_switch, bool state);
static bool try_send_switch_info(APIConnection *api, void *v_a_switch);
void switch_command(const SwitchCommandRequest &msg) override;
#endif
#ifdef USE_TEXT_SENSOR
bool send_text_sensor_state(text_sensor::TextSensor *text_sensor, std::string state);
bool send_text_sensor_info(text_sensor::TextSensor *text_sensor);
void send_text_sensor_info(text_sensor::TextSensor *text_sensor);
static bool try_send_text_sensor_state(APIConnection *api, void *v_text_sensor);
static bool try_send_text_sensor_state(APIConnection *api, text_sensor::TextSensor *text_sensor, std::string state);
static bool try_send_text_sensor_info(APIConnection *api, void *v_text_sensor);
#endif
#ifdef USE_ESP32_CAMERA
void send_camera_state(std::shared_ptr<esp32_camera::CameraImage> image);
bool send_camera_info(esp32_camera::ESP32Camera *camera);
void set_camera_state(std::shared_ptr<esp32_camera::CameraImage> image);
void send_camera_info(esp32_camera::ESP32Camera *camera);
static bool try_send_camera_info(APIConnection *api, void *v_camera);
void camera_image(const CameraImageRequest &msg) override;
#endif
#ifdef USE_CLIMATE
bool send_climate_state(climate::Climate *climate);
bool send_climate_info(climate::Climate *climate);
void send_climate_info(climate::Climate *climate);
static bool try_send_climate_state(APIConnection *api, void *v_climate);
static bool try_send_climate_info(APIConnection *api, void *v_climate);
void climate_command(const ClimateCommandRequest &msg) override;
#endif
#ifdef USE_NUMBER
bool send_number_state(number::Number *number, float state);
bool send_number_info(number::Number *number);
void send_number_info(number::Number *number);
static bool try_send_number_state(APIConnection *api, void *v_number);
static bool try_send_number_state(APIConnection *api, number::Number *number, float state);
static bool try_send_number_info(APIConnection *api, void *v_number);
void number_command(const NumberCommandRequest &msg) override;
#endif
#ifdef USE_DATETIME_DATE
bool send_date_state(datetime::DateEntity *date);
bool send_date_info(datetime::DateEntity *date);
void send_date_info(datetime::DateEntity *date);
static bool try_send_date_state(APIConnection *api, void *v_date);
static bool try_send_date_info(APIConnection *api, void *v_date);
void date_command(const DateCommandRequest &msg) override;
#endif
#ifdef USE_DATETIME_TIME
bool send_time_state(datetime::TimeEntity *time);
bool send_time_info(datetime::TimeEntity *time);
void send_time_info(datetime::TimeEntity *time);
static bool try_send_time_state(APIConnection *api, void *v_time);
static bool try_send_time_info(APIConnection *api, void *v_time);
void time_command(const TimeCommandRequest &msg) override;
#endif
#ifdef USE_DATETIME_DATETIME
bool send_datetime_state(datetime::DateTimeEntity *datetime);
bool send_datetime_info(datetime::DateTimeEntity *datetime);
void send_datetime_info(datetime::DateTimeEntity *datetime);
static bool try_send_datetime_state(APIConnection *api, void *v_datetime);
static bool try_send_datetime_info(APIConnection *api, void *v_datetime);
void datetime_command(const DateTimeCommandRequest &msg) override;
#endif
#ifdef USE_TEXT
bool send_text_state(text::Text *text, std::string state);
bool send_text_info(text::Text *text);
void send_text_info(text::Text *text);
static bool try_send_text_state(APIConnection *api, void *v_text);
static bool try_send_text_state(APIConnection *api, text::Text *text, std::string state);
static bool try_send_text_info(APIConnection *api, void *v_text);
void text_command(const TextCommandRequest &msg) override;
#endif
#ifdef USE_SELECT
bool send_select_state(select::Select *select, std::string state);
bool send_select_info(select::Select *select);
void send_select_info(select::Select *select);
static bool try_send_select_state(APIConnection *api, void *v_select);
static bool try_send_select_state(APIConnection *api, select::Select *select, std::string state);
static bool try_send_select_info(APIConnection *api, void *v_select);
void select_command(const SelectCommandRequest &msg) override;
#endif
#ifdef USE_BUTTON
bool send_button_info(button::Button *button);
void send_button_info(button::Button *button);
static bool try_send_button_info(APIConnection *api, void *v_button);
void button_command(const ButtonCommandRequest &msg) override;
#endif
#ifdef USE_LOCK
bool send_lock_state(lock::Lock *a_lock, lock::LockState state);
bool send_lock_info(lock::Lock *a_lock);
void send_lock_info(lock::Lock *a_lock);
static bool try_send_lock_state(APIConnection *api, void *v_a_lock);
static bool try_send_lock_state(APIConnection *api, lock::Lock *a_lock, lock::LockState state);
static bool try_send_lock_info(APIConnection *api, void *v_a_lock);
void lock_command(const LockCommandRequest &msg) override;
#endif
#ifdef USE_VALVE
bool send_valve_state(valve::Valve *valve);
bool send_valve_info(valve::Valve *valve);
void send_valve_info(valve::Valve *valve);
static bool try_send_valve_state(APIConnection *api, void *v_valve);
static bool try_send_valve_info(APIConnection *api, void *v_valve);
void valve_command(const ValveCommandRequest &msg) override;
#endif
#ifdef USE_MEDIA_PLAYER
bool send_media_player_state(media_player::MediaPlayer *media_player);
bool send_media_player_info(media_player::MediaPlayer *media_player);
void send_media_player_info(media_player::MediaPlayer *media_player);
static bool try_send_media_player_state(APIConnection *api, void *v_media_player);
static bool try_send_media_player_info(APIConnection *api, void *v_media_player);
void media_player_command(const MediaPlayerCommandRequest &msg) override;
#endif
bool send_log_message(int level, const char *tag, const char *line);
bool try_send_log_message(int level, const char *tag, const char *line);
void send_homeassistant_service_call(const HomeassistantServiceResponse &call) {
if (!this->service_call_subscription_)
return;
@@ -160,18 +244,25 @@ class APIConnection : public APIServerConnection {
#ifdef USE_ALARM_CONTROL_PANEL
bool send_alarm_control_panel_state(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel);
bool send_alarm_control_panel_info(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel);
void send_alarm_control_panel_info(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel);
static bool try_send_alarm_control_panel_state(APIConnection *api, void *v_a_alarm_control_panel);
static bool try_send_alarm_control_panel_info(APIConnection *api, void *v_a_alarm_control_panel);
void alarm_control_panel_command(const AlarmControlPanelCommandRequest &msg) override;
#endif
#ifdef USE_EVENT
bool send_event(event::Event *event, std::string event_type);
bool send_event_info(event::Event *event);
void send_event(event::Event *event, std::string event_type);
void send_event_info(event::Event *event);
static bool try_send_event(APIConnection *api, void *v_event);
static bool try_send_event(APIConnection *api, event::Event *event, std::string event_type);
static bool try_send_event_info(APIConnection *api, void *v_event);
#endif
#ifdef USE_UPDATE
bool send_update_state(update::UpdateEntity *update);
bool send_update_info(update::UpdateEntity *update);
void send_update_info(update::UpdateEntity *update);
static bool try_send_update_state(APIConnection *api, void *v_update);
static bool try_send_update_info(APIConnection *api, void *v_update);
void update_command(const UpdateCommandRequest &msg) override;
#endif
@@ -262,6 +353,7 @@ class APIConnection : public APIServerConnection {
bool service_call_subscription_{false};
bool next_close_ = false;
APIServer *parent_;
DeferredMessageQueue deferred_message_queue_;
InitialStateIterator initial_state_iterator_;
ListEntitiesIterator list_entities_iterator_;
int state_subs_at_ = -1;
+9
View File
@@ -838,6 +838,10 @@ bool DeviceInfoResponse::decode_length(uint32_t field_id, ProtoLengthDelimited v
this->suggested_area = value.as_string();
return true;
}
case 18: {
this->bluetooth_mac_address = value.as_string();
return true;
}
default:
return false;
}
@@ -860,6 +864,7 @@ void DeviceInfoResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint32(14, this->legacy_voice_assistant_version);
buffer.encode_uint32(17, this->voice_assistant_feature_flags);
buffer.encode_string(16, this->suggested_area);
buffer.encode_string(18, this->bluetooth_mac_address);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void DeviceInfoResponse::dump_to(std::string &out) const {
@@ -937,6 +942,10 @@ void DeviceInfoResponse::dump_to(std::string &out) const {
out.append(" suggested_area: ");
out.append("'").append(this->suggested_area).append("'");
out.append("\n");
out.append(" bluetooth_mac_address: ");
out.append("'").append(this->bluetooth_mac_address).append("'");
out.append("\n");
out.append("}");
}
#endif
+1
View File
@@ -354,6 +354,7 @@ class DeviceInfoResponse : public ProtoMessage {
uint32_t legacy_voice_assistant_version{0};
uint32_t voice_assistant_feature_flags{0};
std::string suggested_area{};
std::string bluetooth_mac_address{};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
+2 -2
View File
@@ -72,7 +72,7 @@ void APIServer::setup() {
logger::global_logger->add_on_log_callback([this](int level, const char *tag, const char *message) {
for (auto &c : this->clients_) {
if (!c->remove_)
c->send_log_message(level, tag, message);
c->try_send_log_message(level, tag, message);
}
});
}
@@ -86,7 +86,7 @@ void APIServer::setup() {
[this](const std::shared_ptr<esp32_camera::CameraImage> &image) {
for (auto &c : this->clients_) {
if (!c->remove_)
c->send_camera_state(image);
c->set_camera_state(image);
}
});
}
+76 -22
View File
@@ -10,37 +10,63 @@ namespace api {
#ifdef USE_BINARY_SENSOR
bool ListEntitiesIterator::on_binary_sensor(binary_sensor::BinarySensor *binary_sensor) {
return this->client_->send_binary_sensor_info(binary_sensor);
this->client_->send_binary_sensor_info(binary_sensor);
return true;
}
#endif
#ifdef USE_COVER
bool ListEntitiesIterator::on_cover(cover::Cover *cover) { return this->client_->send_cover_info(cover); }
bool ListEntitiesIterator::on_cover(cover::Cover *cover) {
this->client_->send_cover_info(cover);
return true;
}
#endif
#ifdef USE_FAN
bool ListEntitiesIterator::on_fan(fan::Fan *fan) { return this->client_->send_fan_info(fan); }
bool ListEntitiesIterator::on_fan(fan::Fan *fan) {
this->client_->send_fan_info(fan);
return true;
}
#endif
#ifdef USE_LIGHT
bool ListEntitiesIterator::on_light(light::LightState *light) { return this->client_->send_light_info(light); }
bool ListEntitiesIterator::on_light(light::LightState *light) {
this->client_->send_light_info(light);
return true;
}
#endif
#ifdef USE_SENSOR
bool ListEntitiesIterator::on_sensor(sensor::Sensor *sensor) { return this->client_->send_sensor_info(sensor); }
bool ListEntitiesIterator::on_sensor(sensor::Sensor *sensor) {
this->client_->send_sensor_info(sensor);
return true;
}
#endif
#ifdef USE_SWITCH
bool ListEntitiesIterator::on_switch(switch_::Switch *a_switch) { return this->client_->send_switch_info(a_switch); }
bool ListEntitiesIterator::on_switch(switch_::Switch *a_switch) {
this->client_->send_switch_info(a_switch);
return true;
}
#endif
#ifdef USE_BUTTON
bool ListEntitiesIterator::on_button(button::Button *button) { return this->client_->send_button_info(button); }
bool ListEntitiesIterator::on_button(button::Button *button) {
this->client_->send_button_info(button);
return true;
}
#endif
#ifdef USE_TEXT_SENSOR
bool ListEntitiesIterator::on_text_sensor(text_sensor::TextSensor *text_sensor) {
return this->client_->send_text_sensor_info(text_sensor);
this->client_->send_text_sensor_info(text_sensor);
return true;
}
#endif
#ifdef USE_LOCK
bool ListEntitiesIterator::on_lock(lock::Lock *a_lock) { return this->client_->send_lock_info(a_lock); }
bool ListEntitiesIterator::on_lock(lock::Lock *a_lock) {
this->client_->send_lock_info(a_lock);
return true;
}
#endif
#ifdef USE_VALVE
bool ListEntitiesIterator::on_valve(valve::Valve *valve) { return this->client_->send_valve_info(valve); }
bool ListEntitiesIterator::on_valve(valve::Valve *valve) {
this->client_->send_valve_info(valve);
return true;
}
#endif
bool ListEntitiesIterator::on_end() { return this->client_->send_list_info_done(); }
@@ -52,55 +78,83 @@ bool ListEntitiesIterator::on_service(UserServiceDescriptor *service) {
#ifdef USE_ESP32_CAMERA
bool ListEntitiesIterator::on_camera(esp32_camera::ESP32Camera *camera) {
return this->client_->send_camera_info(camera);
this->client_->send_camera_info(camera);
return true;
}
#endif
#ifdef USE_CLIMATE
bool ListEntitiesIterator::on_climate(climate::Climate *climate) { return this->client_->send_climate_info(climate); }
bool ListEntitiesIterator::on_climate(climate::Climate *climate) {
this->client_->send_climate_info(climate);
return true;
}
#endif
#ifdef USE_NUMBER
bool ListEntitiesIterator::on_number(number::Number *number) { return this->client_->send_number_info(number); }
bool ListEntitiesIterator::on_number(number::Number *number) {
this->client_->send_number_info(number);
return true;
}
#endif
#ifdef USE_DATETIME_DATE
bool ListEntitiesIterator::on_date(datetime::DateEntity *date) { return this->client_->send_date_info(date); }
bool ListEntitiesIterator::on_date(datetime::DateEntity *date) {
this->client_->send_date_info(date);
return true;
}
#endif
#ifdef USE_DATETIME_TIME
bool ListEntitiesIterator::on_time(datetime::TimeEntity *time) { return this->client_->send_time_info(time); }
bool ListEntitiesIterator::on_time(datetime::TimeEntity *time) {
this->client_->send_time_info(time);
return true;
}
#endif
#ifdef USE_DATETIME_DATETIME
bool ListEntitiesIterator::on_datetime(datetime::DateTimeEntity *datetime) {
return this->client_->send_datetime_info(datetime);
this->client_->send_datetime_info(datetime);
return true;
}
#endif
#ifdef USE_TEXT
bool ListEntitiesIterator::on_text(text::Text *text) { return this->client_->send_text_info(text); }
bool ListEntitiesIterator::on_text(text::Text *text) {
this->client_->send_text_info(text);
return true;
}
#endif
#ifdef USE_SELECT
bool ListEntitiesIterator::on_select(select::Select *select) { return this->client_->send_select_info(select); }
bool ListEntitiesIterator::on_select(select::Select *select) {
this->client_->send_select_info(select);
return true;
}
#endif
#ifdef USE_MEDIA_PLAYER
bool ListEntitiesIterator::on_media_player(media_player::MediaPlayer *media_player) {
return this->client_->send_media_player_info(media_player);
this->client_->send_media_player_info(media_player);
return true;
}
#endif
#ifdef USE_ALARM_CONTROL_PANEL
bool ListEntitiesIterator::on_alarm_control_panel(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) {
return this->client_->send_alarm_control_panel_info(a_alarm_control_panel);
this->client_->send_alarm_control_panel_info(a_alarm_control_panel);
return true;
}
#endif
#ifdef USE_EVENT
bool ListEntitiesIterator::on_event(event::Event *event) { return this->client_->send_event_info(event); }
bool ListEntitiesIterator::on_event(event::Event *event) {
this->client_->send_event_info(event);
return true;
}
#endif
#ifdef USE_UPDATE
bool ListEntitiesIterator::on_update(update::UpdateEntity *update) { return this->client_->send_update_info(update); }
bool ListEntitiesIterator::on_update(update::UpdateEntity *update) {
this->client_->send_update_info(update);
return true;
}
#endif
} // namespace api
+1
View File
@@ -80,6 +80,7 @@ class ListEntitiesIterator : public ComponentIterator {
bool on_update(update::UpdateEntity *update) override;
#endif
bool on_end() override;
bool completed() { return this->state_ == IteratorState::NONE; }
protected:
APIConnection *client_;
+2
View File
@@ -76,6 +76,8 @@ class InitialStateIterator : public ComponentIterator {
#ifdef USE_UPDATE
bool on_update(update::UpdateEntity *update) override;
#endif
bool completed() { return this->state_ == IteratorState::NONE; }
protected:
APIConnection *client_;
};
@@ -15,6 +15,9 @@
#include "bluetooth_connection.h"
#include <esp_bt.h>
#include <esp_bt_device.h>
namespace esphome {
namespace bluetooth_proxy {
@@ -114,6 +117,11 @@ class BluetoothProxy : public esp32_ble_tracker::ESPBTDeviceListener, public Com
return flags;
}
std::string get_bluetooth_mac_address_pretty() {
const uint8_t *mac = esp_bt_dev_get_address();
return str_snprintf("%02X:%02X:%02X:%02X:%02X:%02X", 17, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}
protected:
void send_api_packet_(const esp32_ble_tracker::ESPBTDevice &device);
+1 -1
View File
@@ -95,7 +95,7 @@ void BMP085Component::read_pressure_() {
return;
}
uint32_t value = (uint32_t(buffer[0]) << 16) | (uint32_t(buffer[1]) << 8) | uint32_t(buffer[0]);
uint32_t value = (uint32_t(buffer[0]) << 16) | (uint32_t(buffer[1]) << 8) | uint32_t(buffer[2]);
if ((value >> 5) == 0) {
ESP_LOGW(TAG, "Invalid pressure!");
this->status_set_warning();
+2
View File
@@ -0,0 +1,2 @@
CODEOWNERS = ["@kkosik20"]
DEPENDENCIES = ["i2c"]
@@ -0,0 +1,47 @@
#include "chsc6x_touchscreen.h"
namespace esphome {
namespace chsc6x {
void CHSC6XTouchscreen::setup() {
ESP_LOGCONFIG(TAG, "Setting up CHSC6X Touchscreen...");
if (this->interrupt_pin_ != nullptr) {
this->interrupt_pin_->setup();
this->attach_interrupt_(this->interrupt_pin_, gpio::INTERRUPT_FALLING_EDGE);
}
if (this->x_raw_max_ == this->x_raw_min_) {
this->x_raw_max_ = this->display_->get_native_width();
}
if (this->y_raw_max_ == this->y_raw_min_) {
this->y_raw_max_ = this->display_->get_native_height();
}
ESP_LOGCONFIG(TAG, "CHSC6X Touchscreen setup complete");
}
void CHSC6XTouchscreen::update_touches() {
uint8_t data[CHSC6X_REG_STATUS_LEN];
if (!this->read_bytes(CHSC6X_REG_STATUS, data, sizeof(data))) {
return;
}
uint8_t num_of_touches = data[CHSC6X_REG_STATUS_TOUCH];
if (num_of_touches == 1) {
uint16_t x = data[CHSC6X_REG_STATUS_X_COR];
uint16_t y = data[CHSC6X_REG_STATUS_Y_COR];
this->add_raw_touch_position_(0, x, y);
}
}
void CHSC6XTouchscreen::dump_config() {
ESP_LOGCONFIG(TAG, "CHSC6X Touchscreen:");
LOG_I2C_DEVICE(this);
LOG_PIN(" Interrupt Pin: ", this->interrupt_pin_);
ESP_LOGCONFIG(TAG, " Touch timeout: %d", this->touch_timeout_);
ESP_LOGCONFIG(TAG, " x_raw_max_: %d", this->x_raw_max_);
ESP_LOGCONFIG(TAG, " y_raw_max_: %d", this->y_raw_max_);
}
} // namespace chsc6x
} // namespace esphome
@@ -0,0 +1,34 @@
#pragma once
#include "esphome/components/i2c/i2c.h"
#include "esphome/components/touchscreen/touchscreen.h"
#include "esphome/core/component.h"
#include "esphome/core/hal.h"
#include "esphome/core/log.h"
namespace esphome {
namespace chsc6x {
static const char *const TAG = "chsc6x.touchscreen";
static const uint8_t CHSC6X_REG_STATUS = 0x00;
static const uint8_t CHSC6X_REG_STATUS_TOUCH = 0x00;
static const uint8_t CHSC6X_REG_STATUS_X_COR = 0x02;
static const uint8_t CHSC6X_REG_STATUS_Y_COR = 0x04;
static const uint8_t CHSC6X_REG_STATUS_LEN = 0x05;
static const uint8_t CHSC6X_CHIP_ID = 0x2e;
class CHSC6XTouchscreen : public touchscreen::Touchscreen, public i2c::I2CDevice {
public:
void setup() override;
void update_touches() override;
void dump_config() override;
void set_interrupt_pin(InternalGPIOPin *pin) { this->interrupt_pin_ = pin; }
protected:
InternalGPIOPin *interrupt_pin_{};
};
} // namespace chsc6x
} // namespace esphome
+33
View File
@@ -0,0 +1,33 @@
from esphome import pins
import esphome.codegen as cg
from esphome.components import i2c, touchscreen
import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_INTERRUPT_PIN
chsc6x_ns = cg.esphome_ns.namespace("chsc6x")
CHSC6XTouchscreen = chsc6x_ns.class_(
"CHSC6XTouchscreen",
touchscreen.Touchscreen,
i2c.I2CDevice,
)
CONFIG_SCHEMA = (
touchscreen.touchscreen_schema("100ms")
.extend(
{
cv.GenerateID(): cv.declare_id(CHSC6XTouchscreen),
cv.Optional(CONF_INTERRUPT_PIN): pins.internal_gpio_input_pin_schema,
}
)
.extend(i2c.i2c_device_schema(0x2E))
)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await touchscreen.register_touchscreen(var, config)
await i2c.register_i2c_device(var, config)
if interrupt_pin := config.get(CONF_INTERRUPT_PIN):
cg.add(var.set_interrupt_pin(await cg.gpio_pin_expression(interrupt_pin)))
-1
View File
@@ -128,7 +128,6 @@ VISUAL_TEMPERATURE_STEP_SCHEMA = cv.Schema(
def visual_temperature_step(value):
# Allow defining target/current temperature steps separately
if isinstance(value, dict):
return VISUAL_TEMPERATURE_STEP_SCHEMA(value)
@@ -1,28 +1,5 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import binary_sensor
from .. import cst816_ns
from ..touchscreen import CST816Touchscreen, CST816ButtonListener
CONF_CST816_ID = "cst816_id"
CST816Button = cst816_ns.class_(
"CST816Button",
binary_sensor.BinarySensor,
cg.Component,
CST816ButtonListener,
cg.Parented.template(CST816Touchscreen),
CONFIG_SCHEMA = cv.invalid(
"The CST816 binary sensor has been removed. Instead use the touchscreen binary sensor with the 'use_raw' flag set."
)
CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(CST816Button).extend(
{
cv.GenerateID(CONF_CST816_ID): cv.use_id(CST816Touchscreen),
}
)
async def to_code(config):
var = await binary_sensor.new_binary_sensor(config)
await cg.register_component(var, config)
await cg.register_parented(var, config[CONF_CST816_ID])
@@ -1,27 +0,0 @@
#pragma once
#include "esphome/components/binary_sensor/binary_sensor.h"
#include "esphome/components/cst816/touchscreen/cst816_touchscreen.h"
#include "esphome/core/component.h"
#include "esphome/core/helpers.h"
namespace esphome {
namespace cst816 {
class CST816Button : public binary_sensor::BinarySensor,
public Component,
public CST816ButtonListener,
public Parented<CST816Touchscreen> {
public:
void setup() override {
this->parent_->register_button_listener(this);
this->publish_initial_state(false);
}
void dump_config() override { LOG_BINARY_SENSOR("", "CST816 Button", this); }
void update_button(bool state) override { this->publish_state(state); }
};
} // namespace cst816
} // namespace esphome
@@ -37,14 +37,6 @@ void CST816Touchscreen::continue_setup_() {
ESP_LOGCONFIG(TAG, "CST816 Touchscreen setup complete");
}
void CST816Touchscreen::update_button_state_(bool state) {
if (this->button_touched_ == state)
return;
this->button_touched_ = state;
for (auto *listener : this->button_listeners_)
listener->update_button(state);
}
void CST816Touchscreen::setup() {
ESP_LOGCONFIG(TAG, "Setting up CST816 Touchscreen...");
if (this->reset_pin_ != nullptr) {
@@ -68,18 +60,13 @@ void CST816Touchscreen::update_touches() {
}
uint8_t num_of_touches = data[REG_TOUCH_NUM] & 3;
if (num_of_touches == 0) {
this->update_button_state_(false);
return;
}
uint16_t x = encode_uint16(data[REG_XPOS_HIGH] & 0xF, data[REG_XPOS_LOW]);
uint16_t y = encode_uint16(data[REG_YPOS_HIGH] & 0xF, data[REG_YPOS_LOW]);
ESP_LOGV(TAG, "Read touch %d/%d", x, y);
if (x >= this->x_raw_max_) {
this->update_button_state_(true);
} else {
this->add_raw_touch_position_(0, x, y);
}
this->add_raw_touch_position_(0, x, y);
}
void CST816Touchscreen::dump_config() {
@@ -87,6 +74,8 @@ void CST816Touchscreen::dump_config() {
LOG_I2C_DEVICE(this);
LOG_PIN(" Interrupt Pin: ", this->interrupt_pin_);
LOG_PIN(" Reset Pin: ", this->reset_pin_);
ESP_LOGCONFIG(TAG, " X Raw Min: %d, X Raw Max: %d", this->x_raw_min_, this->x_raw_max_);
ESP_LOGCONFIG(TAG, " Y Raw Min: %d, Y Raw Max: %d", this->y_raw_min_, this->y_raw_max_);
const char *name;
switch (this->chip_id_) {
case CST820_CHIP_ID:
@@ -40,7 +40,6 @@ class CST816Touchscreen : public touchscreen::Touchscreen, public i2c::I2CDevice
public:
void setup() override;
void update_touches() override;
void register_button_listener(CST816ButtonListener *listener) { this->button_listeners_.push_back(listener); }
void dump_config() override;
void set_interrupt_pin(InternalGPIOPin *pin) { this->interrupt_pin_ = pin; }
@@ -49,14 +48,11 @@ class CST816Touchscreen : public touchscreen::Touchscreen, public i2c::I2CDevice
protected:
void continue_setup_();
void update_button_state_(bool state);
InternalGPIOPin *interrupt_pin_{};
GPIOPin *reset_pin_{};
uint8_t chip_id_{};
bool skip_probe_{}; // if set, do not expect to be able to probe the controller on the i2c bus.
std::vector<CST816ButtonListener *> button_listeners_;
bool button_touched_{};
};
} // namespace cst816
@@ -66,7 +66,9 @@ FINAL_VALIDATE_SCHEMA = esp32_ble.validate_variant
async def to_code(config):
uuid = config[CONF_UUID].hex
uuid_arr = [cg.RawExpression(f"0x{uuid[i:i + 2]}") for i in range(0, len(uuid), 2)]
uuid_arr = [
cg.RawExpression(f"0x{uuid[i : i + 2]}") for i in range(0, len(uuid), 2)
]
var = cg.new_Pvariable(config[CONF_ID], uuid_arr)
parent = await cg.get_variable(config[esp32_ble.CONF_BLE_ID])
+1 -2
View File
@@ -112,8 +112,7 @@ def validate_supports(value):
)
if is_pullup and num == 16:
raise cv.Invalid(
"GPIO Pin 16 does not support pullup pin mode. "
"Please choose another pin.",
"GPIO Pin 16 does not support pullup pin mode. Please choose another pin.",
[CONF_MODE, CONF_PULLUP],
)
if is_pulldown and num != 16:
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -81,7 +81,7 @@ void Font::measure(const char *str, int *width, int *x_offset, int *baseline, in
if (glyph_n < 0) {
// Unknown char, skip
if (!this->get_glyphs().empty())
x += this->get_glyphs()[0].glyph_data_->width;
x += this->get_glyphs()[0].glyph_data_->advance;
i++;
continue;
}
@@ -92,7 +92,7 @@ void Font::measure(const char *str, int *width, int *x_offset, int *baseline, in
} else {
min_x = std::min(min_x, x + glyph.glyph_data_->offset_x);
}
x += glyph.glyph_data_->width + glyph.glyph_data_->offset_x;
x += glyph.glyph_data_->advance;
i += match_length;
has_char = true;
@@ -111,7 +111,7 @@ void Font::print(int x_start, int y_start, display::Display *display, Color colo
// Unknown char, skip
ESP_LOGW(TAG, "Encountered character without representation in font: '%c'", text[i]);
if (!this->get_glyphs().empty()) {
uint8_t glyph_width = this->get_glyphs()[0].glyph_data_->width;
uint8_t glyph_width = this->get_glyphs()[0].glyph_data_->advance;
display->filled_rectangle(x_at, y_start, glyph_width, this->height_, color);
x_at += glyph_width;
}
@@ -161,7 +161,7 @@ void Font::print(int x_start, int y_start, display::Display *display, Color colo
}
}
}
x_at += glyph.glyph_data_->width + glyph.glyph_data_->offset_x;
x_at += glyph.glyph_data_->advance;
i += match_length;
}
+1
View File
@@ -15,6 +15,7 @@ class Font;
struct GlyphData {
const uint8_t *a_char;
const uint8_t *data;
int advance;
int offset_x;
int offset_y;
int width;
+12 -11
View File
@@ -1,9 +1,15 @@
import logging
import esphome.codegen as cg
import esphome.config_validation as cv
import esphome.final_validate as fv
from esphome.components import uart, climate, logger
import logging
from esphome import automation
import esphome.codegen as cg
from esphome.components import climate, logger, uart
from esphome.components.climate import (
CONF_CURRENT_TEMPERATURE,
ClimateMode,
ClimatePreset,
ClimateSwingMode,
)
import esphome.config_validation as cv
from esphome.const import (
CONF_BEEPER,
CONF_DISPLAY,
@@ -24,12 +30,7 @@ from esphome.const import (
CONF_VISUAL,
CONF_WIFI,
)
from esphome.components.climate import (
ClimateMode,
ClimatePreset,
ClimateSwingMode,
CONF_CURRENT_TEMPERATURE,
)
import esphome.final_validate as fv
_LOGGER = logging.getLogger(__name__)
@@ -12,7 +12,7 @@ float HBridgeSwitch::get_setup_priority() const { return setup_priority::HARDWAR
void HBridgeSwitch::setup() {
ESP_LOGCONFIG(TAG, "Setting up H-Bridge Switch '%s'...", this->name_.c_str());
optional<bool> initial_state = this->get_initial_state_with_restore_mode().value_or(false);
optional<bool> initial_state = this->get_initial_state_with_restore_mode();
// Like GPIOSwitch does, set the pin state both before and after pin setup()
this->on_pin_->digital_write(false);
@@ -24,7 +24,7 @@ void HBridgeSwitch::setup() {
this->off_pin_->digital_write(false);
if (initial_state.has_value())
this->write_state(initial_state);
this->write_state(initial_state.value());
}
void HBridgeSwitch::dump_config() {
+2 -1
View File
@@ -53,6 +53,7 @@ PROTOCOLS = {
"mitsubishi_sez": Protocol.PROTOCOL_MITSUBISHI_SEZ,
"panasonic_ckp": Protocol.PROTOCOL_PANASONIC_CKP,
"panasonic_dke": Protocol.PROTOCOL_PANASONIC_DKE,
"panasonic_eke": Protocol.PROTOCOL_PANASONIC_EKE,
"panasonic_jke": Protocol.PROTOCOL_PANASONIC_JKE,
"panasonic_lke": Protocol.PROTOCOL_PANASONIC_LKE,
"panasonic_nke": Protocol.PROTOCOL_PANASONIC_NKE,
@@ -127,6 +128,6 @@ def to_code(config):
cg.add(var.set_max_temperature(config[CONF_MAX_TEMPERATURE]))
cg.add(var.set_min_temperature(config[CONF_MIN_TEMPERATURE]))
cg.add_library("tonia/HeatpumpIR", "1.0.27")
cg.add_library("tonia/HeatpumpIR", "1.0.32")
if CORE.is_libretiny:
CORE.add_platformio_option("lib_ignore", "IRremoteESP8266")
@@ -47,6 +47,7 @@ const std::map<Protocol, std::function<HeatpumpIR *()>> PROTOCOL_CONSTRUCTOR_MAP
{PROTOCOL_MITSUBISHI_SEZ, []() { return new MitsubishiSEZKDXXHeatpumpIR(); }}, // NOLINT
{PROTOCOL_PANASONIC_CKP, []() { return new PanasonicCKPHeatpumpIR(); }}, // NOLINT
{PROTOCOL_PANASONIC_DKE, []() { return new PanasonicDKEHeatpumpIR(); }}, // NOLINT
{PROTOCOL_PANASONIC_EKE, []() { return new PanasonicEKEHeatpumpIR(); }}, // NOLINT
{PROTOCOL_PANASONIC_JKE, []() { return new PanasonicJKEHeatpumpIR(); }}, // NOLINT
{PROTOCOL_PANASONIC_LKE, []() { return new PanasonicLKEHeatpumpIR(); }}, // NOLINT
{PROTOCOL_PANASONIC_NKE, []() { return new PanasonicNKEHeatpumpIR(); }}, // NOLINT
@@ -47,6 +47,7 @@ enum Protocol {
PROTOCOL_MITSUBISHI_SEZ,
PROTOCOL_PANASONIC_CKP,
PROTOCOL_PANASONIC_DKE,
PROTOCOL_PANASONIC_EKE,
PROTOCOL_PANASONIC_JKE,
PROTOCOL_PANASONIC_LKE,
PROTOCOL_PANASONIC_NKE,
+6 -6
View File
@@ -1,23 +1,23 @@
from esphome import pins
import esphome.codegen as cg
import esphome.config_validation as cv
import esphome.final_validate as fv
from esphome import pins
from esphome.const import (
CONF_ADDRESS,
CONF_FREQUENCY,
CONF_TIMEOUT,
CONF_I2C_ID,
CONF_ID,
CONF_INPUT,
CONF_OUTPUT,
CONF_SCAN,
CONF_SCL,
CONF_SDA,
CONF_ADDRESS,
CONF_I2C_ID,
CONF_TIMEOUT,
PLATFORM_ESP32,
PLATFORM_ESP8266,
PLATFORM_RP2040,
)
from esphome.core import coroutine_with_priority, CORE
from esphome.core import CORE, coroutine_with_priority
import esphome.final_validate as fv
CODEOWNERS = ["@esphome/core"]
i2c_ns = cg.esphome_ns.namespace("i2c")
+6 -2
View File
@@ -8,6 +8,10 @@
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 3, 0)
#define SOC_HP_I2C_NUM SOC_I2C_NUM
#endif
namespace esphome {
namespace i2c {
@@ -17,14 +21,14 @@ void IDFI2CBus::setup() {
ESP_LOGCONFIG(TAG, "Setting up I2C bus...");
static i2c_port_t next_port = I2C_NUM_0;
port_ = next_port;
#if SOC_I2C_NUM > 1
#if SOC_HP_I2C_NUM > 1
next_port = (next_port == I2C_NUM_0) ? I2C_NUM_1 : I2C_NUM_MAX;
#else
next_port = I2C_NUM_MAX;
#endif
if (port_ == I2C_NUM_MAX) {
ESP_LOGE(TAG, "Too many I2C buses configured. Max %u supported.", SOC_I2C_NUM);
ESP_LOGE(TAG, "Too many I2C buses configured. Max %u supported.", SOC_HP_I2C_NUM);
this->mark_failed();
return;
}
@@ -203,7 +203,7 @@ size_t I2SAudioSpeaker::play(const uint8_t *data, size_t length, TickType_t tick
this->start();
}
if ((this->state_ != speaker::STATE_RUNNING) || (this->audio_ring_buffer_.use_count() == 1)) {
if ((this->state_ != speaker::STATE_RUNNING) || (this->audio_ring_buffer_.use_count() != 1)) {
// Unable to write data to a running speaker, so delay the max amount of time so it can get ready
vTaskDelay(ticks_to_wait);
ticks_to_wait = 0;
+1
View File
@@ -57,6 +57,7 @@ ColorOrder = display.display_ns.enum("ColorMode")
MODELS = {
"GC9A01A": ili9xxx_ns.class_("ILI9XXXGC9A01A", ILI9XXXDisplay),
"GC9D01N": ili9xxx_ns.class_("ILI9XXXGC9D01N", ILI9XXXDisplay),
"M5STACK": ili9xxx_ns.class_("ILI9XXXM5Stack", ILI9XXXDisplay),
"M5CORE": ili9xxx_ns.class_("ILI9XXXM5CORE", ILI9XXXDisplay),
"TFT_2.4": ili9xxx_ns.class_("ILI9XXXILI9341", ILI9XXXDisplay),
@@ -272,6 +272,11 @@ class ILI9XXXGC9A01A : public ILI9XXXDisplay {
ILI9XXXGC9A01A() : ILI9XXXDisplay(INITCMD_GC9A01A, 240, 240) {}
};
class ILI9XXXGC9D01N : public ILI9XXXDisplay {
public:
ILI9XXXGC9D01N() : ILI9XXXDisplay(INITCMD_GC9D01N, 160, 160) {}
};
//----------- ILI9XXX_24_TFT display --------------
class ILI9XXXST7735 : public ILI9XXXDisplay {
public:
+59
View File
@@ -367,6 +367,65 @@ static const uint8_t PROGMEM INITCMD_GC9A01A[] = {
0x00 // End of list
};
static const uint8_t PROGMEM INITCMD_GC9D01N[] = {
// Enable Inter_command
0xFE, 0, // Inter Register Enable 1 (FEh)
0xEF, 0, // Inter Register Enable 2 (EFh)
// Inter_command is now enabled
0x80, 1, 0xFF,
0x81, 1, 0xFF,
0x82, 1, 0xFF,
0x83, 1, 0xFF,
0x84, 1, 0xFF,
0x85, 1, 0xFF,
0x86, 1, 0xFF,
0x87, 1, 0xFF,
0x88, 1, 0xFF,
0x89, 1, 0xFF,
0x8A, 1, 0xFF,
0x8B, 1, 0xFF,
0x8C, 1, 0xFF,
0x8D, 1, 0xFF,
0x8E, 1, 0xFF,
0x8F, 1, 0xFF,
0X3A, 1, 0x05, // COLMOD: Pixel Format Set (3Ah) MCU interface, 16 bits / pixel
0xEC, 1, 0x01, // Inversion (ECh) DINV=1+2H1V column for Dual Gate (BFh=0)
// According to datasheet Inversion (ECh) value 0x01 isn't valid, but Lilygo uses it everywhere
0x74, 7, 0x02, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00,
0x98, 1, 0x3e,
0x99, 1, 0x3e,
0xB5, 2, 0x0D, 0x0D, // Blanking Porch Control (B5h) VFP=14 VBP=14 HBP=Off
0x60, 4, 0x38, 0x0F, 0x79, 0x67,
0x61, 4, 0x38, 0x11, 0x79, 0x67,
0x64, 6, 0x38, 0x17, 0x71, 0x5F, 0x79, 0x67,
0x65, 6, 0x38, 0x13, 0x71, 0x5B, 0x79, 0x67,
0x6A, 2, 0x00, 0x00,
0x6C, 7, 0x22, 0x02, 0x22, 0x02, 0x22, 0x22, 0x50,
0x6E, 32, 0x03, 0x03, 0x01, 0x01, 0x00, 0x00, 0x0F, 0x0F,
0x0D, 0x0D, 0x0B, 0x0B, 0x09, 0x09, 0x00, 0x00,
0x00, 0x00, 0x0A, 0x0A, 0x0C, 0x0C, 0x0E, 0x0E,
0x10, 0x10, 0x00, 0x00, 0x02, 0x02, 0x04, 0x04,
0xBF, 1, 0x01, // Dual-Single gate select (BFh) 01h = dual gate mode
0xF9, 1, 0x40,
0x9B, 5, 0x3B, 0x93, 0x33, 0x7F, 0x00,
0x7E, 1, 0x30,
0x70, 6, 0x0D, 0x02, 0x08, 0x0D, 0x02, 0x08,
0x71, 3, 0x0D, 0x02, 0x08,
0x91, 2, 0x0E, 0x09,
// Set VREG1A, VREG1B, VREG2A, VREG2B voltage
// According to datasheet set either 0xC3/0xC4 or 0xC9 only, but Lilygo sets both of them
0xC3, 5, 0x19, 0xC4, 0x19, 0xC9, 0x3C,
0xF0, 6, 0x53, 0x15, 0x0A, 0x04, 0x00, 0x3E, // SET_GAMMA1 (F0h)
0xF1, 6, 0x56, 0xA8, 0x7F, 0x33, 0x34, 0x5F, // SET_GAMMA2 (F1h)
0xF2, 6, 0x53, 0x15, 0x0A, 0x04, 0x00, 0x3A, // SET_GAMMA3 (F2h)
0xF3, 6, 0x52, 0xA4, 0x7F, 0x33, 0x34, 0xDF, // SET_GAMMA4 (F3h)
ILI9XXX_SLPOUT, 0, // Sleep Out Mode (11h)
ILI9XXX_DELAY(10),
ILI9XXX_DISPON, 0, // Display ON (29h)
ILI9XXX_DELAY(20),
0x00 // End of list
};
static const uint8_t PROGMEM INITCMD_ST7735[] = {
ILI9XXX_SWRESET, 0, // Soft reset, then delay 10ms
ILI9XXX_DELAY(10),
+51
View File
@@ -0,0 +1,51 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import uart
from esphome.const import (
CONF_ID,
CONF_THROTTLE,
)
DEPENDENCIES = ["uart"]
CODEOWNERS = ["@hareeshmu"]
MULTI_CONF = True
ld2450_ns = cg.esphome_ns.namespace("ld2450")
LD2450Component = ld2450_ns.class_("LD2450Component", cg.Component, uart.UARTDevice)
CONF_LD2450_ID = "ld2450_id"
CONFIG_SCHEMA = cv.All(
cv.Schema(
{
cv.GenerateID(): cv.declare_id(LD2450Component),
cv.Optional(CONF_THROTTLE, default="1000ms"): cv.All(
cv.positive_time_period_milliseconds,
cv.Range(min=cv.TimePeriod(milliseconds=1)),
),
}
)
.extend(uart.UART_DEVICE_SCHEMA)
.extend(cv.COMPONENT_SCHEMA)
)
LD2450BaseSchema = cv.Schema(
{
cv.GenerateID(CONF_LD2450_ID): cv.use_id(LD2450Component),
},
)
FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema(
"ld2450",
require_tx=True,
require_rx=True,
parity="NONE",
stop_bits=1,
)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await uart.register_uart_device(var, config)
cg.add(var.set_throttle(config[CONF_THROTTLE]))
@@ -0,0 +1,47 @@
import esphome.codegen as cg
from esphome.components import binary_sensor
import esphome.config_validation as cv
from esphome.const import (
CONF_HAS_MOVING_TARGET,
CONF_HAS_STILL_TARGET,
CONF_HAS_TARGET,
DEVICE_CLASS_MOTION,
DEVICE_CLASS_OCCUPANCY,
)
from . import CONF_LD2450_ID, LD2450Component
DEPENDENCIES = ["ld2450"]
ICON_MEDITATION = "mdi:meditation"
ICON_SHIELD_ACCOUNT = "mdi:shield-account"
ICON_TARGET_ACCOUNT = "mdi:target-account"
CONFIG_SCHEMA = {
cv.GenerateID(CONF_LD2450_ID): cv.use_id(LD2450Component),
cv.Optional(CONF_HAS_TARGET): binary_sensor.binary_sensor_schema(
device_class=DEVICE_CLASS_OCCUPANCY,
icon=ICON_SHIELD_ACCOUNT,
),
cv.Optional(CONF_HAS_MOVING_TARGET): binary_sensor.binary_sensor_schema(
device_class=DEVICE_CLASS_MOTION,
icon=ICON_TARGET_ACCOUNT,
),
cv.Optional(CONF_HAS_STILL_TARGET): binary_sensor.binary_sensor_schema(
device_class=DEVICE_CLASS_OCCUPANCY,
icon=ICON_MEDITATION,
),
}
async def to_code(config):
ld2450_component = await cg.get_variable(config[CONF_LD2450_ID])
if has_target_config := config.get(CONF_HAS_TARGET):
sens = await binary_sensor.new_binary_sensor(has_target_config)
cg.add(ld2450_component.set_target_binary_sensor(sens))
if has_moving_target_config := config.get(CONF_HAS_MOVING_TARGET):
sens = await binary_sensor.new_binary_sensor(has_moving_target_config)
cg.add(ld2450_component.set_moving_target_binary_sensor(sens))
if has_still_target_config := config.get(CONF_HAS_STILL_TARGET):
sens = await binary_sensor.new_binary_sensor(has_still_target_config)
cg.add(ld2450_component.set_still_target_binary_sensor(sens))

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