mirror of
https://github.com/esphome/esphome.git
synced 2024-11-28 09:44:12 +01:00
Merge branch 'dev' into optolink
This commit is contained in:
commit
9d7063cce4
21 changed files with 187 additions and 57 deletions
|
@ -32,9 +32,11 @@ void Rect::extend(Rect rect) {
|
||||||
this->h = rect.h;
|
this->h = rect.h;
|
||||||
} else {
|
} else {
|
||||||
if (this->x > rect.x) {
|
if (this->x > rect.x) {
|
||||||
|
this->w = this->w + (this->x - rect.x);
|
||||||
this->x = rect.x;
|
this->x = rect.x;
|
||||||
}
|
}
|
||||||
if (this->y > rect.y) {
|
if (this->y > rect.y) {
|
||||||
|
this->h = this->h + (this->y - rect.y);
|
||||||
this->y = rect.y;
|
this->y = rect.y;
|
||||||
}
|
}
|
||||||
if (this->x2() < rect.x2()) {
|
if (this->x2() < rect.x2()) {
|
||||||
|
@ -49,29 +51,35 @@ void Rect::shrink(Rect rect) {
|
||||||
if (!this->inside(rect)) {
|
if (!this->inside(rect)) {
|
||||||
(*this) = Rect();
|
(*this) = Rect();
|
||||||
} else {
|
} else {
|
||||||
if (this->x < rect.x) {
|
|
||||||
this->x = rect.x;
|
|
||||||
}
|
|
||||||
if (this->y < rect.y) {
|
|
||||||
this->y = rect.y;
|
|
||||||
}
|
|
||||||
if (this->x2() > rect.x2()) {
|
if (this->x2() > rect.x2()) {
|
||||||
this->w = rect.x2() - this->x;
|
this->w = rect.x2() - this->x;
|
||||||
}
|
}
|
||||||
|
if (this->x < rect.x) {
|
||||||
|
this->w = this->w + (this->x - rect.x);
|
||||||
|
this->x = rect.x;
|
||||||
|
}
|
||||||
if (this->y2() > rect.y2()) {
|
if (this->y2() > rect.y2()) {
|
||||||
this->h = rect.y2() - this->y;
|
this->h = rect.y2() - this->y;
|
||||||
}
|
}
|
||||||
|
if (this->y < rect.y) {
|
||||||
|
this->h = this->h + (this->y - rect.y);
|
||||||
|
this->y = rect.y;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Rect::inside(int16_t x, int16_t y, bool absolute) { // NOLINT
|
bool Rect::equal(Rect rect) {
|
||||||
|
return (rect.x == this->x) && (rect.w == this->w) && (rect.y == this->y) && (rect.h == this->h);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Rect::inside(int16_t test_x, int16_t test_y, bool absolute) { // NOLINT
|
||||||
if (!this->is_set()) {
|
if (!this->is_set()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (absolute) {
|
if (absolute) {
|
||||||
return ((x >= 0) && (x <= this->w) && (y >= 0) && (y <= this->h));
|
return ((test_x >= this->x) && (test_x <= this->x2()) && (test_y >= this->y) && (test_y <= this->y2()));
|
||||||
} else {
|
} else {
|
||||||
return ((x >= this->x) && (x <= this->x2()) && (y >= this->y) && (y <= this->y2()));
|
return ((test_x >= 0) && (test_x <= this->w) && (test_y >= 0) && (test_y <= this->h));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,15 +88,16 @@ bool Rect::inside(Rect rect, bool absolute) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (absolute) {
|
if (absolute) {
|
||||||
return ((rect.x <= this->w) && (rect.w >= 0) && (rect.y <= this->h) && (rect.h >= 0));
|
|
||||||
} else {
|
|
||||||
return ((rect.x <= this->x2()) && (rect.x2() >= this->x) && (rect.y <= this->y2()) && (rect.y2() >= this->y));
|
return ((rect.x <= this->x2()) && (rect.x2() >= this->x) && (rect.y <= this->y2()) && (rect.y2() >= this->y));
|
||||||
|
} else {
|
||||||
|
return ((rect.x <= this->w) && (rect.w >= 0) && (rect.y <= this->h) && (rect.h >= 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Rect::info(const std::string &prefix) {
|
void Rect::info(const std::string &prefix) {
|
||||||
if (this->is_set()) {
|
if (this->is_set()) {
|
||||||
ESP_LOGI(TAG, "%s [%3d,%3d,%3d,%3d]", prefix.c_str(), this->x, this->y, this->w, this->h);
|
ESP_LOGI(TAG, "%s [%3d,%3d,%3d,%3d] (%3d,%3d)", prefix.c_str(), this->x, this->y, this->w, this->h, this->x2(),
|
||||||
|
this->y2());
|
||||||
} else
|
} else
|
||||||
ESP_LOGI(TAG, "%s ** IS NOT SET **", prefix.c_str());
|
ESP_LOGI(TAG, "%s ** IS NOT SET **", prefix.c_str());
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,8 +120,9 @@ class Rect {
|
||||||
void extend(Rect rect);
|
void extend(Rect rect);
|
||||||
void shrink(Rect rect);
|
void shrink(Rect rect);
|
||||||
|
|
||||||
bool inside(Rect rect, bool absolute = false);
|
bool inside(Rect rect, bool absolute = true);
|
||||||
bool inside(int16_t x, int16_t y, bool absolute = false);
|
bool inside(int16_t test_x, int16_t test_y, bool absolute = true);
|
||||||
|
bool equal(Rect rect);
|
||||||
void info(const std::string &prefix = "rect info:");
|
void info(const std::string &prefix = "rect info:");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ CODEOWNERS = ["@rspaargaren"]
|
||||||
DEPENDENCIES = ["spi"]
|
DEPENDENCIES = ["spi"]
|
||||||
|
|
||||||
CONF_ROTATE_CHIP = "rotate_chip"
|
CONF_ROTATE_CHIP = "rotate_chip"
|
||||||
|
CONF_FLIP_X = "flip_x"
|
||||||
CONF_SCROLL_SPEED = "scroll_speed"
|
CONF_SCROLL_SPEED = "scroll_speed"
|
||||||
CONF_SCROLL_DWELL = "scroll_dwell"
|
CONF_SCROLL_DWELL = "scroll_dwell"
|
||||||
CONF_SCROLL_DELAY = "scroll_delay"
|
CONF_SCROLL_DELAY = "scroll_delay"
|
||||||
|
@ -67,6 +68,7 @@ CONFIG_SCHEMA = (
|
||||||
CONF_SCROLL_DWELL, default="1000ms"
|
CONF_SCROLL_DWELL, default="1000ms"
|
||||||
): cv.positive_time_period_milliseconds,
|
): cv.positive_time_period_milliseconds,
|
||||||
cv.Optional(CONF_REVERSE_ENABLE, default=False): cv.boolean,
|
cv.Optional(CONF_REVERSE_ENABLE, default=False): cv.boolean,
|
||||||
|
cv.Optional(CONF_FLIP_X, default=False): cv.boolean,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.extend(cv.polling_component_schema("500ms"))
|
.extend(cv.polling_component_schema("500ms"))
|
||||||
|
@ -91,6 +93,7 @@ async def to_code(config):
|
||||||
cg.add(var.set_scroll(config[CONF_SCROLL_ENABLE]))
|
cg.add(var.set_scroll(config[CONF_SCROLL_ENABLE]))
|
||||||
cg.add(var.set_scroll_mode(config[CONF_SCROLL_MODE]))
|
cg.add(var.set_scroll_mode(config[CONF_SCROLL_MODE]))
|
||||||
cg.add(var.set_reverse(config[CONF_REVERSE_ENABLE]))
|
cg.add(var.set_reverse(config[CONF_REVERSE_ENABLE]))
|
||||||
|
cg.add(var.set_flip_x([CONF_FLIP_X]))
|
||||||
|
|
||||||
if CONF_LAMBDA in config:
|
if CONF_LAMBDA in config:
|
||||||
lambda_ = await cg.process_lambda(
|
lambda_ = await cg.process_lambda(
|
||||||
|
|
|
@ -261,14 +261,22 @@ void MAX7219Component::send64pixels(uint8_t chip, const uint8_t pixels[8]) {
|
||||||
if (this->orientation_ == 0) {
|
if (this->orientation_ == 0) {
|
||||||
for (uint8_t i = 0; i < 8; i++) {
|
for (uint8_t i = 0; i < 8; i++) {
|
||||||
// run this loop 8 times for all the pixels[8] received
|
// run this loop 8 times for all the pixels[8] received
|
||||||
|
if (this->flip_x_) {
|
||||||
|
b |= ((pixels[i] >> col) & 1) << i; // change the column bits into row bits
|
||||||
|
} else {
|
||||||
b |= ((pixels[i] >> col) & 1) << (7 - i); // change the column bits into row bits
|
b |= ((pixels[i] >> col) & 1) << (7 - i); // change the column bits into row bits
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if (this->orientation_ == 1) {
|
} else if (this->orientation_ == 1) {
|
||||||
b = pixels[col];
|
b = pixels[col];
|
||||||
} else if (this->orientation_ == 2) {
|
} else if (this->orientation_ == 2) {
|
||||||
for (uint8_t i = 0; i < 8; i++) {
|
for (uint8_t i = 0; i < 8; i++) {
|
||||||
|
if (this->flip_x_) {
|
||||||
|
b |= ((pixels[i] >> (7 - col)) & 1) << (7 - i);
|
||||||
|
} else {
|
||||||
b |= ((pixels[i] >> (7 - col)) & 1) << i;
|
b |= ((pixels[i] >> (7 - col)) & 1) << i;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
b = pixels[7 - col];
|
b = pixels[7 - col];
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,7 @@ class MAX7219Component : public PollingComponent,
|
||||||
void set_scroll(bool on_off) { this->scroll_ = on_off; };
|
void set_scroll(bool on_off) { this->scroll_ = on_off; };
|
||||||
void set_scroll_mode(ScrollMode mode) { this->scroll_mode_ = mode; };
|
void set_scroll_mode(ScrollMode mode) { this->scroll_mode_ = mode; };
|
||||||
void set_reverse(bool on_off) { this->reverse_ = on_off; };
|
void set_reverse(bool on_off) { this->reverse_ = on_off; };
|
||||||
|
void set_flip_x(bool flip_x) { this->flip_x_ = flip_x; };
|
||||||
|
|
||||||
void send_char(uint8_t chip, uint8_t data);
|
void send_char(uint8_t chip, uint8_t data);
|
||||||
void send64pixels(uint8_t chip, const uint8_t pixels[8]);
|
void send64pixels(uint8_t chip, const uint8_t pixels[8]);
|
||||||
|
@ -108,6 +109,7 @@ class MAX7219Component : public PollingComponent,
|
||||||
ChipLinesStyle chip_lines_style_;
|
ChipLinesStyle chip_lines_style_;
|
||||||
bool scroll_;
|
bool scroll_;
|
||||||
bool reverse_;
|
bool reverse_;
|
||||||
|
bool flip_x_;
|
||||||
bool update_{false};
|
bool update_{false};
|
||||||
uint16_t scroll_speed_;
|
uint16_t scroll_speed_;
|
||||||
uint16_t scroll_delay_;
|
uint16_t scroll_delay_;
|
||||||
|
|
|
@ -264,13 +264,52 @@ void PMSX003Component::parse_data_() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PMSX003_TYPE_5003T: {
|
case PMSX003_TYPE_5003T: {
|
||||||
|
uint16_t pm_1_0_std_concentration = this->get_16_bit_uint_(4);
|
||||||
|
uint16_t pm_2_5_std_concentration = this->get_16_bit_uint_(6);
|
||||||
|
uint16_t pm_10_0_std_concentration = this->get_16_bit_uint_(8);
|
||||||
|
|
||||||
|
uint16_t pm_1_0_concentration = this->get_16_bit_uint_(10);
|
||||||
uint16_t pm_2_5_concentration = this->get_16_bit_uint_(12);
|
uint16_t pm_2_5_concentration = this->get_16_bit_uint_(12);
|
||||||
|
uint16_t pm_10_0_concentration = this->get_16_bit_uint_(14);
|
||||||
|
|
||||||
|
uint16_t pm_particles_03um = this->get_16_bit_uint_(16);
|
||||||
|
uint16_t pm_particles_05um = this->get_16_bit_uint_(18);
|
||||||
|
uint16_t pm_particles_10um = this->get_16_bit_uint_(20);
|
||||||
|
uint16_t pm_particles_25um = this->get_16_bit_uint_(22);
|
||||||
|
// Note the pm particles 50um & 100um are not returned,
|
||||||
|
// as PMS5003T uses those data values for temperature and humidity.
|
||||||
|
|
||||||
float temperature = this->get_16_bit_uint_(24) / 10.0f;
|
float temperature = this->get_16_bit_uint_(24) / 10.0f;
|
||||||
float humidity = this->get_16_bit_uint_(26) / 10.0f;
|
float humidity = this->get_16_bit_uint_(26) / 10.0f;
|
||||||
ESP_LOGD(TAG, "Got PM2.5 Concentration: %u µg/m^3, Temperature: %.1f°C, Humidity: %.1f%%", pm_2_5_concentration,
|
|
||||||
temperature, humidity);
|
ESP_LOGD(TAG,
|
||||||
|
"Got PM1.0 Concentration: %u µg/m^3, PM2.5 Concentration %u µg/m^3, PM10.0 Concentration: %u µg/m^3, "
|
||||||
|
"Temperature: %.1f°C, Humidity: %.1f%%",
|
||||||
|
pm_1_0_concentration, pm_2_5_concentration, pm_10_0_concentration, temperature, humidity);
|
||||||
|
|
||||||
|
if (this->pm_1_0_std_sensor_ != nullptr)
|
||||||
|
this->pm_1_0_std_sensor_->publish_state(pm_1_0_std_concentration);
|
||||||
|
if (this->pm_2_5_std_sensor_ != nullptr)
|
||||||
|
this->pm_2_5_std_sensor_->publish_state(pm_2_5_std_concentration);
|
||||||
|
if (this->pm_10_0_std_sensor_ != nullptr)
|
||||||
|
this->pm_10_0_std_sensor_->publish_state(pm_10_0_std_concentration);
|
||||||
|
|
||||||
|
if (this->pm_1_0_sensor_ != nullptr)
|
||||||
|
this->pm_1_0_sensor_->publish_state(pm_1_0_concentration);
|
||||||
if (this->pm_2_5_sensor_ != nullptr)
|
if (this->pm_2_5_sensor_ != nullptr)
|
||||||
this->pm_2_5_sensor_->publish_state(pm_2_5_concentration);
|
this->pm_2_5_sensor_->publish_state(pm_2_5_concentration);
|
||||||
|
if (this->pm_10_0_sensor_ != nullptr)
|
||||||
|
this->pm_10_0_sensor_->publish_state(pm_10_0_concentration);
|
||||||
|
|
||||||
|
if (this->pm_particles_03um_sensor_ != nullptr)
|
||||||
|
this->pm_particles_03um_sensor_->publish_state(pm_particles_03um);
|
||||||
|
if (this->pm_particles_05um_sensor_ != nullptr)
|
||||||
|
this->pm_particles_05um_sensor_->publish_state(pm_particles_05um);
|
||||||
|
if (this->pm_particles_10um_sensor_ != nullptr)
|
||||||
|
this->pm_particles_10um_sensor_->publish_state(pm_particles_10um);
|
||||||
|
if (this->pm_particles_25um_sensor_ != nullptr)
|
||||||
|
this->pm_particles_25um_sensor_->publish_state(pm_particles_25um);
|
||||||
|
|
||||||
if (this->temperature_sensor_ != nullptr)
|
if (this->temperature_sensor_ != nullptr)
|
||||||
this->temperature_sensor_->publish_state(temperature);
|
this->temperature_sensor_->publish_state(temperature);
|
||||||
if (this->humidity_sensor_ != nullptr)
|
if (this->humidity_sensor_ != nullptr)
|
||||||
|
|
|
@ -55,9 +55,9 @@ PMSX003_TYPES = {
|
||||||
}
|
}
|
||||||
|
|
||||||
SENSORS_TO_TYPE = {
|
SENSORS_TO_TYPE = {
|
||||||
CONF_PM_1_0: [TYPE_PMSX003, TYPE_PMS5003ST, TYPE_PMS5003S],
|
CONF_PM_1_0: [TYPE_PMSX003, TYPE_PMS5003T, TYPE_PMS5003ST, TYPE_PMS5003S],
|
||||||
CONF_PM_2_5: [TYPE_PMSX003, TYPE_PMS5003T, TYPE_PMS5003ST, TYPE_PMS5003S],
|
CONF_PM_2_5: [TYPE_PMSX003, TYPE_PMS5003T, TYPE_PMS5003ST, TYPE_PMS5003S],
|
||||||
CONF_PM_10_0: [TYPE_PMSX003, TYPE_PMS5003ST, TYPE_PMS5003S],
|
CONF_PM_10_0: [TYPE_PMSX003, TYPE_PMS5003T, TYPE_PMS5003ST, TYPE_PMS5003S],
|
||||||
CONF_TEMPERATURE: [TYPE_PMS5003T, TYPE_PMS5003ST],
|
CONF_TEMPERATURE: [TYPE_PMS5003T, TYPE_PMS5003ST],
|
||||||
CONF_HUMIDITY: [TYPE_PMS5003T, TYPE_PMS5003ST],
|
CONF_HUMIDITY: [TYPE_PMS5003T, TYPE_PMS5003ST],
|
||||||
CONF_FORMALDEHYDE: [TYPE_PMS5003ST, TYPE_PMS5003S],
|
CONF_FORMALDEHYDE: [TYPE_PMS5003ST, TYPE_PMS5003S],
|
||||||
|
|
|
@ -466,9 +466,21 @@ async def lambda_filter_to_code(config, filter_id):
|
||||||
return cg.new_Pvariable(filter_id, lambda_)
|
return cg.new_Pvariable(filter_id, lambda_)
|
||||||
|
|
||||||
|
|
||||||
@FILTER_REGISTRY.register("delta", DeltaFilter, cv.float_)
|
def validate_delta(config):
|
||||||
|
try:
|
||||||
|
return (cv.positive_float(config), False)
|
||||||
|
except cv.Invalid:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
return (cv.percentage(config), True)
|
||||||
|
except cv.Invalid:
|
||||||
|
pass
|
||||||
|
raise cv.Invalid("Delta filter requires a positive number or percentage value.")
|
||||||
|
|
||||||
|
|
||||||
|
@FILTER_REGISTRY.register("delta", DeltaFilter, validate_delta)
|
||||||
async def delta_filter_to_code(config, filter_id):
|
async def delta_filter_to_code(config, filter_id):
|
||||||
return cg.new_Pvariable(filter_id, config)
|
return cg.new_Pvariable(filter_id, *config)
|
||||||
|
|
||||||
|
|
||||||
@FILTER_REGISTRY.register("or", OrFilter, validate_filters)
|
@FILTER_REGISTRY.register("or", OrFilter, validate_filters)
|
||||||
|
|
|
@ -315,19 +315,23 @@ optional<float> ThrottleFilter::new_value(float value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeltaFilter
|
// DeltaFilter
|
||||||
DeltaFilter::DeltaFilter(float min_delta) : min_delta_(min_delta), last_value_(NAN) {}
|
DeltaFilter::DeltaFilter(float delta, bool percentage_mode)
|
||||||
|
: delta_(delta), current_delta_(delta), percentage_mode_(percentage_mode), last_value_(NAN) {}
|
||||||
optional<float> DeltaFilter::new_value(float value) {
|
optional<float> DeltaFilter::new_value(float value) {
|
||||||
if (std::isnan(value)) {
|
if (std::isnan(value)) {
|
||||||
if (std::isnan(this->last_value_)) {
|
if (std::isnan(this->last_value_)) {
|
||||||
return {};
|
return {};
|
||||||
} else {
|
} else {
|
||||||
|
if (this->percentage_mode_) {
|
||||||
|
this->current_delta_ = fabsf(value * this->delta_);
|
||||||
|
}
|
||||||
return this->last_value_ = value;
|
return this->last_value_ = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (std::isnan(this->last_value_)) {
|
if (std::isnan(this->last_value_) || fabsf(value - this->last_value_) >= this->current_delta_) {
|
||||||
return this->last_value_ = value;
|
if (this->percentage_mode_) {
|
||||||
|
this->current_delta_ = fabsf(value * this->delta_);
|
||||||
}
|
}
|
||||||
if (fabsf(value - this->last_value_) >= this->min_delta_) {
|
|
||||||
return this->last_value_ = value;
|
return this->last_value_ = value;
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
|
|
|
@ -325,12 +325,14 @@ class HeartbeatFilter : public Filter, public Component {
|
||||||
|
|
||||||
class DeltaFilter : public Filter {
|
class DeltaFilter : public Filter {
|
||||||
public:
|
public:
|
||||||
explicit DeltaFilter(float min_delta);
|
explicit DeltaFilter(float delta, bool percentage_mode);
|
||||||
|
|
||||||
optional<float> new_value(float value) override;
|
optional<float> new_value(float value) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
float min_delta_;
|
float delta_;
|
||||||
|
float current_delta_;
|
||||||
|
bool percentage_mode_;
|
||||||
float last_value_{NAN};
|
float last_value_{NAN};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ spi_ns = cg.esphome_ns.namespace("spi")
|
||||||
SPIComponent = spi_ns.class_("SPIComponent", cg.Component)
|
SPIComponent = spi_ns.class_("SPIComponent", cg.Component)
|
||||||
SPIDevice = spi_ns.class_("SPIDevice")
|
SPIDevice = spi_ns.class_("SPIDevice")
|
||||||
MULTI_CONF = True
|
MULTI_CONF = True
|
||||||
|
CONF_FORCE_SW = "force_sw"
|
||||||
|
|
||||||
CONFIG_SCHEMA = cv.All(
|
CONFIG_SCHEMA = cv.All(
|
||||||
cv.Schema(
|
cv.Schema(
|
||||||
|
@ -25,6 +26,7 @@ CONFIG_SCHEMA = cv.All(
|
||||||
cv.Required(CONF_CLK_PIN): pins.gpio_output_pin_schema,
|
cv.Required(CONF_CLK_PIN): pins.gpio_output_pin_schema,
|
||||||
cv.Optional(CONF_MISO_PIN): pins.gpio_input_pin_schema,
|
cv.Optional(CONF_MISO_PIN): pins.gpio_input_pin_schema,
|
||||||
cv.Optional(CONF_MOSI_PIN): pins.gpio_output_pin_schema,
|
cv.Optional(CONF_MOSI_PIN): pins.gpio_output_pin_schema,
|
||||||
|
cv.Optional(CONF_FORCE_SW, default=False): cv.boolean,
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
cv.has_at_least_one_key(CONF_MISO_PIN, CONF_MOSI_PIN),
|
cv.has_at_least_one_key(CONF_MISO_PIN, CONF_MOSI_PIN),
|
||||||
|
@ -39,6 +41,7 @@ async def to_code(config):
|
||||||
|
|
||||||
clk = await cg.gpio_pin_expression(config[CONF_CLK_PIN])
|
clk = await cg.gpio_pin_expression(config[CONF_CLK_PIN])
|
||||||
cg.add(var.set_clk(clk))
|
cg.add(var.set_clk(clk))
|
||||||
|
cg.add(var.set_force_sw(config[CONF_FORCE_SW]))
|
||||||
if CONF_MISO_PIN in config:
|
if CONF_MISO_PIN in config:
|
||||||
miso = await cg.gpio_pin_expression(config[CONF_MISO_PIN])
|
miso = await cg.gpio_pin_expression(config[CONF_MISO_PIN])
|
||||||
cg.add(var.set_miso(miso))
|
cg.add(var.set_miso(miso))
|
||||||
|
|
|
@ -25,7 +25,7 @@ void SPIComponent::setup() {
|
||||||
this->clk_->digital_write(true);
|
this->clk_->digital_write(true);
|
||||||
|
|
||||||
#ifdef USE_SPI_ARDUINO_BACKEND
|
#ifdef USE_SPI_ARDUINO_BACKEND
|
||||||
bool use_hw_spi = true;
|
bool use_hw_spi = !this->force_sw_;
|
||||||
const bool has_miso = this->miso_ != nullptr;
|
const bool has_miso = this->miso_ != nullptr;
|
||||||
const bool has_mosi = this->mosi_ != nullptr;
|
const bool has_mosi = this->mosi_ != nullptr;
|
||||||
int8_t clk_pin = -1, miso_pin = -1, mosi_pin = -1;
|
int8_t clk_pin = -1, miso_pin = -1, mosi_pin = -1;
|
||||||
|
|
|
@ -74,6 +74,7 @@ class SPIComponent : public Component {
|
||||||
void set_clk(GPIOPin *clk) { clk_ = clk; }
|
void set_clk(GPIOPin *clk) { clk_ = clk; }
|
||||||
void set_miso(GPIOPin *miso) { miso_ = miso; }
|
void set_miso(GPIOPin *miso) { miso_ = miso; }
|
||||||
void set_mosi(GPIOPin *mosi) { mosi_ = mosi; }
|
void set_mosi(GPIOPin *mosi) { mosi_ = mosi; }
|
||||||
|
void set_force_sw(bool force_sw) { force_sw_ = force_sw; }
|
||||||
|
|
||||||
void setup() override;
|
void setup() override;
|
||||||
|
|
||||||
|
@ -260,6 +261,7 @@ class SPIComponent : public Component {
|
||||||
GPIOPin *miso_{nullptr};
|
GPIOPin *miso_{nullptr};
|
||||||
GPIOPin *mosi_{nullptr};
|
GPIOPin *mosi_{nullptr};
|
||||||
GPIOPin *active_cs_{nullptr};
|
GPIOPin *active_cs_{nullptr};
|
||||||
|
bool force_sw_{false};
|
||||||
#ifdef USE_SPI_ARDUINO_BACKEND
|
#ifdef USE_SPI_ARDUINO_BACKEND
|
||||||
SPIClass *hw_spi_{nullptr};
|
SPIClass *hw_spi_{nullptr};
|
||||||
#endif // USE_SPI_ARDUINO_BACKEND
|
#endif // USE_SPI_ARDUINO_BACKEND
|
||||||
|
|
|
@ -1,26 +1,35 @@
|
||||||
from esphome import pins
|
from esphome import pins
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome.components import light
|
from esphome.components import light, output
|
||||||
from esphome.const import CONF_OUTPUT_ID, CONF_PIN
|
from esphome.const import CONF_OUTPUT, CONF_OUTPUT_ID, CONF_PIN
|
||||||
from .. import status_led_ns
|
from .. import status_led_ns
|
||||||
|
|
||||||
|
AUTO_LOAD = ["output"]
|
||||||
|
|
||||||
StatusLEDLightOutput = status_led_ns.class_(
|
StatusLEDLightOutput = status_led_ns.class_(
|
||||||
"StatusLEDLightOutput", light.LightOutput, cg.Component
|
"StatusLEDLightOutput", light.LightOutput, cg.Component
|
||||||
)
|
)
|
||||||
|
|
||||||
CONFIG_SCHEMA = light.BINARY_LIGHT_SCHEMA.extend(
|
CONFIG_SCHEMA = cv.All(
|
||||||
|
light.BINARY_LIGHT_SCHEMA.extend(
|
||||||
{
|
{
|
||||||
cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(StatusLEDLightOutput),
|
cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(StatusLEDLightOutput),
|
||||||
cv.Required(CONF_PIN): pins.gpio_output_pin_schema,
|
cv.Optional(CONF_PIN): pins.gpio_output_pin_schema,
|
||||||
|
cv.Optional(CONF_OUTPUT): cv.use_id(output.BinaryOutput),
|
||||||
}
|
}
|
||||||
|
),
|
||||||
|
cv.has_at_least_one_key(CONF_PIN, CONF_OUTPUT),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
var = cg.new_Pvariable(config[CONF_OUTPUT_ID])
|
var = cg.new_Pvariable(config[CONF_OUTPUT_ID])
|
||||||
|
if CONF_PIN in config:
|
||||||
pin = await cg.gpio_pin_expression(config[CONF_PIN])
|
pin = await cg.gpio_pin_expression(config[CONF_PIN])
|
||||||
cg.add(var.set_pin(pin))
|
cg.add(var.set_pin(pin))
|
||||||
|
if CONF_OUTPUT in config:
|
||||||
|
out = await cg.get_variable(config[CONF_OUTPUT])
|
||||||
|
cg.add(var.set_output(out))
|
||||||
await cg.register_component(var, config)
|
await cg.register_component(var, config)
|
||||||
# cg.add(cg.App.register_component(var))
|
|
||||||
await light.register_light(var, config)
|
await light.register_light(var, config)
|
||||||
|
|
|
@ -15,10 +15,10 @@ void StatusLEDLightOutput::loop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((new_state & STATUS_LED_ERROR) != 0u) {
|
if ((new_state & STATUS_LED_ERROR) != 0u) {
|
||||||
this->pin_->digital_write(millis() % 250u < 150u);
|
this->output_state_(millis() % 250u < 150u);
|
||||||
this->last_app_state_ = new_state;
|
this->last_app_state_ = new_state;
|
||||||
} else if ((new_state & STATUS_LED_WARNING) != 0u) {
|
} else if ((new_state & STATUS_LED_WARNING) != 0u) {
|
||||||
this->pin_->digital_write(millis() % 1500u < 250u);
|
this->output_state_(millis() % 1500u < 250u);
|
||||||
this->last_app_state_ = new_state;
|
this->last_app_state_ = new_state;
|
||||||
} else if (new_state != this->last_app_state_) {
|
} else if (new_state != this->last_app_state_) {
|
||||||
// if no error/warning -> restore light state or turn off
|
// if no error/warning -> restore light state or turn off
|
||||||
|
@ -26,17 +26,16 @@ void StatusLEDLightOutput::loop() {
|
||||||
|
|
||||||
if (lightstate_)
|
if (lightstate_)
|
||||||
lightstate_->current_values_as_binary(&state);
|
lightstate_->current_values_as_binary(&state);
|
||||||
|
|
||||||
this->pin_->digital_write(state);
|
|
||||||
this->last_app_state_ = new_state;
|
|
||||||
|
|
||||||
ESP_LOGD(TAG, "Restoring light state %s", ONOFF(state));
|
ESP_LOGD(TAG, "Restoring light state %s", ONOFF(state));
|
||||||
|
|
||||||
|
this->output_state_(state);
|
||||||
|
this->last_app_state_ = new_state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StatusLEDLightOutput::setup_state(light::LightState *state) {
|
void StatusLEDLightOutput::setup_state(light::LightState *state) {
|
||||||
lightstate_ = state;
|
lightstate_ = state;
|
||||||
ESP_LOGD(TAG, "'%s': Setting initital state", state->get_name().c_str());
|
ESP_LOGD(TAG, "'%s': Setting initial state", state->get_name().c_str());
|
||||||
this->write_state(state);
|
this->write_state(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,22 +46,31 @@ void StatusLEDLightOutput::write_state(light::LightState *state) {
|
||||||
// if in warning/error, don't overwrite the status_led
|
// if in warning/error, don't overwrite the status_led
|
||||||
// once it is back to OK, the loop will restore the state
|
// once it is back to OK, the loop will restore the state
|
||||||
if ((App.get_app_state() & (STATUS_LED_ERROR | STATUS_LED_WARNING)) == 0u) {
|
if ((App.get_app_state() & (STATUS_LED_ERROR | STATUS_LED_WARNING)) == 0u) {
|
||||||
this->pin_->digital_write(binary);
|
|
||||||
ESP_LOGD(TAG, "'%s': Setting state %s", state->get_name().c_str(), ONOFF(binary));
|
ESP_LOGD(TAG, "'%s': Setting state %s", state->get_name().c_str(), ONOFF(binary));
|
||||||
|
this->output_state_(binary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StatusLEDLightOutput::setup() {
|
void StatusLEDLightOutput::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Setting up Status LED...");
|
ESP_LOGCONFIG(TAG, "Setting up Status LED...");
|
||||||
|
|
||||||
|
if (this->pin_ != nullptr) {
|
||||||
this->pin_->setup();
|
this->pin_->setup();
|
||||||
this->pin_->digital_write(false);
|
this->pin_->digital_write(false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void StatusLEDLightOutput::dump_config() {
|
void StatusLEDLightOutput::dump_config() {
|
||||||
ESP_LOGCONFIG(TAG, "Status Led Light:");
|
ESP_LOGCONFIG(TAG, "Status Led Light:");
|
||||||
LOG_PIN(" Pin: ", this->pin_);
|
LOG_PIN(" Pin: ", this->pin_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StatusLEDLightOutput::output_state_(bool state) {
|
||||||
|
if (this->pin_ != nullptr)
|
||||||
|
this->pin_->digital_write(state);
|
||||||
|
if (this->output_ != nullptr)
|
||||||
|
this->output_->set_state(state);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace status_led
|
} // namespace status_led
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
#include "esphome/core/hal.h"
|
#include "esphome/core/hal.h"
|
||||||
#include "esphome/components/light/light_output.h"
|
#include "esphome/components/light/light_output.h"
|
||||||
|
#include "esphome/components/output/binary_output.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace status_led {
|
namespace status_led {
|
||||||
|
@ -10,6 +11,7 @@ namespace status_led {
|
||||||
class StatusLEDLightOutput : public light::LightOutput, public Component {
|
class StatusLEDLightOutput : public light::LightOutput, public Component {
|
||||||
public:
|
public:
|
||||||
void set_pin(GPIOPin *pin) { pin_ = pin; }
|
void set_pin(GPIOPin *pin) { pin_ = pin; }
|
||||||
|
void set_output(output::BinaryOutput *output) { output_ = output; }
|
||||||
|
|
||||||
light::LightTraits get_traits() override {
|
light::LightTraits get_traits() override {
|
||||||
auto traits = light::LightTraits();
|
auto traits = light::LightTraits();
|
||||||
|
@ -31,9 +33,11 @@ class StatusLEDLightOutput : public light::LightOutput, public Component {
|
||||||
float get_loop_priority() const override { return 50.0f; }
|
float get_loop_priority() const override { return 50.0f; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
GPIOPin *pin_;
|
GPIOPin *pin_{nullptr};
|
||||||
|
output::BinaryOutput *output_{nullptr};
|
||||||
light::LightState *lightstate_{};
|
light::LightState *lightstate_{};
|
||||||
uint32_t last_app_state_{0xFFFF};
|
uint32_t last_app_state_{0xFFFF};
|
||||||
|
void output_state_(bool state);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace status_led
|
} // namespace status_led
|
||||||
|
|
|
@ -1097,7 +1097,7 @@ def possibly_negative_percentage(value):
|
||||||
if isinstance(value, str):
|
if isinstance(value, str):
|
||||||
try:
|
try:
|
||||||
if value.endswith("%"):
|
if value.endswith("%"):
|
||||||
has_percent_sign = False
|
has_percent_sign = True
|
||||||
value = float(value[:-1].rstrip()) / 100.0
|
value = float(value[:-1].rstrip()) / 100.0
|
||||||
else:
|
else:
|
||||||
value = float(value)
|
value = float(value)
|
||||||
|
|
|
@ -23,8 +23,13 @@ bool EntityBase::is_disabled_by_default() const { return this->disabled_by_defau
|
||||||
void EntityBase::set_disabled_by_default(bool disabled_by_default) { this->disabled_by_default_ = disabled_by_default; }
|
void EntityBase::set_disabled_by_default(bool disabled_by_default) { this->disabled_by_default_ = disabled_by_default; }
|
||||||
|
|
||||||
// Entity Icon
|
// Entity Icon
|
||||||
const std::string &EntityBase::get_icon() const { return this->icon_; }
|
std::string EntityBase::get_icon() const {
|
||||||
void EntityBase::set_icon(const std::string &name) { this->icon_ = name; }
|
if (this->icon_c_str_ == nullptr) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return this->icon_c_str_;
|
||||||
|
}
|
||||||
|
void EntityBase::set_icon(const char *icon) { this->icon_c_str_ = icon; }
|
||||||
|
|
||||||
// Entity Category
|
// Entity Category
|
||||||
EntityCategory EntityBase::get_entity_category() const { return this->entity_category_; }
|
EntityCategory EntityBase::get_entity_category() const { return this->entity_category_; }
|
||||||
|
|
|
@ -42,8 +42,8 @@ class EntityBase {
|
||||||
void set_entity_category(EntityCategory entity_category);
|
void set_entity_category(EntityCategory entity_category);
|
||||||
|
|
||||||
// Get/set this entity's icon
|
// Get/set this entity's icon
|
||||||
const std::string &get_icon() const;
|
std::string get_icon() const;
|
||||||
void set_icon(const std::string &name);
|
void set_icon(const char *icon);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// The hash_base() function has been deprecated. It is kept in this
|
/// The hash_base() function has been deprecated. It is kept in this
|
||||||
|
@ -53,7 +53,7 @@ class EntityBase {
|
||||||
|
|
||||||
std::string name_;
|
std::string name_;
|
||||||
std::string object_id_;
|
std::string object_id_;
|
||||||
std::string icon_;
|
const char *icon_c_str_{nullptr};
|
||||||
uint32_t object_id_hash_;
|
uint32_t object_id_hash_;
|
||||||
bool internal_{false};
|
bool internal_{false};
|
||||||
bool disabled_by_default_{false};
|
bool disabled_by_default_{false};
|
||||||
|
|
|
@ -400,6 +400,7 @@ sensor:
|
||||||
- heartbeat: 5s
|
- heartbeat: 5s
|
||||||
- debounce: 0.1s
|
- debounce: 0.1s
|
||||||
- delta: 5.0
|
- delta: 5.0
|
||||||
|
- delta: 1%
|
||||||
- or:
|
- or:
|
||||||
- throttle: 1s
|
- throttle: 1s
|
||||||
- delta: 5.0
|
- delta: 5.0
|
||||||
|
|
|
@ -630,8 +630,26 @@ sensor:
|
||||||
- platform: pmsx003
|
- platform: pmsx003
|
||||||
uart_id: uart5
|
uart_id: uart5
|
||||||
type: PMS5003T
|
type: PMS5003T
|
||||||
|
pm_1_0:
|
||||||
|
name: PM 1.0 Concentration
|
||||||
pm_2_5:
|
pm_2_5:
|
||||||
name: PM 2.5 Concentration
|
name: PM 2.5 Concentration
|
||||||
|
pm_10_0:
|
||||||
|
name: PM 10.0 Concentration
|
||||||
|
pm_1_0_std:
|
||||||
|
name: PM 1.0 Standard Atmospher Concentration
|
||||||
|
pm_2_5_std:
|
||||||
|
name: PM 2.5 Standard Atmospher Concentration
|
||||||
|
pm_10_0_std:
|
||||||
|
name: PM 10.0 Standard Atmospher Concentration
|
||||||
|
pm_0_3um:
|
||||||
|
name: Particulate Count >0.3um
|
||||||
|
pm_0_5um:
|
||||||
|
name: Particulate Count >0.5um
|
||||||
|
pm_1_0um:
|
||||||
|
name: Particulate Count >1.0um
|
||||||
|
pm_2_5um:
|
||||||
|
name: Particulate Count >2.5um
|
||||||
temperature:
|
temperature:
|
||||||
name: PMS Temperature
|
name: PMS Temperature
|
||||||
humidity:
|
humidity:
|
||||||
|
|
Loading…
Reference in a new issue