mirror of
https://github.com/esphome/esphome.git
synced 2024-11-27 17:27:59 +01:00
Merge remote-tracking branch 'origin/dev' into nrf52_core
This commit is contained in:
commit
07ec0a7f49
63 changed files with 611 additions and 314 deletions
4
.github/actions/build-image/action.yaml
vendored
4
.github/actions/build-image/action.yaml
vendored
|
@ -46,7 +46,7 @@ runs:
|
|||
|
||||
- name: Build and push to ghcr by digest
|
||||
id: build-ghcr
|
||||
uses: docker/build-push-action@v6.3.0
|
||||
uses: docker/build-push-action@v6.4.1
|
||||
with:
|
||||
context: .
|
||||
file: ./docker/Dockerfile
|
||||
|
@ -69,7 +69,7 @@ runs:
|
|||
|
||||
- name: Build and push to dockerhub by digest
|
||||
id: build-dockerhub
|
||||
uses: docker/build-push-action@v6.3.0
|
||||
uses: docker/build-push-action@v6.4.1
|
||||
with:
|
||||
context: .
|
||||
file: ./docker/Dockerfile
|
||||
|
|
|
@ -214,7 +214,7 @@ esphome/components/lightwaverf/* @max246
|
|||
esphome/components/lilygo_t5_47/touchscreen/* @jesserockz
|
||||
esphome/components/lock/* @esphome/core
|
||||
esphome/components/logger/* @esphome/core
|
||||
esphome/components/ltr390/* @sjtrny
|
||||
esphome/components/ltr390/* @latonita @sjtrny
|
||||
esphome/components/ltr_als_ps/* @latonita
|
||||
esphome/components/matrix_keypad/* @ssieb
|
||||
esphome/components/max31865/* @DAVe3283
|
||||
|
|
|
@ -703,6 +703,7 @@ def command_rename(args, config):
|
|||
os.remove(new_path)
|
||||
return 1
|
||||
|
||||
if CORE.config_path != new_path:
|
||||
os.remove(CORE.config_path)
|
||||
|
||||
print(color(Fore.BOLD_GREEN, "SUCCESS"))
|
||||
|
|
|
@ -8,7 +8,6 @@ from esphome.const import (
|
|||
CONF_PROTOCOL,
|
||||
CONF_VISUAL,
|
||||
)
|
||||
from esphome.core import CORE
|
||||
|
||||
CODEOWNERS = ["@rob-deutsch"]
|
||||
|
||||
|
@ -67,6 +66,11 @@ PROTOCOLS = {
|
|||
"carrier_qlima_2": Protocol.PROTOCOL_QLIMA_2,
|
||||
"samsung_aqv12msan": Protocol.PROTOCOL_SAMSUNG_AQV12MSAN,
|
||||
"zhjg01": Protocol.PROTOCOL_ZHJG01,
|
||||
"airway": Protocol.PROTOCOL_AIRWAY,
|
||||
"bgh_aud": Protocol.PROTOCOL_BGH_AUD,
|
||||
"panasonic_altdke": Protocol.PROTOCOL_PANASONIC_ALTDKE,
|
||||
"vaillantvai8": Protocol.PROTOCOL_VAILLANTVAI8,
|
||||
"r51m": Protocol.PROTOCOL_R51M,
|
||||
}
|
||||
|
||||
CONF_HORIZONTAL_DEFAULT = "horizontal_default"
|
||||
|
@ -122,7 +126,4 @@ def to_code(config):
|
|||
cg.add(var.set_max_temperature(config[CONF_MAX_TEMPERATURE]))
|
||||
cg.add(var.set_min_temperature(config[CONF_MIN_TEMPERATURE]))
|
||||
|
||||
cg.add_library("tonia/HeatpumpIR", "1.0.26")
|
||||
|
||||
if CORE.is_esp8266 or CORE.is_esp32:
|
||||
cg.add_library("crankyoldgit/IRremoteESP8266", "2.8.6")
|
||||
cg.add_library("tonia/HeatpumpIR", "1.0.27")
|
||||
|
|
|
@ -61,6 +61,11 @@ const std::map<Protocol, std::function<HeatpumpIR *()>> PROTOCOL_CONSTRUCTOR_MAP
|
|||
{PROTOCOL_QLIMA_2, []() { return new Qlima2HeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_SAMSUNG_AQV12MSAN, []() { return new SamsungAQV12MSANHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_ZHJG01, []() { return new ZHJG01HeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_AIRWAY, []() { return new AIRWAYHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_BGH_AUD, []() { return new BGHHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_PANASONIC_ALTDKE, []() { return new PanasonicAltDKEHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_VAILLANTVAI8, []() { return new VaillantHeatpumpIR(); }}, // NOLINT
|
||||
{PROTOCOL_R51M, []() { return new R51MHeatpumpIR(); }}, // NOLINT
|
||||
};
|
||||
|
||||
void HeatpumpIRClimate::setup() {
|
||||
|
|
|
@ -61,6 +61,11 @@ enum Protocol {
|
|||
PROTOCOL_QLIMA_2,
|
||||
PROTOCOL_SAMSUNG_AQV12MSAN,
|
||||
PROTOCOL_ZHJG01,
|
||||
PROTOCOL_AIRWAY,
|
||||
PROTOCOL_BGH_AUD,
|
||||
PROTOCOL_PANASONIC_ALTDKE,
|
||||
PROTOCOL_VAILLANTVAI8,
|
||||
PROTOCOL_R51M,
|
||||
};
|
||||
|
||||
// Simple enum to represent horizontal directios
|
||||
|
|
|
@ -25,6 +25,10 @@ CONF_I2S_LRCLK_PIN = "i2s_lrclk_pin"
|
|||
CONF_I2S_AUDIO = "i2s_audio"
|
||||
CONF_I2S_AUDIO_ID = "i2s_audio_id"
|
||||
|
||||
CONF_I2S_MODE = "i2s_mode"
|
||||
CONF_PRIMARY = "primary"
|
||||
CONF_SECONDARY = "secondary"
|
||||
|
||||
i2s_audio_ns = cg.esphome_ns.namespace("i2s_audio")
|
||||
I2SAudioComponent = i2s_audio_ns.class_("I2SAudioComponent", cg.Component)
|
||||
I2SAudioIn = i2s_audio_ns.class_("I2SAudioIn", cg.Parented.template(I2SAudioComponent))
|
||||
|
@ -32,6 +36,12 @@ I2SAudioOut = i2s_audio_ns.class_(
|
|||
"I2SAudioOut", cg.Parented.template(I2SAudioComponent)
|
||||
)
|
||||
|
||||
i2s_mode_t = cg.global_ns.enum("i2s_mode_t")
|
||||
I2S_MODE_OPTIONS = {
|
||||
CONF_PRIMARY: i2s_mode_t.I2S_MODE_MASTER, # NOLINT
|
||||
CONF_SECONDARY: i2s_mode_t.I2S_MODE_SLAVE, # NOLINT
|
||||
}
|
||||
|
||||
# https://github.com/espressif/esp-idf/blob/master/components/soc/{variant}/include/soc/soc_caps.h
|
||||
I2S_PORTS = {
|
||||
VARIANT_ESP32: 2,
|
||||
|
|
|
@ -7,6 +7,9 @@ from esphome.components import microphone, esp32
|
|||
from esphome.components.adc import ESP32_VARIANT_ADC1_PIN_TO_CHANNEL, validate_adc_pin
|
||||
|
||||
from .. import (
|
||||
CONF_I2S_MODE,
|
||||
CONF_PRIMARY,
|
||||
I2S_MODE_OPTIONS,
|
||||
i2s_audio_ns,
|
||||
I2SAudioComponent,
|
||||
I2SAudioIn,
|
||||
|
@ -68,6 +71,9 @@ BASE_SCHEMA = microphone.MICROPHONE_SCHEMA.extend(
|
|||
_validate_bits, cv.enum(BITS_PER_SAMPLE)
|
||||
),
|
||||
cv.Optional(CONF_USE_APLL, default=False): cv.boolean,
|
||||
cv.Optional(CONF_I2S_MODE, default=CONF_PRIMARY): cv.enum(
|
||||
I2S_MODE_OPTIONS, lower=True
|
||||
),
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA)
|
||||
|
||||
|
@ -107,6 +113,7 @@ async def to_code(config):
|
|||
cg.add(var.set_din_pin(config[CONF_I2S_DIN_PIN]))
|
||||
cg.add(var.set_pdm(config[CONF_PDM]))
|
||||
|
||||
cg.add(var.set_i2s_mode(config[CONF_I2S_MODE]))
|
||||
cg.add(var.set_channel(config[CONF_CHANNEL]))
|
||||
cg.add(var.set_sample_rate(config[CONF_SAMPLE_RATE]))
|
||||
cg.add(var.set_bits_per_sample(config[CONF_BITS_PER_SAMPLE]))
|
||||
|
|
|
@ -46,7 +46,7 @@ void I2SAudioMicrophone::start_() {
|
|||
return; // Waiting for another i2s to return lock
|
||||
}
|
||||
i2s_driver_config_t config = {
|
||||
.mode = (i2s_mode_t) (I2S_MODE_MASTER | I2S_MODE_RX),
|
||||
.mode = (i2s_mode_t) (this->i2s_mode_ | I2S_MODE_RX),
|
||||
.sample_rate = this->sample_rate_,
|
||||
.bits_per_sample = this->bits_per_sample_,
|
||||
.channel_format = this->channel_,
|
||||
|
@ -174,8 +174,7 @@ size_t I2SAudioMicrophone::read(int16_t *buf, size_t len) {
|
|||
size_t samples_read = bytes_read / sizeof(int32_t);
|
||||
samples.resize(samples_read);
|
||||
for (size_t i = 0; i < samples_read; i++) {
|
||||
int32_t temp = reinterpret_cast<int32_t *>(buf)[i] >> 14;
|
||||
samples[i] = clamp<int16_t>(temp, INT16_MIN, INT16_MAX);
|
||||
samples[i] = reinterpret_cast<int32_t *>(buf)[i] >> 16;
|
||||
}
|
||||
memcpy(buf, samples.data(), samples_read * sizeof(int16_t));
|
||||
return samples_read * sizeof(int16_t);
|
||||
|
|
|
@ -30,6 +30,8 @@ class I2SAudioMicrophone : public I2SAudioIn, public microphone::Microphone, pub
|
|||
}
|
||||
#endif
|
||||
|
||||
void set_i2s_mode(i2s_mode_t mode) { this->i2s_mode_ = mode; }
|
||||
|
||||
void set_channel(i2s_channel_fmt_t channel) { this->channel_ = channel; }
|
||||
void set_sample_rate(uint32_t sample_rate) { this->sample_rate_ = sample_rate; }
|
||||
void set_bits_per_sample(i2s_bits_per_sample_t bits_per_sample) { this->bits_per_sample_ = bits_per_sample; }
|
||||
|
@ -46,6 +48,7 @@ class I2SAudioMicrophone : public I2SAudioIn, public microphone::Microphone, pub
|
|||
bool adc_{false};
|
||||
#endif
|
||||
bool pdm_{false};
|
||||
i2s_mode_t i2s_mode_{};
|
||||
i2s_channel_fmt_t channel_;
|
||||
uint32_t sample_rate_;
|
||||
i2s_bits_per_sample_t bits_per_sample_;
|
||||
|
|
|
@ -57,7 +57,7 @@ optional<uint8_t> ImprovSerialComponent::read_byte_() {
|
|||
}
|
||||
}
|
||||
break;
|
||||
#ifdef USE_LOGGER_USB_CDC
|
||||
#if defined(USE_LOGGER_USB_CDC) && defined(CONFIG_ESP_CONSOLE_USB_CDC)
|
||||
case logger::UART_SELECTION_USB_CDC:
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
if (esp_usb_console_available_for_read()) {
|
||||
|
@ -99,7 +99,7 @@ void ImprovSerialComponent::write_data_(std::vector<uint8_t> &data) {
|
|||
#endif // !USE_ESP32_VARIANT_ESP32C3 && !USE_ESP32_VARIANT_ESP32S2 && !USE_ESP32_VARIANT_ESP32S3
|
||||
uart_write_bytes(this->uart_num_, data.data(), data.size());
|
||||
break;
|
||||
#ifdef USE_LOGGER_USB_CDC
|
||||
#if defined(USE_LOGGER_USB_CDC) && defined(CONFIG_ESP_CONSOLE_USB_CDC)
|
||||
case logger::UART_SELECTION_USB_CDC: {
|
||||
const char *msg = (char *) data.data();
|
||||
esp_usb_console_write_buf(msg, data.size());
|
||||
|
@ -109,6 +109,7 @@ void ImprovSerialComponent::write_data_(std::vector<uint8_t> &data) {
|
|||
#ifdef USE_LOGGER_USB_SERIAL_JTAG
|
||||
case logger::UART_SELECTION_USB_SERIAL_JTAG:
|
||||
usb_serial_jtag_write_bytes((char *) data.data(), data.size(), 20 / portTICK_PERIOD_MS);
|
||||
delay(10);
|
||||
usb_serial_jtag_ll_txfifo_flush(); // fixes for issue in IDF 4.4.7
|
||||
break;
|
||||
#endif // USE_LOGGER_USB_SERIAL_JTAG
|
||||
|
|
|
@ -19,6 +19,7 @@ static const uint8_t LTR390_MAIN_STATUS = 0x07;
|
|||
|
||||
static const float GAINVALUES[5] = {1.0, 3.0, 6.0, 9.0, 18.0};
|
||||
static const float RESOLUTIONVALUE[6] = {4.0, 2.0, 1.0, 0.5, 0.25, 0.125};
|
||||
static const uint8_t RESOLUTION_BITS[6] = {20, 19, 18, 17, 16, 13};
|
||||
|
||||
// Request fastest measurement rate - will be slowed by device if conversion rate is slower.
|
||||
static const float RESOLUTION_SETTING[6] = {0x00, 0x10, 0x20, 0x30, 0x40, 0x50};
|
||||
|
@ -74,7 +75,7 @@ void LTR390Component::read_als_() {
|
|||
uint32_t als = *val;
|
||||
|
||||
if (this->light_sensor_ != nullptr) {
|
||||
float lux = ((0.6 * als) / (GAINVALUES[this->gain_] * RESOLUTIONVALUE[this->res_])) * this->wfac_;
|
||||
float lux = ((0.6 * als) / (GAINVALUES[this->gain_als_] * RESOLUTIONVALUE[this->res_als_])) * this->wfac_;
|
||||
this->light_sensor_->publish_state(lux);
|
||||
}
|
||||
|
||||
|
@ -90,7 +91,7 @@ void LTR390Component::read_uvs_() {
|
|||
uint32_t uv = *val;
|
||||
|
||||
if (this->uvi_sensor_ != nullptr) {
|
||||
this->uvi_sensor_->publish_state((uv / this->sensitivity_) * this->wfac_);
|
||||
this->uvi_sensor_->publish_state((uv / this->sensitivity_uv_) * this->wfac_);
|
||||
}
|
||||
|
||||
if (this->uv_sensor_ != nullptr) {
|
||||
|
@ -107,9 +108,23 @@ void LTR390Component::read_mode_(int mode_index) {
|
|||
ctrl[LTR390_CTRL_EN] = true;
|
||||
this->reg(LTR390_MAIN_CTRL) = ctrl.to_ulong();
|
||||
|
||||
uint32_t int_time{0};
|
||||
// Set gain, resolution and measurement rate
|
||||
switch (mode) {
|
||||
case LTR390_MODE_ALS:
|
||||
this->reg(LTR390_GAIN) = this->gain_als_;
|
||||
this->reg(LTR390_MEAS_RATE) = RESOLUTION_SETTING[this->res_als_];
|
||||
int_time = ((uint32_t) RESOLUTIONVALUE[this->res_als_]) * 100;
|
||||
break;
|
||||
case LTR390_MODE_UVS:
|
||||
this->reg(LTR390_GAIN) = this->gain_uv_;
|
||||
this->reg(LTR390_MEAS_RATE) = RESOLUTION_SETTING[this->res_uv_];
|
||||
int_time = ((uint32_t) RESOLUTIONVALUE[this->res_uv_]) * 100;
|
||||
break;
|
||||
}
|
||||
|
||||
// After the sensor integration time do the following
|
||||
this->set_timeout(((uint32_t) RESOLUTIONVALUE[this->res_]) * 100 + LTR390_WAKEUP_TIME + LTR390_SETTLE_TIME,
|
||||
[this, mode_index]() {
|
||||
this->set_timeout(int_time + LTR390_WAKEUP_TIME + LTR390_SETTLE_TIME, [this, mode_index]() {
|
||||
// Read from the sensor
|
||||
std::get<1>(this->mode_funcs_[mode_index])();
|
||||
|
||||
|
@ -151,16 +166,10 @@ void LTR390Component::setup() {
|
|||
return;
|
||||
}
|
||||
|
||||
// Set gain
|
||||
this->reg(LTR390_GAIN) = gain_;
|
||||
|
||||
// Set resolution and measurement rate
|
||||
this->reg(LTR390_MEAS_RATE) = RESOLUTION_SETTING[this->res_];
|
||||
|
||||
// Set sensitivity by linearly scaling against known value in the datasheet
|
||||
float gain_scale = GAINVALUES[this->gain_] / GAIN_MAX;
|
||||
float intg_scale = (RESOLUTIONVALUE[this->res_] * 100) / INTG_MAX;
|
||||
this->sensitivity_ = SENSITIVITY_MAX * gain_scale * intg_scale;
|
||||
float gain_scale_uv = GAINVALUES[this->gain_uv_] / GAIN_MAX;
|
||||
float intg_scale_uv = (RESOLUTIONVALUE[this->res_uv_] * 100) / INTG_MAX;
|
||||
this->sensitivity_uv_ = SENSITIVITY_MAX * gain_scale_uv * intg_scale_uv;
|
||||
|
||||
// Set sensor read state
|
||||
this->reading_ = false;
|
||||
|
@ -176,7 +185,13 @@ void LTR390Component::setup() {
|
|||
}
|
||||
}
|
||||
|
||||
void LTR390Component::dump_config() { LOG_I2C_DEVICE(this); }
|
||||
void LTR390Component::dump_config() {
|
||||
LOG_I2C_DEVICE(this);
|
||||
ESP_LOGCONFIG(TAG, " ALS Gain: X%.0f", GAINVALUES[this->gain_als_]);
|
||||
ESP_LOGCONFIG(TAG, " ALS Resolution: %u-bit", RESOLUTION_BITS[this->res_als_]);
|
||||
ESP_LOGCONFIG(TAG, " UV Gain: X%.0f", GAINVALUES[this->gain_uv_]);
|
||||
ESP_LOGCONFIG(TAG, " UV Resolution: %u-bit", RESOLUTION_BITS[this->res_uv_]);
|
||||
}
|
||||
|
||||
void LTR390Component::update() {
|
||||
if (!this->reading_ && !mode_funcs_.empty()) {
|
||||
|
|
|
@ -49,8 +49,10 @@ class LTR390Component : public PollingComponent, public i2c::I2CDevice {
|
|||
void dump_config() override;
|
||||
void update() override;
|
||||
|
||||
void set_gain_value(LTR390GAIN gain) { this->gain_ = gain; }
|
||||
void set_res_value(LTR390RESOLUTION res) { this->res_ = res; }
|
||||
void set_als_gain_value(LTR390GAIN gain) { this->gain_als_ = gain; }
|
||||
void set_uv_gain_value(LTR390GAIN gain) { this->gain_uv_ = gain; }
|
||||
void set_als_res_value(LTR390RESOLUTION res) { this->res_als_ = res; }
|
||||
void set_uv_res_value(LTR390RESOLUTION res) { this->res_uv_ = res; }
|
||||
void set_wfac_value(float wfac) { this->wfac_ = wfac; }
|
||||
|
||||
void set_light_sensor(sensor::Sensor *light_sensor) { this->light_sensor_ = light_sensor; }
|
||||
|
@ -71,9 +73,11 @@ class LTR390Component : public PollingComponent, public i2c::I2CDevice {
|
|||
// a list of modes and corresponding read functions
|
||||
std::vector<std::tuple<LTR390MODE, std::function<void()>>> mode_funcs_;
|
||||
|
||||
LTR390GAIN gain_;
|
||||
LTR390RESOLUTION res_;
|
||||
float sensitivity_;
|
||||
LTR390GAIN gain_als_;
|
||||
LTR390GAIN gain_uv_;
|
||||
LTR390RESOLUTION res_als_;
|
||||
LTR390RESOLUTION res_uv_;
|
||||
float sensitivity_uv_;
|
||||
float wfac_;
|
||||
|
||||
sensor::Sensor *light_sensor_{nullptr};
|
||||
|
|
|
@ -13,7 +13,7 @@ from esphome.const import (
|
|||
UNIT_LUX,
|
||||
)
|
||||
|
||||
CODEOWNERS = ["@sjtrny"]
|
||||
CODEOWNERS = ["@sjtrny", "@latonita"]
|
||||
DEPENDENCIES = ["i2c"]
|
||||
|
||||
ltr390_ns = cg.esphome_ns.namespace("ltr390")
|
||||
|
@ -76,8 +76,24 @@ CONFIG_SCHEMA = cv.All(
|
|||
accuracy_decimals=1,
|
||||
device_class=DEVICE_CLASS_EMPTY,
|
||||
),
|
||||
cv.Optional(CONF_GAIN, default="X18"): cv.enum(GAIN_OPTIONS),
|
||||
cv.Optional(CONF_RESOLUTION, default=20): cv.enum(RES_OPTIONS),
|
||||
cv.Optional(CONF_GAIN, default="X18"): cv.Any(
|
||||
cv.enum(GAIN_OPTIONS),
|
||||
cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_AMBIENT_LIGHT): cv.enum(GAIN_OPTIONS),
|
||||
cv.Required(CONF_UV): cv.enum(GAIN_OPTIONS),
|
||||
}
|
||||
),
|
||||
),
|
||||
cv.Optional(CONF_RESOLUTION, default=20): cv.Any(
|
||||
cv.enum(RES_OPTIONS),
|
||||
cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_AMBIENT_LIGHT): cv.enum(RES_OPTIONS),
|
||||
cv.Required(CONF_UV): cv.enum(RES_OPTIONS),
|
||||
}
|
||||
),
|
||||
),
|
||||
cv.Optional(CONF_WINDOW_CORRECTION_FACTOR, default=1.0): cv.float_range(
|
||||
min=1.0
|
||||
),
|
||||
|
@ -101,11 +117,25 @@ async def to_code(config):
|
|||
await cg.register_component(var, config)
|
||||
await i2c.register_i2c_device(var, config)
|
||||
|
||||
cg.add(var.set_gain_value(config[CONF_GAIN]))
|
||||
cg.add(var.set_res_value(config[CONF_RESOLUTION]))
|
||||
cg.add(var.set_wfac_value(config[CONF_WINDOW_CORRECTION_FACTOR]))
|
||||
|
||||
for key, funcName in TYPES.items():
|
||||
if key in config:
|
||||
sens = await sensor.new_sensor(config[key])
|
||||
cg.add(getattr(var, funcName)(sens))
|
||||
|
||||
gain_value = config[CONF_GAIN]
|
||||
if isinstance(gain_value, dict):
|
||||
cg.add(var.set_als_gain_value(gain_value[CONF_AMBIENT_LIGHT]))
|
||||
cg.add(var.set_uv_gain_value(gain_value[CONF_UV]))
|
||||
else:
|
||||
cg.add(var.set_als_gain_value(gain_value))
|
||||
cg.add(var.set_uv_gain_value(gain_value))
|
||||
|
||||
res_value = config[CONF_RESOLUTION]
|
||||
if isinstance(res_value, dict):
|
||||
cg.add(var.set_als_res_value(res_value[CONF_AMBIENT_LIGHT]))
|
||||
cg.add(var.set_uv_res_value(res_value[CONF_UV]))
|
||||
else:
|
||||
cg.add(var.set_als_res_value(res_value))
|
||||
cg.add(var.set_uv_res_value(res_value))
|
||||
|
|
|
@ -357,7 +357,9 @@ CONFIG_SCHEMA = cv.All(
|
|||
{
|
||||
cv.GenerateID(): cv.declare_id(MicroWakeWord),
|
||||
cv.GenerateID(CONF_MICROPHONE): cv.use_id(microphone.Microphone),
|
||||
cv.Required(CONF_MODELS): cv.ensure_list(MODEL_SCHEMA),
|
||||
cv.Required(CONF_MODELS): cv.ensure_list(
|
||||
cv.maybe_simple_value(MODEL_SCHEMA, key=CONF_MODEL)
|
||||
),
|
||||
cv.Optional(CONF_ON_WAKE_WORD_DETECTED): automation.validate_automation(
|
||||
single=True
|
||||
),
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
#ifdef USE_ESP32_FRAMEWORK_ARDUINO
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
#include "ota_backend_arduino_esp32.h"
|
||||
#include "ota_backend.h"
|
||||
#include "ota_backend_arduino_esp32.h"
|
||||
|
||||
#include <Update.h>
|
||||
|
||||
namespace esphome {
|
||||
namespace ota {
|
||||
|
||||
static const char *const TAG = "ota.arduino_esp32";
|
||||
|
||||
std::unique_ptr<ota::OTABackend> make_ota_backend() { return make_unique<ota::ArduinoESP32OTABackend>(); }
|
||||
|
||||
OTAResponseTypes ArduinoESP32OTABackend::begin(size_t image_size) {
|
||||
|
@ -20,6 +23,9 @@ OTAResponseTypes ArduinoESP32OTABackend::begin(size_t image_size) {
|
|||
uint8_t error = Update.getError();
|
||||
if (error == UPDATE_ERROR_SIZE)
|
||||
return OTA_RESPONSE_ERROR_ESP32_NOT_ENOUGH_SPACE;
|
||||
|
||||
ESP_LOGE(TAG, "Begin error: %d", error);
|
||||
|
||||
return OTA_RESPONSE_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
|
@ -27,16 +33,25 @@ void ArduinoESP32OTABackend::set_update_md5(const char *md5) { Update.setMD5(md5
|
|||
|
||||
OTAResponseTypes ArduinoESP32OTABackend::write(uint8_t *data, size_t len) {
|
||||
size_t written = Update.write(data, len);
|
||||
if (written != len) {
|
||||
return OTA_RESPONSE_ERROR_WRITING_FLASH;
|
||||
}
|
||||
if (written == len) {
|
||||
return OTA_RESPONSE_OK;
|
||||
}
|
||||
|
||||
uint8_t error = Update.getError();
|
||||
ESP_LOGE(TAG, "Write error: %d", error);
|
||||
|
||||
return OTA_RESPONSE_ERROR_WRITING_FLASH;
|
||||
}
|
||||
|
||||
OTAResponseTypes ArduinoESP32OTABackend::end() {
|
||||
if (!Update.end())
|
||||
return OTA_RESPONSE_ERROR_UPDATE_END;
|
||||
if (Update.end()) {
|
||||
return OTA_RESPONSE_OK;
|
||||
}
|
||||
|
||||
uint8_t error = Update.getError();
|
||||
ESP_LOGE(TAG, "End error: %d", error);
|
||||
|
||||
return OTA_RESPONSE_ERROR_UPDATE_END;
|
||||
}
|
||||
|
||||
void ArduinoESP32OTABackend::abort() { Update.abort(); }
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
#ifdef USE_ARDUINO
|
||||
#ifdef USE_ESP8266
|
||||
#include "ota_backend.h"
|
||||
#include "ota_backend_arduino_esp8266.h"
|
||||
#include "ota_backend.h"
|
||||
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/components/esp8266/preferences.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
#include <Updater.h>
|
||||
|
||||
namespace esphome {
|
||||
namespace ota {
|
||||
|
||||
static const char *const TAG = "ota.arduino_esp8266";
|
||||
|
||||
std::unique_ptr<ota::OTABackend> make_ota_backend() { return make_unique<ota::ArduinoESP8266OTABackend>(); }
|
||||
|
||||
OTAResponseTypes ArduinoESP8266OTABackend::begin(size_t image_size) {
|
||||
|
@ -29,6 +32,9 @@ OTAResponseTypes ArduinoESP8266OTABackend::begin(size_t image_size) {
|
|||
return OTA_RESPONSE_ERROR_WRONG_CURRENT_FLASH_CONFIG;
|
||||
if (error == UPDATE_ERROR_SPACE)
|
||||
return OTA_RESPONSE_ERROR_ESP8266_NOT_ENOUGH_SPACE;
|
||||
|
||||
ESP_LOGE(TAG, "Begin error: %d", error);
|
||||
|
||||
return OTA_RESPONSE_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
|
@ -36,16 +42,25 @@ void ArduinoESP8266OTABackend::set_update_md5(const char *md5) { Update.setMD5(m
|
|||
|
||||
OTAResponseTypes ArduinoESP8266OTABackend::write(uint8_t *data, size_t len) {
|
||||
size_t written = Update.write(data, len);
|
||||
if (written != len) {
|
||||
return OTA_RESPONSE_ERROR_WRITING_FLASH;
|
||||
}
|
||||
if (written == len) {
|
||||
return OTA_RESPONSE_OK;
|
||||
}
|
||||
|
||||
uint8_t error = Update.getError();
|
||||
ESP_LOGE(TAG, "Write error: %d", error);
|
||||
|
||||
return OTA_RESPONSE_ERROR_WRITING_FLASH;
|
||||
}
|
||||
|
||||
OTAResponseTypes ArduinoESP8266OTABackend::end() {
|
||||
if (!Update.end())
|
||||
return OTA_RESPONSE_ERROR_UPDATE_END;
|
||||
if (Update.end()) {
|
||||
return OTA_RESPONSE_OK;
|
||||
}
|
||||
|
||||
uint8_t error = Update.getError();
|
||||
ESP_LOGE(TAG, "End error: %d", error);
|
||||
|
||||
return OTA_RESPONSE_ERROR_UPDATE_END;
|
||||
}
|
||||
|
||||
void ArduinoESP8266OTABackend::abort() {
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
#ifdef USE_LIBRETINY
|
||||
#include "ota_backend.h"
|
||||
#include "ota_backend_arduino_libretiny.h"
|
||||
#include "ota_backend.h"
|
||||
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
#include <Update.h>
|
||||
|
||||
namespace esphome {
|
||||
namespace ota {
|
||||
|
||||
static const char *const TAG = "ota.arduino_libretiny";
|
||||
|
||||
std::unique_ptr<ota::OTABackend> make_ota_backend() { return make_unique<ota::ArduinoLibreTinyOTABackend>(); }
|
||||
|
||||
OTAResponseTypes ArduinoLibreTinyOTABackend::begin(size_t image_size) {
|
||||
|
@ -20,6 +23,9 @@ OTAResponseTypes ArduinoLibreTinyOTABackend::begin(size_t image_size) {
|
|||
uint8_t error = Update.getError();
|
||||
if (error == UPDATE_ERROR_SIZE)
|
||||
return OTA_RESPONSE_ERROR_ESP32_NOT_ENOUGH_SPACE;
|
||||
|
||||
ESP_LOGE(TAG, "Begin error: %d", error);
|
||||
|
||||
return OTA_RESPONSE_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
|
@ -27,16 +33,25 @@ void ArduinoLibreTinyOTABackend::set_update_md5(const char *md5) { Update.setMD5
|
|||
|
||||
OTAResponseTypes ArduinoLibreTinyOTABackend::write(uint8_t *data, size_t len) {
|
||||
size_t written = Update.write(data, len);
|
||||
if (written != len) {
|
||||
return OTA_RESPONSE_ERROR_WRITING_FLASH;
|
||||
}
|
||||
if (written == len) {
|
||||
return OTA_RESPONSE_OK;
|
||||
}
|
||||
|
||||
uint8_t error = Update.getError();
|
||||
ESP_LOGE(TAG, "Write error: %d", error);
|
||||
|
||||
return OTA_RESPONSE_ERROR_WRITING_FLASH;
|
||||
}
|
||||
|
||||
OTAResponseTypes ArduinoLibreTinyOTABackend::end() {
|
||||
if (!Update.end())
|
||||
return OTA_RESPONSE_ERROR_UPDATE_END;
|
||||
if (Update.end()) {
|
||||
return OTA_RESPONSE_OK;
|
||||
}
|
||||
|
||||
uint8_t error = Update.getError();
|
||||
ESP_LOGE(TAG, "End error: %d", error);
|
||||
|
||||
return OTA_RESPONSE_ERROR_UPDATE_END;
|
||||
}
|
||||
|
||||
void ArduinoLibreTinyOTABackend::abort() { Update.abort(); }
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
#ifdef USE_ARDUINO
|
||||
#ifdef USE_RP2040
|
||||
#include "ota_backend.h"
|
||||
#include "ota_backend_arduino_rp2040.h"
|
||||
#include "ota_backend.h"
|
||||
|
||||
#include "esphome/components/rp2040/preferences.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
#include <Updater.h>
|
||||
|
||||
namespace esphome {
|
||||
namespace ota {
|
||||
|
||||
static const char *const TAG = "ota.arduino_rp2040";
|
||||
|
||||
std::unique_ptr<ota::OTABackend> make_ota_backend() { return make_unique<ota::ArduinoRP2040OTABackend>(); }
|
||||
|
||||
OTAResponseTypes ArduinoRP2040OTABackend::begin(size_t image_size) {
|
||||
|
@ -29,6 +32,9 @@ OTAResponseTypes ArduinoRP2040OTABackend::begin(size_t image_size) {
|
|||
return OTA_RESPONSE_ERROR_WRONG_CURRENT_FLASH_CONFIG;
|
||||
if (error == UPDATE_ERROR_SPACE)
|
||||
return OTA_RESPONSE_ERROR_RP2040_NOT_ENOUGH_SPACE;
|
||||
|
||||
ESP_LOGE(TAG, "Begin error: %d", error);
|
||||
|
||||
return OTA_RESPONSE_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
|
@ -36,16 +42,25 @@ void ArduinoRP2040OTABackend::set_update_md5(const char *md5) { Update.setMD5(md
|
|||
|
||||
OTAResponseTypes ArduinoRP2040OTABackend::write(uint8_t *data, size_t len) {
|
||||
size_t written = Update.write(data, len);
|
||||
if (written != len) {
|
||||
return OTA_RESPONSE_ERROR_WRITING_FLASH;
|
||||
}
|
||||
if (written == len) {
|
||||
return OTA_RESPONSE_OK;
|
||||
}
|
||||
|
||||
uint8_t error = Update.getError();
|
||||
ESP_LOGE(TAG, "Write error: %d", error);
|
||||
|
||||
return OTA_RESPONSE_ERROR_WRITING_FLASH;
|
||||
}
|
||||
|
||||
OTAResponseTypes ArduinoRP2040OTABackend::end() {
|
||||
if (!Update.end())
|
||||
return OTA_RESPONSE_ERROR_UPDATE_END;
|
||||
if (Update.end()) {
|
||||
return OTA_RESPONSE_OK;
|
||||
}
|
||||
|
||||
uint8_t error = Update.getError();
|
||||
ESP_LOGE(TAG, "End error: %d", error);
|
||||
|
||||
return OTA_RESPONSE_ERROR_UPDATE_END;
|
||||
}
|
||||
|
||||
void ArduinoRP2040OTABackend::abort() {
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
#ifndef __linux__
|
||||
#error This HostUartComponent implementation is only for Linux
|
||||
#if !(defined(__linux__) || defined(__APPLE__))
|
||||
#error This HostUartComponent implementation is not supported on this host OS
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
@ -24,6 +24,9 @@
|
|||
namespace {
|
||||
|
||||
speed_t get_baud(int baud) {
|
||||
#ifdef __APPLE__
|
||||
return baud;
|
||||
#else
|
||||
switch (baud) {
|
||||
case 50:
|
||||
return B50;
|
||||
|
@ -88,6 +91,7 @@ speed_t get_baud(int baud) {
|
|||
default:
|
||||
return B0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -46,29 +46,6 @@ static const char *const HEADER_CORS_REQ_PNA = "Access-Control-Request-Private-N
|
|||
static const char *const HEADER_CORS_ALLOW_PNA = "Access-Control-Allow-Private-Network";
|
||||
#endif
|
||||
|
||||
#if USE_WEBSERVER_VERSION == 1
|
||||
void write_row(AsyncResponseStream *stream, EntityBase *obj, const std::string &klass, const std::string &action,
|
||||
const std::function<void(AsyncResponseStream &stream, EntityBase *obj)> &action_func = nullptr) {
|
||||
stream->print("<tr class=\"");
|
||||
stream->print(klass.c_str());
|
||||
if (obj->is_internal())
|
||||
stream->print(" internal");
|
||||
stream->print("\" id=\"");
|
||||
stream->print(klass.c_str());
|
||||
stream->print("-");
|
||||
stream->print(obj->get_object_id().c_str());
|
||||
stream->print("\"><td>");
|
||||
stream->print(obj->get_name().c_str());
|
||||
stream->print("</td><td></td><td>");
|
||||
stream->print(action.c_str());
|
||||
if (action_func) {
|
||||
action_func(*stream, obj);
|
||||
}
|
||||
stream->print("</td>");
|
||||
stream->print("</tr>");
|
||||
}
|
||||
#endif
|
||||
|
||||
UrlMatch match_url(const std::string &url, bool only_domain = false) {
|
||||
UrlMatch match;
|
||||
match.valid = false;
|
||||
|
@ -102,11 +79,6 @@ WebServer::WebServer(web_server_base::WebServerBase *base)
|
|||
#endif
|
||||
}
|
||||
|
||||
#if USE_WEBSERVER_VERSION == 1
|
||||
void WebServer::set_css_url(const char *css_url) { this->css_url_ = css_url; }
|
||||
void WebServer::set_js_url(const char *js_url) { this->js_url_ = js_url; }
|
||||
#endif
|
||||
|
||||
#ifdef USE_WEBSERVER_CSS_INCLUDE
|
||||
void WebServer::set_css_include(const char *css_include) { this->css_include_ = css_include; }
|
||||
#endif
|
||||
|
@ -181,187 +153,6 @@ void WebServer::handle_index_request(AsyncWebServerRequest *request) {
|
|||
response->addHeader("Content-Encoding", "gzip");
|
||||
request->send(response);
|
||||
}
|
||||
#elif USE_WEBSERVER_VERSION == 1
|
||||
void WebServer::handle_index_request(AsyncWebServerRequest *request) {
|
||||
AsyncResponseStream *stream = request->beginResponseStream("text/html");
|
||||
const std::string &title = App.get_name();
|
||||
stream->print(F("<!DOCTYPE html><html lang=\"en\"><head><meta charset=UTF-8><meta "
|
||||
"name=viewport content=\"width=device-width, initial-scale=1,user-scalable=no\"><title>"));
|
||||
stream->print(title.c_str());
|
||||
stream->print(F("</title>"));
|
||||
#ifdef USE_WEBSERVER_CSS_INCLUDE
|
||||
stream->print(F("<link rel=\"stylesheet\" href=\"/0.css\">"));
|
||||
#endif
|
||||
if (strlen(this->css_url_) > 0) {
|
||||
stream->print(F(R"(<link rel="stylesheet" href=")"));
|
||||
stream->print(this->css_url_);
|
||||
stream->print(F("\">"));
|
||||
}
|
||||
stream->print(F("</head><body>"));
|
||||
stream->print(F("<article class=\"markdown-body\"><h1>"));
|
||||
stream->print(title.c_str());
|
||||
stream->print(F("</h1>"));
|
||||
stream->print(F("<h2>States</h2><table id=\"states\"><thead><tr><th>Name<th>State<th>Actions<tbody>"));
|
||||
|
||||
#ifdef USE_SENSOR
|
||||
for (auto *obj : App.get_sensors()) {
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
write_row(stream, obj, "sensor", "");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_SWITCH
|
||||
for (auto *obj : App.get_switches()) {
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
write_row(stream, obj, "switch", "<button>Toggle</button>");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_BUTTON
|
||||
for (auto *obj : App.get_buttons())
|
||||
write_row(stream, obj, "button", "<button>Press</button>");
|
||||
#endif
|
||||
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
for (auto *obj : App.get_binary_sensors()) {
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
write_row(stream, obj, "binary_sensor", "");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_FAN
|
||||
for (auto *obj : App.get_fans()) {
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
write_row(stream, obj, "fan", "<button>Toggle</button>");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_LIGHT
|
||||
for (auto *obj : App.get_lights()) {
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
write_row(stream, obj, "light", "<button>Toggle</button>");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
for (auto *obj : App.get_text_sensors()) {
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
write_row(stream, obj, "text_sensor", "");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_COVER
|
||||
for (auto *obj : App.get_covers()) {
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
write_row(stream, obj, "cover", "<button>Open</button><button>Close</button>");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_NUMBER
|
||||
for (auto *obj : App.get_numbers()) {
|
||||
if (this->include_internal_ || !obj->is_internal()) {
|
||||
write_row(stream, obj, "number", "", [](AsyncResponseStream &stream, EntityBase *obj) {
|
||||
number::Number *number = (number::Number *) obj;
|
||||
stream.print(R"(<input type="number" min=")");
|
||||
stream.print(number->traits.get_min_value());
|
||||
stream.print(R"(" max=")");
|
||||
stream.print(number->traits.get_max_value());
|
||||
stream.print(R"(" step=")");
|
||||
stream.print(number->traits.get_step());
|
||||
stream.print(R"(" value=")");
|
||||
stream.print(number->state);
|
||||
stream.print(R"("/>)");
|
||||
});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_TEXT
|
||||
for (auto *obj : App.get_texts()) {
|
||||
if (this->include_internal_ || !obj->is_internal()) {
|
||||
write_row(stream, obj, "text", "", [](AsyncResponseStream &stream, EntityBase *obj) {
|
||||
text::Text *text = (text::Text *) obj;
|
||||
auto mode = (int) text->traits.get_mode();
|
||||
stream.print(R"(<input type=")");
|
||||
if (mode == 2) {
|
||||
stream.print(R"(password)");
|
||||
} else { // default
|
||||
stream.print(R"(text)");
|
||||
}
|
||||
stream.print(R"(" minlength=")");
|
||||
stream.print(text->traits.get_min_length());
|
||||
stream.print(R"(" maxlength=")");
|
||||
stream.print(text->traits.get_max_length());
|
||||
stream.print(R"(" pattern=")");
|
||||
stream.print(text->traits.get_pattern().c_str());
|
||||
stream.print(R"(" value=")");
|
||||
stream.print(text->state.c_str());
|
||||
stream.print(R"("/>)");
|
||||
});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_SELECT
|
||||
for (auto *obj : App.get_selects()) {
|
||||
if (this->include_internal_ || !obj->is_internal()) {
|
||||
write_row(stream, obj, "select", "", [](AsyncResponseStream &stream, EntityBase *obj) {
|
||||
select::Select *select = (select::Select *) obj;
|
||||
stream.print("<select>");
|
||||
stream.print("<option></option>");
|
||||
for (auto const &option : select->traits.get_options()) {
|
||||
stream.print("<option>");
|
||||
stream.print(option.c_str());
|
||||
stream.print("</option>");
|
||||
}
|
||||
stream.print("</select>");
|
||||
});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_LOCK
|
||||
for (auto *obj : App.get_locks()) {
|
||||
if (this->include_internal_ || !obj->is_internal()) {
|
||||
write_row(stream, obj, "lock", "", [](AsyncResponseStream &stream, EntityBase *obj) {
|
||||
lock::Lock *lock = (lock::Lock *) obj;
|
||||
stream.print("<button>Lock</button><button>Unlock</button>");
|
||||
if (lock->traits.get_supports_open()) {
|
||||
stream.print("<button>Open</button>");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_CLIMATE
|
||||
for (auto *obj : App.get_climates()) {
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
write_row(stream, obj, "climate", "");
|
||||
}
|
||||
#endif
|
||||
|
||||
stream->print(F("</tbody></table><p>See <a href=\"https://esphome.io/web-api/index.html\">ESPHome Web API</a> for "
|
||||
"REST API documentation.</p>"));
|
||||
if (this->allow_ota_) {
|
||||
stream->print(
|
||||
F("<h2>OTA Update</h2><form method=\"POST\" action=\"/update\" enctype=\"multipart/form-data\"><input "
|
||||
"type=\"file\" name=\"update\"><input type=\"submit\" value=\"Update\"></form>"));
|
||||
}
|
||||
stream->print(F("<h2>Debug Log</h2><pre id=\"log\"></pre>"));
|
||||
#ifdef USE_WEBSERVER_JS_INCLUDE
|
||||
if (this->js_include_ != nullptr) {
|
||||
stream->print(F("<script type=\"module\" src=\"/0.js\"></script>"));
|
||||
}
|
||||
#endif
|
||||
if (strlen(this->js_url_) > 0) {
|
||||
stream->print(F("<script src=\""));
|
||||
stream->print(this->js_url_);
|
||||
stream->print(F("\"></script>"));
|
||||
}
|
||||
stream->print(F("</article></body></html>"));
|
||||
request->send(stream);
|
||||
}
|
||||
#elif USE_WEBSERVER_VERSION >= 2
|
||||
void WebServer::handle_index_request(AsyncWebServerRequest *request) {
|
||||
AsyncWebServerResponse *response =
|
||||
|
|
217
esphome/components/web_server/web_server_v1.cpp
Normal file
217
esphome/components/web_server/web_server_v1.cpp
Normal file
|
@ -0,0 +1,217 @@
|
|||
#include "web_server.h"
|
||||
#include "esphome/core/application.h"
|
||||
|
||||
#if USE_WEBSERVER_VERSION == 1
|
||||
|
||||
namespace esphome {
|
||||
namespace web_server {
|
||||
|
||||
void write_row(AsyncResponseStream *stream, EntityBase *obj, const std::string &klass, const std::string &action,
|
||||
const std::function<void(AsyncResponseStream &stream, EntityBase *obj)> &action_func = nullptr) {
|
||||
stream->print("<tr class=\"");
|
||||
stream->print(klass.c_str());
|
||||
if (obj->is_internal())
|
||||
stream->print(" internal");
|
||||
stream->print("\" id=\"");
|
||||
stream->print(klass.c_str());
|
||||
stream->print("-");
|
||||
stream->print(obj->get_object_id().c_str());
|
||||
stream->print("\"><td>");
|
||||
stream->print(obj->get_name().c_str());
|
||||
stream->print("</td><td></td><td>");
|
||||
stream->print(action.c_str());
|
||||
if (action_func) {
|
||||
action_func(*stream, obj);
|
||||
}
|
||||
stream->print("</td>");
|
||||
stream->print("</tr>");
|
||||
}
|
||||
|
||||
void WebServer::set_css_url(const char *css_url) { this->css_url_ = css_url; }
|
||||
|
||||
void WebServer::set_js_url(const char *js_url) { this->js_url_ = js_url; }
|
||||
|
||||
void WebServer::handle_index_request(AsyncWebServerRequest *request) {
|
||||
AsyncResponseStream *stream = request->beginResponseStream("text/html");
|
||||
const std::string &title = App.get_name();
|
||||
stream->print(F("<!DOCTYPE html><html lang=\"en\"><head><meta charset=UTF-8><meta "
|
||||
"name=viewport content=\"width=device-width, initial-scale=1,user-scalable=no\"><title>"));
|
||||
stream->print(title.c_str());
|
||||
stream->print(F("</title>"));
|
||||
#ifdef USE_WEBSERVER_CSS_INCLUDE
|
||||
stream->print(F("<link rel=\"stylesheet\" href=\"/0.css\">"));
|
||||
#endif
|
||||
if (strlen(this->css_url_) > 0) {
|
||||
stream->print(F(R"(<link rel="stylesheet" href=")"));
|
||||
stream->print(this->css_url_);
|
||||
stream->print(F("\">"));
|
||||
}
|
||||
stream->print(F("</head><body>"));
|
||||
stream->print(F("<article class=\"markdown-body\"><h1>"));
|
||||
stream->print(title.c_str());
|
||||
stream->print(F("</h1>"));
|
||||
stream->print(F("<h2>States</h2><table id=\"states\"><thead><tr><th>Name<th>State<th>Actions<tbody>"));
|
||||
|
||||
#ifdef USE_SENSOR
|
||||
for (auto *obj : App.get_sensors()) {
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
write_row(stream, obj, "sensor", "");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_SWITCH
|
||||
for (auto *obj : App.get_switches()) {
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
write_row(stream, obj, "switch", "<button>Toggle</button>");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_BUTTON
|
||||
for (auto *obj : App.get_buttons())
|
||||
write_row(stream, obj, "button", "<button>Press</button>");
|
||||
#endif
|
||||
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
for (auto *obj : App.get_binary_sensors()) {
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
write_row(stream, obj, "binary_sensor", "");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_FAN
|
||||
for (auto *obj : App.get_fans()) {
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
write_row(stream, obj, "fan", "<button>Toggle</button>");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_LIGHT
|
||||
for (auto *obj : App.get_lights()) {
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
write_row(stream, obj, "light", "<button>Toggle</button>");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
for (auto *obj : App.get_text_sensors()) {
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
write_row(stream, obj, "text_sensor", "");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_COVER
|
||||
for (auto *obj : App.get_covers()) {
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
write_row(stream, obj, "cover", "<button>Open</button><button>Close</button>");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_NUMBER
|
||||
for (auto *obj : App.get_numbers()) {
|
||||
if (this->include_internal_ || !obj->is_internal()) {
|
||||
write_row(stream, obj, "number", "", [](AsyncResponseStream &stream, EntityBase *obj) {
|
||||
number::Number *number = (number::Number *) obj;
|
||||
stream.print(R"(<input type="number" min=")");
|
||||
stream.print(number->traits.get_min_value());
|
||||
stream.print(R"(" max=")");
|
||||
stream.print(number->traits.get_max_value());
|
||||
stream.print(R"(" step=")");
|
||||
stream.print(number->traits.get_step());
|
||||
stream.print(R"(" value=")");
|
||||
stream.print(number->state);
|
||||
stream.print(R"("/>)");
|
||||
});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_TEXT
|
||||
for (auto *obj : App.get_texts()) {
|
||||
if (this->include_internal_ || !obj->is_internal()) {
|
||||
write_row(stream, obj, "text", "", [](AsyncResponseStream &stream, EntityBase *obj) {
|
||||
text::Text *text = (text::Text *) obj;
|
||||
auto mode = (int) text->traits.get_mode();
|
||||
stream.print(R"(<input type=")");
|
||||
if (mode == 2) {
|
||||
stream.print(R"(password)");
|
||||
} else { // default
|
||||
stream.print(R"(text)");
|
||||
}
|
||||
stream.print(R"(" minlength=")");
|
||||
stream.print(text->traits.get_min_length());
|
||||
stream.print(R"(" maxlength=")");
|
||||
stream.print(text->traits.get_max_length());
|
||||
stream.print(R"(" pattern=")");
|
||||
stream.print(text->traits.get_pattern().c_str());
|
||||
stream.print(R"(" value=")");
|
||||
stream.print(text->state.c_str());
|
||||
stream.print(R"("/>)");
|
||||
});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_SELECT
|
||||
for (auto *obj : App.get_selects()) {
|
||||
if (this->include_internal_ || !obj->is_internal()) {
|
||||
write_row(stream, obj, "select", "", [](AsyncResponseStream &stream, EntityBase *obj) {
|
||||
select::Select *select = (select::Select *) obj;
|
||||
stream.print("<select>");
|
||||
stream.print("<option></option>");
|
||||
for (auto const &option : select->traits.get_options()) {
|
||||
stream.print("<option>");
|
||||
stream.print(option.c_str());
|
||||
stream.print("</option>");
|
||||
}
|
||||
stream.print("</select>");
|
||||
});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_LOCK
|
||||
for (auto *obj : App.get_locks()) {
|
||||
if (this->include_internal_ || !obj->is_internal()) {
|
||||
write_row(stream, obj, "lock", "", [](AsyncResponseStream &stream, EntityBase *obj) {
|
||||
lock::Lock *lock = (lock::Lock *) obj;
|
||||
stream.print("<button>Lock</button><button>Unlock</button>");
|
||||
if (lock->traits.get_supports_open()) {
|
||||
stream.print("<button>Open</button>");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_CLIMATE
|
||||
for (auto *obj : App.get_climates()) {
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
write_row(stream, obj, "climate", "");
|
||||
}
|
||||
#endif
|
||||
|
||||
stream->print(F("</tbody></table><p>See <a href=\"https://esphome.io/web-api/index.html\">ESPHome Web API</a> for "
|
||||
"REST API documentation.</p>"));
|
||||
if (this->allow_ota_) {
|
||||
stream->print(
|
||||
F("<h2>OTA Update</h2><form method=\"POST\" action=\"/update\" enctype=\"multipart/form-data\"><input "
|
||||
"type=\"file\" name=\"update\"><input type=\"submit\" value=\"Update\"></form>"));
|
||||
}
|
||||
stream->print(F("<h2>Debug Log</h2><pre id=\"log\"></pre>"));
|
||||
#ifdef USE_WEBSERVER_JS_INCLUDE
|
||||
if (this->js_include_ != nullptr) {
|
||||
stream->print(F("<script type=\"module\" src=\"/0.js\"></script>"));
|
||||
}
|
||||
#endif
|
||||
if (strlen(this->js_url_) > 0) {
|
||||
stream->print(F("<script src=\""));
|
||||
stream->print(this->js_url_);
|
||||
stream->print(F("\"></script>"));
|
||||
}
|
||||
stream->print(F("</article></body></html>"));
|
||||
request->send(stream);
|
||||
}
|
||||
|
||||
} // namespace web_server
|
||||
} // namespace esphome
|
||||
#endif
|
|
@ -82,8 +82,8 @@ bool WiFiComponent::wifi_mode_(optional<bool> sta, optional<bool> ap) {
|
|||
|
||||
// WiFiClass::mode above calls esp_netif_create_default_wifi_sta() and
|
||||
// esp_netif_create_default_wifi_ap(), which creates the interfaces.
|
||||
if (set_sta)
|
||||
s_sta_netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
|
||||
// s_sta_netif handle is set during ESPHOME_EVENT_ID_WIFI_STA_START event
|
||||
|
||||
#ifdef USE_WIFI_AP
|
||||
if (set_ap)
|
||||
s_ap_netif = esp_netif_get_handle_from_ifkey("WIFI_AP_DEF");
|
||||
|
@ -495,6 +495,7 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_
|
|||
case ESPHOME_EVENT_ID_WIFI_STA_START: {
|
||||
ESP_LOGV(TAG, "Event: WiFi STA start");
|
||||
// apply hostname
|
||||
s_sta_netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
|
||||
esp_err_t err = esp_netif_set_hostname(s_sta_netif, App.get_name().c_str());
|
||||
if (err != ERR_OK) {
|
||||
ESP_LOGW(TAG, "esp_netif_set_hostname failed: %s", esp_err_to_name(err));
|
||||
|
|
|
@ -65,7 +65,7 @@ lib_deps =
|
|||
glmnet/Dsmr@0.7 ; dsmr
|
||||
rweather/Crypto@0.4.0 ; dsmr
|
||||
dudanov/MideaUART@1.1.9 ; midea
|
||||
tonia/HeatpumpIR@1.0.26 ; heatpumpir
|
||||
tonia/HeatpumpIR@1.0.27 ; heatpumpir
|
||||
build_flags =
|
||||
${common.build_flags}
|
||||
-DUSE_ARDUINO
|
||||
|
@ -93,8 +93,8 @@ lib_deps =
|
|||
ESP8266HTTPClient ; http_request (Arduino built-in)
|
||||
ESP8266mDNS ; mdns (Arduino built-in)
|
||||
DNSServer ; captive_portal (Arduino built-in)
|
||||
crankyoldgit/IRremoteESP8266@2.8.6 ; heatpumpir
|
||||
droscy/esp_wireguard@0.4.2 ; wireguard
|
||||
|
||||
build_flags =
|
||||
${common:arduino.build_flags}
|
||||
-Wno-nonnull-compare
|
||||
|
@ -123,8 +123,8 @@ lib_deps =
|
|||
ESPmDNS ; mdns (Arduino built-in)
|
||||
DNSServer ; captive_portal (Arduino built-in)
|
||||
esphome/ESP32-audioI2S@2.0.7 ; i2s_audio
|
||||
crankyoldgit/IRremoteESP8266@2.8.6 ; heatpumpir
|
||||
droscy/esp_wireguard@0.4.2 ; wireguard
|
||||
|
||||
build_flags =
|
||||
${common:arduino.build_flags}
|
||||
-DUSE_ESP32
|
||||
|
|
|
@ -105,3 +105,33 @@ disable = [
|
|||
|
||||
[tool.pylint.FORMAT]
|
||||
expected-line-ending-format = "LF"
|
||||
|
||||
[tool.ruff]
|
||||
required-version = ">=0.5.0"
|
||||
|
||||
[tool.ruff.lint]
|
||||
select = [
|
||||
"E", # pycodestyle
|
||||
"F", # pyflakes/autoflake
|
||||
"I", # isort
|
||||
"PL", # pylint
|
||||
"UP", # pyupgrade
|
||||
]
|
||||
|
||||
ignore = [
|
||||
"E501", # line too long
|
||||
"PLR0911", # Too many return statements ({returns} > {max_returns})
|
||||
"PLR0912", # Too many branches ({branches} > {max_branches})
|
||||
"PLR0913", # Too many arguments to function call ({c_args} > {max_args})
|
||||
"PLR0915", # Too many statements ({statements} > {max_statements})
|
||||
"PLR2004", # Magic value used in comparison, consider replacing {value} with a constant variable
|
||||
"PLW2901", # Outer {outer_kind} variable {name} overwritten by inner {inner_kind} target
|
||||
]
|
||||
|
||||
[tool.ruff.lint.isort]
|
||||
force-sort-within-sections = true
|
||||
known-first-party = [
|
||||
"esphome",
|
||||
]
|
||||
combine-as-imports = true
|
||||
split-on-trailing-comma = false
|
||||
|
|
19
tests/components/heatpumpir/test.bk72xx-ard.yaml
Normal file
19
tests/components/heatpumpir/test.bk72xx-ard.yaml
Normal file
|
@ -0,0 +1,19 @@
|
|||
remote_transmitter:
|
||||
pin: 6
|
||||
carrier_duty_percent: 50%
|
||||
|
||||
climate:
|
||||
- platform: heatpumpir
|
||||
protocol: daikin
|
||||
horizontal_default: mleft
|
||||
vertical_default: mup
|
||||
name: HeatpumpIR Climate
|
||||
min_temperature: 18
|
||||
max_temperature: 30
|
||||
- platform: heatpumpir
|
||||
protocol: panasonic_altdke
|
||||
horizontal_default: mright
|
||||
vertical_default: mdown
|
||||
name: HeatpumpIR Climate
|
||||
min_temperature: 18
|
||||
max_temperature: 30
|
|
@ -2,4 +2,7 @@ wifi:
|
|||
ssid: MySSID
|
||||
password: password1
|
||||
|
||||
logger:
|
||||
hardware_uart: UART0
|
||||
|
||||
improv_serial:
|
8
tests/components/improv_serial/common-usb_cdc.yaml
Normal file
8
tests/components/improv_serial/common-usb_cdc.yaml
Normal file
|
@ -0,0 +1,8 @@
|
|||
wifi:
|
||||
ssid: MySSID
|
||||
password: password1
|
||||
|
||||
logger:
|
||||
hardware_uart: USB_CDC
|
||||
|
||||
improv_serial:
|
|
@ -0,0 +1,8 @@
|
|||
wifi:
|
||||
ssid: MySSID
|
||||
password: password1
|
||||
|
||||
logger:
|
||||
hardware_uart: USB_SERIAL_JTAG
|
||||
|
||||
improv_serial:
|
1
tests/components/improv_serial/test-uart0.esp32-ard.yaml
Normal file
1
tests/components/improv_serial/test-uart0.esp32-ard.yaml
Normal file
|
@ -0,0 +1 @@
|
|||
<<: !include common-uart0.yaml
|
|
@ -0,0 +1 @@
|
|||
<<: !include common-uart0.yaml
|
|
@ -0,0 +1 @@
|
|||
<<: !include common-uart0.yaml
|
1
tests/components/improv_serial/test-uart0.esp32-idf.yaml
Normal file
1
tests/components/improv_serial/test-uart0.esp32-idf.yaml
Normal file
|
@ -0,0 +1 @@
|
|||
<<: !include common-uart0.yaml
|
|
@ -0,0 +1 @@
|
|||
<<: !include common-uart0.yaml
|
|
@ -0,0 +1 @@
|
|||
<<: !include common-uart0.yaml
|
|
@ -0,0 +1 @@
|
|||
<<: !include common-uart0.yaml
|
|
@ -0,0 +1 @@
|
|||
<<: !include common-uart0.yaml
|
|
@ -0,0 +1 @@
|
|||
<<: !include common-uart0.yaml
|
|
@ -0,0 +1 @@
|
|||
<<: !include common-uart0.yaml
|
|
@ -0,0 +1 @@
|
|||
<<: !include common-usb_cdc.yaml
|
|
@ -0,0 +1 @@
|
|||
<<: !include common-usb_cdc.yaml
|
|
@ -0,0 +1 @@
|
|||
<<: !include common-usb_cdc.yaml
|
|
@ -0,0 +1 @@
|
|||
<<: !include common-usb_cdc.yaml
|
|
@ -0,0 +1 @@
|
|||
<<: !include common-usb_cdc.yaml
|
|
@ -0,0 +1 @@
|
|||
<<: !include common-usb_serial_jtag.yaml
|
|
@ -0,0 +1 @@
|
|||
<<: !include common-usb_serial_jtag.yaml
|
|
@ -1 +0,0 @@
|
|||
<<: !include common.yaml
|
|
@ -1 +0,0 @@
|
|||
<<: !include common.yaml
|
|
@ -1 +0,0 @@
|
|||
<<: !include common.yaml
|
|
@ -1 +0,0 @@
|
|||
<<: !include common.yaml
|
|
@ -1 +0,0 @@
|
|||
<<: !include common.yaml
|
|
@ -1 +0,0 @@
|
|||
<<: !include common.yaml
|
|
@ -18,3 +18,21 @@ sensor:
|
|||
window_correction_factor: 1.0
|
||||
address: 0x53
|
||||
update_interval: 60s
|
||||
- platform: ltr390
|
||||
uv:
|
||||
name: LTR390 UV
|
||||
uv_index:
|
||||
name: LTR390 UVI
|
||||
light:
|
||||
name: LTR390 Light
|
||||
ambient_light:
|
||||
name: LTR390 ALS
|
||||
gain:
|
||||
ambient_light: X9
|
||||
uv: X3
|
||||
resolution:
|
||||
ambient_light: 18
|
||||
uv: 13
|
||||
window_correction_factor: 1.0
|
||||
address: 0x53
|
||||
update_interval: 60s
|
||||
|
|
|
@ -13,7 +13,9 @@ sensor:
|
|||
name: LTR390 Light
|
||||
ambient_light:
|
||||
name: LTR390 ALS
|
||||
gain: X3
|
||||
gain:
|
||||
ambient_light: X9
|
||||
uv: X3
|
||||
resolution: 18
|
||||
window_correction_factor: 1.0
|
||||
address: 0x53
|
||||
|
|
|
@ -2,6 +2,37 @@ wifi:
|
|||
ssid: MySSID
|
||||
password: password1
|
||||
|
||||
web_server:
|
||||
port: 8080
|
||||
version: 2
|
||||
binary_sensor:
|
||||
cover:
|
||||
fan:
|
||||
light:
|
||||
sensor:
|
||||
switch:
|
||||
button:
|
||||
text_sensor:
|
||||
climate:
|
||||
number:
|
||||
text:
|
||||
select:
|
||||
lock:
|
||||
valve:
|
||||
alarm_control_panel:
|
||||
api:
|
||||
time:
|
||||
- platform: homeassistant
|
||||
id: homeassistant_time
|
||||
datetime:
|
||||
- platform: template
|
||||
id: my_datetime_date
|
||||
type: date
|
||||
optimistic: yes
|
||||
- platform: template
|
||||
id: my_datetime_time
|
||||
type: time
|
||||
optimistic: yes
|
||||
- platform: template
|
||||
id: my_datetime
|
||||
type: datetime
|
||||
optimistic: yes
|
||||
event:
|
||||
update:
|
||||
|
|
5
tests/components/web_server/common_v1.yaml
Normal file
5
tests/components/web_server/common_v1.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<<: !include common.yaml
|
||||
|
||||
web_server:
|
||||
port: 8080
|
||||
version: 1
|
5
tests/components/web_server/common_v2.yaml
Normal file
5
tests/components/web_server/common_v2.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<<: !include common.yaml
|
||||
|
||||
web_server:
|
||||
port: 8080
|
||||
version: 2
|
|
@ -1 +1 @@
|
|||
<<: !include common.yaml
|
||||
<<: !include common_v2.yaml
|
||||
|
|
|
@ -1 +1 @@
|
|||
<<: !include common.yaml
|
||||
<<: !include common_v2.yaml
|
||||
|
|
|
@ -1 +1 @@
|
|||
<<: !include common.yaml
|
||||
<<: !include common_v2.yaml
|
||||
|
|
|
@ -1 +1 @@
|
|||
<<: !include common.yaml
|
||||
<<: !include common_v2.yaml
|
||||
|
|
|
@ -1 +1 @@
|
|||
<<: !include common.yaml
|
||||
<<: !include common_v2.yaml
|
||||
|
|
1
tests/components/web_server/test_v1.esp32-ard.yaml
Normal file
1
tests/components/web_server/test_v1.esp32-ard.yaml
Normal file
|
@ -0,0 +1 @@
|
|||
<<: !include common_v1.yaml
|
Loading…
Reference in a new issue