Compare commits

..

34 Commits

Author SHA1 Message Date
Jesse Hills
70aa5d0f6c Merge pull request #4870 from esphome/bump-2023.5.2
2023.5.2
2023-05-22 12:15:07 +12:00
Jesse Hills
8fcec8e2cb Bump version to 2023.5.2 2023-05-22 11:31:30 +12:00
Stefan Rado
2d3b48f86f Fix i2s_audio media_player mutex acquisition (#4867)
Co-authored-by: Rajan Patel <rpatel3001@gmail.com>
2023-05-22 11:31:30 +12:00
Jesse Hills
99c10bc6de Merge pull request #4852 from esphome/bump-2023.5.1
2023.5.1
2023-05-18 14:27:55 +12:00
Jesse Hills
f30f20db86 Bump version to 2023.5.1 2023-05-18 13:00:37 +12:00
Keith Burzinski
9bf946e196 Sprinkler fixes (#4816) 2023-05-18 13:00:36 +12:00
Jesse Hills
bfaad1f28d Remove i2c dependency from ttp229_bsf (#4851) 2023-05-18 13:00:36 +12:00
Jesse Hills
f90e9ba871 Merge pull request #4846 from esphome/bump-2023.5.0
2023.5.0
2023-05-17 13:17:10 +12:00
Jesse Hills
726bdd7be2 Bump version to 2023.5.0 2023-05-17 12:45:42 +12:00
Jesse Hills
52db40eb41 Merge pull request #4845 from esphome/bump-2023.5.0b5
2023.5.0b5
2023-05-17 12:04:22 +12:00
Jesse Hills
3c371a0c59 Bump version to 2023.5.0b5 2023-05-17 09:57:36 +12:00
Samuel Sieb
c941bc4109 handle Wiegand 8-bit keys (#4837)
Co-authored-by: Samuel Sieb <samuel@sieb.net>
2023-05-17 09:57:35 +12:00
Samuel Sieb
cc76e5353c support sending keys to the collector (#4838)
Co-authored-by: Samuel Sieb <samuel@sieb.net>
2023-05-17 09:57:35 +12:00
Jesse Hills
11bb46e393 Merge pull request #4835 from esphome/bump-2023.5.0b4
2023.5.0b4
2023-05-16 12:00:39 +12:00
Jesse Hills
71c4714a6e Bump version to 2023.5.0b4 2023-05-16 11:16:14 +12:00
github-actions[bot]
a4e63c5f86 Synchronise Device Classes from Home Assistant (#4825)
Co-authored-by: esphomebot <esphome@nabucasa.com>
2023-05-16 11:16:14 +12:00
Justin Gerace
c71e7d0132 Start UART assignment at UART0 if the logger is not enabled or is not configured for hardware logging on ESP32 (#4762) 2023-05-16 11:16:13 +12:00
dependabot[bot]
daa966975e Bump tzlocal from 4.2 to 5.0.1 (#4829)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-16 11:16:13 +12:00
Federico G. Schwindt
2e5757a3f0 Fix time period validation for the auto cleaning interval (#4811) 2023-05-16 11:16:13 +12:00
Jesse Hills
f66024b37c Bump esphome-dashboard to 20230516.0 (#4831) 2023-05-16 11:16:13 +12:00
Christian
c16ca7be13 Update PulseLightEffect with range brightness (#4820)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-05-16 11:16:13 +12:00
dependabot[bot]
e13e754bc4 Bump aioesphomeapi from 13.7.2 to 13.7.5 (#4830)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-16 11:16:13 +12:00
RoboMagus
6ccea59f71 Fix missing stop trait in send_cover_info (#4826) 2023-05-16 11:16:13 +12:00
Jesse Hills
71b28be3c8 Merge pull request #4822 from esphome/bump-2023.5.0b3
2023.5.0b3
2023-05-15 13:06:10 +12:00
Jesse Hills
e25d92e1f5 Bump version to 2023.5.0b3 2023-05-15 11:37:55 +12:00
Jesse Hills
65cda10884 Dontr try stop if not actually started (#4814) 2023-05-15 11:37:55 +12:00
Jesse Hills
625126df68 Fix i2s media player volume control (#4813) 2023-05-15 11:37:55 +12:00
richardhopton
e0ee8ca17c Tuya: Prevent loop when setting colors on case-sensitive dps (#4809)
Co-authored-by: Samuel Sieb <samuel-github@sieb.net>
2023-05-15 11:37:54 +12:00
Federico G. Schwindt
af95e781f5 Wording (#4805) 2023-05-15 11:37:54 +12:00
Jesse Hills
9b230a7d93 Merge pull request #4808 from esphome/bump-2023.5.0b2
2023.5.0b2
2023-05-12 11:02:45 +12:00
Jesse Hills
e2f3e7c3a6 Bump version to 2023.5.0b2 2023-05-12 10:32:59 +12:00
Alex Dekker
2fd2e5ceb2 Supposed to fix #4069, by changing the default value to 0s (timeunit instead of int) to pass validation (#4806)
Co-authored-by: Alex1602 <alex1602@gmail.com>
2023-05-12 10:32:59 +12:00
Jesse Hills
d88358be8e Remove AUTO_LOAD from apds9960 (#4746) 2023-05-12 10:32:59 +12:00
Jimmy Hedman
d80885c7a8 Fixed access point for ESP32 IDF platform (#4784) 2023-05-12 10:32:59 +12:00
31 changed files with 375 additions and 220 deletions

View File

@@ -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"

View File

@@ -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

View File

@@ -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,

View File

@@ -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))

View File

@@ -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))

View File

@@ -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();

View File

@@ -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
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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:

View File

@@ -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_) {

View File

@@ -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);

View File

@@ -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.

View File

@@ -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

View File

@@ -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,

View File

@@ -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()) {

View File

@@ -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,

View File

@@ -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,

View File

@@ -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"

View File

@@ -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])

View File

@@ -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()));

View File

@@ -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_;

View File

@@ -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"

View File

@@ -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(&current_red, &current_green, &current_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);
}
}

View File

@@ -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)
}

View File

@@ -2,6 +2,7 @@
#ifdef USE_ESP32_FRAMEWORK_ARDUINO
#include <driver/uart.h>
#include <HardwareSerial.h>
#include <vector>
#include "esphome/core/component.h"

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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"

View File

@@ -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

View File

@@ -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