mirror of
https://github.com/esphome/esphome.git
synced 2025-11-01 23:51:47 +00:00
Compare commits
127 Commits
2023.4.0b1
...
2023.4.4
Author | SHA1 | Date | |
---|---|---|---|
|
2f78c4acfa | ||
|
72f6841aac | ||
|
10bd9b14fc | ||
|
e725e15f7a | ||
|
4d1113e265 | ||
|
52352ac27a | ||
|
f60b2b754d | ||
|
b89c04b928 | ||
|
12090657bb | ||
|
4e21cf0bdd | ||
|
ba4ef72d56 | ||
|
f3e6a4314f | ||
|
e14ce3d950 | ||
|
0f1e186189 | ||
|
96d208e0d8 | ||
|
38ed38864e | ||
|
a12ba7bd38 | ||
|
19fc1417ae | ||
|
e2fefa51f5 | ||
|
f668d5617f | ||
|
47c4ff15d6 | ||
|
ccf1bdc0b4 | ||
|
e993fcf80c | ||
|
1bdc30a09e | ||
|
f56e89597f | ||
|
9460fb28c4 | ||
|
7207b9734f | ||
|
3be3267d06 | ||
|
98db604dba | ||
|
ebf6f8c6de | ||
|
2ebacad398 | ||
|
53c59cf675 | ||
|
9da261cb39 | ||
|
e4b2de5c68 | ||
|
f862b479e7 | ||
|
358c59bd8d | ||
|
74fe135c9c | ||
|
8d3896172d | ||
|
9d9725144d | ||
|
dd8dc1ef1d | ||
|
bc427de16a | ||
|
db5988bbe1 | ||
|
a3875af4b4 | ||
|
e6737479f7 | ||
|
7f75832bf1 | ||
|
33339e3bd8 | ||
|
c037e95861 | ||
|
2e1b35959f | ||
|
7f46d9e0f9 | ||
|
069b5f81a0 | ||
|
3a36d0b13f | ||
|
f0760e99b7 | ||
|
18fecf8c09 | ||
|
414cf1b333 | ||
|
d10f891f51 | ||
|
b5927322e6 | ||
|
1cf4107e1c | ||
|
c12408326c | ||
|
4434e59e5a | ||
|
45180d98f6 | ||
|
44494ad18e | ||
|
1447536906 | ||
|
27ec517084 | ||
|
ce1f034bac | ||
|
f1f96f16e9 | ||
|
4af4649e23 | ||
|
8bcddef39d | ||
|
4ac96ccea2 | ||
|
3c5de77ae9 | ||
|
a2925b1d37 | ||
|
73748e9e20 | ||
|
75c9823899 | ||
|
c8c0bd3351 | ||
|
e1cdeb7c8f | ||
|
7f97f42552 | ||
|
aa7f3569ec | ||
|
2d0a08442e | ||
|
d2380756b2 | ||
|
925e3cb6c9 | ||
|
6757acba56 | ||
|
5cc91cdd95 | ||
|
2b41886819 | ||
|
72c6efd6a0 | ||
|
a1f1804112 | ||
|
a8b1ceb4e9 | ||
|
4fb0f7f8c6 | ||
|
958cadeca8 | ||
|
00f2655f1a | ||
|
074f5029eb | ||
|
1691976587 | ||
|
60e6b4d21e | ||
|
5750591df2 | ||
|
a75da54455 | ||
|
de7f6c3f5f | ||
|
4245480656 | ||
|
1824c8131e | ||
|
4e9606d2e0 | ||
|
78500fa933 | ||
|
9c69b98a49 | ||
|
e6d8ef98d3 | ||
|
3f1af1690b | ||
|
84374b6b1e | ||
|
391316c9b5 | ||
|
705c62ebd7 | ||
|
7209dd8bae | ||
|
ab736c89bb | ||
|
6911639617 | ||
|
b9720d0715 | ||
|
47b3267ed4 | ||
|
e16ba2adb5 | ||
|
0a19b1e32c | ||
|
bae9a950c0 | ||
|
72b2943332 | ||
|
4ec0ef7548 | ||
|
25bc6761f6 | ||
|
81b6562c25 | ||
|
ae74189fc2 | ||
|
9e516efe10 | ||
|
366e29439e | ||
|
1c9c700d7f | ||
|
b2e6b9d31f | ||
|
7623f63846 | ||
|
2bfaf9dce3 | ||
|
5c2c1560bb | ||
|
f7096ab78e | ||
|
98f8feb625 | ||
|
9944ca414e |
@@ -428,14 +428,17 @@ void APIServer::on_shutdown() {
|
||||
}
|
||||
|
||||
#ifdef USE_VOICE_ASSISTANT
|
||||
void APIServer::start_voice_assistant() {
|
||||
bool APIServer::start_voice_assistant() {
|
||||
for (auto &c : this->clients_) {
|
||||
c->request_voice_assistant(true);
|
||||
if (c->request_voice_assistant(true))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void APIServer::stop_voice_assistant() {
|
||||
for (auto &c : this->clients_) {
|
||||
c->request_voice_assistant(false);
|
||||
if (c->request_voice_assistant(false))
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@@ -96,7 +96,7 @@ class APIServer : public Component, public Controller {
|
||||
#endif
|
||||
|
||||
#ifdef USE_VOICE_ASSISTANT
|
||||
void start_voice_assistant();
|
||||
bool start_voice_assistant();
|
||||
void stop_voice_assistant();
|
||||
#endif
|
||||
|
||||
|
@@ -1,15 +1,11 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
import esphome.final_validate as fv
|
||||
from esphome.components import logger
|
||||
from esphome.const import (
|
||||
CONF_BLOCK,
|
||||
CONF_DEVICE,
|
||||
CONF_FRAGMENTATION,
|
||||
CONF_FREE,
|
||||
CONF_ID,
|
||||
CONF_LEVEL,
|
||||
CONF_LOGGER,
|
||||
CONF_LOOP_TIME,
|
||||
)
|
||||
|
||||
@@ -21,38 +17,29 @@ debug_ns = cg.esphome_ns.namespace("debug")
|
||||
DebugComponent = debug_ns.class_("DebugComponent", cg.PollingComponent)
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(DebugComponent),
|
||||
cv.Optional(CONF_DEVICE): cv.invalid(
|
||||
"The 'device' option has been moved to the 'debug' text_sensor component"
|
||||
),
|
||||
cv.Optional(CONF_FREE): cv.invalid(
|
||||
"The 'free' option has been moved to the 'debug' sensor component"
|
||||
),
|
||||
cv.Optional(CONF_BLOCK): cv.invalid(
|
||||
"The 'block' option has been moved to the 'debug' sensor component"
|
||||
),
|
||||
cv.Optional(CONF_FRAGMENTATION): cv.invalid(
|
||||
"The 'fragmentation' option has been moved to the 'debug' sensor component"
|
||||
),
|
||||
cv.Optional(CONF_LOOP_TIME): cv.invalid(
|
||||
"The 'loop_time' option has been moved to the 'debug' sensor component"
|
||||
),
|
||||
}
|
||||
).extend(cv.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
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(DebugComponent),
|
||||
cv.Optional(CONF_DEVICE): cv.invalid(
|
||||
"The 'device' option has been moved to the 'debug' text_sensor component"
|
||||
),
|
||||
cv.Optional(CONF_FREE): cv.invalid(
|
||||
"The 'free' option has been moved to the 'debug' sensor component"
|
||||
),
|
||||
cv.Optional(CONF_BLOCK): cv.invalid(
|
||||
"The 'block' option has been moved to the 'debug' sensor component"
|
||||
),
|
||||
cv.Optional(CONF_FRAGMENTATION): cv.invalid(
|
||||
"The 'fragmentation' option has been moved to the 'debug' sensor component"
|
||||
),
|
||||
cv.Optional(CONF_LOOP_TIME): cv.invalid(
|
||||
"The 'loop_time' option has been moved to the 'debug' sensor component"
|
||||
),
|
||||
}
|
||||
).extend(cv.polling_component_schema("60s")),
|
||||
cv.only_on(["esp32", "esp8266"]),
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
|
@@ -37,6 +37,10 @@ static uint32_t get_free_heap() {
|
||||
}
|
||||
|
||||
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 reset_reason;
|
||||
device_info.reserve(256);
|
||||
|
@@ -163,7 +163,7 @@ RECOMMENDED_ARDUINO_FRAMEWORK_VERSION = cv.Version(2, 0, 5)
|
||||
# The platformio/espressif32 version to use for arduino frameworks
|
||||
# - https://github.com/platformio/platform-espressif32/releases
|
||||
# - 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
|
||||
# - https://github.com/espressif/esp-idf/releases
|
||||
|
@@ -12,6 +12,8 @@ CONF_BLE_ID = "ble_id"
|
||||
|
||||
NO_BLUTOOTH_VARIANTS = [const.VARIANT_ESP32S2]
|
||||
|
||||
NO_BLUTOOTH_VARIANTS = [const.VARIANT_ESP32S2]
|
||||
|
||||
esp32_ble_ns = cg.esphome_ns.namespace("esp32_ble")
|
||||
ESP32BLE = esp32_ble_ns.class_("ESP32BLE", cg.Component)
|
||||
|
||||
|
@@ -26,8 +26,10 @@ EthernetComponent::EthernetComponent() { global_eth_component = this; }
|
||||
|
||||
void EthernetComponent::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Setting up Ethernet...");
|
||||
// Delay here to allow power to stabilise before Ethernet is initialised.
|
||||
delay(300); // NOLINT
|
||||
if (esp_reset_reason() != ESP_RST_DEEPSLEEP) {
|
||||
// Delay here to allow power to stabilise before Ethernet is initialized.
|
||||
delay(300); // NOLINT
|
||||
}
|
||||
|
||||
esp_err_t err;
|
||||
err = esp_netif_init();
|
||||
@@ -52,30 +54,29 @@ void EthernetComponent::setup() {
|
||||
|
||||
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config);
|
||||
|
||||
esp_eth_phy_t *phy;
|
||||
switch (this->type_) {
|
||||
case ETHERNET_TYPE_LAN8720: {
|
||||
phy = esp_eth_phy_new_lan87xx(&phy_config);
|
||||
this->phy_ = esp_eth_phy_new_lan87xx(&phy_config);
|
||||
break;
|
||||
}
|
||||
case ETHERNET_TYPE_RTL8201: {
|
||||
phy = esp_eth_phy_new_rtl8201(&phy_config);
|
||||
this->phy_ = esp_eth_phy_new_rtl8201(&phy_config);
|
||||
break;
|
||||
}
|
||||
case ETHERNET_TYPE_DP83848: {
|
||||
phy = esp_eth_phy_new_dp83848(&phy_config);
|
||||
this->phy_ = esp_eth_phy_new_dp83848(&phy_config);
|
||||
break;
|
||||
}
|
||||
case ETHERNET_TYPE_IP101: {
|
||||
phy = esp_eth_phy_new_ip101(&phy_config);
|
||||
this->phy_ = esp_eth_phy_new_ip101(&phy_config);
|
||||
break;
|
||||
}
|
||||
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: {
|
||||
phy = esp_eth_phy_new_ksz8081(&phy_config);
|
||||
this->phy_ = esp_eth_phy_new_ksz8081(&phy_config);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -84,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;
|
||||
err = esp_eth_driver_install(ð_config, &this->eth_handle_);
|
||||
ESPHL_ERROR_CHECK(err, "ETH driver install error");
|
||||
@@ -276,7 +277,7 @@ void EthernetComponent::start_connect_() {
|
||||
#endif
|
||||
dns_setserver(0, &d);
|
||||
}
|
||||
if (uint32_t(this->manual_ip_->dns1) != 0) {
|
||||
if (uint32_t(this->manual_ip_->dns2) != 0) {
|
||||
ip_addr_t d;
|
||||
#if LWIP_IPV6
|
||||
d.type = IPADDR_TYPE_V4;
|
||||
@@ -356,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; }
|
||||
|
||||
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 esphome
|
||||
|
||||
|
@@ -45,6 +45,7 @@ class EthernetComponent : public Component {
|
||||
void dump_config() override;
|
||||
float get_setup_priority() const override;
|
||||
bool can_proceed() override;
|
||||
void on_shutdown() override { powerdown(); }
|
||||
bool is_connected();
|
||||
|
||||
void set_phy_addr(uint8_t phy_addr);
|
||||
@@ -58,6 +59,7 @@ class EthernetComponent : public Component {
|
||||
network::IPAddress get_ip_address();
|
||||
std::string get_use_address() const;
|
||||
void set_use_address(const std::string &use_address);
|
||||
bool powerdown();
|
||||
|
||||
protected:
|
||||
static void eth_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data);
|
||||
@@ -82,6 +84,7 @@ class EthernetComponent : public Component {
|
||||
uint32_t connect_begin_;
|
||||
esp_netif_t *eth_netif_{nullptr};
|
||||
esp_eth_handle_t eth_handle_;
|
||||
esp_eth_phy_t *phy_{nullptr};
|
||||
};
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
|
@@ -77,10 +77,12 @@ void FingerprintGrowComponent::finish_enrollment(uint8_t result) {
|
||||
this->enrollment_done_callback_.call(this->enrollment_slot_);
|
||||
this->get_fingerprint_count_();
|
||||
} else {
|
||||
this->enrollment_failed_callback_.call(this->enrollment_slot_);
|
||||
if (this->enrollment_slot_ != ENROLLMENT_SLOT_UNUSED) {
|
||||
this->enrollment_failed_callback_.call(this->enrollment_slot_);
|
||||
}
|
||||
}
|
||||
this->enrollment_image_ = 0;
|
||||
this->enrollment_slot_ = 0;
|
||||
this->enrollment_slot_ = ENROLLMENT_SLOT_UNUSED;
|
||||
if (this->enrolling_binary_sensor_ != nullptr) {
|
||||
this->enrolling_binary_sensor_->publish_state(false);
|
||||
}
|
||||
|
@@ -13,6 +13,8 @@ namespace fingerprint_grow {
|
||||
|
||||
static const uint16_t START_CODE = 0xEF01;
|
||||
|
||||
static const uint16_t ENROLLMENT_SLOT_UNUSED = 0xFFFF;
|
||||
|
||||
enum GrowPacketType {
|
||||
COMMAND = 0x01,
|
||||
DATA = 0x02,
|
||||
@@ -158,7 +160,7 @@ class FingerprintGrowComponent : public PollingComponent, public uart::UARTDevic
|
||||
uint32_t new_password_ = -1;
|
||||
GPIOPin *sensing_pin_{nullptr};
|
||||
uint8_t enrollment_image_ = 0;
|
||||
uint16_t enrollment_slot_ = 0;
|
||||
uint16_t enrollment_slot_ = ENROLLMENT_SLOT_UNUSED;
|
||||
uint8_t enrollment_buffers_ = 5;
|
||||
bool waiting_removal_ = false;
|
||||
uint32_t last_aura_led_control_ = 0;
|
||||
|
@@ -3,6 +3,7 @@
|
||||
#include "i2c_bus_arduino.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/application.h"
|
||||
#include <Arduino.h>
|
||||
#include <cstring>
|
||||
|
||||
@@ -154,18 +155,25 @@ ErrorCode ArduinoI2CBus::writev(uint8_t address, WriteBuffer *buffers, size_t cn
|
||||
}
|
||||
}
|
||||
uint8_t status = wire_->endTransmission(stop);
|
||||
if (status == 0) {
|
||||
return ERROR_OK;
|
||||
} else if (status == 1) {
|
||||
// transmit buffer not large enough
|
||||
ESP_LOGVV(TAG, "TX failed: buffer not large enough");
|
||||
return ERROR_UNKNOWN;
|
||||
} else if (status == 2 || status == 3) {
|
||||
ESP_LOGVV(TAG, "TX failed: not acknowledged");
|
||||
return ERROR_NOT_ACKNOWLEDGED;
|
||||
switch (status) {
|
||||
case 0:
|
||||
return ERROR_OK;
|
||||
case 1:
|
||||
// transmit buffer not large enough
|
||||
ESP_LOGVV(TAG, "TX failed: buffer not large enough");
|
||||
return ERROR_UNKNOWN;
|
||||
case 2:
|
||||
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:
|
||||
@@ -220,10 +228,14 @@ void ArduinoI2CBus::recover_() {
|
||||
// When SCL is kept LOW at this point, we might be looking at a device
|
||||
// that applies clock stretching. Wait for the release of the SCL line,
|
||||
// but not forever. There is no specification for the maximum allowed
|
||||
// time. We'll stick to 500ms here.
|
||||
auto wait = 20;
|
||||
// time. We yield and reset the WDT, so as to avoid triggering reset.
|
||||
// No point in trying to recover the bus by forcing a uC reset. Bus
|
||||
// should recover in a few ms or less else not likely to recovery at
|
||||
// all.
|
||||
auto wait = 250;
|
||||
while (wait-- && digitalRead(scl_pin_) == LOW) { // NOLINT
|
||||
delay(25);
|
||||
App.feed_wdt();
|
||||
delayMicroseconds(half_period_usec * 2);
|
||||
}
|
||||
if (digitalRead(scl_pin_) == LOW) { // NOLINT
|
||||
ESP_LOGE(TAG, "Recovery failed: SCL is held LOW during clock pulse cycle");
|
||||
|
@@ -4,6 +4,7 @@
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/application.h"
|
||||
#include <cstring>
|
||||
#include <cinttypes>
|
||||
|
||||
@@ -273,10 +274,14 @@ void IDFI2CBus::recover_() {
|
||||
// When SCL is kept LOW at this point, we might be looking at a device
|
||||
// that applies clock stretching. Wait for the release of the SCL line,
|
||||
// but not forever. There is no specification for the maximum allowed
|
||||
// time. We'll stick to 500ms here.
|
||||
auto wait = 20;
|
||||
// time. We yield and reset the WDT, so as to avoid triggering reset.
|
||||
// No point in trying to recover the bus by forcing a uC reset. Bus
|
||||
// should recover in a few ms or less else not likely to recovery at
|
||||
// all.
|
||||
auto wait = 250;
|
||||
while (wait-- && gpio_get_level(scl_pin) == 0) {
|
||||
delay(25);
|
||||
App.feed_wdt();
|
||||
delayMicroseconds(half_period_usec * 2);
|
||||
}
|
||||
if (gpio_get_level(scl_pin) == 0) {
|
||||
ESP_LOGE(TAG, "Recovery failed: SCL is held LOW during clock pulse cycle");
|
||||
|
@@ -141,7 +141,7 @@ void I2SAudioMediaPlayer::start_() {
|
||||
this->audio_ = make_unique<Audio>(true, this->internal_dac_mode_, this->parent_->get_port());
|
||||
} else {
|
||||
#endif
|
||||
this->audio_ = make_unique<Audio>(false, I2S_DAC_CHANNEL_BOTH_EN, this->parent_->get_port());
|
||||
this->audio_ = make_unique<Audio>(false, 3, this->parent_->get_port());
|
||||
|
||||
i2s_pin_config_t pin_config = this->parent_->get_pin_config();
|
||||
pin_config.data_out_num = this->dout_pin_;
|
||||
|
@@ -93,7 +93,7 @@ async def to_code(config):
|
||||
cg.add(var.set_scroll(config[CONF_SCROLL_ENABLE]))
|
||||
cg.add(var.set_scroll_mode(config[CONF_SCROLL_MODE]))
|
||||
cg.add(var.set_reverse(config[CONF_REVERSE_ENABLE]))
|
||||
cg.add(var.set_flip_x([CONF_FLIP_X]))
|
||||
cg.add(var.set_flip_x(config[CONF_FLIP_X]))
|
||||
|
||||
if CONF_LAMBDA in config:
|
||||
lambda_ = await cg.process_lambda(
|
||||
|
@@ -25,10 +25,12 @@ from esphome.const import (
|
||||
CONF_STATE_CLASS,
|
||||
CONF_TO,
|
||||
CONF_TRIGGER_ID,
|
||||
CONF_TYPE,
|
||||
CONF_UNIT_OF_MEASUREMENT,
|
||||
CONF_WINDOW_SIZE,
|
||||
CONF_MQTT_ID,
|
||||
CONF_FORCE_UPDATE,
|
||||
CONF_VALUE,
|
||||
DEVICE_CLASS_APPARENT_POWER,
|
||||
DEVICE_CLASS_AQI,
|
||||
DEVICE_CLASS_ATMOSPHERIC_PRESSURE,
|
||||
@@ -476,21 +478,38 @@ async def lambda_filter_to_code(config, filter_id):
|
||||
return cg.new_Pvariable(filter_id, lambda_)
|
||||
|
||||
|
||||
DELTA_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_VALUE): cv.positive_float,
|
||||
cv.Optional(CONF_TYPE, default="absolute"): cv.one_of(
|
||||
"absolute", "percentage", lower=True
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def validate_delta(config):
|
||||
try:
|
||||
return (cv.positive_float(config), False)
|
||||
value = cv.positive_float(config)
|
||||
return DELTA_SCHEMA({CONF_VALUE: value, CONF_TYPE: "absolute"})
|
||||
except cv.Invalid:
|
||||
pass
|
||||
try:
|
||||
return (cv.percentage(config), True)
|
||||
value = cv.percentage(config)
|
||||
return DELTA_SCHEMA({CONF_VALUE: value, CONF_TYPE: "percentage"})
|
||||
except cv.Invalid:
|
||||
pass
|
||||
raise cv.Invalid("Delta filter requires a positive number or percentage value.")
|
||||
|
||||
|
||||
@FILTER_REGISTRY.register("delta", DeltaFilter, validate_delta)
|
||||
@FILTER_REGISTRY.register("delta", DeltaFilter, cv.Any(DELTA_SCHEMA, validate_delta))
|
||||
async def delta_filter_to_code(config, filter_id):
|
||||
return cg.new_Pvariable(filter_id, *config)
|
||||
percentage = config[CONF_TYPE] == "percentage"
|
||||
return cg.new_Pvariable(
|
||||
filter_id,
|
||||
config[CONF_VALUE],
|
||||
percentage,
|
||||
)
|
||||
|
||||
|
||||
@FILTER_REGISTRY.register("or", OrFilter, validate_filters)
|
||||
|
@@ -7,6 +7,8 @@
|
||||
namespace esphome {
|
||||
namespace socket {
|
||||
|
||||
Socket::~Socket() {}
|
||||
|
||||
std::unique_ptr<Socket> socket_ip(int type, int protocol) {
|
||||
#if LWIP_IPV6
|
||||
return socket(AF_INET6, type, protocol);
|
||||
|
@@ -11,7 +11,7 @@ namespace socket {
|
||||
class Socket {
|
||||
public:
|
||||
Socket() = default;
|
||||
virtual ~Socket() = default;
|
||||
virtual ~Socket();
|
||||
Socket(const Socket &) = delete;
|
||||
Socket &operator=(const Socket &) = delete;
|
||||
|
||||
@@ -34,7 +34,7 @@ class Socket {
|
||||
virtual ssize_t readv(const struct iovec *iov, int iovcnt) = 0;
|
||||
virtual ssize_t write(const void *buf, size_t len) = 0;
|
||||
virtual ssize_t writev(const struct iovec *iov, int iovcnt) = 0;
|
||||
virtual ssize_t sendto(const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen);
|
||||
virtual ssize_t sendto(const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen) = 0;
|
||||
|
||||
virtual int setblocking(bool blocking) = 0;
|
||||
virtual int loop() { return 0; };
|
||||
|
@@ -286,7 +286,9 @@ SPRINKLER_VALVE_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Optional(CONF_ENABLE_SWITCH): cv.maybe_simple_value(
|
||||
switch.switch_schema(
|
||||
SprinklerControllerSwitch, entity_category=ENTITY_CATEGORY_CONFIG
|
||||
SprinklerControllerSwitch,
|
||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||
default_restore_mode="RESTORE_DEFAULT_OFF",
|
||||
),
|
||||
key=CONF_NAME,
|
||||
),
|
||||
@@ -333,7 +335,9 @@ SPRINKLER_CONTROLLER_SCHEMA = cv.Schema(
|
||||
cv.Optional(CONF_NAME): cv.string,
|
||||
cv.Optional(CONF_AUTO_ADVANCE_SWITCH): cv.maybe_simple_value(
|
||||
switch.switch_schema(
|
||||
SprinklerControllerSwitch, entity_category=ENTITY_CATEGORY_CONFIG
|
||||
SprinklerControllerSwitch,
|
||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||
default_restore_mode="RESTORE_DEFAULT_OFF",
|
||||
),
|
||||
key=CONF_NAME,
|
||||
),
|
||||
@@ -343,19 +347,25 @@ SPRINKLER_CONTROLLER_SCHEMA = cv.Schema(
|
||||
),
|
||||
cv.Optional(CONF_QUEUE_ENABLE_SWITCH): cv.maybe_simple_value(
|
||||
switch.switch_schema(
|
||||
SprinklerControllerSwitch, entity_category=ENTITY_CATEGORY_CONFIG
|
||||
SprinklerControllerSwitch,
|
||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||
default_restore_mode="RESTORE_DEFAULT_OFF",
|
||||
),
|
||||
key=CONF_NAME,
|
||||
),
|
||||
cv.Optional(CONF_REVERSE_SWITCH): cv.maybe_simple_value(
|
||||
switch.switch_schema(
|
||||
SprinklerControllerSwitch, entity_category=ENTITY_CATEGORY_CONFIG
|
||||
SprinklerControllerSwitch,
|
||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||
default_restore_mode="RESTORE_DEFAULT_OFF",
|
||||
),
|
||||
key=CONF_NAME,
|
||||
),
|
||||
cv.Optional(CONF_STANDBY_SWITCH): cv.maybe_simple_value(
|
||||
switch.switch_schema(
|
||||
SprinklerControllerSwitch, entity_category=ENTITY_CATEGORY_CONFIG
|
||||
SprinklerControllerSwitch,
|
||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||
default_restore_mode="RESTORE_DEFAULT_OFF",
|
||||
),
|
||||
key=CONF_NAME,
|
||||
),
|
||||
|
@@ -1176,6 +1176,21 @@ optional<uint32_t> Sprinkler::time_remaining_current_operation() {
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
bool Sprinkler::any_controller_is_active() {
|
||||
if (this->state_ != IDLE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (auto &controller : this->other_controllers_) {
|
||||
if (controller != this) { // dummy check
|
||||
if (controller->controller_state() != IDLE) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
SprinklerControllerSwitch *Sprinkler::control_switch(size_t valve_number) {
|
||||
if (this->is_a_valid_valve(valve_number)) {
|
||||
return this->valve_[valve_number].controller_switch;
|
||||
|
@@ -406,6 +406,12 @@ class Sprinkler : public Component {
|
||||
/// returns the amount of time remaining in seconds for all valves remaining, including the active valve, if any
|
||||
optional<uint32_t> time_remaining_current_operation();
|
||||
|
||||
/// returns true if this or any sprinkler controller this controller knows about is active
|
||||
bool any_controller_is_active();
|
||||
|
||||
/// returns the current state of the sprinkler controller
|
||||
SprinklerState controller_state() { return this->state_; };
|
||||
|
||||
/// returns a pointer to a valve's control switch object
|
||||
SprinklerControllerSwitch *control_switch(size_t valve_number);
|
||||
|
||||
@@ -503,7 +509,6 @@ class Sprinkler : public Component {
|
||||
/// callback functions for timers
|
||||
void valve_selection_callback_();
|
||||
void sm_timer_callback_();
|
||||
void pump_stop_delay_callback_();
|
||||
|
||||
/// Maximum allowed queue size
|
||||
const uint8_t max_queue_size_{100};
|
||||
|
@@ -11,6 +11,14 @@ DEPENDENCIES = ["api", "microphone"]
|
||||
|
||||
CODEOWNERS = ["@jesserockz"]
|
||||
|
||||
CONF_ON_START = "on_start"
|
||||
CONF_ON_STT_END = "on_stt_end"
|
||||
CONF_ON_TTS_START = "on_tts_start"
|
||||
CONF_ON_TTS_END = "on_tts_end"
|
||||
CONF_ON_END = "on_end"
|
||||
CONF_ON_ERROR = "on_error"
|
||||
|
||||
|
||||
voice_assistant_ns = cg.esphome_ns.namespace("voice_assistant")
|
||||
VoiceAssistant = voice_assistant_ns.class_("VoiceAssistant", cg.Component)
|
||||
|
||||
@@ -26,6 +34,12 @@ CONFIG_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(VoiceAssistant),
|
||||
cv.GenerateID(CONF_MICROPHONE): cv.use_id(microphone.Microphone),
|
||||
cv.Optional(CONF_ON_START): automation.validate_automation(single=True),
|
||||
cv.Optional(CONF_ON_STT_END): automation.validate_automation(single=True),
|
||||
cv.Optional(CONF_ON_TTS_START): automation.validate_automation(single=True),
|
||||
cv.Optional(CONF_ON_TTS_END): automation.validate_automation(single=True),
|
||||
cv.Optional(CONF_ON_END): automation.validate_automation(single=True),
|
||||
cv.Optional(CONF_ON_ERROR): automation.validate_automation(single=True),
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA)
|
||||
|
||||
@@ -37,6 +51,40 @@ async def to_code(config):
|
||||
mic = await cg.get_variable(config[CONF_MICROPHONE])
|
||||
cg.add(var.set_microphone(mic))
|
||||
|
||||
if CONF_ON_START in config:
|
||||
await automation.build_automation(
|
||||
var.get_start_trigger(), [], config[CONF_ON_START]
|
||||
)
|
||||
|
||||
if CONF_ON_STT_END in config:
|
||||
await automation.build_automation(
|
||||
var.get_stt_end_trigger(), [(cg.std_string, "x")], config[CONF_ON_STT_END]
|
||||
)
|
||||
|
||||
if CONF_ON_TTS_START in config:
|
||||
await automation.build_automation(
|
||||
var.get_tts_start_trigger(),
|
||||
[(cg.std_string, "x")],
|
||||
config[CONF_ON_TTS_START],
|
||||
)
|
||||
|
||||
if CONF_ON_TTS_END in config:
|
||||
await automation.build_automation(
|
||||
var.get_tts_end_trigger(), [(cg.std_string, "x")], config[CONF_ON_TTS_END]
|
||||
)
|
||||
|
||||
if CONF_ON_END in config:
|
||||
await automation.build_automation(
|
||||
var.get_end_trigger(), [], config[CONF_ON_END]
|
||||
)
|
||||
|
||||
if CONF_ON_ERROR in config:
|
||||
await automation.build_automation(
|
||||
var.get_error_trigger(),
|
||||
[(cg.std_string, "code"), (cg.std_string, "message")],
|
||||
config[CONF_ON_ERROR],
|
||||
)
|
||||
|
||||
cg.add_define("USE_VOICE_ASSISTANT")
|
||||
|
||||
|
||||
|
@@ -63,7 +63,10 @@ void VoiceAssistant::start(struct sockaddr_storage *addr, uint16_t port) {
|
||||
|
||||
void VoiceAssistant::request_start() {
|
||||
ESP_LOGD(TAG, "Requesting start...");
|
||||
api::global_api_server->start_voice_assistant();
|
||||
if (!api::global_api_server->start_voice_assistant()) {
|
||||
ESP_LOGW(TAG, "Could not request start.");
|
||||
this->error_trigger_->trigger("not-connected", "Could not request start.");
|
||||
}
|
||||
}
|
||||
|
||||
void VoiceAssistant::signal_stop() {
|
||||
@@ -76,8 +79,9 @@ void VoiceAssistant::signal_stop() {
|
||||
|
||||
void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) {
|
||||
switch (msg.event_type) {
|
||||
case api::enums::VOICE_ASSISTANT_RUN_END:
|
||||
ESP_LOGD(TAG, "Voice Assistant ended.");
|
||||
case api::enums::VOICE_ASSISTANT_RUN_START:
|
||||
ESP_LOGD(TAG, "Assist Pipeline running");
|
||||
this->start_trigger_->trigger();
|
||||
break;
|
||||
case api::enums::VOICE_ASSISTANT_STT_END: {
|
||||
std::string text;
|
||||
@@ -91,7 +95,7 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) {
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(TAG, "Speech recognised as: \"%s\"", text.c_str());
|
||||
// TODO `on_stt_end` trigger
|
||||
this->stt_end_trigger_->trigger(text);
|
||||
break;
|
||||
}
|
||||
case api::enums::VOICE_ASSISTANT_TTS_START: {
|
||||
@@ -106,7 +110,7 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) {
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(TAG, "Response: \"%s\"", text.c_str());
|
||||
// TODO `on_tts_start` trigger
|
||||
this->tts_start_trigger_->trigger(text);
|
||||
break;
|
||||
}
|
||||
case api::enums::VOICE_ASSISTANT_TTS_END: {
|
||||
@@ -121,9 +125,13 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) {
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(TAG, "Response URL: \"%s\"", url.c_str());
|
||||
// TODO `on_tts_end` trigger
|
||||
this->tts_end_trigger_->trigger(url);
|
||||
break;
|
||||
}
|
||||
case api::enums::VOICE_ASSISTANT_RUN_END:
|
||||
ESP_LOGD(TAG, "Assist Pipeline ended");
|
||||
this->end_trigger_->trigger();
|
||||
break;
|
||||
case api::enums::VOICE_ASSISTANT_ERROR: {
|
||||
std::string code = "";
|
||||
std::string message = "";
|
||||
@@ -135,7 +143,7 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) {
|
||||
}
|
||||
}
|
||||
ESP_LOGE(TAG, "Error: %s - %s", code.c_str(), message.c_str());
|
||||
// TODO `on_error` trigger
|
||||
this->error_trigger_->trigger(code, message);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
|
@@ -25,10 +25,24 @@ class VoiceAssistant : public Component {
|
||||
|
||||
void on_event(const api::VoiceAssistantEventResponse &msg);
|
||||
|
||||
Trigger<> *get_start_trigger() const { return this->start_trigger_; }
|
||||
Trigger<std::string> *get_stt_end_trigger() const { return this->stt_end_trigger_; }
|
||||
Trigger<std::string> *get_tts_start_trigger() const { return this->tts_start_trigger_; }
|
||||
Trigger<std::string> *get_tts_end_trigger() const { return this->tts_end_trigger_; }
|
||||
Trigger<> *get_end_trigger() const { return this->end_trigger_; }
|
||||
Trigger<std::string, std::string> *get_error_trigger() const { return this->error_trigger_; }
|
||||
|
||||
protected:
|
||||
std::unique_ptr<socket::Socket> socket_ = nullptr;
|
||||
struct sockaddr_storage dest_addr_;
|
||||
|
||||
Trigger<> *start_trigger_ = new Trigger<>();
|
||||
Trigger<std::string> *stt_end_trigger_ = new Trigger<std::string>();
|
||||
Trigger<std::string> *tts_start_trigger_ = new Trigger<std::string>();
|
||||
Trigger<std::string> *tts_end_trigger_ = new Trigger<std::string>();
|
||||
Trigger<> *end_trigger_ = new Trigger<>();
|
||||
Trigger<std::string, std::string> *error_trigger_ = new Trigger<std::string, std::string>();
|
||||
|
||||
microphone::Microphone *mic_{nullptr};
|
||||
|
||||
bool running_{false};
|
||||
|
@@ -1,6 +1,6 @@
|
||||
"""Constants used by esphome."""
|
||||
|
||||
__version__ = "2023.4.0b1"
|
||||
__version__ = "2023.4.4"
|
||||
|
||||
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
|
||||
|
||||
|
@@ -1,8 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <iterator>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include "esphome/core/defines.h"
|
||||
|
||||
#ifdef USE_JSON
|
||||
|
@@ -103,7 +103,7 @@ extra_scripts = post:esphome/components/esp8266/post_build.py.script
|
||||
; This are common settings for the ESP32 (all variants) using Arduino.
|
||||
[common:esp32-arduino]
|
||||
extends = common:arduino
|
||||
platform = platformio/espressif32 @ 5.2.0
|
||||
platform = platformio/espressif32 @ 5.3.0
|
||||
platform_packages =
|
||||
platformio/framework-arduinoespressif32 @ ~3.20005.0
|
||||
|
||||
|
@@ -696,3 +696,23 @@ microphone:
|
||||
|
||||
voice_assistant:
|
||||
microphone: mic_id
|
||||
on_start:
|
||||
- logger.log: "Voice assistant started"
|
||||
on_stt_end:
|
||||
- logger.log:
|
||||
format: "Voice assistant STT ended with result %s"
|
||||
args: [x.c_str()]
|
||||
on_tts_start:
|
||||
- logger.log:
|
||||
format: "Voice assistant TTS started with text %s"
|
||||
args: [x.c_str()]
|
||||
on_tts_end:
|
||||
- logger.log:
|
||||
format: "Voice assistant TTS ended with url %s"
|
||||
args: [x.c_str()]
|
||||
on_end:
|
||||
- logger.log: "Voice assistant ended"
|
||||
on_error:
|
||||
- logger.log:
|
||||
format: "Voice assistant error - code %s, message: %s"
|
||||
args: [code.c_str(), message.c_str()]
|
||||
|
Reference in New Issue
Block a user