Skip to content

Commit

Permalink
Merge branch 'dev' of https://github.com/clydebarrow/esphome into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
clydebarrow committed May 2, 2024
2 parents e832100 + 6fe328e commit e27d558
Show file tree
Hide file tree
Showing 50 changed files with 5,272 additions and 828 deletions.
7 changes: 5 additions & 2 deletions esphome/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,9 +343,10 @@ def upload_program(config, args, host):
password = ota_conf.get(CONF_PASSWORD, "")

if (
not is_ip_address(CORE.address)
not is_ip_address(CORE.address) # pylint: disable=too-many-boolean-expressions
and (get_port_type(host) == "MQTT" or config[CONF_MDNS][CONF_DISABLED])
and CONF_MQTT in config
and (not args.device or args.device == "MQTT")
):
from esphome import mqtt

Expand Down Expand Up @@ -768,7 +769,9 @@ def parse_args(argv):
)

parser_upload = subparsers.add_parser(
"upload", help="Validate the configuration and upload the latest binary."
"upload",
help="Validate the configuration and upload the latest binary.",
parents=[mqtt_options],
)
parser_upload.add_argument(
"configuration", help="Your YAML configuration file(s).", nargs="+"
Expand Down
10 changes: 10 additions & 0 deletions esphome/automation.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,20 @@


def maybe_simple_id(*validators):
"""Allow a raw ID to be specified in place of a config block.
If the value that's being validated is a dictionary, it's passed as-is to the specified validators. Otherwise, it's
wrapped in a dict that looks like ``{"id": <value>}``, and that dict is then handed off to the specified validators.
"""
return maybe_conf(CONF_ID, *validators)


def maybe_conf(conf, *validators):
"""Allow a raw value to be specified in place of a config block.
If the value that's being validated is a dictionary, it's passed as-is to the specified validators. Otherwise, it's
wrapped in a dict that looks like ``{<conf>: <value>}``, and that dict is then handed off to the specified
validators.
(This is a general case of ``maybe_simple_id`` that allows the wrapping key to be something other than ``id``.)
"""
validator = cv.All(*validators)

@schema_extractor("maybe")
Expand Down
6 changes: 3 additions & 3 deletions esphome/components/binary_sensor/automation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,15 @@ void binary_sensor::MultiClickTrigger::on_state_(bool state) {
MultiClickTriggerEvent evt = this->timing_[*this->at_index_];

if (evt.max_length != 4294967294UL) {
ESP_LOGV(TAG, "A i=%u min=%" PRIu32 " max=%" PRIu32, *this->at_index_, evt.min_length, evt.max_length); // NOLINT
ESP_LOGV(TAG, "A i=%zu min=%" PRIu32 " max=%" PRIu32, *this->at_index_, evt.min_length, evt.max_length); // NOLINT
this->schedule_is_valid_(evt.min_length);
this->schedule_is_not_valid_(evt.max_length);
} else if (*this->at_index_ + 1 != this->timing_.size()) {
ESP_LOGV(TAG, "B i=%u min=%" PRIu32, *this->at_index_, evt.min_length); // NOLINT
ESP_LOGV(TAG, "B i=%zu min=%" PRIu32, *this->at_index_, evt.min_length); // NOLINT
this->cancel_timeout("is_not_valid");
this->schedule_is_valid_(evt.min_length);
} else {
ESP_LOGV(TAG, "C i=%u min=%" PRIu32, *this->at_index_, evt.min_length); // NOLINT
ESP_LOGV(TAG, "C i=%zu min=%" PRIu32, *this->at_index_, evt.min_length); // NOLINT
this->is_valid_ = false;
this->cancel_timeout("is_not_valid");
this->set_timeout("trigger", evt.min_length, [this]() { this->trigger_(); });
Expand Down
194 changes: 98 additions & 96 deletions esphome/components/captive_portal/captive_index.h

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions esphome/components/display/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
)

CONF_ON_PAGE_CHANGE = "on_page_change"
CONF_SHOW_TEST_CARD = "show_test_card"

DISPLAY_ROTATIONS = {
0: display_ns.DISPLAY_ROTATION_0_DEGREES,
Expand Down Expand Up @@ -82,6 +83,7 @@ def validate_rotation(value):
}
),
cv.Optional(CONF_AUTO_CLEAR_ENABLED, default=True): cv.boolean,
cv.Optional(CONF_SHOW_TEST_CARD): cv.boolean,
}
)

