mirror of
https://github.com/esphome/esphome.git
synced 2025-08-10 20:29:24 +00:00
Compare commits
34 Commits
2023.5.0b1
...
2023.5.2
Author | SHA1 | Date | |
---|---|---|---|
![]() |
70aa5d0f6c | ||
![]() |
8fcec8e2cb | ||
![]() |
2d3b48f86f | ||
![]() |
99c10bc6de | ||
![]() |
f30f20db86 | ||
![]() |
9bf946e196 | ||
![]() |
bfaad1f28d | ||
![]() |
f90e9ba871 | ||
![]() |
726bdd7be2 | ||
![]() |
52db40eb41 | ||
![]() |
3c371a0c59 | ||
![]() |
c941bc4109 | ||
![]() |
cc76e5353c | ||
![]() |
11bb46e393 | ||
![]() |
71c4714a6e | ||
![]() |
a4e63c5f86 | ||
![]() |
c71e7d0132 | ||
![]() |
daa966975e | ||
![]() |
2e5757a3f0 | ||
![]() |
f66024b37c | ||
![]() |
c16ca7be13 | ||
![]() |
e13e754bc4 | ||
![]() |
6ccea59f71 | ||
![]() |
71b28be3c8 | ||
![]() |
e25d92e1f5 | ||
![]() |
65cda10884 | ||
![]() |
625126df68 | ||
![]() |
e0ee8ca17c | ||
![]() |
af95e781f5 | ||
![]() |
9b230a7d93 | ||
![]() |
e2f3e7c3a6 | ||
![]() |
2fd2e5ceb2 | ||
![]() |
d88358be8e | ||
![]() |
d80885c7a8 |
@@ -4,7 +4,6 @@ from esphome.components import i2c
|
||||
from esphome.const import CONF_ID
|
||||
|
||||
DEPENDENCIES = ["i2c"]
|
||||
AUTO_LOAD = ["sensor", "binary_sensor"]
|
||||
MULTI_CONF = True
|
||||
|
||||
CONF_APDS9960_ID = "apds9960_id"
|
||||
|
@@ -116,8 +116,12 @@ void APDS9960::setup() {
|
||||
APDS9960_WRITE_BYTE(0x80, val);
|
||||
}
|
||||
bool APDS9960::is_color_enabled_() const {
|
||||
return this->red_channel_ != nullptr || this->green_channel_ != nullptr || this->blue_channel_ != nullptr ||
|
||||
this->clear_channel_ != nullptr;
|
||||
#ifdef USE_SENSOR
|
||||
return this->red_sensor_ != nullptr || this->green_sensor_ != nullptr || this->blue_sensor_ != nullptr ||
|
||||
this->clear_sensor_ != nullptr;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void APDS9960::dump_config() {
|
||||
@@ -125,6 +129,15 @@ void APDS9960::dump_config() {
|
||||
LOG_I2C_DEVICE(this);
|
||||
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
|
||||
#ifdef USE_SENSOR
|
||||
LOG_SENSOR(" ", "Red channel", this->red_sensor_);
|
||||
LOG_SENSOR(" ", "Green channel", this->green_sensor_);
|
||||
LOG_SENSOR(" ", "Blue channel", this->blue_sensor_);
|
||||
LOG_SENSOR(" ", "Clear channel", this->clear_sensor_);
|
||||
LOG_SENSOR(" ", "Proximity", this->proximity_sensor_);
|
||||
#endif
|
||||
|
||||
if (this->is_failed()) {
|
||||
switch (this->error_code_) {
|
||||
case COMMUNICATION_FAILED:
|
||||
@@ -181,17 +194,22 @@ void APDS9960::read_color_data_(uint8_t status) {
|
||||
float blue_perc = (uint_blue / float(UINT16_MAX)) * 100.0f;
|
||||
|
||||
ESP_LOGD(TAG, "Got clear=%.1f%% red=%.1f%% green=%.1f%% blue=%.1f%%", clear_perc, red_perc, green_perc, blue_perc);
|
||||
if (this->clear_channel_ != nullptr)
|
||||
this->clear_channel_->publish_state(clear_perc);
|
||||
if (this->red_channel_ != nullptr)
|
||||
this->red_channel_->publish_state(red_perc);
|
||||
if (this->green_channel_ != nullptr)
|
||||
this->green_channel_->publish_state(green_perc);
|
||||
if (this->blue_channel_ != nullptr)
|
||||
this->blue_channel_->publish_state(blue_perc);
|
||||
#ifdef USE_SENSOR
|
||||
if (this->clear_sensor_ != nullptr)
|
||||
this->clear_sensor_->publish_state(clear_perc);
|
||||
if (this->red_sensor_ != nullptr)
|
||||
this->red_sensor_->publish_state(red_perc);
|
||||
if (this->green_sensor_ != nullptr)
|
||||
this->green_sensor_->publish_state(green_perc);
|
||||
if (this->blue_sensor_ != nullptr)
|
||||
this->blue_sensor_->publish_state(blue_perc);
|
||||
#endif
|
||||
}
|
||||
void APDS9960::read_proximity_data_(uint8_t status) {
|
||||
if (this->proximity_ == nullptr)
|
||||
#ifndef USE_SENSOR
|
||||
return;
|
||||
#else
|
||||
if (this->proximity_sensor_ == nullptr)
|
||||
return;
|
||||
|
||||
if ((status & 0b10) == 0x00) {
|
||||
@@ -204,7 +222,8 @@ void APDS9960::read_proximity_data_(uint8_t status) {
|
||||
|
||||
float prox_perc = (prox / float(UINT8_MAX)) * 100.0f;
|
||||
ESP_LOGD(TAG, "Got proximity=%.1f%%", prox_perc);
|
||||
this->proximity_->publish_state(prox_perc);
|
||||
this->proximity_sensor_->publish_state(prox_perc);
|
||||
#endif
|
||||
}
|
||||
void APDS9960::read_gesture_data_() {
|
||||
if (!this->is_gesture_enabled_())
|
||||
@@ -256,28 +275,29 @@ void APDS9960::read_gesture_data_() {
|
||||
}
|
||||
}
|
||||
void APDS9960::report_gesture_(int gesture) {
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
binary_sensor::BinarySensor *bin;
|
||||
switch (gesture) {
|
||||
case 1:
|
||||
bin = this->up_direction_;
|
||||
bin = this->up_direction_binary_sensor_;
|
||||
this->gesture_up_started_ = false;
|
||||
this->gesture_down_started_ = false;
|
||||
ESP_LOGD(TAG, "Got gesture UP");
|
||||
break;
|
||||
case 2:
|
||||
bin = this->down_direction_;
|
||||
bin = this->down_direction_binary_sensor_;
|
||||
this->gesture_up_started_ = false;
|
||||
this->gesture_down_started_ = false;
|
||||
ESP_LOGD(TAG, "Got gesture DOWN");
|
||||
break;
|
||||
case 3:
|
||||
bin = this->left_direction_;
|
||||
bin = this->left_direction_binary_sensor_;
|
||||
this->gesture_left_started_ = false;
|
||||
this->gesture_right_started_ = false;
|
||||
ESP_LOGD(TAG, "Got gesture LEFT");
|
||||
break;
|
||||
case 4:
|
||||
bin = this->right_direction_;
|
||||
bin = this->right_direction_binary_sensor_;
|
||||
this->gesture_left_started_ = false;
|
||||
this->gesture_right_started_ = false;
|
||||
ESP_LOGD(TAG, "Got gesture RIGHT");
|
||||
@@ -290,6 +310,7 @@ void APDS9960::report_gesture_(int gesture) {
|
||||
bin->publish_state(true);
|
||||
bin->publish_state(false);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
void APDS9960::process_dataset_(int up, int down, int left, int right) {
|
||||
/* Algorithm: (see Figure 11 in datasheet)
|
||||
@@ -365,10 +386,22 @@ void APDS9960::process_dataset_(int up, int down, int left, int right) {
|
||||
}
|
||||
}
|
||||
float APDS9960::get_setup_priority() const { return setup_priority::DATA; }
|
||||
bool APDS9960::is_proximity_enabled_() const { return this->proximity_ != nullptr || this->is_gesture_enabled_(); }
|
||||
bool APDS9960::is_proximity_enabled_() const {
|
||||
return
|
||||
#ifdef USE_SENSOR
|
||||
this->proximity_sensor_ != nullptr
|
||||
#else
|
||||
false
|
||||
#endif
|
||||
|| this->is_gesture_enabled_();
|
||||
}
|
||||
bool APDS9960::is_gesture_enabled_() const {
|
||||
return this->up_direction_ != nullptr || this->left_direction_ != nullptr || this->down_direction_ != nullptr ||
|
||||
this->right_direction_ != nullptr;
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
return this->up_direction_binary_sensor_ != nullptr || this->left_direction_binary_sensor_ != nullptr ||
|
||||
this->down_direction_binary_sensor_ != nullptr || this->right_direction_binary_sensor_ != nullptr;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace apds9960
|
||||
|
@@ -1,14 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/i2c/i2c.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#ifdef USE_SENSOR
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#endif
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
#include "esphome/components/binary_sensor/binary_sensor.h"
|
||||
#endif
|
||||
|
||||
namespace esphome {
|
||||
namespace apds9960 {
|
||||
|
||||
class APDS9960 : public PollingComponent, public i2c::I2CDevice {
|
||||
#ifdef USE_SENSOR
|
||||
SUB_SENSOR(red)
|
||||
SUB_SENSOR(green)
|
||||
SUB_SENSOR(blue)
|
||||
SUB_SENSOR(clear)
|
||||
SUB_SENSOR(proximity)
|
||||
#endif
|
||||
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
SUB_BINARY_SENSOR(up_direction)
|
||||
SUB_BINARY_SENSOR(right_direction)
|
||||
SUB_BINARY_SENSOR(down_direction)
|
||||
SUB_BINARY_SENSOR(left_direction)
|
||||
#endif
|
||||
|
||||
public:
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
@@ -23,16 +43,6 @@ class APDS9960 : public PollingComponent, public i2c::I2CDevice {
|
||||
void set_gesture_gain(uint8_t gain) { this->gesture_gain_ = gain; }
|
||||
void set_gesture_wait_time(uint8_t wait_time) { this->gesture_wait_time_ = wait_time; }
|
||||
|
||||
void set_red_channel(sensor::Sensor *red_channel) { red_channel_ = red_channel; }
|
||||
void set_green_channel(sensor::Sensor *green_channel) { green_channel_ = green_channel; }
|
||||
void set_blue_channel(sensor::Sensor *blue_channel) { blue_channel_ = blue_channel; }
|
||||
void set_clear_channel(sensor::Sensor *clear_channel) { clear_channel_ = clear_channel; }
|
||||
void set_up_direction(binary_sensor::BinarySensor *up_direction) { up_direction_ = up_direction; }
|
||||
void set_right_direction(binary_sensor::BinarySensor *right_direction) { right_direction_ = right_direction; }
|
||||
void set_down_direction(binary_sensor::BinarySensor *down_direction) { down_direction_ = down_direction; }
|
||||
void set_left_direction(binary_sensor::BinarySensor *left_direction) { left_direction_ = left_direction; }
|
||||
void set_proximity(sensor::Sensor *proximity) { proximity_ = proximity; }
|
||||
|
||||
protected:
|
||||
bool is_color_enabled_() const;
|
||||
bool is_proximity_enabled_() const;
|
||||
@@ -50,15 +60,6 @@ class APDS9960 : public PollingComponent, public i2c::I2CDevice {
|
||||
uint8_t gesture_gain_;
|
||||
uint8_t gesture_wait_time_;
|
||||
|
||||
sensor::Sensor *red_channel_{nullptr};
|
||||
sensor::Sensor *green_channel_{nullptr};
|
||||
sensor::Sensor *blue_channel_{nullptr};
|
||||
sensor::Sensor *clear_channel_{nullptr};
|
||||
binary_sensor::BinarySensor *up_direction_{nullptr};
|
||||
binary_sensor::BinarySensor *right_direction_{nullptr};
|
||||
binary_sensor::BinarySensor *down_direction_{nullptr};
|
||||
binary_sensor::BinarySensor *left_direction_{nullptr};
|
||||
sensor::Sensor *proximity_{nullptr};
|
||||
enum ErrorCode {
|
||||
NONE = 0,
|
||||
COMMUNICATION_FAILED,
|
||||
|
@@ -6,19 +6,14 @@ from . import APDS9960, CONF_APDS9960_ID
|
||||
|
||||
DEPENDENCIES = ["apds9960"]
|
||||
|
||||
DIRECTIONS = {
|
||||
"UP": "set_up_direction",
|
||||
"DOWN": "set_down_direction",
|
||||
"LEFT": "set_left_direction",
|
||||
"RIGHT": "set_right_direction",
|
||||
}
|
||||
DIRECTIONS = ["up", "down", "left", "right"]
|
||||
|
||||
CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(
|
||||
device_class=DEVICE_CLASS_MOVING
|
||||
).extend(
|
||||
{
|
||||
cv.GenerateID(CONF_APDS9960_ID): cv.use_id(APDS9960),
|
||||
cv.Required(CONF_DIRECTION): cv.one_of(*DIRECTIONS, upper=True),
|
||||
cv.Required(CONF_DIRECTION): cv.one_of(*DIRECTIONS, lower=True),
|
||||
}
|
||||
)
|
||||
|
||||
@@ -26,5 +21,5 @@ CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(
|
||||
async def to_code(config):
|
||||
hub = await cg.get_variable(config[CONF_APDS9960_ID])
|
||||
var = await binary_sensor.new_binary_sensor(config)
|
||||
func = getattr(hub, DIRECTIONS[config[CONF_DIRECTION]])
|
||||
func = getattr(hub, f"set_{config[CONF_DIRECTION]}_direction_binary_sensor")
|
||||
cg.add(func(var))
|
||||
|
@@ -11,13 +11,7 @@ from . import APDS9960, CONF_APDS9960_ID
|
||||
|
||||
DEPENDENCIES = ["apds9960"]
|
||||
|
||||
TYPES = {
|
||||
"CLEAR": "set_clear_channel",
|
||||
"RED": "set_red_channel",
|
||||
"GREEN": "set_green_channel",
|
||||
"BLUE": "set_blue_channel",
|
||||
"PROXIMITY": "set_proximity",
|
||||
}
|
||||
TYPES = ["clear", "red", "green", "blue", "proximity"]
|
||||
|
||||
CONFIG_SCHEMA = sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_PERCENT,
|
||||
@@ -26,7 +20,7 @@ CONFIG_SCHEMA = sensor.sensor_schema(
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
).extend(
|
||||
{
|
||||
cv.Required(CONF_TYPE): cv.one_of(*TYPES, upper=True),
|
||||
cv.Required(CONF_TYPE): cv.one_of(*TYPES, lower=True),
|
||||
cv.GenerateID(CONF_APDS9960_ID): cv.use_id(APDS9960),
|
||||
}
|
||||
)
|
||||
@@ -35,5 +29,5 @@ CONFIG_SCHEMA = sensor.sensor_schema(
|
||||
async def to_code(config):
|
||||
hub = await cg.get_variable(config[CONF_APDS9960_ID])
|
||||
var = await sensor.new_sensor(config)
|
||||
func = getattr(hub, TYPES[config[CONF_TYPE]])
|
||||
func = getattr(hub, f"set_{config[CONF_TYPE]}_sensor")
|
||||
cg.add(func(var))
|
||||
|
@@ -223,6 +223,7 @@ bool APIConnection::send_cover_info(cover::Cover *cover) {
|
||||
msg.assumed_state = traits.get_is_assumed_state();
|
||||
msg.supports_position = traits.get_supports_position();
|
||||
msg.supports_tilt = traits.get_supports_tilt();
|
||||
msg.supports_stop = traits.get_supports_stop();
|
||||
msg.device_class = cover->get_device_class();
|
||||
msg.disabled_by_default = cover->is_disabled_by_default();
|
||||
msg.icon = cover->get_icon();
|
||||
|
@@ -22,14 +22,14 @@ void I2SAudioMediaPlayer::control(const media_player::MediaPlayerCall &call) {
|
||||
this->start();
|
||||
}
|
||||
}
|
||||
if (this->i2s_state_ != I2S_STATE_RUNNING) {
|
||||
return;
|
||||
}
|
||||
if (call.get_volume().has_value()) {
|
||||
this->volume = call.get_volume().value();
|
||||
this->set_volume_(volume);
|
||||
this->unmute_();
|
||||
}
|
||||
if (this->i2s_state_ != I2S_STATE_RUNNING) {
|
||||
return;
|
||||
}
|
||||
if (call.get_command().has_value()) {
|
||||
switch (call.get_command().value()) {
|
||||
case media_player::MEDIA_PLAYER_COMMAND_PLAY:
|
||||
@@ -97,7 +97,8 @@ void I2SAudioMediaPlayer::unmute_() {
|
||||
this->muted_ = false;
|
||||
}
|
||||
void I2SAudioMediaPlayer::set_volume_(float volume, bool publish) {
|
||||
this->audio_->setVolume(remap<uint8_t, float>(volume, 0.0f, 1.0f, 0, 21));
|
||||
if (this->audio_ != nullptr)
|
||||
this->audio_->setVolume(remap<uint8_t, float>(volume, 0.0f, 1.0f, 0, 21));
|
||||
if (publish)
|
||||
this->volume = volume;
|
||||
}
|
||||
@@ -132,7 +133,7 @@ void I2SAudioMediaPlayer::play_() {
|
||||
|
||||
void I2SAudioMediaPlayer::start() { this->i2s_state_ = I2S_STATE_STARTING; }
|
||||
void I2SAudioMediaPlayer::start_() {
|
||||
if (this->parent_->try_lock()) {
|
||||
if (!this->parent_->try_lock()) {
|
||||
return; // Waiting for another i2s to return lock
|
||||
}
|
||||
|
||||
@@ -155,15 +156,26 @@ void I2SAudioMediaPlayer::start_() {
|
||||
#if SOC_I2S_SUPPORTS_DAC
|
||||
}
|
||||
#endif
|
||||
|
||||
this->i2s_state_ = I2S_STATE_RUNNING;
|
||||
this->high_freq_.start();
|
||||
this->audio_->setVolume(remap<uint8_t, float>(this->volume, 0.0f, 1.0f, 0, 21));
|
||||
if (this->current_url_.has_value()) {
|
||||
this->audio_->connecttohost(this->current_url_.value().c_str());
|
||||
this->state = media_player::MEDIA_PLAYER_STATE_PLAYING;
|
||||
this->publish_state();
|
||||
}
|
||||
}
|
||||
void I2SAudioMediaPlayer::stop() { this->i2s_state_ = I2S_STATE_STOPPING; }
|
||||
void I2SAudioMediaPlayer::stop() {
|
||||
if (this->i2s_state_ == I2S_STATE_STOPPED) {
|
||||
return;
|
||||
}
|
||||
if (this->i2s_state_ == I2S_STATE_STARTING) {
|
||||
this->i2s_state_ = I2S_STATE_STOPPED;
|
||||
return;
|
||||
}
|
||||
this->i2s_state_ = I2S_STATE_STOPPING;
|
||||
}
|
||||
void I2SAudioMediaPlayer::stop_() {
|
||||
if (this->audio_->isRunning()) {
|
||||
this->audio_->stopSong();
|
||||
@@ -207,6 +219,12 @@ void I2SAudioMediaPlayer::dump_config() {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
#endif
|
||||
ESP_LOGCONFIG(TAG, " External DAC channels: %d", this->external_dac_channels_);
|
||||
ESP_LOGCONFIG(TAG, " I2S DOUT Pin: %d", this->dout_pin_);
|
||||
LOG_PIN(" Mute Pin: ", this->mute_pin_);
|
||||
#if SOC_I2S_SUPPORTS_DAC
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@@ -89,6 +89,10 @@ void I2SAudioMicrophone::start_() {
|
||||
void I2SAudioMicrophone::stop() {
|
||||
if (this->state_ == microphone::STATE_STOPPED || this->is_failed())
|
||||
return;
|
||||
if (this->state_ == microphone::STATE_STARTING) {
|
||||
this->state_ = microphone::STATE_STOPPED;
|
||||
return;
|
||||
}
|
||||
this->state_ = microphone::STATE_STOPPING;
|
||||
}
|
||||
|
||||
|
@@ -136,6 +136,10 @@ void I2SAudioSpeaker::player_task(void *params) {
|
||||
void I2SAudioSpeaker::stop() {
|
||||
if (this->state_ == speaker::STATE_STOPPED)
|
||||
return;
|
||||
if (this->state_ == speaker::STATE_STARTING) {
|
||||
this->state_ = speaker::STATE_STOPPED;
|
||||
return;
|
||||
}
|
||||
this->state_ = speaker::STATE_STOPPING;
|
||||
DataEvent data;
|
||||
data.stop = true;
|
||||
|
@@ -33,7 +33,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
cv.COMPONENT_SCHEMA.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(KeyCollector),
|
||||
cv.GenerateID(CONF_SOURCE_ID): cv.use_id(key_provider.KeyProvider),
|
||||
cv.Optional(CONF_SOURCE_ID): cv.use_id(key_provider.KeyProvider),
|
||||
cv.Optional(CONF_MIN_LENGTH): cv.int_,
|
||||
cv.Optional(CONF_MAX_LENGTH): cv.int_,
|
||||
cv.Optional(CONF_START_KEYS): cv.string,
|
||||
@@ -55,8 +55,9 @@ CONFIG_SCHEMA = cv.All(
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await cg.register_component(var, config)
|
||||
source = await cg.get_variable(config[CONF_SOURCE_ID])
|
||||
cg.add(var.set_provider(source))
|
||||
if CONF_SOURCE_ID in config:
|
||||
source = await cg.get_variable(config[CONF_SOURCE_ID])
|
||||
cg.add(var.set_provider(source))
|
||||
if CONF_MIN_LENGTH in config:
|
||||
cg.add(var.set_min_length(config[CONF_MIN_LENGTH]))
|
||||
if CONF_MAX_LENGTH in config:
|
||||
|
@@ -52,6 +52,8 @@ void KeyCollector::clear(bool progress_update) {
|
||||
this->progress_trigger_->trigger(this->result_, 0);
|
||||
}
|
||||
|
||||
void KeyCollector::send_key(uint8_t key) { this->key_pressed_(key); }
|
||||
|
||||
void KeyCollector::key_pressed_(uint8_t key) {
|
||||
this->last_key_time_ = millis();
|
||||
if (!this->start_keys_.empty() && !this->start_key_) {
|
||||
|
@@ -27,6 +27,7 @@ class KeyCollector : public Component {
|
||||
void set_timeout(int timeout) { this->timeout_ = timeout; };
|
||||
|
||||
void clear(bool progress_update = true);
|
||||
void send_key(uint8_t key);
|
||||
|
||||
protected:
|
||||
void key_pressed_(uint8_t key);
|
||||
|
@@ -25,7 +25,7 @@ class PulseLightEffect : public LightEffect {
|
||||
return;
|
||||
}
|
||||
auto call = this->state_->turn_on();
|
||||
float out = this->on_ ? 1.0 : 0.0;
|
||||
float out = this->on_ ? this->max_brightness : this->min_brightness;
|
||||
call.set_brightness_if_supported(out);
|
||||
this->on_ = !this->on_;
|
||||
call.set_transition_length_if_supported(this->transition_length_);
|
||||
@@ -41,11 +41,18 @@ class PulseLightEffect : public LightEffect {
|
||||
|
||||
void set_update_interval(uint32_t update_interval) { this->update_interval_ = update_interval; }
|
||||
|
||||
void set_min_max_brightness(float min, float max) {
|
||||
this->min_brightness = min;
|
||||
this->max_brightness = max;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool on_ = false;
|
||||
uint32_t last_color_change_{0};
|
||||
uint32_t transition_length_{};
|
||||
uint32_t update_interval_{};
|
||||
float min_brightness{0.0};
|
||||
float max_brightness{1.0};
|
||||
};
|
||||
|
||||
/// Random effect. Sets random colors every 10 seconds and slowly transitions between them.
|
||||
|
@@ -28,6 +28,8 @@ from esphome.const import (
|
||||
CONF_NUM_LEDS,
|
||||
CONF_RANDOM,
|
||||
CONF_SEQUENCE,
|
||||
CONF_MAX_BRIGHTNESS,
|
||||
CONF_MIN_BRIGHTNESS,
|
||||
)
|
||||
from esphome.util import Registry
|
||||
from .types import (
|
||||
@@ -174,12 +176,19 @@ async def automation_effect_to_code(config, effect_id):
|
||||
cv.Optional(
|
||||
CONF_UPDATE_INTERVAL, default="1s"
|
||||
): cv.positive_time_period_milliseconds,
|
||||
cv.Optional(CONF_MIN_BRIGHTNESS, default="0%"): cv.percentage,
|
||||
cv.Optional(CONF_MAX_BRIGHTNESS, default="100%"): cv.percentage,
|
||||
},
|
||||
)
|
||||
async def pulse_effect_to_code(config, effect_id):
|
||||
effect = cg.new_Pvariable(effect_id, config[CONF_NAME])
|
||||
cg.add(effect.set_transition_length(config[CONF_TRANSITION_LENGTH]))
|
||||
cg.add(effect.set_update_interval(config[CONF_UPDATE_INTERVAL]))
|
||||
cg.add(
|
||||
effect.set_min_max_brightness(
|
||||
config[CONF_MIN_BRIGHTNESS], config[CONF_MAX_BRIGHTNESS]
|
||||
)
|
||||
)
|
||||
return effect
|
||||
|
||||
|
||||
|
@@ -57,6 +57,7 @@ from esphome.const import (
|
||||
DEVICE_CLASS_SULPHUR_DIOXIDE,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS,
|
||||
DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS,
|
||||
DEVICE_CLASS_VOLTAGE,
|
||||
DEVICE_CLASS_VOLUME,
|
||||
DEVICE_CLASS_VOLUME_STORAGE,
|
||||
@@ -109,6 +110,7 @@ DEVICE_CLASSES = [
|
||||
DEVICE_CLASS_SULPHUR_DIOXIDE,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS,
|
||||
DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS,
|
||||
DEVICE_CLASS_VOLTAGE,
|
||||
DEVICE_CLASS_VOLUME,
|
||||
DEVICE_CLASS_VOLUME_STORAGE,
|
||||
|
@@ -252,7 +252,7 @@ void SEN5XComponent::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, " Firmware version: %d", this->firmware_version_);
|
||||
ESP_LOGCONFIG(TAG, " Serial number %02d.%02d.%02d", serial_number_[0], serial_number_[1], serial_number_[2]);
|
||||
if (this->auto_cleaning_interval_.has_value()) {
|
||||
ESP_LOGCONFIG(TAG, " Auto auto cleaning interval %d seconds", auto_cleaning_interval_.value());
|
||||
ESP_LOGCONFIG(TAG, " Auto cleaning interval %d seconds", auto_cleaning_interval_.value());
|
||||
}
|
||||
if (this->acceleration_mode_.has_value()) {
|
||||
switch (this->acceleration_mode_.value()) {
|
||||
|
@@ -119,7 +119,7 @@ CONFIG_SCHEMA = (
|
||||
device_class=DEVICE_CLASS_PM10,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional(CONF_AUTO_CLEANING_INTERVAL): cv.time_period_in_seconds_,
|
||||
cv.Optional(CONF_AUTO_CLEANING_INTERVAL): cv.update_interval,
|
||||
cv.Optional(CONF_VOC): sensor.sensor_schema(
|
||||
icon=ICON_RADIATOR,
|
||||
accuracy_decimals=0,
|
||||
|
@@ -73,6 +73,7 @@ from esphome.const import (
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
DEVICE_CLASS_TIMESTAMP,
|
||||
DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS,
|
||||
DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS,
|
||||
DEVICE_CLASS_VOLTAGE,
|
||||
DEVICE_CLASS_VOLUME,
|
||||
DEVICE_CLASS_VOLUME_STORAGE,
|
||||
@@ -129,6 +130,7 @@ DEVICE_CLASSES = [
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
DEVICE_CLASS_TIMESTAMP,
|
||||
DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS,
|
||||
DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS,
|
||||
DEVICE_CLASS_VOLTAGE,
|
||||
DEVICE_CLASS_VOLUME,
|
||||
DEVICE_CLASS_VOLUME_STORAGE,
|
||||
|
@@ -23,6 +23,8 @@ from esphome.const import (
|
||||
DEVICE_CLASS_POWER,
|
||||
DEVICE_CLASS_VOLTAGE,
|
||||
DEVICE_CLASS_CURRENT,
|
||||
CONF_MIN_BRIGHTNESS,
|
||||
CONF_MAX_BRIGHTNESS,
|
||||
)
|
||||
from esphome.core import HexInt, CORE
|
||||
|
||||
@@ -41,8 +43,7 @@ CONF_UPDATE = "update"
|
||||
CONF_LEADING_EDGE = "leading_edge"
|
||||
CONF_WARMUP_BRIGHTNESS = "warmup_brightness"
|
||||
# CONF_WARMUP_TIME = "warmup_time"
|
||||
CONF_MIN_BRIGHTNESS = "min_brightness"
|
||||
CONF_MAX_BRIGHTNESS = "max_brightness"
|
||||
|
||||
|
||||
CONF_NRST_PIN = "nrst_pin"
|
||||
CONF_BOOT0_PIN = "boot0_pin"
|
||||
|
@@ -275,7 +275,7 @@ SPRINKLER_ACTION_SET_RUN_DURATION_SCHEMA = cv.Schema(
|
||||
SPRINKLER_ACTION_QUEUE_VALVE_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_ID): cv.use_id(Sprinkler),
|
||||
cv.Optional(CONF_RUN_DURATION, default=0): cv.templatable(
|
||||
cv.Optional(CONF_RUN_DURATION, default="0s"): cv.templatable(
|
||||
cv.positive_time_period_seconds
|
||||
),
|
||||
cv.Required(CONF_VALVE_NUMBER): cv.templatable(cv.positive_int),
|
||||
@@ -599,15 +599,6 @@ async def to_code(config):
|
||||
)
|
||||
cg.add(var.set_controller_auto_adv_switch(sw_aa_var))
|
||||
|
||||
if CONF_QUEUE_ENABLE_SWITCH in sprinkler_controller:
|
||||
sw_qen_var = await switch.new_switch(
|
||||
sprinkler_controller[CONF_QUEUE_ENABLE_SWITCH]
|
||||
)
|
||||
await cg.register_component(
|
||||
sw_qen_var, sprinkler_controller[CONF_QUEUE_ENABLE_SWITCH]
|
||||
)
|
||||
cg.add(var.set_controller_queue_enable_switch(sw_qen_var))
|
||||
|
||||
if CONF_REVERSE_SWITCH in sprinkler_controller:
|
||||
sw_rev_var = await switch.new_switch(
|
||||
sprinkler_controller[CONF_REVERSE_SWITCH]
|
||||
@@ -617,78 +608,83 @@ async def to_code(config):
|
||||
)
|
||||
cg.add(var.set_controller_reverse_switch(sw_rev_var))
|
||||
|
||||
if CONF_STANDBY_SWITCH in sprinkler_controller:
|
||||
sw_stb_var = await switch.new_switch(
|
||||
sprinkler_controller[CONF_STANDBY_SWITCH]
|
||||
)
|
||||
await cg.register_component(
|
||||
sw_stb_var, sprinkler_controller[CONF_STANDBY_SWITCH]
|
||||
)
|
||||
cg.add(var.set_controller_standby_switch(sw_stb_var))
|
||||
if CONF_STANDBY_SWITCH in sprinkler_controller:
|
||||
sw_stb_var = await switch.new_switch(
|
||||
sprinkler_controller[CONF_STANDBY_SWITCH]
|
||||
)
|
||||
await cg.register_component(
|
||||
sw_stb_var, sprinkler_controller[CONF_STANDBY_SWITCH]
|
||||
)
|
||||
cg.add(var.set_controller_standby_switch(sw_stb_var))
|
||||
|
||||
if CONF_MULTIPLIER_NUMBER in sprinkler_controller:
|
||||
num_mult_var = await number.new_number(
|
||||
sprinkler_controller[CONF_MULTIPLIER_NUMBER],
|
||||
min_value=sprinkler_controller[CONF_MULTIPLIER_NUMBER][
|
||||
CONF_MIN_VALUE
|
||||
],
|
||||
max_value=sprinkler_controller[CONF_MULTIPLIER_NUMBER][
|
||||
CONF_MAX_VALUE
|
||||
],
|
||||
step=sprinkler_controller[CONF_MULTIPLIER_NUMBER][CONF_STEP],
|
||||
if CONF_QUEUE_ENABLE_SWITCH in sprinkler_controller:
|
||||
sw_qen_var = await switch.new_switch(
|
||||
sprinkler_controller[CONF_QUEUE_ENABLE_SWITCH]
|
||||
)
|
||||
await cg.register_component(
|
||||
sw_qen_var, sprinkler_controller[CONF_QUEUE_ENABLE_SWITCH]
|
||||
)
|
||||
cg.add(var.set_controller_queue_enable_switch(sw_qen_var))
|
||||
|
||||
if CONF_MULTIPLIER_NUMBER in sprinkler_controller:
|
||||
num_mult_var = await number.new_number(
|
||||
sprinkler_controller[CONF_MULTIPLIER_NUMBER],
|
||||
min_value=sprinkler_controller[CONF_MULTIPLIER_NUMBER][CONF_MIN_VALUE],
|
||||
max_value=sprinkler_controller[CONF_MULTIPLIER_NUMBER][CONF_MAX_VALUE],
|
||||
step=sprinkler_controller[CONF_MULTIPLIER_NUMBER][CONF_STEP],
|
||||
)
|
||||
await cg.register_component(
|
||||
num_mult_var, sprinkler_controller[CONF_MULTIPLIER_NUMBER]
|
||||
)
|
||||
cg.add(
|
||||
num_mult_var.set_initial_value(
|
||||
sprinkler_controller[CONF_MULTIPLIER_NUMBER][CONF_INITIAL_VALUE]
|
||||
)
|
||||
await cg.register_component(
|
||||
num_mult_var, sprinkler_controller[CONF_MULTIPLIER_NUMBER]
|
||||
)
|
||||
cg.add(
|
||||
num_mult_var.set_restore_value(
|
||||
sprinkler_controller[CONF_MULTIPLIER_NUMBER][CONF_RESTORE_VALUE]
|
||||
)
|
||||
cg.add(
|
||||
num_mult_var.set_initial_value(
|
||||
sprinkler_controller[CONF_MULTIPLIER_NUMBER][CONF_INITIAL_VALUE]
|
||||
)
|
||||
)
|
||||
cg.add(
|
||||
num_mult_var.set_restore_value(
|
||||
sprinkler_controller[CONF_MULTIPLIER_NUMBER][CONF_RESTORE_VALUE]
|
||||
)
|
||||
)
|
||||
|
||||
if CONF_SET_ACTION in sprinkler_controller[CONF_MULTIPLIER_NUMBER]:
|
||||
await automation.build_automation(
|
||||
num_mult_var.get_set_trigger(),
|
||||
[(float, "x")],
|
||||
sprinkler_controller[CONF_MULTIPLIER_NUMBER][CONF_SET_ACTION],
|
||||
)
|
||||
|
||||
if CONF_SET_ACTION in sprinkler_controller[CONF_MULTIPLIER_NUMBER]:
|
||||
await automation.build_automation(
|
||||
num_mult_var.get_set_trigger(),
|
||||
[(float, "x")],
|
||||
sprinkler_controller[CONF_MULTIPLIER_NUMBER][CONF_SET_ACTION],
|
||||
)
|
||||
cg.add(var.set_controller_multiplier_number(num_mult_var))
|
||||
|
||||
cg.add(var.set_controller_multiplier_number(num_mult_var))
|
||||
if CONF_REPEAT_NUMBER in sprinkler_controller:
|
||||
num_repeat_var = await number.new_number(
|
||||
sprinkler_controller[CONF_REPEAT_NUMBER],
|
||||
min_value=sprinkler_controller[CONF_REPEAT_NUMBER][CONF_MIN_VALUE],
|
||||
max_value=sprinkler_controller[CONF_REPEAT_NUMBER][CONF_MAX_VALUE],
|
||||
step=sprinkler_controller[CONF_REPEAT_NUMBER][CONF_STEP],
|
||||
)
|
||||
await cg.register_component(
|
||||
num_repeat_var, sprinkler_controller[CONF_REPEAT_NUMBER]
|
||||
)
|
||||
cg.add(
|
||||
num_repeat_var.set_initial_value(
|
||||
sprinkler_controller[CONF_REPEAT_NUMBER][CONF_INITIAL_VALUE]
|
||||
)
|
||||
)
|
||||
cg.add(
|
||||
num_repeat_var.set_restore_value(
|
||||
sprinkler_controller[CONF_REPEAT_NUMBER][CONF_RESTORE_VALUE]
|
||||
)
|
||||
)
|
||||
|
||||
if CONF_REPEAT_NUMBER in sprinkler_controller:
|
||||
num_repeat_var = await number.new_number(
|
||||
sprinkler_controller[CONF_REPEAT_NUMBER],
|
||||
min_value=sprinkler_controller[CONF_REPEAT_NUMBER][CONF_MIN_VALUE],
|
||||
max_value=sprinkler_controller[CONF_REPEAT_NUMBER][CONF_MAX_VALUE],
|
||||
step=sprinkler_controller[CONF_REPEAT_NUMBER][CONF_STEP],
|
||||
)
|
||||
await cg.register_component(
|
||||
num_repeat_var, sprinkler_controller[CONF_REPEAT_NUMBER]
|
||||
)
|
||||
cg.add(
|
||||
num_repeat_var.set_initial_value(
|
||||
sprinkler_controller[CONF_REPEAT_NUMBER][CONF_INITIAL_VALUE]
|
||||
)
|
||||
)
|
||||
cg.add(
|
||||
num_repeat_var.set_restore_value(
|
||||
sprinkler_controller[CONF_REPEAT_NUMBER][CONF_RESTORE_VALUE]
|
||||
)
|
||||
if CONF_SET_ACTION in sprinkler_controller[CONF_REPEAT_NUMBER]:
|
||||
await automation.build_automation(
|
||||
num_repeat_var.get_set_trigger(),
|
||||
[(float, "x")],
|
||||
sprinkler_controller[CONF_REPEAT_NUMBER][CONF_SET_ACTION],
|
||||
)
|
||||
|
||||
if CONF_SET_ACTION in sprinkler_controller[CONF_REPEAT_NUMBER]:
|
||||
await automation.build_automation(
|
||||
num_repeat_var.get_set_trigger(),
|
||||
[(float, "x")],
|
||||
sprinkler_controller[CONF_REPEAT_NUMBER][CONF_SET_ACTION],
|
||||
)
|
||||
|
||||
cg.add(var.set_controller_repeat_number(num_repeat_var))
|
||||
cg.add(var.set_controller_repeat_number(num_repeat_var))
|
||||
|
||||
for valve in sprinkler_controller[CONF_VALVES]:
|
||||
sw_valve_var = await switch.new_switch(valve[CONF_VALVE_SWITCH])
|
||||
|
@@ -147,22 +147,22 @@ SprinklerValveOperator::SprinklerValveOperator(SprinklerValve *valve, Sprinkler
|
||||
: controller_(controller), valve_(valve) {}
|
||||
|
||||
void SprinklerValveOperator::loop() {
|
||||
if (millis() >= this->pinned_millis_) { // dummy check
|
||||
if (millis() >= this->start_millis_) { // dummy check
|
||||
switch (this->state_) {
|
||||
case STARTING:
|
||||
if (millis() > (this->pinned_millis_ + this->start_delay_)) {
|
||||
if (millis() > (this->start_millis_ + this->start_delay_)) {
|
||||
this->run_(); // start_delay_ has been exceeded, so ensure both valves are on and update the state
|
||||
}
|
||||
break;
|
||||
|
||||
case ACTIVE:
|
||||
if (millis() > (this->pinned_millis_ + this->start_delay_ + this->run_duration_)) {
|
||||
if (millis() > (this->start_millis_ + this->start_delay_ + this->run_duration_)) {
|
||||
this->stop(); // start_delay_ + run_duration_ has been exceeded, start shutting down
|
||||
}
|
||||
break;
|
||||
|
||||
case STOPPING:
|
||||
if (millis() > (this->pinned_millis_ + this->stop_delay_)) {
|
||||
if (millis() > (this->stop_millis_ + this->stop_delay_)) {
|
||||
this->kill_(); // stop_delay_has been exceeded, ensure all valves are off
|
||||
}
|
||||
break;
|
||||
@@ -183,11 +183,12 @@ void SprinklerValveOperator::set_controller(Sprinkler *controller) {
|
||||
|
||||
void SprinklerValveOperator::set_valve(SprinklerValve *valve) {
|
||||
if (valve != nullptr) {
|
||||
this->state_ = IDLE; // reset state
|
||||
this->run_duration_ = 0; // reset to ensure the valve isn't started without updating it
|
||||
this->pinned_millis_ = 0; // reset because (new) valve has not been started yet
|
||||
this->kill_(); // ensure everything is off before we let go!
|
||||
this->valve_ = valve; // finally, set the pointer to the new valve
|
||||
this->state_ = IDLE; // reset state
|
||||
this->run_duration_ = 0; // reset to ensure the valve isn't started without updating it
|
||||
this->start_millis_ = 0; // reset because (new) valve has not been started yet
|
||||
this->stop_millis_ = 0; // reset because (new) valve has not been started yet
|
||||
this->kill_(); // ensure everything is off before we let go!
|
||||
this->valve_ = valve; // finally, set the pointer to the new valve
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,7 +222,8 @@ void SprinklerValveOperator::start() {
|
||||
} else {
|
||||
this->run_(); // there is no start_delay_, so just start the pump and valve
|
||||
}
|
||||
this->pinned_millis_ = millis(); // save the time the start request was made
|
||||
this->stop_millis_ = 0;
|
||||
this->start_millis_ = millis(); // save the time the start request was made
|
||||
}
|
||||
|
||||
void SprinklerValveOperator::stop() {
|
||||
@@ -238,19 +240,33 @@ void SprinklerValveOperator::stop() {
|
||||
if (this->pump_switch()->state()) { // if the pump is still on at this point, it may be in use...
|
||||
this->valve_off_(); // ...so just switch the valve off now to ensure consistent run time
|
||||
}
|
||||
this->pinned_millis_ = millis(); // save the time the stop request was made
|
||||
} else {
|
||||
this->kill_(); // there is no stop_delay_, so just stop the pump and valve
|
||||
}
|
||||
this->stop_millis_ = millis(); // save the time the stop request was made
|
||||
}
|
||||
|
||||
uint32_t SprinklerValveOperator::run_duration() { return this->run_duration_; }
|
||||
uint32_t SprinklerValveOperator::run_duration() { return this->run_duration_ / 1000; }
|
||||
|
||||
uint32_t SprinklerValveOperator::time_remaining() {
|
||||
if ((this->state_ == STARTING) || (this->state_ == ACTIVE)) {
|
||||
return (this->pinned_millis_ + this->start_delay_ + this->run_duration_ - millis()) / 1000;
|
||||
if (this->start_millis_ == 0) {
|
||||
return this->run_duration(); // hasn't been started yet
|
||||
}
|
||||
return 0;
|
||||
|
||||
if (this->stop_millis_) {
|
||||
if (this->stop_millis_ - this->start_millis_ >= this->start_delay_ + this->run_duration_) {
|
||||
return 0; // valve was active for more than its configured duration, so we are done
|
||||
} else {
|
||||
// we're stopped; return time remaining
|
||||
return (this->run_duration_ - (this->stop_millis_ - this->start_millis_)) / 1000;
|
||||
}
|
||||
}
|
||||
|
||||
auto completed_millis = this->start_millis_ + this->start_delay_ + this->run_duration_;
|
||||
if (completed_millis > millis()) {
|
||||
return (completed_millis - millis()) / 1000; // running now
|
||||
}
|
||||
return 0; // run completed
|
||||
}
|
||||
|
||||
SprinklerState SprinklerValveOperator::state() { return this->state_; }
|
||||
@@ -386,6 +402,9 @@ void Sprinkler::loop() {
|
||||
for (auto &vo : this->valve_op_) {
|
||||
vo.loop();
|
||||
}
|
||||
if (this->prev_req_.has_request() && this->prev_req_.valve_operator()->state() == IDLE) {
|
||||
this->prev_req_.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void Sprinkler::add_valve(SprinklerControllerSwitch *valve_sw, SprinklerControllerSwitch *enable_sw) {
|
||||
@@ -732,7 +751,7 @@ bool Sprinkler::auto_advance() {
|
||||
if (this->auto_adv_sw_ != nullptr) {
|
||||
return this->auto_adv_sw_->state;
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
float Sprinkler::multiplier() {
|
||||
@@ -972,7 +991,14 @@ optional<SprinklerValveRunRequestOrigin> Sprinkler::active_valve_request_is_from
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
optional<size_t> Sprinkler::active_valve() { return this->active_req_.valve_as_opt(); }
|
||||
optional<size_t> Sprinkler::active_valve() {
|
||||
if (!this->valve_overlap_ && this->prev_req_.has_request() &&
|
||||
(this->prev_req_.valve_operator()->state() == STARTING || this->prev_req_.valve_operator()->state() == ACTIVE)) {
|
||||
return this->prev_req_.valve_as_opt();
|
||||
}
|
||||
return this->active_req_.valve_as_opt();
|
||||
}
|
||||
|
||||
optional<size_t> Sprinkler::paused_valve() { return this->paused_valve_; }
|
||||
|
||||
optional<size_t> Sprinkler::queued_valve() {
|
||||
@@ -1097,22 +1123,35 @@ uint32_t Sprinkler::total_cycle_time_enabled_valves() {
|
||||
|
||||
uint32_t Sprinkler::total_cycle_time_enabled_incomplete_valves() {
|
||||
uint32_t total_time_remaining = 0;
|
||||
uint32_t valve_count = 0;
|
||||
uint32_t enabled_valve_count = 0;
|
||||
uint32_t incomplete_valve_count = 0;
|
||||
|
||||
for (size_t valve = 0; valve < this->number_of_valves(); valve++) {
|
||||
if (this->valve_is_enabled_(valve) && !this->valve_cycle_complete_(valve)) {
|
||||
if (!this->active_valve().has_value() || (valve != this->active_valve().value())) {
|
||||
total_time_remaining += this->valve_run_duration_adjusted(valve);
|
||||
valve_count++;
|
||||
if (this->valve_is_enabled_(valve)) {
|
||||
enabled_valve_count++;
|
||||
if (!this->valve_cycle_complete_(valve)) {
|
||||
if (!this->active_valve().has_value() || (valve != this->active_valve().value())) {
|
||||
total_time_remaining += this->valve_run_duration_adjusted(valve);
|
||||
incomplete_valve_count++;
|
||||
} else {
|
||||
// to get here, there must be an active valve and this valve must be equal to 'valve'
|
||||
if (this->active_req_.valve_operator() == nullptr) { // no SVO has been assigned yet so it hasn't started
|
||||
total_time_remaining += this->valve_run_duration_adjusted(valve);
|
||||
incomplete_valve_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (valve_count) {
|
||||
if (incomplete_valve_count >= enabled_valve_count) {
|
||||
incomplete_valve_count--;
|
||||
}
|
||||
if (incomplete_valve_count) {
|
||||
if (this->valve_overlap_) {
|
||||
total_time_remaining -= this->switching_delay_.value_or(0) * (valve_count - 1);
|
||||
total_time_remaining -= this->switching_delay_.value_or(0) * incomplete_valve_count;
|
||||
} else {
|
||||
total_time_remaining += this->switching_delay_.value_or(0) * (valve_count - 1);
|
||||
total_time_remaining += this->switching_delay_.value_or(0) * incomplete_valve_count;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1149,31 +1188,32 @@ optional<uint32_t> Sprinkler::time_remaining_active_valve() {
|
||||
return this->active_req_.valve_operator()->time_remaining();
|
||||
}
|
||||
}
|
||||
for (auto &vo : this->valve_op_) { // ...else return the value from the first non-IDLE SprinklerValveOperator
|
||||
if (vo.state() != IDLE) {
|
||||
return vo.time_remaining();
|
||||
if (this->prev_req_.has_request()) { // try to return the value based on prev_req_...
|
||||
if (this->prev_req_.valve_operator() != nullptr) {
|
||||
return this->prev_req_.valve_operator()->time_remaining();
|
||||
}
|
||||
}
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
optional<uint32_t> Sprinkler::time_remaining_current_operation() {
|
||||
auto total_time_remaining = this->time_remaining_active_valve();
|
||||
if (!this->time_remaining_active_valve().has_value() && this->state_ == IDLE) {
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
if (total_time_remaining.has_value()) {
|
||||
if (this->auto_advance()) {
|
||||
total_time_remaining = total_time_remaining.value() + this->total_cycle_time_enabled_incomplete_valves();
|
||||
total_time_remaining =
|
||||
total_time_remaining.value() +
|
||||
auto total_time_remaining = this->time_remaining_active_valve().value_or(0);
|
||||
if (this->auto_advance()) {
|
||||
total_time_remaining += this->total_cycle_time_enabled_incomplete_valves();
|
||||
if (this->repeat().value_or(0) > 0) {
|
||||
total_time_remaining +=
|
||||
(this->total_cycle_time_enabled_valves() * (this->repeat().value_or(0) - this->repeat_count().value_or(0)));
|
||||
}
|
||||
|
||||
if (this->queue_enabled()) {
|
||||
total_time_remaining = total_time_remaining.value() + this->total_queue_time();
|
||||
}
|
||||
return total_time_remaining;
|
||||
}
|
||||
return nullopt;
|
||||
|
||||
if (this->queue_enabled()) {
|
||||
total_time_remaining += this->total_queue_time();
|
||||
}
|
||||
return total_time_remaining;
|
||||
}
|
||||
|
||||
bool Sprinkler::any_controller_is_active() {
|
||||
@@ -1305,6 +1345,12 @@ optional<size_t> Sprinkler::next_valve_number_in_cycle_(const optional<size_t> f
|
||||
}
|
||||
|
||||
void Sprinkler::load_next_valve_run_request_(const optional<size_t> first_valve) {
|
||||
if (this->active_req_.has_request()) {
|
||||
this->prev_req_ = this->active_req_;
|
||||
} else {
|
||||
this->prev_req_.reset();
|
||||
}
|
||||
|
||||
if (this->next_req_.has_request()) {
|
||||
if (!this->next_req_.run_duration()) { // ensure the run duration is set correctly for consumption later on
|
||||
this->next_req_.set_run_duration(this->valve_run_duration_adjusted(this->next_req_.valve()));
|
||||
|
@@ -170,7 +170,8 @@ class SprinklerValveOperator {
|
||||
uint32_t start_delay_{0};
|
||||
uint32_t stop_delay_{0};
|
||||
uint32_t run_duration_{0};
|
||||
uint64_t pinned_millis_{0};
|
||||
uint64_t start_millis_{0};
|
||||
uint64_t stop_millis_{0};
|
||||
Sprinkler *controller_{nullptr};
|
||||
SprinklerValve *valve_{nullptr};
|
||||
SprinklerState state_{IDLE};
|
||||
@@ -538,15 +539,18 @@ class Sprinkler : public Component {
|
||||
/// The valve run request that is currently active
|
||||
SprinklerValveRunRequest active_req_;
|
||||
|
||||
/// The next run request for the controller to consume after active_req_ is complete
|
||||
SprinklerValveRunRequest next_req_;
|
||||
|
||||
/// The previous run request the controller processed
|
||||
SprinklerValveRunRequest prev_req_;
|
||||
|
||||
/// The number of the manually selected valve currently selected
|
||||
optional<size_t> manual_valve_;
|
||||
|
||||
/// The number of the valve to resume from (if paused)
|
||||
optional<size_t> paused_valve_;
|
||||
|
||||
/// The next run request for the controller to consume after active_req_ is complete
|
||||
SprinklerValveRunRequest next_req_;
|
||||
|
||||
/// Set the number of times to repeat a full cycle
|
||||
optional<uint32_t> target_repeats_;
|
||||
|
||||
|
@@ -3,7 +3,6 @@ import esphome.config_validation as cv
|
||||
from esphome import pins
|
||||
from esphome.const import CONF_ID, CONF_SDO_PIN, CONF_SCL_PIN
|
||||
|
||||
DEPENDENCIES = ["i2c"]
|
||||
AUTO_LOAD = ["binary_sensor"]
|
||||
|
||||
CONF_TTP229_ID = "ttp229_id"
|
||||
|
@@ -57,37 +57,43 @@ void TuyaLight::setup() {
|
||||
return;
|
||||
}
|
||||
|
||||
float red, green, blue;
|
||||
switch (*this->color_type_) {
|
||||
case TuyaColorType::RGBHSV:
|
||||
case TuyaColorType::RGB: {
|
||||
auto red = parse_hex<uint8_t>(datapoint.value_string.substr(0, 2));
|
||||
auto green = parse_hex<uint8_t>(datapoint.value_string.substr(2, 2));
|
||||
auto blue = parse_hex<uint8_t>(datapoint.value_string.substr(4, 2));
|
||||
if (red.has_value() && green.has_value() && blue.has_value()) {
|
||||
auto rgb_call = this->state_->make_call();
|
||||
rgb_call.set_rgb(float(*red) / 255, float(*green) / 255, float(*blue) / 255);
|
||||
rgb_call.perform();
|
||||
}
|
||||
auto rgb = parse_hex<uint32_t>(datapoint.value_string.substr(0, 6));
|
||||
if (!rgb.has_value())
|
||||
return;
|
||||
|
||||
red = (*rgb >> 16) / 255.0f;
|
||||
green = ((*rgb >> 8) & 0xff) / 255.0f;
|
||||
blue = (*rgb & 0xff) / 255.0f;
|
||||
break;
|
||||
}
|
||||
case TuyaColorType::HSV: {
|
||||
auto hue = parse_hex<uint16_t>(datapoint.value_string.substr(0, 4));
|
||||
auto saturation = parse_hex<uint16_t>(datapoint.value_string.substr(4, 4));
|
||||
auto value = parse_hex<uint16_t>(datapoint.value_string.substr(8, 4));
|
||||
if (hue.has_value() && saturation.has_value() && value.has_value()) {
|
||||
float red, green, blue;
|
||||
hsv_to_rgb(*hue, float(*saturation) / 1000, float(*value) / 1000, red, green, blue);
|
||||
auto rgb_call = this->state_->make_call();
|
||||
rgb_call.set_rgb(red, green, blue);
|
||||
rgb_call.perform();
|
||||
}
|
||||
if (!hue.has_value() || !saturation.has_value() || !value.has_value())
|
||||
return;
|
||||
|
||||
hsv_to_rgb(*hue, float(*saturation) / 1000, float(*value) / 1000, red, green, blue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
float current_red, current_green, current_blue;
|
||||
this->state_->current_values_as_rgb(¤t_red, ¤t_green, ¤t_blue);
|
||||
if (red == current_red && green == current_green && blue == current_blue)
|
||||
return;
|
||||
auto rgb_call = this->state_->make_call();
|
||||
rgb_call.set_rgb(red, green, blue);
|
||||
rgb_call.perform();
|
||||
});
|
||||
}
|
||||
|
||||
if (min_value_datapoint_id_.has_value()) {
|
||||
parent_->set_integer_datapoint_value(*this->min_value_datapoint_id_, this->min_value_);
|
||||
this->parent_->set_integer_datapoint_value(*this->min_value_datapoint_id_, this->min_value_);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,7 +162,7 @@ void TuyaLight::write_state(light::LightState *state) {
|
||||
}
|
||||
|
||||
if (!state->current_values.is_on() && this->switch_id_.has_value()) {
|
||||
parent_->set_boolean_datapoint_value(*this->switch_id_, false);
|
||||
this->parent_->set_boolean_datapoint_value(*this->switch_id_, false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -166,14 +172,14 @@ void TuyaLight::write_state(light::LightState *state) {
|
||||
if (this->color_temperature_invert_) {
|
||||
color_temp_int = this->color_temperature_max_value_ - color_temp_int;
|
||||
}
|
||||
parent_->set_integer_datapoint_value(*this->color_temperature_id_, color_temp_int);
|
||||
this->parent_->set_integer_datapoint_value(*this->color_temperature_id_, color_temp_int);
|
||||
}
|
||||
|
||||
if (this->dimmer_id_.has_value()) {
|
||||
auto brightness_int = static_cast<uint32_t>(brightness * this->max_value_);
|
||||
brightness_int = std::max(brightness_int, this->min_value_);
|
||||
|
||||
parent_->set_integer_datapoint_value(*this->dimmer_id_, brightness_int);
|
||||
this->parent_->set_integer_datapoint_value(*this->dimmer_id_, brightness_int);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,7 +216,7 @@ void TuyaLight::write_state(light::LightState *state) {
|
||||
}
|
||||
|
||||
if (this->switch_id_.has_value()) {
|
||||
parent_->set_boolean_datapoint_value(*this->switch_id_, true);
|
||||
this->parent_->set_boolean_datapoint_value(*this->switch_id_, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -86,10 +86,26 @@ void ESP32ArduinoUARTComponent::setup() {
|
||||
is_default_tx = tx_pin_ == nullptr || tx_pin_->get_pin() == 1;
|
||||
is_default_rx = rx_pin_ == nullptr || rx_pin_->get_pin() == 3;
|
||||
#endif
|
||||
if (is_default_tx && is_default_rx) {
|
||||
static uint8_t next_uart_num = 0;
|
||||
if (is_default_tx && is_default_rx && next_uart_num == 0) {
|
||||
this->hw_serial_ = &Serial;
|
||||
next_uart_num++;
|
||||
} else {
|
||||
static uint8_t next_uart_num = 1;
|
||||
#ifdef USE_LOGGER
|
||||
// The logger doesn't use this UART component, instead it targets the UARTs
|
||||
// directly (i.e. Serial/Serial0, Serial1, and Serial2). If the logger is
|
||||
// enabled, skip the UART that it is configured to use.
|
||||
if (logger::global_logger->get_baud_rate() > 0 && logger::global_logger->get_uart() == next_uart_num) {
|
||||
next_uart_num++;
|
||||
}
|
||||
#endif // USE_LOGGER
|
||||
|
||||
if (next_uart_num >= UART_NUM_MAX) {
|
||||
ESP_LOGW(TAG, "Maximum number of UART components created already.");
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
|
||||
this->number_ = next_uart_num;
|
||||
this->hw_serial_ = new HardwareSerial(next_uart_num++); // NOLINT(cppcoreguidelines-owning-memory)
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
#ifdef USE_ESP32_FRAMEWORK_ARDUINO
|
||||
|
||||
#include <driver/uart.h>
|
||||
#include <HardwareSerial.h>
|
||||
#include <vector>
|
||||
#include "esphome/core/component.h"
|
||||
|
@@ -102,6 +102,16 @@ void Wiegand::loop() {
|
||||
uint8_t key = KEYS[value];
|
||||
this->send_key_(key);
|
||||
}
|
||||
} else if (count == 8) {
|
||||
if ((value ^ 0xf0) >> 4 == (value & 0xf)) {
|
||||
value &= 0xf;
|
||||
for (auto *trigger : this->key_triggers_)
|
||||
trigger->trigger(value);
|
||||
if (value < 12) {
|
||||
uint8_t key = KEYS[value];
|
||||
this->send_key_(key);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ESP_LOGD(TAG, "received unknown %d-bit value: %llx", count, value);
|
||||
}
|
||||
|
@@ -767,11 +767,10 @@ bool WiFiComponent::wifi_ap_ip_config_(optional<ManualIP> manual_ip) {
|
||||
info.gw.addr = static_cast<uint32_t>(network::IPAddress(192, 168, 4, 1));
|
||||
info.netmask.addr = static_cast<uint32_t>(network::IPAddress(255, 255, 255, 0));
|
||||
}
|
||||
esp_netif_dhcp_status_t dhcp_status;
|
||||
esp_netif_dhcps_get_status(s_sta_netif, &dhcp_status);
|
||||
err = esp_netif_dhcps_stop(s_sta_netif);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGV(TAG, "esp_netif_dhcps_stop failed! %d", err);
|
||||
|
||||
err = esp_netif_dhcpc_stop(s_sta_netif);
|
||||
if (err != ESP_OK && err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED) {
|
||||
ESP_LOGV(TAG, "esp_netif_dhcpc_stop failed: %s", esp_err_to_name(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
"""Constants used by esphome."""
|
||||
|
||||
__version__ = "2023.5.0b1"
|
||||
__version__ = "2023.5.2"
|
||||
|
||||
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
|
||||
|
||||
@@ -377,6 +377,7 @@ CONF_MAKE_ID = "make_id"
|
||||
CONF_MANUAL_IP = "manual_ip"
|
||||
CONF_MANUFACTURER_ID = "manufacturer_id"
|
||||
CONF_MASK_DISTURBER = "mask_disturber"
|
||||
CONF_MAX_BRIGHTNESS = "max_brightness"
|
||||
CONF_MAX_COOLING_RUN_TIME = "max_cooling_run_time"
|
||||
CONF_MAX_CURRENT = "max_current"
|
||||
CONF_MAX_DURATION = "max_duration"
|
||||
@@ -396,6 +397,7 @@ CONF_MEDIUM = "medium"
|
||||
CONF_MEMORY_BLOCKS = "memory_blocks"
|
||||
CONF_METHOD = "method"
|
||||
CONF_MICROPHONE = "microphone"
|
||||
CONF_MIN_BRIGHTNESS = "min_brightness"
|
||||
CONF_MIN_COOLING_OFF_TIME = "min_cooling_off_time"
|
||||
CONF_MIN_COOLING_RUN_TIME = "min_cooling_run_time"
|
||||
CONF_MIN_FAN_MODE_SWITCHING_TIME = "min_fan_mode_switching_time"
|
||||
@@ -1002,6 +1004,7 @@ DEVICE_CLASS_TIMESTAMP = "timestamp"
|
||||
DEVICE_CLASS_UPDATE = "update"
|
||||
DEVICE_CLASS_VIBRATION = "vibration"
|
||||
DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS = "volatile_organic_compounds"
|
||||
DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS = "volatile_organic_compounds_parts"
|
||||
DEVICE_CLASS_VOLTAGE = "voltage"
|
||||
DEVICE_CLASS_VOLUME = "volume"
|
||||
DEVICE_CLASS_VOLUME_STORAGE = "volume_storage"
|
||||
|
@@ -3,14 +3,14 @@ PyYAML==6.0
|
||||
paho-mqtt==1.6.1
|
||||
colorama==0.4.6
|
||||
tornado==6.3.1
|
||||
tzlocal==4.2 # from time
|
||||
tzlocal==5.0.1 # from time
|
||||
tzdata>=2021.1 # from time
|
||||
pyserial==3.5
|
||||
platformio==6.1.6 # When updating platformio, also update Dockerfile
|
||||
esptool==4.5.1
|
||||
click==8.1.3
|
||||
esphome-dashboard==20230214.0
|
||||
aioesphomeapi==13.7.2
|
||||
esphome-dashboard==20230516.0
|
||||
aioesphomeapi==13.7.5
|
||||
zeroconf==0.60.0
|
||||
|
||||
# esp-idf requires this, but doesn't bundle it by default
|
||||
|
@@ -489,6 +489,7 @@ sensor:
|
||||
offset: 0
|
||||
normalized_offset_slope: 0
|
||||
time_constant: 0
|
||||
auto_cleaning_interval: 604800s
|
||||
acceleration_mode: low
|
||||
store_baseline: true
|
||||
address: 0x69
|
||||
|
Reference in New Issue
Block a user