mirror of
https://github.com/esphome/esphome.git
synced 2025-11-05 09:31:54 +00:00
Compare commits
29 Commits
2024.2.0b2
...
2024.2.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
833affc1bf | ||
|
|
e2b197dc2c | ||
|
|
f39dc49f49 | ||
|
|
b0a25401f7 | ||
|
|
37d2b3c797 | ||
|
|
63cce916e2 | ||
|
|
1aab87b41c | ||
|
|
a3fc1acdcb | ||
|
|
cc115e7cc9 | ||
|
|
badac933ae | ||
|
|
b1b8217713 | ||
|
|
f3174c58bc | ||
|
|
e66e135a63 | ||
|
|
d814ed1d4a | ||
|
|
84c6e52be2 | ||
|
|
2cf6393161 | ||
|
|
5a7759f1c4 | ||
|
|
db5205931b | ||
|
|
62d59cffcc | ||
|
|
2e7129e816 | ||
|
|
2d22a2d1c2 | ||
|
|
c92968da8a | ||
|
|
86580d07cb | ||
|
|
03ea71034f | ||
|
|
7bf676abfa | ||
|
|
fb16e6b027 | ||
|
|
4eb04afa62 | ||
|
|
841a831c63 | ||
|
|
ae4af2966a |
@@ -1449,6 +1449,7 @@ message VoiceAssistantRequest {
|
|||||||
string conversation_id = 2;
|
string conversation_id = 2;
|
||||||
uint32 flags = 3;
|
uint32 flags = 3;
|
||||||
VoiceAssistantAudioSettings audio_settings = 4;
|
VoiceAssistantAudioSettings audio_settings = 4;
|
||||||
|
string wake_word_phrase = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message VoiceAssistantResponse {
|
message VoiceAssistantResponse {
|
||||||
|
|||||||
@@ -6594,6 +6594,10 @@ bool VoiceAssistantRequest::decode_length(uint32_t field_id, ProtoLengthDelimite
|
|||||||
this->audio_settings = value.as_message<VoiceAssistantAudioSettings>();
|
this->audio_settings = value.as_message<VoiceAssistantAudioSettings>();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
case 5: {
|
||||||
|
this->wake_word_phrase = value.as_string();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -6603,6 +6607,7 @@ void VoiceAssistantRequest::encode(ProtoWriteBuffer buffer) const {
|
|||||||
buffer.encode_string(2, this->conversation_id);
|
buffer.encode_string(2, this->conversation_id);
|
||||||
buffer.encode_uint32(3, this->flags);
|
buffer.encode_uint32(3, this->flags);
|
||||||
buffer.encode_message<VoiceAssistantAudioSettings>(4, this->audio_settings);
|
buffer.encode_message<VoiceAssistantAudioSettings>(4, this->audio_settings);
|
||||||
|
buffer.encode_string(5, this->wake_word_phrase);
|
||||||
}
|
}
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
void VoiceAssistantRequest::dump_to(std::string &out) const {
|
void VoiceAssistantRequest::dump_to(std::string &out) const {
|
||||||
@@ -6624,6 +6629,10 @@ void VoiceAssistantRequest::dump_to(std::string &out) const {
|
|||||||
out.append(" audio_settings: ");
|
out.append(" audio_settings: ");
|
||||||
this->audio_settings.dump_to(out);
|
this->audio_settings.dump_to(out);
|
||||||
out.append("\n");
|
out.append("\n");
|
||||||
|
|
||||||
|
out.append(" wake_word_phrase: ");
|
||||||
|
out.append("'").append(this->wake_word_phrase).append("'");
|
||||||
|
out.append("\n");
|
||||||
out.append("}");
|
out.append("}");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1701,6 +1701,7 @@ class VoiceAssistantRequest : public ProtoMessage {
|
|||||||
std::string conversation_id{};
|
std::string conversation_id{};
|
||||||
uint32_t flags{0};
|
uint32_t flags{0};
|
||||||
VoiceAssistantAudioSettings audio_settings{};
|
VoiceAssistantAudioSettings audio_settings{};
|
||||||
|
std::string wake_word_phrase{};
|
||||||
void encode(ProtoWriteBuffer buffer) const override;
|
void encode(ProtoWriteBuffer buffer) const override;
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
void dump_to(std::string &out) const override;
|
void dump_to(std::string &out) const override;
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ void CSE7766Component::parse_data_() {
|
|||||||
uint32_t power_coeff = this->get_24_bit_uint_(14);
|
uint32_t power_coeff = this->get_24_bit_uint_(14);
|
||||||
uint32_t power_cycle = this->get_24_bit_uint_(17);
|
uint32_t power_cycle = this->get_24_bit_uint_(17);
|
||||||
uint8_t adj = this->raw_data_[20];
|
uint8_t adj = this->raw_data_[20];
|
||||||
uint32_t cf_pulses = (this->raw_data_[21] << 8) + this->raw_data_[22];
|
uint16_t cf_pulses = (this->raw_data_[21] << 8) + this->raw_data_[22];
|
||||||
|
|
||||||
bool have_power = adj & 0x10;
|
bool have_power = adj & 0x10;
|
||||||
bool have_current = adj & 0x20;
|
bool have_current = adj & 0x20;
|
||||||
@@ -132,8 +132,19 @@ void CSE7766Component::parse_data_() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float energy = 0.0;
|
||||||
|
if (this->energy_sensor_ != nullptr) {
|
||||||
|
if (this->cf_pulses_last_ == 0 && !this->energy_sensor_->has_state()) {
|
||||||
|
this->cf_pulses_last_ = cf_pulses;
|
||||||
|
}
|
||||||
|
uint16_t cf_diff = cf_pulses - this->cf_pulses_last_;
|
||||||
|
this->cf_pulses_total_ += cf_diff;
|
||||||
|
this->cf_pulses_last_ = cf_pulses;
|
||||||
|
energy = this->cf_pulses_total_ * float(power_coeff) / 1000000.0f / 3600.0f;
|
||||||
|
this->energy_sensor_->publish_state(energy);
|
||||||
|
}
|
||||||
|
|
||||||
float power = 0.0f;
|
float power = 0.0f;
|
||||||
float energy = 0.0f;
|
|
||||||
if (power_cycle_exceeds_range) {
|
if (power_cycle_exceeds_range) {
|
||||||
// Datasheet: power cycle exceeding range means active power is 0
|
// Datasheet: power cycle exceeding range means active power is 0
|
||||||
if (this->power_sensor_ != nullptr) {
|
if (this->power_sensor_ != nullptr) {
|
||||||
@@ -144,27 +155,6 @@ void CSE7766Component::parse_data_() {
|
|||||||
if (this->power_sensor_ != nullptr) {
|
if (this->power_sensor_ != nullptr) {
|
||||||
this->power_sensor_->publish_state(power);
|
this->power_sensor_->publish_state(power);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add CF pulses to the total energy only if we have Power coefficient to multiply by
|
|
||||||
|
|
||||||
if (this->cf_pulses_last_ == 0) {
|
|
||||||
this->cf_pulses_last_ = cf_pulses;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t cf_diff;
|
|
||||||
if (cf_pulses < this->cf_pulses_last_) {
|
|
||||||
cf_diff = cf_pulses + (0x10000 - this->cf_pulses_last_);
|
|
||||||
} else {
|
|
||||||
cf_diff = cf_pulses - this->cf_pulses_last_;
|
|
||||||
}
|
|
||||||
this->cf_pulses_last_ = cf_pulses;
|
|
||||||
|
|
||||||
energy = cf_diff * float(power_coeff) / 1000000.0f / 3600.0f;
|
|
||||||
this->energy_total_ += energy;
|
|
||||||
if (this->energy_sensor_ != nullptr)
|
|
||||||
this->energy_sensor_->publish_state(this->energy_total_);
|
|
||||||
} else if ((this->energy_sensor_ != nullptr) && !this->energy_sensor_->has_state()) {
|
|
||||||
this->energy_sensor_->publish_state(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float current = 0.0f;
|
float current = 0.0f;
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ class CSE7766Component : public Component, public uart::UARTDevice {
|
|||||||
sensor::Sensor *current_sensor_{nullptr};
|
sensor::Sensor *current_sensor_{nullptr};
|
||||||
sensor::Sensor *power_sensor_{nullptr};
|
sensor::Sensor *power_sensor_{nullptr};
|
||||||
sensor::Sensor *energy_sensor_{nullptr};
|
sensor::Sensor *energy_sensor_{nullptr};
|
||||||
float energy_total_{0.0f};
|
uint32_t cf_pulses_total_{0};
|
||||||
uint32_t cf_pulses_last_{0};
|
uint16_t cf_pulses_last_{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace cse7766
|
} // namespace cse7766
|
||||||
|
|||||||
@@ -168,10 +168,6 @@ bool IRAM_ATTR DallasTemperatureSensor::read_scratch_pad() {
|
|||||||
if (!wire->reset()) {
|
if (!wire->reset()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
InterruptLock lock;
|
|
||||||
|
|
||||||
wire->select(this->address_);
|
wire->select(this->address_);
|
||||||
wire->write8(DALLAS_COMMAND_READ_SCRATCH_PAD);
|
wire->write8(DALLAS_COMMAND_READ_SCRATCH_PAD);
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ CODEOWNERS = ["@ellull"]
|
|||||||
|
|
||||||
DEPENDENCIES = ["i2c"]
|
DEPENDENCIES = ["i2c"]
|
||||||
|
|
||||||
|
MULTI_CONF = True
|
||||||
|
|
||||||
CONF_PWM = "pwm"
|
CONF_PWM = "pwm"
|
||||||
CONF_DIVIDER = "divider"
|
CONF_DIVIDER = "divider"
|
||||||
CONF_DAC = "dac"
|
CONF_DAC = "dac"
|
||||||
|
|||||||
@@ -336,6 +336,8 @@ void FingerprintGrowComponent::aura_led_control(uint8_t state, uint8_t speed, ui
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint8_t FingerprintGrowComponent::send_command_() {
|
uint8_t FingerprintGrowComponent::send_command_() {
|
||||||
|
while (this->available())
|
||||||
|
this->read();
|
||||||
this->write((uint8_t) (START_CODE >> 8));
|
this->write((uint8_t) (START_CODE >> 8));
|
||||||
this->write((uint8_t) (START_CODE & 0xFF));
|
this->write((uint8_t) (START_CODE & 0xFF));
|
||||||
this->write(this->address_[0]);
|
this->write(this->address_[0]);
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ void MicroWakeWord::loop() {
|
|||||||
this->set_state_(State::IDLE);
|
this->set_state_(State::IDLE);
|
||||||
if (this->detected_) {
|
if (this->detected_) {
|
||||||
this->detected_ = false;
|
this->detected_ = false;
|
||||||
this->wake_word_detected_trigger_->trigger("");
|
this->wake_word_detected_trigger_->trigger(this->wake_word_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -252,7 +252,9 @@ ThrottleAverageFilter::ThrottleAverageFilter(uint32_t time_period) : time_period
|
|||||||
|
|
||||||
optional<float> ThrottleAverageFilter::new_value(float value) {
|
optional<float> ThrottleAverageFilter::new_value(float value) {
|
||||||
ESP_LOGVV(TAG, "ThrottleAverageFilter(%p)::new_value(value=%f)", this, value);
|
ESP_LOGVV(TAG, "ThrottleAverageFilter(%p)::new_value(value=%f)", this, value);
|
||||||
if (!std::isnan(value)) {
|
if (std::isnan(value)) {
|
||||||
|
this->have_nan_ = true;
|
||||||
|
} else {
|
||||||
this->sum_ += value;
|
this->sum_ += value;
|
||||||
this->n_++;
|
this->n_++;
|
||||||
}
|
}
|
||||||
@@ -262,12 +264,14 @@ void ThrottleAverageFilter::setup() {
|
|||||||
this->set_interval("throttle_average", this->time_period_, [this]() {
|
this->set_interval("throttle_average", this->time_period_, [this]() {
|
||||||
ESP_LOGVV(TAG, "ThrottleAverageFilter(%p)::interval(sum=%f, n=%i)", this, this->sum_, this->n_);
|
ESP_LOGVV(TAG, "ThrottleAverageFilter(%p)::interval(sum=%f, n=%i)", this, this->sum_, this->n_);
|
||||||
if (this->n_ == 0) {
|
if (this->n_ == 0) {
|
||||||
this->output(NAN);
|
if (this->have_nan_)
|
||||||
|
this->output(NAN);
|
||||||
} else {
|
} else {
|
||||||
this->output(this->sum_ / this->n_);
|
this->output(this->sum_ / this->n_);
|
||||||
this->sum_ = 0.0f;
|
this->sum_ = 0.0f;
|
||||||
this->n_ = 0;
|
this->n_ = 0;
|
||||||
}
|
}
|
||||||
|
this->have_nan_ = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
float ThrottleAverageFilter::get_setup_priority() const { return setup_priority::HARDWARE; }
|
float ThrottleAverageFilter::get_setup_priority() const { return setup_priority::HARDWARE; }
|
||||||
|
|||||||
@@ -245,6 +245,7 @@ class ThrottleAverageFilter : public Filter, public Component {
|
|||||||
uint32_t time_period_;
|
uint32_t time_period_;
|
||||||
float sum_{0.0f};
|
float sum_{0.0f};
|
||||||
unsigned int n_{0};
|
unsigned int n_{0};
|
||||||
|
bool have_nan_{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
using lambda_filter_t = std::function<optional<float>(float)>;
|
using lambda_filter_t = std::function<optional<float>(float)>;
|
||||||
|
|||||||
@@ -14,12 +14,14 @@ from esphome.const import (
|
|||||||
|
|
||||||
from .. import speed_ns
|
from .. import speed_ns
|
||||||
|
|
||||||
|
AUTO_LOAD = ["output"]
|
||||||
|
|
||||||
SpeedFan = speed_ns.class_("SpeedFan", cg.Component, fan.Fan)
|
SpeedFan = speed_ns.class_("SpeedFan", cg.Component, fan.Fan)
|
||||||
|
|
||||||
CONFIG_SCHEMA = fan.FAN_SCHEMA.extend(
|
CONFIG_SCHEMA = fan.FAN_SCHEMA.extend(
|
||||||
{
|
{
|
||||||
cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(SpeedFan),
|
cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(SpeedFan),
|
||||||
cv.Required(CONF_OUTPUT): cv.use_id(output.FloatOutput),
|
cv.Optional(CONF_OUTPUT): cv.use_id(output.FloatOutput),
|
||||||
cv.Optional(CONF_OSCILLATION_OUTPUT): cv.use_id(output.BinaryOutput),
|
cv.Optional(CONF_OSCILLATION_OUTPUT): cv.use_id(output.BinaryOutput),
|
||||||
cv.Optional(CONF_DIRECTION_OUTPUT): cv.use_id(output.BinaryOutput),
|
cv.Optional(CONF_DIRECTION_OUTPUT): cv.use_id(output.BinaryOutput),
|
||||||
cv.Optional(CONF_SPEED): cv.invalid(
|
cv.Optional(CONF_SPEED): cv.invalid(
|
||||||
@@ -32,11 +34,14 @@ CONFIG_SCHEMA = fan.FAN_SCHEMA.extend(
|
|||||||
|
|
||||||
|
|
||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
output_ = await cg.get_variable(config[CONF_OUTPUT])
|
var = cg.new_Pvariable(config[CONF_OUTPUT_ID], config[CONF_SPEED_COUNT])
|
||||||
var = cg.new_Pvariable(config[CONF_OUTPUT_ID], output_, config[CONF_SPEED_COUNT])
|
|
||||||
await cg.register_component(var, config)
|
await cg.register_component(var, config)
|
||||||
await fan.register_fan(var, config)
|
await fan.register_fan(var, config)
|
||||||
|
|
||||||
|
if CONF_OUTPUT in config:
|
||||||
|
output_ = await cg.get_variable(config[CONF_OUTPUT])
|
||||||
|
cg.add(var.set_output(output_))
|
||||||
|
|
||||||
if CONF_OSCILLATION_OUTPUT in config:
|
if CONF_OSCILLATION_OUTPUT in config:
|
||||||
oscillation_output = await cg.get_variable(config[CONF_OSCILLATION_OUTPUT])
|
oscillation_output = await cg.get_variable(config[CONF_OSCILLATION_OUTPUT])
|
||||||
cg.add(var.set_oscillating(oscillation_output))
|
cg.add(var.set_oscillating(oscillation_output))
|
||||||
|
|||||||
@@ -36,9 +36,10 @@ void SpeedFan::control(const fan::FanCall &call) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SpeedFan::write_state_() {
|
void SpeedFan::write_state_() {
|
||||||
float speed = this->state ? static_cast<float>(this->speed) / static_cast<float>(this->speed_count_) : 0.0f;
|
if (this->output_ != nullptr) {
|
||||||
this->output_->set_level(speed);
|
float speed = this->state ? static_cast<float>(this->speed) / static_cast<float>(this->speed_count_) : 0.0f;
|
||||||
|
this->output_->set_level(speed);
|
||||||
|
}
|
||||||
if (this->oscillating_ != nullptr)
|
if (this->oscillating_ != nullptr)
|
||||||
this->oscillating_->set_state(this->oscillating);
|
this->oscillating_->set_state(this->oscillating);
|
||||||
if (this->direction_ != nullptr)
|
if (this->direction_ != nullptr)
|
||||||
|
|||||||
@@ -12,9 +12,10 @@ namespace speed {
|
|||||||
|
|
||||||
class SpeedFan : public Component, public fan::Fan {
|
class SpeedFan : public Component, public fan::Fan {
|
||||||
public:
|
public:
|
||||||
SpeedFan(output::FloatOutput *output, int speed_count) : output_(output), speed_count_(speed_count) {}
|
SpeedFan(int speed_count) : speed_count_(speed_count) {}
|
||||||
void setup() override;
|
void setup() override;
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
|
void set_output(output::FloatOutput *output) { this->output_ = output; }
|
||||||
void set_oscillating(output::BinaryOutput *oscillating) { this->oscillating_ = oscillating; }
|
void set_oscillating(output::BinaryOutput *oscillating) { this->oscillating_ = oscillating; }
|
||||||
void set_direction(output::BinaryOutput *direction) { this->direction_ = direction; }
|
void set_direction(output::BinaryOutput *direction) { this->direction_ = direction; }
|
||||||
void set_preset_modes(const std::set<std::string> &presets) { this->preset_modes_ = presets; }
|
void set_preset_modes(const std::set<std::string> &presets) { this->preset_modes_ = presets; }
|
||||||
@@ -24,7 +25,7 @@ class SpeedFan : public Component, public fan::Fan {
|
|||||||
void control(const fan::FanCall &call) override;
|
void control(const fan::FanCall &call) override;
|
||||||
void write_state_();
|
void write_state_();
|
||||||
|
|
||||||
output::FloatOutput *output_;
|
output::FloatOutput *output_{nullptr};
|
||||||
output::BinaryOutput *oscillating_{nullptr};
|
output::BinaryOutput *oscillating_{nullptr};
|
||||||
output::BinaryOutput *direction_{nullptr};
|
output::BinaryOutput *direction_{nullptr};
|
||||||
int speed_count_{};
|
int speed_count_{};
|
||||||
|
|||||||
@@ -74,7 +74,8 @@ CONF_FORCE_SW = "force_sw"
|
|||||||
CONF_INTERFACE = "interface"
|
CONF_INTERFACE = "interface"
|
||||||
CONF_INTERFACE_INDEX = "interface_index"
|
CONF_INTERFACE_INDEX = "interface_index"
|
||||||
|
|
||||||
# RP2040 SPI pin assignments are complicated. Refer to https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf
|
# RP2040 SPI pin assignments are complicated;
|
||||||
|
# refer to GPIO function select table in https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf
|
||||||
|
|
||||||
RP_SPI_PINSETS = [
|
RP_SPI_PINSETS = [
|
||||||
{
|
{
|
||||||
@@ -85,7 +86,7 @@ RP_SPI_PINSETS = [
|
|||||||
{
|
{
|
||||||
CONF_MISO_PIN: [8, 12, 24, 28, -1],
|
CONF_MISO_PIN: [8, 12, 24, 28, -1],
|
||||||
CONF_CLK_PIN: [10, 14, 26],
|
CONF_CLK_PIN: [10, 14, 26],
|
||||||
CONF_MOSI_PIN: [11, 23, 27, -1],
|
CONF_MOSI_PIN: [11, 15, 27, -1],
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#include "thermostat_climate.h"
|
#include "thermostat_climate.h"
|
||||||
#include "esphome/core/log.h"
|
#include "esphome/core/log.h"
|
||||||
#include <cinttypes>
|
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace thermostat {
|
namespace thermostat {
|
||||||
@@ -63,6 +62,15 @@ void ThermostatClimate::setup() {
|
|||||||
this->publish_state();
|
this->publish_state();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ThermostatClimate::loop() {
|
||||||
|
for (auto &timer : this->timer_) {
|
||||||
|
if (timer.active && (timer.started + timer.time < millis())) {
|
||||||
|
timer.active = false;
|
||||||
|
timer.func();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
float ThermostatClimate::cool_deadband() { return this->cooling_deadband_; }
|
float ThermostatClimate::cool_deadband() { return this->cooling_deadband_; }
|
||||||
float ThermostatClimate::cool_overrun() { return this->cooling_overrun_; }
|
float ThermostatClimate::cool_overrun() { return this->cooling_overrun_; }
|
||||||
float ThermostatClimate::heat_deadband() { return this->heating_deadband_; }
|
float ThermostatClimate::heat_deadband() { return this->heating_deadband_; }
|
||||||
@@ -439,6 +447,7 @@ void ThermostatClimate::switch_to_action_(climate::ClimateAction action, bool pu
|
|||||||
this->start_timer_(thermostat::TIMER_FANNING_ON);
|
this->start_timer_(thermostat::TIMER_FANNING_ON);
|
||||||
trig_fan = this->fan_only_action_trigger_;
|
trig_fan = this->fan_only_action_trigger_;
|
||||||
}
|
}
|
||||||
|
this->cooling_max_runtime_exceeded_ = false;
|
||||||
trig = this->cool_action_trigger_;
|
trig = this->cool_action_trigger_;
|
||||||
ESP_LOGVV(TAG, "Switching to COOLING action");
|
ESP_LOGVV(TAG, "Switching to COOLING action");
|
||||||
action_ready = true;
|
action_ready = true;
|
||||||
@@ -452,6 +461,7 @@ void ThermostatClimate::switch_to_action_(climate::ClimateAction action, bool pu
|
|||||||
this->start_timer_(thermostat::TIMER_FANNING_ON);
|
this->start_timer_(thermostat::TIMER_FANNING_ON);
|
||||||
trig_fan = this->fan_only_action_trigger_;
|
trig_fan = this->fan_only_action_trigger_;
|
||||||
}
|
}
|
||||||
|
this->heating_max_runtime_exceeded_ = false;
|
||||||
trig = this->heat_action_trigger_;
|
trig = this->heat_action_trigger_;
|
||||||
ESP_LOGVV(TAG, "Switching to HEATING action");
|
ESP_LOGVV(TAG, "Switching to HEATING action");
|
||||||
action_ready = true;
|
action_ready = true;
|
||||||
@@ -752,15 +762,15 @@ bool ThermostatClimate::heating_action_ready_() {
|
|||||||
|
|
||||||
void ThermostatClimate::start_timer_(const ThermostatClimateTimerIndex timer_index) {
|
void ThermostatClimate::start_timer_(const ThermostatClimateTimerIndex timer_index) {
|
||||||
if (this->timer_duration_(timer_index) > 0) {
|
if (this->timer_duration_(timer_index) > 0) {
|
||||||
this->set_timeout(this->timer_[timer_index].name, this->timer_duration_(timer_index),
|
this->timer_[timer_index].started = millis();
|
||||||
this->timer_cbf_(timer_index));
|
|
||||||
this->timer_[timer_index].active = true;
|
this->timer_[timer_index].active = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ThermostatClimate::cancel_timer_(ThermostatClimateTimerIndex timer_index) {
|
bool ThermostatClimate::cancel_timer_(ThermostatClimateTimerIndex timer_index) {
|
||||||
|
auto ret = this->timer_[timer_index].active;
|
||||||
this->timer_[timer_index].active = false;
|
this->timer_[timer_index].active = false;
|
||||||
return this->cancel_timeout(this->timer_[timer_index].name);
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ThermostatClimate::timer_active_(ThermostatClimateTimerIndex timer_index) {
|
bool ThermostatClimate::timer_active_(ThermostatClimateTimerIndex timer_index) {
|
||||||
@@ -777,7 +787,6 @@ std::function<void()> ThermostatClimate::timer_cbf_(ThermostatClimateTimerIndex
|
|||||||
|
|
||||||
void ThermostatClimate::cooling_max_run_time_timer_callback_() {
|
void ThermostatClimate::cooling_max_run_time_timer_callback_() {
|
||||||
ESP_LOGVV(TAG, "cooling_max_run_time timer expired");
|
ESP_LOGVV(TAG, "cooling_max_run_time timer expired");
|
||||||
this->timer_[thermostat::TIMER_COOLING_MAX_RUN_TIME].active = false;
|
|
||||||
this->cooling_max_runtime_exceeded_ = true;
|
this->cooling_max_runtime_exceeded_ = true;
|
||||||
this->trigger_supplemental_action_();
|
this->trigger_supplemental_action_();
|
||||||
this->switch_to_supplemental_action_(this->compute_supplemental_action_());
|
this->switch_to_supplemental_action_(this->compute_supplemental_action_());
|
||||||
@@ -785,21 +794,18 @@ void ThermostatClimate::cooling_max_run_time_timer_callback_() {
|
|||||||
|
|
||||||
void ThermostatClimate::cooling_off_timer_callback_() {
|
void ThermostatClimate::cooling_off_timer_callback_() {
|
||||||
ESP_LOGVV(TAG, "cooling_off timer expired");
|
ESP_LOGVV(TAG, "cooling_off timer expired");
|
||||||
this->timer_[thermostat::TIMER_COOLING_OFF].active = false;
|
|
||||||
this->switch_to_action_(this->compute_action_());
|
this->switch_to_action_(this->compute_action_());
|
||||||
this->switch_to_supplemental_action_(this->compute_supplemental_action_());
|
this->switch_to_supplemental_action_(this->compute_supplemental_action_());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThermostatClimate::cooling_on_timer_callback_() {
|
void ThermostatClimate::cooling_on_timer_callback_() {
|
||||||
ESP_LOGVV(TAG, "cooling_on timer expired");
|
ESP_LOGVV(TAG, "cooling_on timer expired");
|
||||||
this->timer_[thermostat::TIMER_COOLING_ON].active = false;
|
|
||||||
this->switch_to_action_(this->compute_action_());
|
this->switch_to_action_(this->compute_action_());
|
||||||
this->switch_to_supplemental_action_(this->compute_supplemental_action_());
|
this->switch_to_supplemental_action_(this->compute_supplemental_action_());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThermostatClimate::fan_mode_timer_callback_() {
|
void ThermostatClimate::fan_mode_timer_callback_() {
|
||||||
ESP_LOGVV(TAG, "fan_mode timer expired");
|
ESP_LOGVV(TAG, "fan_mode timer expired");
|
||||||
this->timer_[thermostat::TIMER_FAN_MODE].active = false;
|
|
||||||
this->switch_to_fan_mode_(this->fan_mode.value_or(climate::CLIMATE_FAN_ON));
|
this->switch_to_fan_mode_(this->fan_mode.value_or(climate::CLIMATE_FAN_ON));
|
||||||
if (this->supports_fan_only_action_uses_fan_mode_timer_)
|
if (this->supports_fan_only_action_uses_fan_mode_timer_)
|
||||||
this->switch_to_action_(this->compute_action_());
|
this->switch_to_action_(this->compute_action_());
|
||||||
@@ -807,19 +813,16 @@ void ThermostatClimate::fan_mode_timer_callback_() {
|
|||||||
|
|
||||||
void ThermostatClimate::fanning_off_timer_callback_() {
|
void ThermostatClimate::fanning_off_timer_callback_() {
|
||||||
ESP_LOGVV(TAG, "fanning_off timer expired");
|
ESP_LOGVV(TAG, "fanning_off timer expired");
|
||||||
this->timer_[thermostat::TIMER_FANNING_OFF].active = false;
|
|
||||||
this->switch_to_action_(this->compute_action_());
|
this->switch_to_action_(this->compute_action_());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThermostatClimate::fanning_on_timer_callback_() {
|
void ThermostatClimate::fanning_on_timer_callback_() {
|
||||||
ESP_LOGVV(TAG, "fanning_on timer expired");
|
ESP_LOGVV(TAG, "fanning_on timer expired");
|
||||||
this->timer_[thermostat::TIMER_FANNING_ON].active = false;
|
|
||||||
this->switch_to_action_(this->compute_action_());
|
this->switch_to_action_(this->compute_action_());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThermostatClimate::heating_max_run_time_timer_callback_() {
|
void ThermostatClimate::heating_max_run_time_timer_callback_() {
|
||||||
ESP_LOGVV(TAG, "heating_max_run_time timer expired");
|
ESP_LOGVV(TAG, "heating_max_run_time timer expired");
|
||||||
this->timer_[thermostat::TIMER_HEATING_MAX_RUN_TIME].active = false;
|
|
||||||
this->heating_max_runtime_exceeded_ = true;
|
this->heating_max_runtime_exceeded_ = true;
|
||||||
this->trigger_supplemental_action_();
|
this->trigger_supplemental_action_();
|
||||||
this->switch_to_supplemental_action_(this->compute_supplemental_action_());
|
this->switch_to_supplemental_action_(this->compute_supplemental_action_());
|
||||||
@@ -827,21 +830,18 @@ void ThermostatClimate::heating_max_run_time_timer_callback_() {
|
|||||||
|
|
||||||
void ThermostatClimate::heating_off_timer_callback_() {
|
void ThermostatClimate::heating_off_timer_callback_() {
|
||||||
ESP_LOGVV(TAG, "heating_off timer expired");
|
ESP_LOGVV(TAG, "heating_off timer expired");
|
||||||
this->timer_[thermostat::TIMER_HEATING_OFF].active = false;
|
|
||||||
this->switch_to_action_(this->compute_action_());
|
this->switch_to_action_(this->compute_action_());
|
||||||
this->switch_to_supplemental_action_(this->compute_supplemental_action_());
|
this->switch_to_supplemental_action_(this->compute_supplemental_action_());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThermostatClimate::heating_on_timer_callback_() {
|
void ThermostatClimate::heating_on_timer_callback_() {
|
||||||
ESP_LOGVV(TAG, "heating_on timer expired");
|
ESP_LOGVV(TAG, "heating_on timer expired");
|
||||||
this->timer_[thermostat::TIMER_HEATING_ON].active = false;
|
|
||||||
this->switch_to_action_(this->compute_action_());
|
this->switch_to_action_(this->compute_action_());
|
||||||
this->switch_to_supplemental_action_(this->compute_supplemental_action_());
|
this->switch_to_supplemental_action_(this->compute_supplemental_action_());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThermostatClimate::idle_on_timer_callback_() {
|
void ThermostatClimate::idle_on_timer_callback_() {
|
||||||
ESP_LOGVV(TAG, "idle_on timer expired");
|
ESP_LOGVV(TAG, "idle_on timer expired");
|
||||||
this->timer_[thermostat::TIMER_IDLE_ON].active = false;
|
|
||||||
this->switch_to_action_(this->compute_action_());
|
this->switch_to_action_(this->compute_action_());
|
||||||
this->switch_to_supplemental_action_(this->compute_supplemental_action_());
|
this->switch_to_supplemental_action_(this->compute_supplemental_action_());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "esphome/core/component.h"
|
|
||||||
#include "esphome/core/automation.h"
|
#include "esphome/core/automation.h"
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/core/hal.h"
|
||||||
#include "esphome/components/climate/climate.h"
|
#include "esphome/components/climate/climate.h"
|
||||||
#include "esphome/components/sensor/sensor.h"
|
#include "esphome/components/sensor/sensor.h"
|
||||||
|
|
||||||
|
#include <cinttypes>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -26,9 +28,9 @@ enum ThermostatClimateTimerIndex : size_t {
|
|||||||
|
|
||||||
enum OnBootRestoreFrom : size_t { MEMORY = 0, DEFAULT_PRESET = 1 };
|
enum OnBootRestoreFrom : size_t { MEMORY = 0, DEFAULT_PRESET = 1 };
|
||||||
struct ThermostatClimateTimer {
|
struct ThermostatClimateTimer {
|
||||||
const std::string name;
|
|
||||||
bool active;
|
bool active;
|
||||||
uint32_t time;
|
uint32_t time;
|
||||||
|
uint32_t started;
|
||||||
std::function<void()> func;
|
std::function<void()> func;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -59,6 +61,7 @@ class ThermostatClimate : public climate::Climate, public Component {
|
|||||||
ThermostatClimate();
|
ThermostatClimate();
|
||||||
void setup() override;
|
void setup() override;
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
|
void loop() override;
|
||||||
|
|
||||||
void set_default_preset(const std::string &custom_preset);
|
void set_default_preset(const std::string &custom_preset);
|
||||||
void set_default_preset(climate::ClimatePreset preset);
|
void set_default_preset(climate::ClimatePreset preset);
|
||||||
@@ -441,16 +444,17 @@ class ThermostatClimate : public climate::Climate, public Component {
|
|||||||
|
|
||||||
/// Climate action timers
|
/// Climate action timers
|
||||||
std::vector<ThermostatClimateTimer> timer_{
|
std::vector<ThermostatClimateTimer> timer_{
|
||||||
{"cool_run", false, 0, std::bind(&ThermostatClimate::cooling_max_run_time_timer_callback_, this)},
|
{false, 0, 0, std::bind(&ThermostatClimate::cooling_max_run_time_timer_callback_, this)},
|
||||||
{"cool_off", false, 0, std::bind(&ThermostatClimate::cooling_off_timer_callback_, this)},
|
{false, 0, 0, std::bind(&ThermostatClimate::cooling_off_timer_callback_, this)},
|
||||||
{"cool_on", false, 0, std::bind(&ThermostatClimate::cooling_on_timer_callback_, this)},
|
{false, 0, 0, std::bind(&ThermostatClimate::cooling_on_timer_callback_, this)},
|
||||||
{"fan_mode", false, 0, std::bind(&ThermostatClimate::fan_mode_timer_callback_, this)},
|
{false, 0, 0, std::bind(&ThermostatClimate::fan_mode_timer_callback_, this)},
|
||||||
{"fan_off", false, 0, std::bind(&ThermostatClimate::fanning_off_timer_callback_, this)},
|
{false, 0, 0, std::bind(&ThermostatClimate::fanning_off_timer_callback_, this)},
|
||||||
{"fan_on", false, 0, std::bind(&ThermostatClimate::fanning_on_timer_callback_, this)},
|
{false, 0, 0, std::bind(&ThermostatClimate::fanning_on_timer_callback_, this)},
|
||||||
{"heat_run", false, 0, std::bind(&ThermostatClimate::heating_max_run_time_timer_callback_, this)},
|
{false, 0, 0, std::bind(&ThermostatClimate::heating_max_run_time_timer_callback_, this)},
|
||||||
{"heat_off", false, 0, std::bind(&ThermostatClimate::heating_off_timer_callback_, this)},
|
{false, 0, 0, std::bind(&ThermostatClimate::heating_off_timer_callback_, this)},
|
||||||
{"heat_on", false, 0, std::bind(&ThermostatClimate::heating_on_timer_callback_, this)},
|
{false, 0, 0, std::bind(&ThermostatClimate::heating_on_timer_callback_, this)},
|
||||||
{"idle_on", false, 0, std::bind(&ThermostatClimate::idle_on_timer_callback_, this)}};
|
{false, 0, 0, std::bind(&ThermostatClimate::idle_on_timer_callback_, this)},
|
||||||
|
};
|
||||||
|
|
||||||
/// The set of standard preset configurations this thermostat supports (Eg. AWAY, ECO, etc)
|
/// The set of standard preset configurations this thermostat supports (Eg. AWAY, ECO, etc)
|
||||||
std::map<climate::ClimatePreset, ThermostatClimateTargetTempConfig> preset_config_{};
|
std::map<climate::ClimatePreset, ThermostatClimateTargetTempConfig> preset_config_{};
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ from esphome.const import (
|
|||||||
CODEOWNERS = ["@freekode"]
|
CODEOWNERS = ["@freekode"]
|
||||||
|
|
||||||
tm1651_ns = cg.esphome_ns.namespace("tm1651")
|
tm1651_ns = cg.esphome_ns.namespace("tm1651")
|
||||||
|
TM1651Brightness = tm1651_ns.enum("TM1651Brightness")
|
||||||
TM1651Display = tm1651_ns.class_("TM1651Display", cg.Component)
|
TM1651Display = tm1651_ns.class_("TM1651Display", cg.Component)
|
||||||
|
|
||||||
SetLevelPercentAction = tm1651_ns.class_("SetLevelPercentAction", automation.Action)
|
SetLevelPercentAction = tm1651_ns.class_("SetLevelPercentAction", automation.Action)
|
||||||
@@ -24,9 +25,9 @@ TurnOffAction = tm1651_ns.class_("SetLevelPercentAction", automation.Action)
|
|||||||
CONF_LEVEL_PERCENT = "level_percent"
|
CONF_LEVEL_PERCENT = "level_percent"
|
||||||
|
|
||||||
TM1651_BRIGHTNESS_OPTIONS = {
|
TM1651_BRIGHTNESS_OPTIONS = {
|
||||||
1: TM1651Display.TM1651_BRIGHTNESS_LOW,
|
1: TM1651Brightness.TM1651_BRIGHTNESS_LOW,
|
||||||
2: TM1651Display.TM1651_BRIGHTNESS_MEDIUM,
|
2: TM1651Brightness.TM1651_BRIGHTNESS_MEDIUM,
|
||||||
3: TM1651Display.TM1651_BRIGHTNESS_HIGH,
|
3: TM1651Brightness.TM1651_BRIGHTNESS_HIGH,
|
||||||
}
|
}
|
||||||
|
|
||||||
CONFIG_SCHEMA = cv.All(
|
CONFIG_SCHEMA = cv.All(
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ static const char *const TAG = "tm1651.display";
|
|||||||
static const uint8_t MAX_INPUT_LEVEL_PERCENT = 100;
|
static const uint8_t MAX_INPUT_LEVEL_PERCENT = 100;
|
||||||
static const uint8_t TM1651_MAX_LEVEL = 7;
|
static const uint8_t TM1651_MAX_LEVEL = 7;
|
||||||
|
|
||||||
static const uint8_t TM1651_BRIGHTNESS_LOW = 0;
|
static const uint8_t TM1651_BRIGHTNESS_LOW_HW = 0;
|
||||||
static const uint8_t TM1651_BRIGHTNESS_MEDIUM = 2;
|
static const uint8_t TM1651_BRIGHTNESS_MEDIUM_HW = 2;
|
||||||
static const uint8_t TM1651_BRIGHTNESS_HIGH = 7;
|
static const uint8_t TM1651_BRIGHTNESS_HIGH_HW = 7;
|
||||||
|
|
||||||
void TM1651Display::setup() {
|
void TM1651Display::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Setting up TM1651...");
|
ESP_LOGCONFIG(TAG, "Setting up TM1651...");
|
||||||
@@ -78,14 +78,14 @@ uint8_t TM1651Display::calculate_level_(uint8_t new_level) {
|
|||||||
|
|
||||||
uint8_t TM1651Display::calculate_brightness_(uint8_t new_brightness) {
|
uint8_t TM1651Display::calculate_brightness_(uint8_t new_brightness) {
|
||||||
if (new_brightness <= 1) {
|
if (new_brightness <= 1) {
|
||||||
return TM1651_BRIGHTNESS_LOW;
|
return TM1651_BRIGHTNESS_LOW_HW;
|
||||||
} else if (new_brightness == 2) {
|
} else if (new_brightness == 2) {
|
||||||
return TM1651_BRIGHTNESS_MEDIUM;
|
return TM1651_BRIGHTNESS_MEDIUM_HW;
|
||||||
} else if (new_brightness >= 3) {
|
} else if (new_brightness >= 3) {
|
||||||
return TM1651_BRIGHTNESS_HIGH;
|
return TM1651_BRIGHTNESS_HIGH_HW;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TM1651_BRIGHTNESS_LOW;
|
return TM1651_BRIGHTNESS_LOW_HW;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace tm1651
|
} // namespace tm1651
|
||||||
|
|||||||
@@ -13,6 +13,12 @@
|
|||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace tm1651 {
|
namespace tm1651 {
|
||||||
|
|
||||||
|
enum TM1651Brightness : uint8_t {
|
||||||
|
TM1651_BRIGHTNESS_LOW = 1,
|
||||||
|
TM1651_BRIGHTNESS_MEDIUM = 2,
|
||||||
|
TM1651_BRIGHTNESS_HIGH = 3,
|
||||||
|
};
|
||||||
|
|
||||||
class TM1651Display : public Component {
|
class TM1651Display : public Component {
|
||||||
public:
|
public:
|
||||||
void set_clk_pin(InternalGPIOPin *pin) { clk_pin_ = pin; }
|
void set_clk_pin(InternalGPIOPin *pin) { clk_pin_ = pin; }
|
||||||
@@ -24,6 +30,7 @@ class TM1651Display : public Component {
|
|||||||
void set_level_percent(uint8_t new_level);
|
void set_level_percent(uint8_t new_level);
|
||||||
void set_level(uint8_t new_level);
|
void set_level(uint8_t new_level);
|
||||||
void set_brightness(uint8_t new_brightness);
|
void set_brightness(uint8_t new_brightness);
|
||||||
|
void set_brightness(TM1651Brightness new_brightness) { this->set_brightness(static_cast<uint8_t>(new_brightness)); }
|
||||||
|
|
||||||
void turn_on();
|
void turn_on();
|
||||||
void turn_off();
|
void turn_off();
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ void TMP102Component::dump_config() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TMP102Component::update() {
|
void TMP102Component::update() {
|
||||||
uint16_t raw_temperature;
|
int16_t raw_temperature;
|
||||||
if (this->write(&TMP102_REGISTER_TEMPERATURE, 1) != i2c::ERROR_OK) {
|
if (this->write(&TMP102_REGISTER_TEMPERATURE, 1) != i2c::ERROR_OK) {
|
||||||
this->status_set_warning();
|
this->status_set_warning();
|
||||||
return;
|
return;
|
||||||
@@ -39,7 +39,6 @@ void TMP102Component::update() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
raw_temperature = i2c::i2ctohs(raw_temperature);
|
raw_temperature = i2c::i2ctohs(raw_temperature);
|
||||||
|
|
||||||
raw_temperature = raw_temperature >> 4;
|
raw_temperature = raw_temperature >> 4;
|
||||||
float temperature = raw_temperature * TMP102_CONVERSION_FACTOR;
|
float temperature = raw_temperature * TMP102_CONVERSION_FACTOR;
|
||||||
ESP_LOGD(TAG, "Got Temperature=%.1f°C", temperature);
|
ESP_LOGD(TAG, "Got Temperature=%.1f°C", temperature);
|
||||||
|
|||||||
@@ -34,9 +34,13 @@ void TuyaFan::setup() {
|
|||||||
}
|
}
|
||||||
if (this->oscillation_id_.has_value()) {
|
if (this->oscillation_id_.has_value()) {
|
||||||
this->parent_->register_listener(*this->oscillation_id_, [this](const TuyaDatapoint &datapoint) {
|
this->parent_->register_listener(*this->oscillation_id_, [this](const TuyaDatapoint &datapoint) {
|
||||||
|
// Whether data type is BOOL or ENUM, it will still be a 1 or a 0, so the functions below are valid in both
|
||||||
|
// scenarios
|
||||||
ESP_LOGV(TAG, "MCU reported oscillation is: %s", ONOFF(datapoint.value_bool));
|
ESP_LOGV(TAG, "MCU reported oscillation is: %s", ONOFF(datapoint.value_bool));
|
||||||
this->oscillating = datapoint.value_bool;
|
this->oscillating = datapoint.value_bool;
|
||||||
this->publish_state();
|
this->publish_state();
|
||||||
|
|
||||||
|
this->oscillation_type_ = datapoint.type;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (this->direction_id_.has_value()) {
|
if (this->direction_id_.has_value()) {
|
||||||
@@ -80,7 +84,11 @@ void TuyaFan::control(const fan::FanCall &call) {
|
|||||||
this->parent_->set_boolean_datapoint_value(*this->switch_id_, *call.get_state());
|
this->parent_->set_boolean_datapoint_value(*this->switch_id_, *call.get_state());
|
||||||
}
|
}
|
||||||
if (this->oscillation_id_.has_value() && call.get_oscillating().has_value()) {
|
if (this->oscillation_id_.has_value() && call.get_oscillating().has_value()) {
|
||||||
this->parent_->set_boolean_datapoint_value(*this->oscillation_id_, *call.get_oscillating());
|
if (this->oscillation_type_ == TuyaDatapointType::ENUM) {
|
||||||
|
this->parent_->set_enum_datapoint_value(*this->oscillation_id_, *call.get_oscillating());
|
||||||
|
} else if (this->speed_type_ == TuyaDatapointType::BOOLEAN) {
|
||||||
|
this->parent_->set_boolean_datapoint_value(*this->oscillation_id_, *call.get_oscillating());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (this->direction_id_.has_value() && call.get_direction().has_value()) {
|
if (this->direction_id_.has_value() && call.get_direction().has_value()) {
|
||||||
bool enable = *call.get_direction() == fan::FanDirection::REVERSE;
|
bool enable = *call.get_direction() == fan::FanDirection::REVERSE;
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ class TuyaFan : public Component, public fan::Fan {
|
|||||||
optional<uint8_t> direction_id_{};
|
optional<uint8_t> direction_id_{};
|
||||||
int speed_count_{};
|
int speed_count_{};
|
||||||
TuyaDatapointType speed_type_{};
|
TuyaDatapointType speed_type_{};
|
||||||
|
TuyaDatapointType oscillation_type_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace tuya
|
} // namespace tuya
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ CONF_ON_TTS_START = "on_tts_start"
|
|||||||
CONF_ON_TTS_STREAM_START = "on_tts_stream_start"
|
CONF_ON_TTS_STREAM_START = "on_tts_stream_start"
|
||||||
CONF_ON_TTS_STREAM_END = "on_tts_stream_end"
|
CONF_ON_TTS_STREAM_END = "on_tts_stream_end"
|
||||||
CONF_ON_WAKE_WORD_DETECTED = "on_wake_word_detected"
|
CONF_ON_WAKE_WORD_DETECTED = "on_wake_word_detected"
|
||||||
|
CONF_ON_IDLE = "on_idle"
|
||||||
|
|
||||||
CONF_SILENCE_DETECTION = "silence_detection"
|
CONF_SILENCE_DETECTION = "silence_detection"
|
||||||
CONF_USE_WAKE_WORD = "use_wake_word"
|
CONF_USE_WAKE_WORD = "use_wake_word"
|
||||||
@@ -41,6 +42,8 @@ CONF_AUTO_GAIN = "auto_gain"
|
|||||||
CONF_NOISE_SUPPRESSION_LEVEL = "noise_suppression_level"
|
CONF_NOISE_SUPPRESSION_LEVEL = "noise_suppression_level"
|
||||||
CONF_VOLUME_MULTIPLIER = "volume_multiplier"
|
CONF_VOLUME_MULTIPLIER = "volume_multiplier"
|
||||||
|
|
||||||
|
CONF_WAKE_WORD = "wake_word"
|
||||||
|
|
||||||
|
|
||||||
voice_assistant_ns = cg.esphome_ns.namespace("voice_assistant")
|
voice_assistant_ns = cg.esphome_ns.namespace("voice_assistant")
|
||||||
VoiceAssistant = voice_assistant_ns.class_("VoiceAssistant", cg.Component)
|
VoiceAssistant = voice_assistant_ns.class_("VoiceAssistant", cg.Component)
|
||||||
@@ -127,6 +130,7 @@ CONFIG_SCHEMA = cv.All(
|
|||||||
cv.Optional(CONF_ON_TTS_STREAM_END): automation.validate_automation(
|
cv.Optional(CONF_ON_TTS_STREAM_END): automation.validate_automation(
|
||||||
single=True
|
single=True
|
||||||
),
|
),
|
||||||
|
cv.Optional(CONF_ON_IDLE): automation.validate_automation(single=True),
|
||||||
}
|
}
|
||||||
).extend(cv.COMPONENT_SCHEMA),
|
).extend(cv.COMPONENT_SCHEMA),
|
||||||
tts_stream_validate,
|
tts_stream_validate,
|
||||||
@@ -259,6 +263,13 @@ async def to_code(config):
|
|||||||
config[CONF_ON_TTS_STREAM_END],
|
config[CONF_ON_TTS_STREAM_END],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if CONF_ON_IDLE in config:
|
||||||
|
await automation.build_automation(
|
||||||
|
var.get_idle_trigger(),
|
||||||
|
[],
|
||||||
|
config[CONF_ON_IDLE],
|
||||||
|
)
|
||||||
|
|
||||||
cg.add_define("USE_VOICE_ASSISTANT")
|
cg.add_define("USE_VOICE_ASSISTANT")
|
||||||
|
|
||||||
|
|
||||||
@@ -276,6 +287,7 @@ VOICE_ASSISTANT_ACTION_SCHEMA = cv.Schema({cv.GenerateID(): cv.use_id(VoiceAssis
|
|||||||
VOICE_ASSISTANT_ACTION_SCHEMA.extend(
|
VOICE_ASSISTANT_ACTION_SCHEMA.extend(
|
||||||
{
|
{
|
||||||
cv.Optional(CONF_SILENCE_DETECTION, default=True): cv.boolean,
|
cv.Optional(CONF_SILENCE_DETECTION, default=True): cv.boolean,
|
||||||
|
cv.Optional(CONF_WAKE_WORD): cv.templatable(cv.string),
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -284,6 +296,9 @@ async def voice_assistant_listen_to_code(config, action_id, template_arg, args):
|
|||||||
await cg.register_parented(var, config[CONF_ID])
|
await cg.register_parented(var, config[CONF_ID])
|
||||||
if CONF_SILENCE_DETECTION in config:
|
if CONF_SILENCE_DETECTION in config:
|
||||||
cg.add(var.set_silence_detection(config[CONF_SILENCE_DETECTION]))
|
cg.add(var.set_silence_detection(config[CONF_SILENCE_DETECTION]))
|
||||||
|
if wake_word := config.get(CONF_WAKE_WORD):
|
||||||
|
templ = await cg.templatable(wake_word, args, cg.std_string)
|
||||||
|
cg.add(var.set_wake_word(templ))
|
||||||
return var
|
return var
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -135,6 +135,8 @@ void VoiceAssistant::loop() {
|
|||||||
switch (this->state_) {
|
switch (this->state_) {
|
||||||
case State::IDLE: {
|
case State::IDLE: {
|
||||||
if (this->continuous_ && this->desired_state_ == State::IDLE) {
|
if (this->continuous_ && this->desired_state_ == State::IDLE) {
|
||||||
|
this->idle_trigger_->trigger();
|
||||||
|
|
||||||
this->ring_buffer_->reset();
|
this->ring_buffer_->reset();
|
||||||
#ifdef USE_ESP_ADF
|
#ifdef USE_ESP_ADF
|
||||||
if (this->use_wake_word_) {
|
if (this->use_wake_word_) {
|
||||||
@@ -213,6 +215,8 @@ void VoiceAssistant::loop() {
|
|||||||
msg.conversation_id = this->conversation_id_;
|
msg.conversation_id = this->conversation_id_;
|
||||||
msg.flags = flags;
|
msg.flags = flags;
|
||||||
msg.audio_settings = audio_settings;
|
msg.audio_settings = audio_settings;
|
||||||
|
msg.wake_word_phrase = this->wake_word_;
|
||||||
|
this->wake_word_ = "";
|
||||||
|
|
||||||
if (this->api_client_ == nullptr || !this->api_client_->send_voice_assistant_request(msg)) {
|
if (this->api_client_ == nullptr || !this->api_client_->send_voice_assistant_request(msg)) {
|
||||||
ESP_LOGW(TAG, "Could not request start");
|
ESP_LOGW(TAG, "Could not request start");
|
||||||
@@ -618,6 +622,9 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) {
|
|||||||
{
|
{
|
||||||
this->set_state_(State::IDLE, State::IDLE);
|
this->set_state_(State::IDLE, State::IDLE);
|
||||||
}
|
}
|
||||||
|
} else if (this->state_ == State::AWAITING_RESPONSE) {
|
||||||
|
// No TTS start event ("nevermind")
|
||||||
|
this->set_state_(State::IDLE, State::IDLE);
|
||||||
}
|
}
|
||||||
this->defer([this]() { this->end_trigger_->trigger(); });
|
this->defer([this]() { this->end_trigger_->trigger(); });
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -116,6 +116,7 @@ class VoiceAssistant : public Component {
|
|||||||
Trigger<std::string> *get_tts_end_trigger() const { return this->tts_end_trigger_; }
|
Trigger<std::string> *get_tts_end_trigger() const { return this->tts_end_trigger_; }
|
||||||
Trigger<std::string> *get_tts_start_trigger() const { return this->tts_start_trigger_; }
|
Trigger<std::string> *get_tts_start_trigger() const { return this->tts_start_trigger_; }
|
||||||
Trigger<std::string, std::string> *get_error_trigger() const { return this->error_trigger_; }
|
Trigger<std::string, std::string> *get_error_trigger() const { return this->error_trigger_; }
|
||||||
|
Trigger<> *get_idle_trigger() const { return this->idle_trigger_; }
|
||||||
|
|
||||||
Trigger<> *get_client_connected_trigger() const { return this->client_connected_trigger_; }
|
Trigger<> *get_client_connected_trigger() const { return this->client_connected_trigger_; }
|
||||||
Trigger<> *get_client_disconnected_trigger() const { return this->client_disconnected_trigger_; }
|
Trigger<> *get_client_disconnected_trigger() const { return this->client_disconnected_trigger_; }
|
||||||
@@ -123,6 +124,8 @@ class VoiceAssistant : public Component {
|
|||||||
void client_subscription(api::APIConnection *client, bool subscribe);
|
void client_subscription(api::APIConnection *client, bool subscribe);
|
||||||
api::APIConnection *get_api_connection() const { return this->api_client_; }
|
api::APIConnection *get_api_connection() const { return this->api_client_; }
|
||||||
|
|
||||||
|
void set_wake_word(const std::string &wake_word) { this->wake_word_ = wake_word; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int read_microphone_();
|
int read_microphone_();
|
||||||
void set_state_(State state);
|
void set_state_(State state);
|
||||||
@@ -148,6 +151,7 @@ class VoiceAssistant : public Component {
|
|||||||
Trigger<std::string> *tts_end_trigger_ = new Trigger<std::string>();
|
Trigger<std::string> *tts_end_trigger_ = new Trigger<std::string>();
|
||||||
Trigger<std::string> *tts_start_trigger_ = new Trigger<std::string>();
|
Trigger<std::string> *tts_start_trigger_ = new Trigger<std::string>();
|
||||||
Trigger<std::string, std::string> *error_trigger_ = new Trigger<std::string, std::string>();
|
Trigger<std::string, std::string> *error_trigger_ = new Trigger<std::string, std::string>();
|
||||||
|
Trigger<> *idle_trigger_ = new Trigger<>();
|
||||||
|
|
||||||
Trigger<> *client_connected_trigger_ = new Trigger<>();
|
Trigger<> *client_connected_trigger_ = new Trigger<>();
|
||||||
Trigger<> *client_disconnected_trigger_ = new Trigger<>();
|
Trigger<> *client_disconnected_trigger_ = new Trigger<>();
|
||||||
@@ -173,6 +177,8 @@ class VoiceAssistant : public Component {
|
|||||||
|
|
||||||
std::string conversation_id_{""};
|
std::string conversation_id_{""};
|
||||||
|
|
||||||
|
std::string wake_word_{""};
|
||||||
|
|
||||||
HighFrequencyLoopRequester high_freq_;
|
HighFrequencyLoopRequester high_freq_;
|
||||||
|
|
||||||
#ifdef USE_ESP_ADF
|
#ifdef USE_ESP_ADF
|
||||||
@@ -198,8 +204,13 @@ class VoiceAssistant : public Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<typename... Ts> class StartAction : public Action<Ts...>, public Parented<VoiceAssistant> {
|
template<typename... Ts> class StartAction : public Action<Ts...>, public Parented<VoiceAssistant> {
|
||||||
|
TEMPLATABLE_VALUE(std::string, wake_word);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void play(Ts... x) override { this->parent_->request_start(false, this->silence_detection_); }
|
void play(Ts... x) override {
|
||||||
|
this->parent_->set_wake_word(this->wake_word_.value(x...));
|
||||||
|
this->parent_->request_start(false, this->silence_detection_);
|
||||||
|
}
|
||||||
|
|
||||||
void set_silence_detection(bool silence_detection) { this->silence_detection_ = silence_detection; }
|
void set_silence_detection(bool silence_detection) { this->silence_detection_ = silence_detection; }
|
||||||
|
|
||||||
|
|||||||
@@ -785,6 +785,8 @@ std::string WebServer::cover_json(cover::Cover *obj, JsonDetail start_config) {
|
|||||||
obj->position, start_config);
|
obj->position, start_config);
|
||||||
root["current_operation"] = cover::cover_operation_to_str(obj->current_operation);
|
root["current_operation"] = cover::cover_operation_to_str(obj->current_operation);
|
||||||
|
|
||||||
|
if (obj->get_traits().get_supports_position())
|
||||||
|
root["position"] = obj->position;
|
||||||
if (obj->get_traits().get_supports_tilt())
|
if (obj->get_traits().get_supports_tilt())
|
||||||
root["tilt"] = obj->tilt;
|
root["tilt"] = obj->tilt;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"""Constants used by esphome."""
|
"""Constants used by esphome."""
|
||||||
|
|
||||||
__version__ = "2024.2.0b2"
|
__version__ = "2024.2.2"
|
||||||
|
|
||||||
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
|
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
|
||||||
VALID_SUBSTITUTIONS_CHARACTERS = (
|
VALID_SUBSTITUTIONS_CHARACTERS = (
|
||||||
|
|||||||
@@ -8,3 +8,5 @@ MAX_EXECUTOR_WORKERS = 48
|
|||||||
|
|
||||||
|
|
||||||
SENTINEL = object()
|
SENTINEL = object()
|
||||||
|
|
||||||
|
DASHBOARD_COMMAND = ["esphome", "--dashboard"]
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import contextlib
|
||||||
import logging
|
import logging
|
||||||
import threading
|
import threading
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from typing import TYPE_CHECKING, Any, Callable
|
from typing import TYPE_CHECKING, Any, Callable
|
||||||
|
from collections.abc import Coroutine
|
||||||
|
|
||||||
from ..zeroconf import DiscoveredImport
|
from ..zeroconf import DiscoveredImport
|
||||||
from .dns import DNSCache
|
from .dns import DNSCache
|
||||||
@@ -71,6 +73,7 @@ class ESPHomeDashboard:
|
|||||||
"mdns_status",
|
"mdns_status",
|
||||||
"settings",
|
"settings",
|
||||||
"dns_cache",
|
"dns_cache",
|
||||||
|
"_background_tasks",
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
@@ -85,6 +88,7 @@ class ESPHomeDashboard:
|
|||||||
self.mdns_status: MDNSStatus | None = None
|
self.mdns_status: MDNSStatus | None = None
|
||||||
self.settings = DashboardSettings()
|
self.settings = DashboardSettings()
|
||||||
self.dns_cache = DNSCache()
|
self.dns_cache = DNSCache()
|
||||||
|
self._background_tasks: set[asyncio.Task] = set()
|
||||||
|
|
||||||
async def async_setup(self) -> None:
|
async def async_setup(self) -> None:
|
||||||
"""Setup the dashboard."""
|
"""Setup the dashboard."""
|
||||||
@@ -132,7 +136,19 @@ class ESPHomeDashboard:
|
|||||||
if settings.status_use_mqtt:
|
if settings.status_use_mqtt:
|
||||||
status_thread_mqtt.join()
|
status_thread_mqtt.join()
|
||||||
self.mqtt_ping_request.set()
|
self.mqtt_ping_request.set()
|
||||||
|
for task in self._background_tasks:
|
||||||
|
task.cancel()
|
||||||
|
with contextlib.suppress(asyncio.CancelledError):
|
||||||
|
await task
|
||||||
await asyncio.sleep(0)
|
await asyncio.sleep(0)
|
||||||
|
|
||||||
|
def async_create_background_task(
|
||||||
|
self, coro: Coroutine[Any, Any, Any]
|
||||||
|
) -> asyncio.Task:
|
||||||
|
"""Create a background task."""
|
||||||
|
task = self.loop.create_task(coro)
|
||||||
|
task.add_done_callback(self._background_tasks.discard)
|
||||||
|
return task
|
||||||
|
|
||||||
|
|
||||||
DASHBOARD = ESPHomeDashboard()
|
DASHBOARD = ESPHomeDashboard()
|
||||||
|
|||||||
@@ -10,12 +10,14 @@ from esphome import const, util
|
|||||||
from esphome.storage_json import StorageJSON, ext_storage_path
|
from esphome.storage_json import StorageJSON, ext_storage_path
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
|
DASHBOARD_COMMAND,
|
||||||
EVENT_ENTRY_ADDED,
|
EVENT_ENTRY_ADDED,
|
||||||
EVENT_ENTRY_REMOVED,
|
EVENT_ENTRY_REMOVED,
|
||||||
EVENT_ENTRY_STATE_CHANGED,
|
EVENT_ENTRY_STATE_CHANGED,
|
||||||
EVENT_ENTRY_UPDATED,
|
EVENT_ENTRY_UPDATED,
|
||||||
)
|
)
|
||||||
from .enum import StrEnum
|
from .enum import StrEnum
|
||||||
|
from .util.subprocess import async_run_system_command
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .core import ESPHomeDashboard
|
from .core import ESPHomeDashboard
|
||||||
@@ -235,6 +237,14 @@ class DashboardEntries:
|
|||||||
)
|
)
|
||||||
return path_to_cache_key
|
return path_to_cache_key
|
||||||
|
|
||||||
|
def async_schedule_storage_json_update(self, filename: str) -> None:
|
||||||
|
"""Schedule a task to update the storage JSON file."""
|
||||||
|
self._dashboard.async_create_background_task(
|
||||||
|
async_run_system_command(
|
||||||
|
[*DASHBOARD_COMMAND, "compile", "--only-generate", filename]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class DashboardEntry:
|
class DashboardEntry:
|
||||||
"""Represents a single dashboard entry.
|
"""Represents a single dashboard entry.
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ import hashlib
|
|||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import time
|
|
||||||
import secrets
|
import secrets
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import threading
|
import threading
|
||||||
|
import time
|
||||||
from collections.abc import Iterable
|
from collections.abc import Iterable
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import TYPE_CHECKING, Any, Callable, TypeVar
|
from typing import TYPE_CHECKING, Any, Callable, TypeVar
|
||||||
@@ -40,6 +40,7 @@ from esphome.storage_json import StorageJSON, ext_storage_path, trash_storage_pa
|
|||||||
from esphome.util import get_serial_ports, shlex_quote
|
from esphome.util import get_serial_ports, shlex_quote
|
||||||
from esphome.yaml_util import FastestAvailableSafeLoader
|
from esphome.yaml_util import FastestAvailableSafeLoader
|
||||||
|
|
||||||
|
from .const import DASHBOARD_COMMAND
|
||||||
from .core import DASHBOARD
|
from .core import DASHBOARD
|
||||||
from .entries import EntryState, entry_state_to_bool
|
from .entries import EntryState, entry_state_to_bool
|
||||||
from .util.file import write_file
|
from .util.file import write_file
|
||||||
@@ -286,9 +287,6 @@ class EsphomeCommandWebSocket(tornado.websocket.WebSocketHandler):
|
|||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
DASHBOARD_COMMAND = ["esphome", "--dashboard"]
|
|
||||||
|
|
||||||
|
|
||||||
class EsphomePortCommandWebSocket(EsphomeCommandWebSocket):
|
class EsphomePortCommandWebSocket(EsphomeCommandWebSocket):
|
||||||
"""Base class for commands that require a port."""
|
"""Base class for commands that require a port."""
|
||||||
|
|
||||||
@@ -808,12 +806,21 @@ class EditRequestHandler(BaseHandler):
|
|||||||
@bind_config
|
@bind_config
|
||||||
async def get(self, configuration: str | None = None) -> None:
|
async def get(self, configuration: str | None = None) -> None:
|
||||||
"""Get the content of a file."""
|
"""Get the content of a file."""
|
||||||
loop = asyncio.get_running_loop()
|
if not configuration.endswith((".yaml", ".yml")):
|
||||||
|
self.send_error(404)
|
||||||
|
return
|
||||||
|
|
||||||
filename = settings.rel_path(configuration)
|
filename = settings.rel_path(configuration)
|
||||||
|
if Path(filename).resolve().parent != settings.absolute_config_dir:
|
||||||
|
self.send_error(404)
|
||||||
|
return
|
||||||
|
|
||||||
|
loop = asyncio.get_running_loop()
|
||||||
content = await loop.run_in_executor(
|
content = await loop.run_in_executor(
|
||||||
None, self._read_file, filename, configuration
|
None, self._read_file, filename, configuration
|
||||||
)
|
)
|
||||||
if content is not None:
|
if content is not None:
|
||||||
|
self.set_header("Content-Type", "application/yaml")
|
||||||
self.write(content)
|
self.write(content)
|
||||||
|
|
||||||
def _read_file(self, filename: str, configuration: str) -> bytes | None:
|
def _read_file(self, filename: str, configuration: str) -> bytes | None:
|
||||||
@@ -835,15 +842,19 @@ class EditRequestHandler(BaseHandler):
|
|||||||
@bind_config
|
@bind_config
|
||||||
async def post(self, configuration: str | None = None) -> None:
|
async def post(self, configuration: str | None = None) -> None:
|
||||||
"""Write the content of a file."""
|
"""Write the content of a file."""
|
||||||
|
if not configuration.endswith((".yaml", ".yml")):
|
||||||
|
self.send_error(404)
|
||||||
|
return
|
||||||
|
|
||||||
|
filename = settings.rel_path(configuration)
|
||||||
|
if Path(filename).resolve().parent != settings.absolute_config_dir:
|
||||||
|
self.send_error(404)
|
||||||
|
return
|
||||||
|
|
||||||
loop = asyncio.get_running_loop()
|
loop = asyncio.get_running_loop()
|
||||||
config_file = settings.rel_path(configuration)
|
await loop.run_in_executor(None, self._write_file, filename, self.request.body)
|
||||||
await loop.run_in_executor(
|
|
||||||
None, self._write_file, config_file, self.request.body
|
|
||||||
)
|
|
||||||
# Ensure the StorageJSON is updated as well
|
# Ensure the StorageJSON is updated as well
|
||||||
await async_run_system_command(
|
DASHBOARD.entries.async_schedule_storage_json_update(filename)
|
||||||
[*DASHBOARD_COMMAND, "compile", "--only-generate", config_file]
|
|
||||||
)
|
|
||||||
self.set_status(200)
|
self.set_status(200)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ class DashboardImportDiscovery:
|
|||||||
self, zeroconf: Zeroconf, info: AsyncServiceInfo, service_type: str, name: str
|
self, zeroconf: Zeroconf, info: AsyncServiceInfo, service_type: str, name: str
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Process a service info."""
|
"""Process a service info."""
|
||||||
if await info.async_request(zeroconf):
|
if await info.async_request(zeroconf, timeout=3000):
|
||||||
self._process_service_info(name, info)
|
self._process_service_info(name, info)
|
||||||
|
|
||||||
def _process_service_info(self, name: str, info: ServiceInfo) -> None:
|
def _process_service_info(self, name: str, info: ServiceInfo) -> None:
|
||||||
|
|||||||
Reference in New Issue
Block a user