Expand Down Expand Up @@ -113,6 +115,8 @@ async def setup_display_core_(var, config):
await automation.build_automation(
trigger, [(DisplayPagePtr, "from"), (DisplayPagePtr, "to")], conf
)
if config.get(CONF_SHOW_TEST_CARD):
cg.add(var.show_test_card())


async def register_display(var, config):
Expand Down
64 changes: 61 additions & 3 deletions esphome/components/display/display.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include "display.h"

#include "display_color_utils.h"
#include <utility>

#include "esphome/core/hal.h"
#include "esphome/core/log.h"

namespace esphome {
Expand Down Expand Up @@ -507,7 +507,9 @@ void Display::do_update_() {
if (this->auto_clear_enabled_) {
this->clear();
}
if (this->page_ != nullptr) {
if (this->show_test_card_) {
this->test_card();
} else if (this->page_ != nullptr) {
this->page_->get_writer()(*this);
} else if (this->writer_.has_value()) {
(*this->writer_)(*this);
Expand Down Expand Up @@ -608,6 +610,62 @@ bool Display::clamp_y_(int y, int h, int &min_y, int &max_y) {
return min_y < max_y;
}

const uint8_t TESTCARD_FONT[3][8] PROGMEM = {{0x41, 0x7F, 0x7F, 0x09, 0x19, 0x7F, 0x66, 0x00}, // 'R'
{0x1C, 0x3E, 0x63, 0x41, 0x51, 0x73, 0x72, 0x00}, // 'G'
{0x41, 0x7F, 0x7F, 0x49, 0x49, 0x7F, 0x36, 0x00}}; // 'B'

void Display::test_card() {
int w = get_width(), h = get_height(), image_w, image_h;
this->clear();
this->show_test_card_ = false;
if (this->get_display_type() == DISPLAY_TYPE_COLOR) {
Color r(255, 0, 0), g(0, 255, 0), b(0, 0, 255);
image_w = std::min(w - 20, 310);
image_h = std::min(h - 20, 255);

int shift_x = (w - image_w) / 2;
int shift_y = (h - image_h) / 2;
int line_w = (image_w - 6) / 6;
int image_c = image_w / 2;
for (auto i = 0; i <= image_h; i++) {
int c = esp_scale(i, image_h);
this->horizontal_line(shift_x + 0, shift_y + i, line_w, r.fade_to_white(c));
this->horizontal_line(shift_x + line_w, shift_y + i, line_w, r.fade_to_black(c)); //

this->horizontal_line(shift_x + image_c - line_w, shift_y + i, line_w, g.fade_to_white(c));
this->horizontal_line(shift_x + image_c, shift_y + i, line_w, g.fade_to_black(c));

this->horizontal_line(shift_x + image_w - (line_w * 2), shift_y + i, line_w, b.fade_to_white(c));
this->horizontal_line(shift_x + image_w - line_w, shift_y + i, line_w, b.fade_to_black(c));
}
this->rectangle(shift_x, shift_y, image_w, image_h, Color(127, 127, 0));

uint16_t shift_r = shift_x + line_w - (8 * 3);
uint16_t shift_g = shift_x + image_c - (8 * 3);
uint16_t shift_b = shift_x + image_w - line_w - (8 * 3);
shift_y = h / 2 - (8 * 3);
for (auto i = 0; i < 8; i++) {
uint8_t ftr = progmem_read_byte(&TESTCARD_FONT[0][i]);
uint8_t ftg = progmem_read_byte(&TESTCARD_FONT[1][i]);
uint8_t ftb = progmem_read_byte(&TESTCARD_FONT[2][i]);
for (auto k = 0; k < 8; k++) {
if ((ftr & (1 << k)) != 0) {
this->filled_rectangle(shift_r + (i * 6), shift_y + (k * 6), 6, 6, COLOR_OFF);
}
if ((ftg & (1 << k)) != 0) {
this->filled_rectangle(shift_g + (i * 6), shift_y + (k * 6), 6, 6, COLOR_OFF);
}
if ((ftb & (1 << k)) != 0) {
this->filled_rectangle(shift_b + (i * 6), shift_y + (k * 6), 6, 6, COLOR_OFF);
}
}
}
}
this->rectangle(0, 0, w, h, Color(127, 0, 127));
this->filled_rectangle(0, 0, 10, 10, Color(255, 0, 255));
this->stop_poller();
}

DisplayPage::DisplayPage(display_writer_t writer) : writer_(std::move(writer)) {}
void DisplayPage::show() { this->parent_->show_page(this); }
void DisplayPage::show_next() { this->next_->show(); }
Expand Down
4 changes: 4 additions & 0 deletions esphome/components/display/display.h
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,9 @@ class Display : public PollingComponent {
*/
bool clip(int x, int y);

void test_card();
void show_test_card() { this->show_test_card_ = true; }

protected:
bool clamp_x_(int x, int w, int &min_x, int &max_x);
bool clamp_y_(int y, int h, int &min_y, int &max_y);
Expand Down Expand Up @@ -659,6 +662,7 @@ class Display : public PollingComponent {
std::vector<DisplayOnPageChangeTrigger *> on_page_change_triggers_;
bool auto_clear_enabled_{true};
std::vector<Rect> clipping_rectangle_;
bool show_test_card_{false};
};

class DisplayPage {
Expand Down
14 changes: 9 additions & 5 deletions esphome/components/graph/graph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,22 +177,26 @@ void Graph::draw(Display *buff, uint16_t x_offset, uint16_t y_offset, Color colo
bool b = (trace->get_line_type() & bit) == bit;
if (b) {
int16_t y = (int16_t) roundf((this->height_ - 1) * (1.0 - v)) - thick / 2 + y_offset;
auto draw_pixel_at = [&buff, c, y_offset, this](int16_t x, int16_t y) {
if (y >= y_offset && y < y_offset + this->height_)
buff->draw_pixel_at(x, y, c);
};
if (!continuous || !has_prev || !prev_b || (abs(y - prev_y) <= thick)) {
for (int16_t t = 0; t < thick; t++) {
buff->draw_pixel_at(x, y + t, c);
draw_pixel_at(x, y + t);
}
} else {
int16_t mid_y = (y + prev_y + thick) / 2;
if (y > prev_y) {
for (int16_t t = prev_y + thick; t <= mid_y; t++)
buff->draw_pixel_at(x + 1, t, c);
draw_pixel_at(x + 1, t);
for (int16_t t = mid_y + 1; t < y + thick; t++)
buff->draw_pixel_at(x, t, c);
draw_pixel_at(x, t);
} else {
for (int16_t t = prev_y - 1; t >= mid_y; t--)
buff->draw_pixel_at(x + 1, t, c);
draw_pixel_at(x + 1, t);
for (int16_t t = mid_y - 1; t >= y; t--)
buff->draw_pixel_at(x, t, c);
draw_pixel_at(x, t);
}
}
prev_y = y;
Expand Down
13 changes: 8 additions & 5 deletions esphome/components/hm3301/aqi_calculator.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include "abstract_aqi_calculator.h"
// https://www.airnow.gov/sites/default/files/2020-05/aqi-technical-assistance-document-sept2018.pdf

namespace esphome {
namespace hm3301 {
Expand All @@ -15,14 +16,16 @@ class AQICalculator : public AbstractAQICalculator {
}

protected:
static const int AMOUNT_OF_LEVELS = 6;
static const int AMOUNT_OF_LEVELS = 7;

int index_grid_[AMOUNT_OF_LEVELS][2] = {{0, 51}, {51, 100}, {101, 150}, {151, 200}, {201, 300}, {301, 500}};
int index_grid_[AMOUNT_OF_LEVELS][2] = {{0, 50}, {51, 100}, {101, 150}, {151, 200},
{201, 300}, {301, 400}, {401, 500}};

int pm2_5_calculation_grid_[AMOUNT_OF_LEVELS][2] = {{0, 12}, {13, 35}, {36, 55}, {56, 150}, {151, 250}, {251, 500}};
int pm2_5_calculation_grid_[AMOUNT_OF_LEVELS][2] = {{0, 12}, {13, 35}, {36, 55}, {56, 150},
{151, 250}, {251, 350}, {351, 500}};

int pm10_0_calculation_grid_[AMOUNT_OF_LEVELS][2] = {{0, 54}, {55, 154}, {155, 254},
{255, 354}, {355, 424}, {425, 604}};
int pm10_0_calculation_grid_[AMOUNT_OF_LEVELS][2] = {{0, 54}, {55, 154}, {155, 254}, {255, 354},
{355, 424}, {425, 504}, {505, 604}};

int calculate_index_(uint16_t value, int array[AMOUNT_OF_LEVELS][2]) {
int grid_index = get_grid_index_(value, array);
Expand Down
65 changes: 58 additions & 7 deletions esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,28 +61,57 @@ void I2SAudioMicrophone::start_() {
.bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT,
};

esp_err_t err;

#if SOC_I2S_SUPPORTS_ADC
if (this->adc_) {
config.mode = (i2s_mode_t) (config.mode | I2S_MODE_ADC_BUILT_IN);
i2s_driver_install(this->parent_->get_port(), &config, 0, nullptr);
err = i2s_driver_install(this->parent_->get_port(), &config, 0, nullptr);
if (err != ESP_OK) {
ESP_LOGW(TAG, "Error installing I2S driver: %s", esp_err_to_name(err));
this->status_set_error();
return;
}

err = i2s_set_adc_mode(ADC_UNIT_1, this->adc_channel_);
if (err != ESP_OK) {
ESP_LOGW(TAG, "Error setting ADC mode: %s", esp_err_to_name(err));
this->status_set_error();
return;
}
err = i2s_adc_enable(this->parent_->get_port());
if (err != ESP_OK) {
ESP_LOGW(TAG, "Error enabling ADC: %s", esp_err_to_name(err));
this->status_set_error();
return;
}

i2s_set_adc_mode(ADC_UNIT_1, this->adc_channel_);
i2s_adc_enable(this->parent_->get_port());
} else
#endif
{
if (this->pdm_)
config.mode = (i2s_mode_t) (config.mode | I2S_MODE_PDM);

i2s_driver_install(this->parent_->get_port(), &config, 0, nullptr);
err = i2s_driver_install(this->parent_->get_port(), &config, 0, nullptr);
if (err != ESP_OK) {
ESP_LOGW(TAG, "Error installing I2S driver: %s", esp_err_to_name(err));
this->status_set_error();
return;
}

i2s_pin_config_t pin_config = this->parent_->get_pin_config();
pin_config.data_in_num = this->din_pin_;

i2s_set_pin(this->parent_->get_port(), &pin_config);
err = i2s_set_pin(this->parent_->get_port(), &pin_config);
if (err != ESP_OK) {
ESP_LOGW(TAG, "Error setting I2S pin: %s", esp_err_to_name(err));
this->status_set_error();
return;
}
}
this->state_ = microphone::STATE_RUNNING;
this->high_freq_.start();
this->status_clear_error();
}

void I2SAudioMicrophone::stop() {
Expand All @@ -96,11 +125,33 @@ void I2SAudioMicrophone::stop() {
}

void I2SAudioMicrophone::stop_() {
i2s_stop(this->parent_->get_port());
i2s_driver_uninstall(this->parent_->get_port());
esp_err_t err;
#if SOC_I2S_SUPPORTS_ADC
if (this->adc_) {
err = i2s_adc_disable(this->parent_->get_port());
if (err != ESP_OK) {
ESP_LOGW(TAG, "Error disabling ADC: %s", esp_err_to_name(err));
this->status_set_error();
return;
}
}
#endif
err = i2s_stop(this->parent_->get_port());
if (err != ESP_OK) {
ESP_LOGW(TAG, "Error stopping I2S microphone: %s", esp_err_to_name(err));
this->status_set_error();
return;
}
err = i2s_driver_uninstall(this->parent_->get_port());
if (err != ESP_OK) {
ESP_LOGW(TAG, "Error uninstalling I2S driver: %s", esp_err_to_name(err));
this->status_set_error();
return;
}
this->parent_->unlock();
this->state_ = microphone::STATE_STOPPED;
this->high_freq_.stop();
this->status_clear_error();
}

size_t I2SAudioMicrophone::read(int16_t *buf, size_t len) {
Expand Down
3 changes: 2 additions & 1 deletion esphome/components/light/base_light_effects.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ class AutomationLightEffect : public LightEffect {
struct StrobeLightEffectColor {
LightColorValues color;
uint32_t duration;
uint32_t transition_length;
};

class StrobeLightEffect : public LightEffect {
Expand All @@ -174,7 +175,7 @@ class StrobeLightEffect : public LightEffect {
}
call.set_publish(false);
call.set_save(false);
call.set_transition_length_if_supported(0);
call.set_transition_length_if_supported(this->colors_[this->at_color_].transition_length);
call.perform();
this->last_switch_ = now;
}
Expand Down
4 changes: 4 additions & 0 deletions esphome/components/light/effects.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,9 @@ async def random_effect_to_code(config, effect_id):
cv.Required(
CONF_DURATION
): cv.positive_time_period_milliseconds,
cv.Optional(
CONF_TRANSITION_LENGTH, default="0s"
): cv.positive_time_period_milliseconds,
}
),
cv.has_at_least_one_key(
Expand Down Expand Up @@ -310,6 +313,7 @@ async def strobe_effect_to_code(config, effect_id):
),
),
("duration", color[CONF_DURATION]),
("transition_length", color[CONF_TRANSITION_LENGTH]),
)
)
cg.add(var.set_colors(colors))
Expand Down
Loading

0 comments on commit e27d558

Please sign in to comment.