1
0
mirror of https://github.com/esphome/esphome.git synced 2025-11-01 23:51:47 +00:00

Compare commits

...

22 Commits

Author SHA1 Message Date
Jesse Hills
b973238323 Merge pull request #5555 from esphome/bump-2023.10.0
2023.10.0
2023-10-18 17:38:50 +13:00
Jesse Hills
582b8383d2 Bump version to 2023.10.0 2023-10-18 16:47:03 +13:00
Jesse Hills
e1c9418aee Merge pull request #5554 from esphome/bump-2023.10.0b4
2023.10.0b4
2023-10-18 15:44:37 +13:00
Jesse Hills
2aa787f5f0 Bump version to 2023.10.0b4 2023-10-18 14:28:03 +13:00
Jesse Hills
2189a40a39 esp32_improv advertise capabilities and state in ble service data (#5553) 2023-10-18 14:28:03 +13:00
Fabian Bläse
51688d4078 SML: fix incomplete sign extension for abbreviated transmissions (#5544) 2023-10-18 14:28:03 +13:00
Jesse Hills
cc4c0e3e0b Fix default libretiny manufacturer reported to HA (#5549) 2023-10-18 14:28:02 +13:00
Jesse Hills
1a44c6487e Merge pull request #5548 from esphome/bump-2023.10.0b3
2023.10.0b3
2023-10-17 20:49:16 +13:00
Jesse Hills
5e7ce610a0 Bump version to 2023.10.0b3 2023-10-17 20:15:14 +13:00
Jesse Hills
1f02096edb More voice assistant fixes (#5547) 2023-10-17 20:15:14 +13:00
Jesse Hills
fd7d3c4332 Fix esp32_improv authorizer with no binary sensors in config (#5546) 2023-10-17 20:15:14 +13:00
Jesse Hills
61cf566560 Add stream start and end events (#5545) 2023-10-17 20:15:14 +13:00
Christian
97d624114d Add change i2c address and allow multi conf for TB6612FNG (#5492) 2023-10-17 20:15:14 +13:00
raineth
52e8a2e9e4 Make IPAddress's operator!= compare values, not memory addresses. (#5537)
Co-authored-by: Ben Winslow <rain@bluecherry.net>
2023-10-17 20:15:14 +13:00
Jesse Hills
261c271d60 Prometheus fix for esp-idf and fix newlines (#5536) 2023-10-17 20:15:14 +13:00
Jesse Hills
cb6e314336 Merge pull request #5528 from esphome/bump-2023.10.0b2
2023.10.0b2
2023-10-13 15:56:01 +13:00
Jesse Hills
90315b3c40 Bump version to 2023.10.0b2 2023-10-13 14:16:22 +13:00
Cossid
5d7c3d1622 BP1658CJ - Clear all channels before sleeping. (#5525) 2023-10-13 14:16:22 +13:00
Cossid
8c1ad1e9a6 SM10BIT_BASE - Add delays and ACKs, clear all channels before sleeping. (#5526) 2023-10-13 14:16:22 +13:00
Jesse Hills
969f6dbe13 Update Improv BLE component (#5518) 2023-10-13 14:16:22 +13:00
Cossid
6cce6d4c36 BD5758D - Add delays and ACKs (#5524) 2023-10-13 14:16:22 +13:00
Nippey
d27e5e9c97 Update htu21d.cpp, fix publishing of heater level (#5520) 2023-10-13 14:16:22 +13:00
28 changed files with 314 additions and 106 deletions

View File

@@ -1459,6 +1459,8 @@ enum VoiceAssistantEvent {
VOICE_ASSISTANT_WAKE_WORD_END = 10;
VOICE_ASSISTANT_STT_VAD_START = 11;
VOICE_ASSISTANT_STT_VAD_END = 12;
VOICE_ASSISTANT_TTS_STREAM_START = 98;
VOICE_ASSISTANT_TTS_STREAM_END = 99;
}
message VoiceAssistantEventData {

View File

@@ -452,6 +452,10 @@ template<> const char *proto_enum_to_string<enums::VoiceAssistantEvent>(enums::V
return "VOICE_ASSISTANT_STT_VAD_START";
case enums::VOICE_ASSISTANT_STT_VAD_END:
return "VOICE_ASSISTANT_STT_VAD_END";
case enums::VOICE_ASSISTANT_TTS_STREAM_START:
return "VOICE_ASSISTANT_TTS_STREAM_START";
case enums::VOICE_ASSISTANT_TTS_STREAM_END:
return "VOICE_ASSISTANT_TTS_STREAM_END";
default:
return "UNKNOWN";
}

View File

@@ -184,6 +184,8 @@ enum VoiceAssistantEvent : uint32_t {
VOICE_ASSISTANT_WAKE_WORD_END = 10,
VOICE_ASSISTANT_STT_VAD_START = 11,
VOICE_ASSISTANT_STT_VAD_END = 12,
VOICE_ASSISTANT_TTS_STREAM_START = 98,
VOICE_ASSISTANT_TTS_STREAM_END = 99,
};
enum AlarmControlPanelState : uint32_t {
ALARM_STATE_DISARMED = 0,

View File

@@ -37,10 +37,14 @@ void BP1658CJ::loop() {
uint8_t data[12];
if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 &&
this->pwm_amounts_[3] == 0 && this->pwm_amounts_[4] == 0) {
// Off / Sleep
data[0] = BP1658CJ_MODEL_ID + BP1658CJ_ADDR_STANDBY;
for (int i = 1; i < 12; i++)
data[i] = 0;
// First turn all channels off
data[0] = BP1658CJ_MODEL_ID + BP1658CJ_ADDR_START_5CH;
this->write_buffer_(data, 12);
// Then sleep
data[0] = BP1658CJ_MODEL_ID + BP1658CJ_ADDR_STANDBY;
this->write_buffer_(data, 12);
} else if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 &&
(this->pwm_amounts_[3] > 0 || this->pwm_amounts_[4] > 0)) {

View File

@@ -17,12 +17,16 @@ static const uint8_t BP5758D_ADDR_START_2CH = 0b00100000;
static const uint8_t BP5758D_ADDR_START_5CH = 0b00110000;
static const uint8_t BP5758D_ALL_DATA_CHANNEL_ENABLEMENT = 0b00011111;
static const uint8_t BP5758D_DELAY = 2;
void BP5758D::setup() {
ESP_LOGCONFIG(TAG, "Setting up BP5758D Output Component...");
this->data_pin_->setup();
this->data_pin_->digital_write(false);
delayMicroseconds(BP5758D_DELAY);
this->clock_pin_->setup();
this->clock_pin_->digital_write(false);
delayMicroseconds(BP5758D_DELAY);
this->channel_current_.resize(5, 0);
this->pwm_amounts_.resize(5, 0);
}
@@ -39,11 +43,11 @@ void BP5758D::loop() {
uint8_t data[17];
if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 &&
this->pwm_amounts_[3] == 0 && this->pwm_amounts_[4] == 0) {
for (int i = 1; i < 16; i++)
for (int i = 1; i < 17; i++)
data[i] = 0;
// First turn all channels off
data[0] = BP5758D_MODEL_ID + BP5758D_ADDR_START_3CH;
data[0] = BP5758D_MODEL_ID + BP5758D_ADDR_START_5CH;
this->write_buffer_(data, 17);
// Then sleep
data[0] = BP5758D_MODEL_ID + BP5758D_ADDR_STANDBY;
@@ -123,28 +127,42 @@ void BP5758D::set_channel_value_(uint8_t channel, uint16_t value) {
void BP5758D::set_channel_current_(uint8_t channel, uint8_t current) { this->channel_current_[channel] = current; }
void BP5758D::write_bit_(bool value) {
this->clock_pin_->digital_write(false);
this->data_pin_->digital_write(value);
delayMicroseconds(BP5758D_DELAY);
this->clock_pin_->digital_write(true);
delayMicroseconds(BP5758D_DELAY);
this->clock_pin_->digital_write(false);
delayMicroseconds(BP5758D_DELAY);
}
void BP5758D::write_byte_(uint8_t data) {
for (uint8_t mask = 0x80; mask; mask >>= 1) {
this->write_bit_(data & mask);
}
this->clock_pin_->digital_write(false);
this->data_pin_->digital_write(true);
// ack bit
this->data_pin_->pin_mode(gpio::FLAG_INPUT);
this->clock_pin_->digital_write(true);
delayMicroseconds(BP5758D_DELAY);
this->clock_pin_->digital_write(false);
delayMicroseconds(BP5758D_DELAY);
this->data_pin_->pin_mode(gpio::FLAG_OUTPUT);
}
void BP5758D::write_buffer_(uint8_t *buffer, uint8_t size) {
this->data_pin_->digital_write(false);
delayMicroseconds(BP5758D_DELAY);
this->clock_pin_->digital_write(false);
delayMicroseconds(BP5758D_DELAY);
for (uint32_t i = 0; i < size; i++) {
this->write_byte_(buffer[i]);
}
this->clock_pin_->digital_write(false);
this->clock_pin_->digital_write(true);
delayMicroseconds(BP5758D_DELAY);
this->data_pin_->digital_write(true);
delayMicroseconds(BP5758D_DELAY);
}
} // namespace bp5758d

View File

@@ -2,9 +2,9 @@
#ifdef USE_ESP32
#include "ble_uuid.h"
#include <cstring>
#include <cstdio>
#include <cstring>
#include "ble_uuid.h"
#include "esphome/core/log.h"
namespace esphome {
@@ -16,8 +16,8 @@ BLEAdvertising::BLEAdvertising() {
this->advertising_data_.set_scan_rsp = false;
this->advertising_data_.include_name = true;
this->advertising_data_.include_txpower = true;
this->advertising_data_.min_interval = 0x20;
this->advertising_data_.max_interval = 0x40;
this->advertising_data_.min_interval = 0;
this->advertising_data_.max_interval = 0;
this->advertising_data_.appearance = 0x00;
this->advertising_data_.manufacturer_len = 0;
this->advertising_data_.p_manufacturer_data = nullptr;
@@ -42,6 +42,17 @@ void BLEAdvertising::remove_service_uuid(ESPBTUUID uuid) {
this->advertising_uuids_.end());
}
void BLEAdvertising::set_service_data(const std::vector<uint8_t> &data) {
delete[] this->advertising_data_.p_service_data;
this->advertising_data_.p_service_data = nullptr;
this->advertising_data_.service_data_len = data.size();
if (!data.empty()) {
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
this->advertising_data_.p_service_data = new uint8_t[data.size()];
memcpy(this->advertising_data_.p_service_data, data.data(), data.size());
}
}
void BLEAdvertising::set_manufacturer_data(const std::vector<uint8_t> &data) {
delete[] this->advertising_data_.p_manufacturer_data;
this->advertising_data_.p_manufacturer_data = nullptr;
@@ -85,8 +96,6 @@ void BLEAdvertising::start() {
this->scan_response_data_.set_scan_rsp = true;
this->scan_response_data_.include_name = true;
this->scan_response_data_.include_txpower = true;
this->scan_response_data_.min_interval = 0;
this->scan_response_data_.max_interval = 0;
this->scan_response_data_.manufacturer_len = 0;
this->scan_response_data_.appearance = 0;
this->scan_response_data_.flag = 0;

View File

@@ -21,6 +21,7 @@ class BLEAdvertising {
void set_scan_response(bool scan_response) { this->scan_response_ = scan_response; }
void set_min_preferred_interval(uint16_t interval) { this->advertising_data_.min_interval = interval; }
void set_manufacturer_data(const std::vector<uint8_t> &data);
void set_service_data(const std::vector<uint8_t> &data);
void start();
void stop();

View File

@@ -90,6 +90,8 @@ void BLEService::stop() {
ESP_LOGE(TAG, "esp_ble_gatts_stop_service failed: %d", err);
return;
}
esp32_ble::global_ble->get_advertising()->remove_service_uuid(this->uuid_);
esp32_ble::global_ble->get_advertising()->start();
this->running_state_ = STOPPING;
}

View File

@@ -7,11 +7,11 @@
#ifdef USE_ESP32
#include <esp_bt_defs.h>
#include <esp_gap_ble_api.h>
#include <esp_gatt_defs.h>
#include <esp_gattc_api.h>
#include <esp_gatts_api.h>
#include <esp_bt_defs.h>
namespace esphome {
namespace esp32_ble_server {

View File

@@ -4,7 +4,7 @@ from esphome.components import binary_sensor, output, esp32_ble_server
from esphome.const import CONF_ID
AUTO_LOAD = ["binary_sensor", "output", "esp32_ble_server"]
AUTO_LOAD = ["esp32_ble_server"]
CODEOWNERS = ["@jesserockz"]
CONFLICTS_WITH = ["esp32_ble_beacon"]
DEPENDENCIES = ["wifi", "esp32"]

View File

@@ -18,6 +18,17 @@ ESP32ImprovComponent::ESP32ImprovComponent() { global_improv_component = this; }
void ESP32ImprovComponent::setup() {
this->service_ = global_ble_server->create_service(improv::SERVICE_UUID, true);
this->setup_characteristics();
#ifdef USE_BINARY_SENSOR
if (this->authorizer_ != nullptr) {
this->authorizer_->add_on_state_callback([this](bool state) {
if (state) {
this->authorized_start_ = millis();
this->identify_start_ = 0;
}
});
}
#endif
}
void ESP32ImprovComponent::setup_characteristics() {
@@ -50,8 +61,10 @@ void ESP32ImprovComponent::setup_characteristics() {
BLEDescriptor *capabilities_descriptor = new BLE2902();
this->capabilities_->add_descriptor(capabilities_descriptor);
uint8_t capabilities = 0x00;
#ifdef USE_OUTPUT
if (this->status_indicator_ != nullptr)
capabilities |= improv::CAPABILITY_IDENTIFY;
#endif
this->capabilities_->set_value(capabilities);
this->setup_complete_ = true;
}
@@ -63,8 +76,7 @@ void ESP32ImprovComponent::loop() {
switch (this->state_) {
case improv::STATE_STOPPED:
if (this->status_indicator_ != nullptr)
this->status_indicator_->turn_off();
this->set_status_indicator_state_(false);
if (this->service_->is_created() && this->should_start_ && this->setup_complete_) {
if (this->service_->is_running()) {
@@ -80,18 +92,22 @@ void ESP32ImprovComponent::loop() {
}
break;
case improv::STATE_AWAITING_AUTHORIZATION: {
if (this->authorizer_ == nullptr || this->authorizer_->state) {
#ifdef USE_BINARY_SENSOR
if (this->authorizer_ == nullptr ||
(this->authorized_start_ != 0 && ((now - this->authorized_start_) < this->authorized_duration_))) {
this->set_state_(improv::STATE_AUTHORIZED);
this->authorized_start_ = now;
} else {
if (this->status_indicator_ != nullptr) {
if (!this->check_identify_())
this->status_indicator_->turn_on();
}
} else
#else
this->set_state_(improv::STATE_AUTHORIZED);
#endif
{
if (!this->check_identify_())
this->set_status_indicator_state_(true);
}
break;
}
case improv::STATE_AUTHORIZED: {
#ifdef USE_BINARY_SENSOR
if (this->authorizer_ != nullptr) {
if (now - this->authorized_start_ > this->authorized_duration_) {
ESP_LOGD(TAG, "Authorization timeout");
@@ -99,25 +115,14 @@ void ESP32ImprovComponent::loop() {
return;
}
}
if (this->status_indicator_ != nullptr) {
if (!this->check_identify_()) {
if ((now % 1000) < 500) {
this->status_indicator_->turn_on();
} else {
this->status_indicator_->turn_off();
}
}
#endif
if (!this->check_identify_()) {
this->set_status_indicator_state_((now % 1000) < 500);
}
break;
}
case improv::STATE_PROVISIONING: {
if (this->status_indicator_ != nullptr) {
if ((now % 200) < 100) {
this->status_indicator_->turn_on();
} else {
this->status_indicator_->turn_off();
}
}
this->set_status_indicator_state_((now % 200) < 100);
if (wifi::global_wifi_component->is_connected()) {
wifi::global_wifi_component->save_wifi_sta(this->connecting_sta_.get_ssid(),
this->connecting_sta_.get_password());
@@ -142,13 +147,27 @@ void ESP32ImprovComponent::loop() {
}
case improv::STATE_PROVISIONED: {
this->incoming_data_.clear();
if (this->status_indicator_ != nullptr)
this->status_indicator_->turn_off();
this->set_status_indicator_state_(false);
break;
}
}
}
void ESP32ImprovComponent::set_status_indicator_state_(bool state) {
#ifdef USE_OUTPUT
if (this->status_indicator_ == nullptr)
return;
if (this->status_indicator_state_ == state)
return;
this->status_indicator_state_ = state;
if (state) {
this->status_indicator_->turn_on();
} else {
this->status_indicator_->turn_off();
}
#endif
}
bool ESP32ImprovComponent::check_identify_() {
uint32_t now = millis();
@@ -156,11 +175,7 @@ bool ESP32ImprovComponent::check_identify_() {
if (identify) {
uint32_t time = now % 1000;
if (time < 600 && time % 200 < 100) {
this->status_indicator_->turn_on();
} else {
this->status_indicator_->turn_off();
}
this->set_status_indicator_state_(time < 600 && time % 200 < 100);
}
return identify;
}
@@ -174,6 +189,25 @@ void ESP32ImprovComponent::set_state_(improv::State state) {
if (state != improv::STATE_STOPPED)
this->status_->notify();
}
std::vector<uint8_t> service_data(8, 0);
service_data[0] = 0x77; // PR
service_data[1] = 0x46; // IM
service_data[2] = static_cast<uint8_t>(state);
uint8_t capabilities = 0x00;
#ifdef USE_OUTPUT
if (this->status_indicator_ != nullptr)
capabilities |= improv::CAPABILITY_IDENTIFY;
#endif
service_data[3] = capabilities;
service_data[4] = 0x00; // Reserved
service_data[5] = 0x00; // Reserved
service_data[6] = 0x00; // Reserved
service_data[7] = 0x00; // Reserved
esp32_ble::global_ble->get_advertising()->set_service_data(service_data);
esp32_ble::global_ble->get_advertising()->start();
}
void ESP32ImprovComponent::set_error_(improv::Error error) {
@@ -213,8 +247,12 @@ float ESP32ImprovComponent::get_setup_priority() const { return setup_priority::
void ESP32ImprovComponent::dump_config() {
ESP_LOGCONFIG(TAG, "ESP32 Improv:");
#ifdef USE_BINARY_SENSOR
LOG_BINARY_SENSOR(" ", "Authorizer", this->authorizer_);
#endif
#ifdef USE_OUTPUT
ESP_LOGCONFIG(TAG, " Status Indicator: '%s'", YESNO(this->status_indicator_ != nullptr));
#endif
}
void ESP32ImprovComponent::process_incoming_data_() {
@@ -273,8 +311,10 @@ void ESP32ImprovComponent::process_incoming_data_() {
void ESP32ImprovComponent::on_wifi_connect_timeout_() {
this->set_error_(improv::ERROR_UNABLE_TO_CONNECT);
this->set_state_(improv::STATE_AUTHORIZED);
#ifdef USE_BINARY_SENSOR
if (this->authorizer_ != nullptr)
this->authorized_start_ = millis();
#endif
ESP_LOGW(TAG, "Timed out trying to connect to given WiFi network");
wifi::global_wifi_component->clear_sta();
}

View File

@@ -1,14 +1,22 @@
#pragma once
#include "esphome/components/binary_sensor/binary_sensor.h"
#include "esphome/components/esp32_ble_server/ble_characteristic.h"
#include "esphome/components/esp32_ble_server/ble_server.h"
#include "esphome/components/output/binary_output.h"
#include "esphome/components/wifi/wifi_component.h"
#include "esphome/core/component.h"
#include "esphome/core/defines.h"
#include "esphome/core/helpers.h"
#include "esphome/core/preferences.h"
#include "esphome/components/esp32_ble_server/ble_characteristic.h"
#include "esphome/components/esp32_ble_server/ble_server.h"
#include "esphome/components/wifi/wifi_component.h"
#ifdef USE_BINARY_SENSOR
#include "esphome/components/binary_sensor/binary_sensor.h"
#endif
#ifdef USE_OUTPUT
#include "esphome/components/output/binary_output.h"
#endif
#include <vector>
#ifdef USE_ESP32
@@ -34,8 +42,12 @@ class ESP32ImprovComponent : public Component, public BLEServiceComponent {
void stop() override;
bool is_active() const { return this->state_ != improv::STATE_STOPPED; }
#ifdef USE_BINARY_SENSOR
void set_authorizer(binary_sensor::BinarySensor *authorizer) { this->authorizer_ = authorizer; }
#endif
#ifdef USE_OUTPUT
void set_status_indicator(output::BinaryOutput *status_indicator) { this->status_indicator_ = status_indicator; }
#endif
void set_identify_duration(uint32_t identify_duration) { this->identify_duration_ = identify_duration; }
void set_authorized_duration(uint32_t authorized_duration) { this->authorized_duration_ = authorized_duration; }
@@ -58,12 +70,19 @@ class ESP32ImprovComponent : public Component, public BLEServiceComponent {
BLECharacteristic *rpc_response_;
BLECharacteristic *capabilities_;
#ifdef USE_BINARY_SENSOR
binary_sensor::BinarySensor *authorizer_{nullptr};
#endif
#ifdef USE_OUTPUT
output::BinaryOutput *status_indicator_{nullptr};
#endif
improv::State state_{improv::STATE_STOPPED};
improv::Error error_state_{improv::ERROR_NONE};
bool status_indicator_state_{false};
void set_status_indicator_state_(bool state);
void set_state_(improv::State state);
void set_error_(improv::Error error);
void send_response_(std::vector<uint8_t> &response);

View File

@@ -8,12 +8,15 @@ from esphome.const import (
CONF_CHANNEL,
CONF_SPEED,
CONF_DIRECTION,
CONF_ADDRESS,
)
DEPENDENCIES = ["i2c"]
CODEOWNERS = ["@max246"]
MULTI_CONF = True
grove_tb6612fng_ns = cg.esphome_ns.namespace("grove_tb6612fng")
GROVE_TB6612FNG = grove_tb6612fng_ns.class_(
"GroveMotorDriveTB6612FNG", cg.Component, i2c.I2CDevice
@@ -33,6 +36,9 @@ GROVETB6612FNGMotorStandbyAction = grove_tb6612fng_ns.class_(
GROVETB6612FNGMotorNoStandbyAction = grove_tb6612fng_ns.class_(
"GROVETB6612FNGMotorNoStandbyAction", automation.Action
)
GROVETB6612FNGMotorChangeAddressAction = grove_tb6612fng_ns.class_(
"GROVETB6612FNGMotorChangeAddressAction", automation.Action
)
DIRECTION_TYPE = {
"FORWARD": 1,
@@ -150,3 +156,22 @@ async def grove_tb6612fng_no_standby_to_code(config, action_id, template_arg, ar
await cg.register_parented(var, config[CONF_ID])
return var
@automation.register_action(
"grove_tb6612fng.change_address",
GROVETB6612FNGMotorChangeAddressAction,
cv.Schema(
{
cv.Required(CONF_ID): cv.use_id(GROVE_TB6612FNG),
cv.Required(CONF_ADDRESS): cv.i2c_address,
}
),
)
async def grove_tb6612fng_change_address_to_code(config, action_id, template_arg, args):
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
template_channel = await cg.templatable(config[CONF_ADDRESS], args, int)
cg.add(var.set_address(template_channel))
return var

View File

@@ -84,8 +84,7 @@ class GroveMotorDriveTB6612FNG : public Component, public i2c::I2CDevice {
*************************************************************/
void set_i2c_addr(uint8_t addr);
/*************************************************************
Description
/***********************************change_address
Drive a motor.
Parameter
chl: MOTOR_CHA or MOTOR_CHB
@@ -204,5 +203,13 @@ class GROVETB6612FNGMotorNoStandbyAction : public Action<Ts...>, public Parented
void play(Ts... x) override { this->parent_->not_standby(); }
};
template<typename... Ts>
class GROVETB6612FNGMotorChangeAddressAction : public Action<Ts...>, public Parented<GroveMotorDriveTB6612FNG> {
public:
TEMPLATABLE_VALUE(uint8_t, address)
void play(Ts... x) override { this->parent_->set_i2c_addr(this->address_.value(x...)); }
};
} // namespace grove_tb6612fng
} // namespace esphome

View File

@@ -76,7 +76,7 @@ void HTU21DComponent::update() {
if (this->humidity_ != nullptr)
this->humidity_->publish_state(humidity);
if (this->heater_ != nullptr)
this->heater_->publish_state(humidity);
this->heater_->publish_state(heater_level);
this->status_clear_warning();
}

View File

@@ -37,6 +37,8 @@ void I2SAudioMicrophone::setup() {
void I2SAudioMicrophone::start() {
if (this->is_failed())
return;
if (this->state_ == microphone::STATE_RUNNING)
return; // Already running
this->state_ = microphone::STATE_STARTING;
}
void I2SAudioMicrophone::start_() {

View File

@@ -158,8 +158,13 @@ void I2SAudioSpeaker::watch_() {
if (xQueueReceive(this->event_queue_, &event, 0) == pdTRUE) {
switch (event.type) {
case TaskEventType::STARTING:
ESP_LOGD(TAG, "Starting I2S Audio Speaker");
break;
case TaskEventType::STARTED:
ESP_LOGD(TAG, "Started I2S Audio Speaker");
break;
case TaskEventType::STOPPING:
ESP_LOGD(TAG, "Stopping I2S Audio Speaker");
break;
case TaskEventType::PLAYING:
this->status_clear_warning();
@@ -170,6 +175,7 @@ void I2SAudioSpeaker::watch_() {
this->player_task_handle_ = nullptr;
this->parent_->unlock();
xQueueReset(this->buffer_queue_);
ESP_LOGD(TAG, "Stopped I2S Audio Speaker");
break;
case TaskEventType::WARNING:
ESP_LOGW(TAG, "Error writing to I2S: %s", esp_err_to_name(event.err));

View File

@@ -251,7 +251,7 @@ async def component_to_code(config):
# setup board config
cg.add_platformio_option("board", config[CONF_BOARD])
cg.add_build_flag("-DUSE_LIBRETINY")
cg.add_build_flag(f"-DUSE_{config[CONF_COMPONENT_ID]}")
cg.add_build_flag(f"-DUSE_{config[CONF_COMPONENT_ID].upper()}")
cg.add_build_flag(f"-DUSE_LIBRETINY_VARIANT_{config[CONF_FAMILY]}")
cg.add_define("ESPHOME_BOARD", config[CONF_BOARD])
cg.add_define("ESPHOME_VARIANT", FAMILY_FRIENDLY[config[CONF_FAMILY]])

View File

@@ -87,7 +87,7 @@ struct IPAddress {
bool is_ip6() { return IP_IS_V6(&ip_addr_); }
std::string str() const { return ipaddr_ntoa(&ip_addr_); }
bool operator==(const IPAddress &other) const { return ip_addr_cmp(&ip_addr_, &other.ip_addr_); }
bool operator!=(const IPAddress &other) const { return !(&ip_addr_ == &other.ip_addr_); }
bool operator!=(const IPAddress &other) const { return !ip_addr_cmp(&ip_addr_, &other.ip_addr_); }
IPAddress &operator+=(uint8_t increase) {
if (IP_IS_V4(&ip_addr_)) {
#if LWIP_IPV6

View File

@@ -106,4 +106,5 @@ async def output_set_level_to_code(config, action_id, template_arg, args):
async def to_code(config):
cg.add_define("USE_OUTPUT")
cg.add_global(output_ns.using)

View File

@@ -1,5 +1,3 @@
#ifdef USE_ARDUINO
#include "prometheus_handler.h"
#include "esphome/core/application.h"
@@ -89,7 +87,7 @@ void PrometheusHandler::sensor_row_(AsyncResponseStream *stream, sensor::Sensor
stream->print(obj->get_unit_of_measurement().c_str());
stream->print(F("\"} "));
stream->print(value_accuracy_to_string(obj->state, obj->get_accuracy_decimals()).c_str());
stream->print('\n');
stream->print(F("\n"));
} else {
// Invalid state
stream->print(F("esphome_sensor_failed{id=\""));
@@ -124,7 +122,7 @@ void PrometheusHandler::binary_sensor_row_(AsyncResponseStream *stream, binary_s
stream->print(relabel_name_(obj).c_str());
stream->print(F("\"} "));
stream->print(obj->state);
stream->print('\n');
stream->print(F("\n"));
} else {
// Invalid state
stream->print(F("esphome_binary_sensor_failed{id=\""));
@@ -158,7 +156,7 @@ void PrometheusHandler::fan_row_(AsyncResponseStream *stream, fan::Fan *obj) {
stream->print(relabel_name_(obj).c_str());
stream->print(F("\"} "));
stream->print(obj->state);
stream->print('\n');
stream->print(F("\n"));
// Speed if available
if (obj->get_traits().supports_speed()) {
stream->print(F("esphome_fan_speed{id=\""));
@@ -167,7 +165,7 @@ void PrometheusHandler::fan_row_(AsyncResponseStream *stream, fan::Fan *obj) {
stream->print(relabel_name_(obj).c_str());
stream->print(F("\"} "));
stream->print(obj->speed);
stream->print('\n');
stream->print(F("\n"));
}
// Oscillation if available
if (obj->get_traits().supports_oscillation()) {
@@ -177,7 +175,7 @@ void PrometheusHandler::fan_row_(AsyncResponseStream *stream, fan::Fan *obj) {
stream->print(relabel_name_(obj).c_str());
stream->print(F("\"} "));
stream->print(obj->oscillating);
stream->print('\n');
stream->print(F("\n"));
}
}
#endif
@@ -281,7 +279,7 @@ void PrometheusHandler::cover_row_(AsyncResponseStream *stream, cover::Cover *ob
stream->print(relabel_name_(obj).c_str());
stream->print(F("\"} "));
stream->print(obj->position);
stream->print('\n');
stream->print(F("\n"));
if (obj->get_traits().get_supports_tilt()) {
stream->print(F("esphome_cover_tilt{id=\""));
stream->print(relabel_id_(obj).c_str());
@@ -289,7 +287,7 @@ void PrometheusHandler::cover_row_(AsyncResponseStream *stream, cover::Cover *ob
stream->print(relabel_name_(obj).c_str());
stream->print(F("\"} "));
stream->print(obj->tilt);
stream->print('\n');
stream->print(F("\n"));
}
} else {
// Invalid state
@@ -322,7 +320,7 @@ void PrometheusHandler::switch_row_(AsyncResponseStream *stream, switch_::Switch
stream->print(relabel_name_(obj).c_str());
stream->print(F("\"} "));
stream->print(obj->state);
stream->print('\n');
stream->print(F("\n"));
}
#endif
@@ -346,11 +344,9 @@ void PrometheusHandler::lock_row_(AsyncResponseStream *stream, lock::Lock *obj)
stream->print(relabel_name_(obj).c_str());
stream->print(F("\"} "));
stream->print(obj->state);
stream->print('\n');
stream->print(F("\n"));
}
#endif
} // namespace prometheus
} // namespace esphome
#endif // USE_ARDUINO

View File

@@ -1,14 +1,12 @@
#pragma once
#ifdef USE_ARDUINO
#include <map>
#include <utility>
#include "esphome/core/entity_base.h"
#include "esphome/components/web_server_base/web_server_base.h"
#include "esphome/core/controller.h"
#include "esphome/core/component.h"
#include "esphome/core/controller.h"
#include "esphome/core/entity_base.h"
namespace esphome {
namespace prometheus {
@@ -119,5 +117,3 @@ class PrometheusHandler : public AsyncWebHandler, public Component {
} // namespace prometheus
} // namespace esphome
#endif // USE_ARDUINO

View File

@@ -11,6 +11,8 @@ static const uint8_t SM10BIT_ADDR_START_3CH = 0x8;
static const uint8_t SM10BIT_ADDR_START_2CH = 0x10;
static const uint8_t SM10BIT_ADDR_START_5CH = 0x18;
static const uint8_t SM10BIT_DELAY = 2;
// Power current values
// HEX | Binary | RGB level | White level | Config value
// 0x0 | 0000 | RGB 10mA | CW 5mA | 0
@@ -37,10 +39,13 @@ void Sm10BitBase::loop() {
uint8_t data[12];
if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 &&
this->pwm_amounts_[3] == 0 && this->pwm_amounts_[4] == 0) {
// Off / Sleep
data[0] = this->model_id_ + SM10BIT_ADDR_STANDBY;
for (int i = 1; i < 12; i++)
data[i] = 0;
// First turn all channels off
data[0] = this->model_id_ + SM10BIT_ADDR_START_5CH;
this->write_buffer_(data, 12);
// Then sleep
data[0] = this->model_id_ + SM10BIT_ADDR_STANDBY;
this->write_buffer_(data, 12);
} else if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 &&
(this->pwm_amounts_[3] > 0 || this->pwm_amounts_[4] > 0)) {
@@ -84,28 +89,42 @@ void Sm10BitBase::set_channel_value_(uint8_t channel, uint16_t value) {
this->pwm_amounts_[channel] = value;
}
void Sm10BitBase::write_bit_(bool value) {
this->clock_pin_->digital_write(false);
this->data_pin_->digital_write(value);
delayMicroseconds(SM10BIT_DELAY);
this->clock_pin_->digital_write(true);
delayMicroseconds(SM10BIT_DELAY);
this->clock_pin_->digital_write(false);
delayMicroseconds(SM10BIT_DELAY);
}
void Sm10BitBase::write_byte_(uint8_t data) {
for (uint8_t mask = 0x80; mask; mask >>= 1) {
this->write_bit_(data & mask);
}
this->clock_pin_->digital_write(false);
this->data_pin_->digital_write(true);
// ack bit
this->data_pin_->pin_mode(gpio::FLAG_INPUT);
this->clock_pin_->digital_write(true);
delayMicroseconds(SM10BIT_DELAY);
this->clock_pin_->digital_write(false);
delayMicroseconds(SM10BIT_DELAY);
this->data_pin_->pin_mode(gpio::FLAG_OUTPUT);
}
void Sm10BitBase::write_buffer_(uint8_t *buffer, uint8_t size) {
this->data_pin_->digital_write(false);
delayMicroseconds(SM10BIT_DELAY);
this->clock_pin_->digital_write(false);
delayMicroseconds(SM10BIT_DELAY);
for (uint32_t i = 0; i < size; i++) {
this->write_byte_(buffer[i]);
}
this->clock_pin_->digital_write(false);
this->clock_pin_->digital_write(true);
delayMicroseconds(SM10BIT_DELAY);
this->data_pin_->digital_write(true);
delayMicroseconds(SM10BIT_DELAY);
}
} // namespace sm10bit_base

View File

@@ -88,11 +88,6 @@ uint64_t bytes_to_uint(const bytes &buffer) {
for (auto const value : buffer) {
val = (val << 8) + value;
}
// Some smart meters send 24 bit signed integers. Sign extend to 64 bit if the
// 24 bit value is negative.
if (buffer.size() == 3 && buffer[0] & 0x80) {
val |= 0xFFFFFFFFFF000000;
}
return val;
}
@@ -100,19 +95,15 @@ int64_t bytes_to_int(const bytes &buffer) {
uint64_t tmp = bytes_to_uint(buffer);
int64_t val;
switch (buffer.size()) {
case 1: // int8
val = (int8_t) tmp;
break;
case 2: // int16
val = (int16_t) tmp;
break;
case 4: // int32
val = (int32_t) tmp;
break;
default: // int64
val = (int64_t) tmp;
// sign extension for abbreviations of leading ones (e.g. 3 byte transmissions, see 6.2.2 of SML protocol definition)
// see https://stackoverflow.com/questions/42534749/signed-extension-from-24-bit-to-32-bit-in-c
if (buffer.size() < 8) {
const int bits = buffer.size() * 8;
const uint64_t m = 1u << (bits - 1);
tmp = (tmp ^ m) - m;
}
val = (int64_t) tmp;
return val;
}

View File

@@ -281,11 +281,15 @@ void VoiceAssistant::loop() {
memmove(this->speaker_buffer_, this->speaker_buffer_ + written, this->speaker_buffer_size_ - written);
this->speaker_buffer_size_ -= written;
this->speaker_buffer_index_ -= written;
this->set_timeout("speaker-timeout", 1000, [this]() { this->speaker_->stop(); });
this->set_timeout("speaker-timeout", 2000, [this]() { this->speaker_->stop(); });
} else {
ESP_LOGW(TAG, "Speaker buffer full.");
}
}
if (this->wait_for_stream_end_) {
this->cancel_timeout("playing");
break; // We dont want to timeout here as the STREAM_END event will take care of that.
}
playing = this->speaker_->is_running();
}
#endif
@@ -295,28 +299,77 @@ void VoiceAssistant::loop() {
}
#endif
if (playing) {
this->set_timeout("playing", 100, [this]() {
this->set_timeout("playing", 2000, [this]() {
this->cancel_timeout("speaker-timeout");
this->set_state_(State::IDLE, State::IDLE);
});
}
break;
}
case State::RESPONSE_FINISHED: {
#ifdef USE_SPEAKER
if (this->speaker_ != nullptr) {
this->speaker_->stop();
this->cancel_timeout("speaker-timeout");
this->cancel_timeout("playing");
this->speaker_buffer_size_ = 0;
this->speaker_buffer_index_ = 0;
memset(this->speaker_buffer_, 0, SPEAKER_BUFFER_SIZE);
}
#endif
this->wait_for_stream_end_ = false;
this->set_state_(State::IDLE, State::IDLE);
break;
}
default:
break;
}
}
static const LogString *voice_assistant_state_to_string(State state) {
switch (state) {
case State::IDLE:
return LOG_STR("IDLE");
case State::START_MICROPHONE:
return LOG_STR("START_MICROPHONE");
case State::STARTING_MICROPHONE:
return LOG_STR("STARTING_MICROPHONE");
case State::WAIT_FOR_VAD:
return LOG_STR("WAIT_FOR_VAD");
case State::WAITING_FOR_VAD:
return LOG_STR("WAITING_FOR_VAD");
case State::START_PIPELINE:
return LOG_STR("START_PIPELINE");
case State::STARTING_PIPELINE:
return LOG_STR("STARTING_PIPELINE");
case State::STREAMING_MICROPHONE:
return LOG_STR("STREAMING_MICROPHONE");
case State::STOP_MICROPHONE:
return LOG_STR("STOP_MICROPHONE");
case State::STOPPING_MICROPHONE:
return LOG_STR("STOPPING_MICROPHONE");
case State::AWAITING_RESPONSE:
return LOG_STR("AWAITING_RESPONSE");
case State::STREAMING_RESPONSE:
return LOG_STR("STREAMING_RESPONSE");
case State::RESPONSE_FINISHED:
return LOG_STR("RESPONSE_FINISHED");
default:
return LOG_STR("UNKNOWN");
}
};
void VoiceAssistant::set_state_(State state) {
State old_state = this->state_;
this->state_ = state;
ESP_LOGD(TAG, "State changed from %d to %d", static_cast<uint8_t>(old_state), static_cast<uint8_t>(state));
ESP_LOGD(TAG, "State changed from %s to %s", LOG_STR_ARG(voice_assistant_state_to_string(old_state)),
LOG_STR_ARG(voice_assistant_state_to_string(state)));
}
void VoiceAssistant::set_state_(State state, State desired_state) {
this->set_state_(state);
this->desired_state_ = desired_state;
ESP_LOGD(TAG, "Desired state set to %d", static_cast<uint8_t>(desired_state));
ESP_LOGD(TAG, "Desired state set to %s", LOG_STR_ARG(voice_assistant_state_to_string(desired_state)));
}
void VoiceAssistant::failed_to_start() {
@@ -400,6 +453,7 @@ void VoiceAssistant::request_stop() {
break;
case State::AWAITING_RESPONSE:
case State::STREAMING_RESPONSE:
case State::RESPONSE_FINISHED:
break; // Let the incoming audio stream finish then it will go to idle.
}
}
@@ -531,6 +585,14 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) {
this->error_trigger_->trigger(code, message);
break;
}
case api::enums::VOICE_ASSISTANT_TTS_STREAM_START: {
this->wait_for_stream_end_ = true;
break;
}
case api::enums::VOICE_ASSISTANT_TTS_STREAM_END: {
this->set_state_(State::RESPONSE_FINISHED, State::IDLE);
break;
}
default:
ESP_LOGD(TAG, "Unhandled event type: %d", msg.event_type);
break;

View File

@@ -46,6 +46,7 @@ enum class State {
STOPPING_MICROPHONE,
AWAITING_RESPONSE,
STREAMING_RESPONSE,
RESPONSE_FINISHED,
};
class VoiceAssistant : public Component {
@@ -132,10 +133,10 @@ class VoiceAssistant : public Component {
uint8_t *speaker_buffer_;
size_t speaker_buffer_index_{0};
size_t speaker_buffer_size_{0};
bool wait_for_stream_end_{false};
#endif
#ifdef USE_MEDIA_PLAYER
media_player::MediaPlayer *media_player_{nullptr};
bool playing_tts_{false};
#endif
bool local_output_{false};

View File

@@ -1,6 +1,6 @@
"""Constants used by esphome."""
__version__ = "2023.10.0b1"
__version__ = "2023.10.0"
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
VALID_SUBSTITUTIONS_CHARACTERS = (

View File

@@ -37,6 +37,7 @@
#define USE_OTA
#define USE_OTA_PASSWORD
#define USE_OTA_STATE_CALLBACK
#define USE_OUTPUT
#define USE_POWER_SUPPLY
#define USE_QR_CODE
#define USE_SELECT
@@ -117,6 +118,6 @@
#endif
// Disabled feature flags
//#define USE_BSEC // Requires a library with proprietary license.
// #define USE_BSEC // Requires a library with proprietary license.
#define USE_DASHBOARD_IMPORT