mirror of https://github.com/esphome/esphome.git
Merge branch 'dev' into ltr303
This commit is contained in:
commit
0e5a829f86
|
@ -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
|
||||
|
||||
|
@ -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="+"
|
||||
|
|
|
@ -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_(); });
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
|
|
@ -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() {
|
||||
|
@ -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) {
|
||||
|
|
|
@ -150,6 +150,7 @@ class AutomationLightEffect : public LightEffect {
|
|||
struct StrobeLightEffectColor {
|
||||
LightColorValues color;
|
||||
uint32_t duration;
|
||||
uint32_t transition_length;
|
||||
};
|
||||
|
||||
class StrobeLightEffect : public LightEffect {
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
@ -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))
|
||||
|
|
|
@ -116,7 +116,7 @@ def do_substitution_pass(config, command_line_substitutions, ignore_missing=Fals
|
|||
if CONF_SUBSTITUTIONS not in config and not command_line_substitutions:
|
||||
return
|
||||
|
||||
substitutions = config[CONF_SUBSTITUTIONS]
|
||||
substitutions = config.get(CONF_SUBSTITUTIONS)
|
||||
if substitutions is None:
|
||||
substitutions = command_line_substitutions
|
||||
elif command_line_substitutions:
|
||||
|
|
|
@ -374,7 +374,10 @@ class LoadValidationStep(ConfigValidationStep):
|
|||
path + [CONF_ID],
|
||||
)
|
||||
continue
|
||||
result.add_str_error("No platform specified! See 'platform' key.", path)
|
||||
result.add_str_error(
|
||||
f"'{self.domain}' requires a 'platform' key but it was not specified.",
|
||||
path,
|
||||
)
|
||||
continue
|
||||
# Remove temp output path and construct new one
|
||||
result.remove_output_path(path, p_domain)
|
||||
|
@ -449,9 +452,28 @@ class MetadataValidationStep(ConfigValidationStep):
|
|||
|
||||
success = True
|
||||
for dependency in self.comp.dependencies:
|
||||
if dependency not in result:
|
||||
dependency_parts = dependency.split(".")
|
||||
if len(dependency_parts) > 2:
|
||||
result.add_str_error(
|
||||
f"Component {self.domain} requires component {dependency}",
|
||||
"Dependencies must be specified as a single component or in component.platform format only",
|
||||
self.path,
|
||||
)
|
||||
return
|
||||
component_dep = dependency_parts[0]
|
||||
platform_dep = dependency_parts[-1]
|
||||
if component_dep not in result:
|
||||
result.add_str_error(
|
||||
f"Component {self.domain} requires component {component_dep}",
|
||||
self.path,
|
||||
)
|
||||
success = False
|
||||
elif component_dep != platform_dep and (
|
||||
not isinstance(platform_list := result.get(component_dep), list)
|
||||
or not any(CONF_PLATFORM in p for p in platform_list)
|
||||
or not any(p[CONF_PLATFORM] == platform_dep for p in platform_list)
|
||||
):
|
||||
result.add_str_error(
|
||||
f"Component {self.domain} requires 'platform: {platform_dep}' in component '{component_dep}'",
|
||||
self.path,
|
||||
)
|
||||
success = False
|
||||
|
@ -756,11 +778,11 @@ def validate_config(
|
|||
CORE.raw_config = config
|
||||
|
||||
# 1. Load substitutions
|
||||
if CONF_SUBSTITUTIONS in config:
|
||||
if CONF_SUBSTITUTIONS in config or command_line_substitutions:
|
||||
from esphome.components import substitutions
|
||||
|
||||
result[CONF_SUBSTITUTIONS] = {
|
||||
**config[CONF_SUBSTITUTIONS],
|
||||
**config.get(CONF_SUBSTITUTIONS, {}),
|
||||
**command_line_substitutions,
|
||||
}
|
||||
result.add_output_path([CONF_SUBSTITUTIONS], CONF_SUBSTITUTIONS)
|
||||
|
|
|
@ -437,7 +437,7 @@ static inline bool is_base64(char c) { return (isalnum(c) || (c == '+') || (c ==
|
|||
|
||||
std::string base64_encode(const std::vector<uint8_t> &buf) { return base64_encode(buf.data(), buf.size()); }
|
||||
|
||||
std::string base64_encode(const char *buf, unsigned int buf_len) {
|
||||
std::string base64_encode(const uint8_t *buf, size_t buf_len) {
|
||||
std::string ret;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
|
|
|
@ -69,7 +69,9 @@ def create_components_graph():
|
|||
sys.exit(1)
|
||||
|
||||
for dependency in comp.dependencies:
|
||||
add_item_to_components_graph(components_graph, dependency, name)
|
||||
add_item_to_components_graph(
|
||||
components_graph, dependency.split(".")[0], name
|
||||
)
|
||||
|
||||
for target_config in TARGET_CONFIGURATIONS:
|
||||
CORE.data[KEY_CORE] = target_config
|
||||
|
@ -87,7 +89,9 @@ def create_components_graph():
|
|||
add_item_to_components_graph(components_graph, platform_name, name)
|
||||
|
||||
for dependency in platform.dependencies:
|
||||
add_item_to_components_graph(components_graph, dependency, name)
|
||||
add_item_to_components_graph(
|
||||
components_graph, dependency.split(".")[0], name
|
||||
)
|
||||
|
||||
for target_config in TARGET_CONFIGURATIONS:
|
||||
CORE.data[KEY_CORE] = target_config
|
||||
|
|
|
@ -37,9 +37,9 @@ start_esphome() {
|
|||
|
||||
# Start esphome process
|
||||
echo "> [$target_component] [$test_name] [$target_platform]"
|
||||
echo "esphome -s component_name $target_component -s test_name $test_name -s target_platform $target_platform $esphome_command $component_test_file"
|
||||
echo "esphome -s component_name $target_component -s component_dir ../../components/$target_component -s test_name $test_name -s target_platform $target_platform $esphome_command $component_test_file"
|
||||
# TODO: Validate escape of Command line substitution value
|
||||
esphome -s component_name $target_component -s test_name $test_name -s target_platform $target_platform $esphome_command $component_test_file
|
||||
esphome -s component_name $target_component -s component_dir ../../components/$target_component -s test_name $test_name -s target_platform $target_platform $esphome_command $component_test_file
|
||||
}
|
||||
|
||||
# Find all test yaml files.
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
time:
|
||||
- platform: sntp
|
||||
id: esptime
|
||||
timezone: Australia/Sydney
|
||||
|
||||
logger:
|
||||
level: VERBOSE
|
||||
logs:
|
||||
lvgl: INFO
|
||||
display: DEBUG
|
||||
sensor: INFO
|
||||
vnc: DEBUG
|
||||
|
||||
host:
|
||||
mac_address: "62:23:45:AF:B3:DD"
|
|
@ -12,8 +12,4 @@ packages:
|
|||
component_under_test: !include
|
||||
file: $component_test_file
|
||||
vars:
|
||||
component_name: $component_name
|
||||
test_name: $test_name
|
||||
target_platform: $target_platform
|
||||
component_test_file: $component_test_file
|
||||
component_dir: "../../components/$component_name"
|
||||
|
|
|
@ -14,8 +14,4 @@ packages:
|
|||
component_under_test: !include
|
||||
file: $component_test_file
|
||||
vars:
|
||||
component_name: $component_name
|
||||
test_name: $test_name
|
||||
target_platform: $target_platform
|
||||
component_test_file: $component_test_file
|
||||
component_dir: "../../components/$component_name"
|
||||
|
|
|
@ -14,8 +14,4 @@ packages:
|
|||
component_under_test: !include
|
||||
file: $component_test_file
|
||||
vars:
|
||||
component_name: $component_name
|
||||
test_name: $test_name
|
||||
target_platform: $target_platform
|
||||
component_test_file: $component_test_file
|
||||
component_dir: "../../components/$component_name"
|
||||
|
|
|
@ -14,8 +14,4 @@ packages:
|
|||
component_under_test: !include
|
||||
file: $component_test_file
|
||||
vars:
|
||||
component_name: $component_name
|
||||
test_name: $test_name
|
||||
target_platform: $target_platform
|
||||
component_test_file: $component_test_file
|
||||
component_dir: "../../components/$component_name"
|
||||
|
|
|
@ -14,8 +14,4 @@ packages:
|
|||
component_under_test: !include
|
||||
file: $component_test_file
|
||||
vars:
|
||||
component_name: $component_name
|
||||
test_name: $test_name
|
||||
target_platform: $target_platform
|
||||
component_test_file: $component_test_file
|
||||
component_dir: "../../components/$component_name"
|
||||
|
|
|
@ -15,8 +15,4 @@ packages:
|
|||
component_under_test: !include
|
||||
file: $component_test_file
|
||||
vars:
|
||||
component_name: $component_name
|
||||
test_name: $test_name
|
||||
target_platform: $target_platform
|
||||
component_test_file: $component_test_file
|
||||
component_dir: "../../components/$component_name"
|
||||
|
|
|
@ -15,8 +15,4 @@ packages:
|
|||
component_under_test: !include
|
||||
file: $component_test_file
|
||||
vars:
|
||||
component_name: $component_name
|
||||
test_name: $test_name
|
||||
target_platform: $target_platform
|
||||
component_test_file: $component_test_file
|
||||
component_dir: "../../components/$component_name"
|
||||
|
|
|
@ -15,8 +15,4 @@ packages:
|
|||
component_under_test: !include
|
||||
file: $component_test_file
|
||||
vars:
|
||||
component_name: $component_name
|
||||
test_name: $test_name
|
||||
target_platform: $target_platform
|
||||
component_test_file: $component_test_file
|
||||
component_dir: "../../components/$component_name"
|
||||
|
|
|
@ -15,8 +15,4 @@ packages:
|
|||
component_under_test: !include
|
||||
file: $component_test_file
|
||||
vars:
|
||||
component_name: $component_name
|
||||
test_name: $test_name
|
||||
target_platform: $target_platform
|
||||
component_test_file: $component_test_file
|
||||
component_dir: "../../components/$component_name"
|
||||
|
|
|
@ -12,8 +12,4 @@ packages:
|
|||
component_under_test: !include
|
||||
file: $component_test_file
|
||||
vars:
|
||||
component_name: $component_name
|
||||
test_name: $test_name
|
||||
target_platform: $target_platform
|
||||
component_test_file: $component_test_file
|
||||
component_dir: "../../components/$component_name"
|
||||
|
|
|
@ -12,8 +12,4 @@ packages:
|
|||
component_under_test: !include
|
||||
file: $component_test_file
|
||||
vars:
|
||||
component_name: $component_name
|
||||
test_name: $test_name
|
||||
target_platform: $target_platform
|
||||
component_test_file: $component_test_file
|
||||
component_dir: "../../components/$component_name"
|
||||
|
|
|
@ -15,8 +15,4 @@ packages:
|
|||
component_under_test: !include
|
||||
file: $component_test_file
|
||||
vars:
|
||||
component_name: $component_name
|
||||
test_name: $test_name
|
||||
target_platform: $target_platform
|
||||
component_test_file: $component_test_file
|
||||
component_dir: "../../components/$component_name"
|
||||
|
|
Loading…
Reference in New Issue