Compare commits

..
462 changed files with 3995 additions and 6906 deletions

No files matched your search

+1 -4
View File
@@ -395,8 +395,6 @@ jobs:
- common
- determine-jobs
if: needs.determine-jobs.outputs.integration-tests == 'true'
# A hung test is failed by pytest's --timeout below; this bounds the rest
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
@@ -473,8 +471,7 @@ jobs:
exit 1
fi
echo "Bucket ${{ matrix.bucket.name }}: running ${#test_files[@]} integration tests"
# A hung test fails after 30 min: the 15 min shared build lock wait plus a cold compile
pytest -vv --no-cov --tb=native --durations=30 -n auto --dist worksteal --timeout=1800 \
pytest -vv --no-cov --tb=native --durations=30 -n auto --dist worksteal \
--junitxml=junit-integration.xml "${test_files[@]}"
- name: Upload test artifacts
# Tests that compare rendered output write the image they actually got here, so a
+19 -10
View File
@@ -225,15 +225,6 @@ file does, and it is the authority when they disagree. The most useful starting
stays inside the `#ifdef`.
* **Failures after `setup()`:** `mark_failed()` is for `setup()` only. A runtime read or write failure
sets `status_set_warning()` and the next success clears it; writes skip work when `is_failed()`.
* **`dump_config()` already prints the failure reason:** for a failed component, core prints
`<component> is marked FAILED: <reason>` right after the component's `dump_config()`, using the reason
passed to `mark_failed()`. So `dump_config()` never checks `is_failed()` to log a failure, and no
`error_code_` member exists only to pick that message. Pass the reason where setup fails instead:
`this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL))` for a failed bus transfer, a short specific reason
otherwise (`LOG_STR("Wrong chip ID")`). Core also logs it at that moment, so no `ESP_LOGE` repeats it
before `mark_failed()`; keep a separate line only when it prints a value read at run time, such as the
chip ID that did not match. Only the first reason is kept, so do not call `status_set_error()` before
`mark_failed()` and do not mark the component failed again after a helper already did.
* **Fixed platform facts compile to nothing:** gate on `#ifdef USE_ESP8266` and friends, not on a
runtime check of something the build already knows.
* **Logging string literals:** wrap literals passed as `%s` arguments in `LOG_STR_LITERAL()` so they
@@ -404,7 +395,7 @@ file does, and it is the authority when they disagree. The most useful starting
* **Triggers -- Callback method (preferred):**
Use `build_callback_automation()` for simple triggers. This eliminates the need for a C++ Trigger class by using a lightweight pointer-sized forwarder struct registered directly as a callback. No `CONF_TRIGGER_ID` in the schema.
Use `build_callback_automation()` for simple triggers. The automation is registered directly as a callback on the parent, so there is no C++ Trigger class and nothing is allocated. No `CONF_TRIGGER_ID` in the schema.
**Python:**
```python
@@ -457,6 +448,24 @@ file does, and it is the authority when they disagree. The most useful starting
forward=[cg.StringRef(parent.option_at(index)), index],
)
```
**Choosing the filter:** a filter that many automations share, such as entering one value of a state enum,
is a small forwarder struct templated on that value. Every automation for that value then shares one
function and passes only its `Automation *`. `when` generates a separate lambda per automation, which cost
16 to 64 bytes more flash when lock, media_player, alarm_control_panel and fusb302b were tried with it.
```cpp
template<LockState State> struct LockStateForwarder {
Automation<> *automation;
void operator()(LockState state) const {
if (state == State)
this->automation->trigger();
}
};
```
Use `when` for a test that is not a fixed value shared across automations, e.g. one that reads the parent:
`when="{parent}->is_fully_open()"` (valve). Only a trigger that must remember something between calls
(the last position, a click count) keeps a Trigger class.
`build_parent_callback_automation`, `build_trigger_callback`, `build_callback_automations` and
`build_trigger_automations` cover the other shapes; see their docstrings in `esphome/automation.py`.
-2
View File
@@ -252,7 +252,6 @@ esphome/components/haier/text_sensor/* @paveldn
esphome/components/haier_tundra/* @fauxpark
esphome/components/haier_tundra/button/* @fauxpark
esphome/components/haier_tundra/switch/* @fauxpark
esphome/components/haier_water_heater/* @TheLexus
esphome/components/havells_solar/* @sourabhjaiswal
esphome/components/hbridge/fan/* @WeekendWarrior
esphome/components/hbridge/light/* @DotNetDann
@@ -391,7 +390,6 @@ esphome/components/micro_wake_word/* @jesserockz @kahrendt
esphome/components/micronova/* @edenhaus @jorre05
esphome/components/microphone/* @jesserockz @kahrendt
esphome/components/mics_4514/* @jesserockz
esphome/components/mics_5524/* @nliaudat
esphome/components/midea/* @dudanov
esphome/components/midea_ir/* @dudanov
esphome/components/midea_portasplit/* @Fexiven
+1 -1
View File
@@ -22,7 +22,7 @@ RUN \
-r /requirements.txt
# Install the ESPHome Device Builder dashboard.
RUN uv pip install --no-cache-dir esphome-device-builder==1.24.0
RUN uv pip install --no-cache-dir esphome-device-builder==1.23.1
RUN \
platformio settings set enable_telemetry No \
+3 -11
View File
@@ -426,20 +426,12 @@ def _apply_function(
) -> MockObj:
"""Emit the generated function and declare ``id_`` as the ``ApplyAction`` or
``ApplyCondition`` templated on it, so ``play()`` calls it directly."""
fn = apply_static_function(id_, return_type, lambda_args, statements)
fn = cg.static_function(
f"esphome__{id_.id}__fn", return_type, lambda_args, statements
)
return cg.new_Pvariable(id_, cg.TemplateArguments(fn, *template_arg))
def apply_static_function(
id_: ID,
return_type: SafeExpType,
params: TemplateArgsType,
statements: list[str],
) -> MockObj:
"""Emit the static function generated for ``id_`` and return an expression naming it."""
return cg.static_function(f"esphome__{id_.id}__fn", return_type, params, statements)
async def _render_values(
name: str,
target: str,
+5 -2
View File
@@ -11,7 +11,7 @@ static const uint8_t ADS1115_REGISTER_CONFIG = 0x01;
void ADS1115Component::setup() {
uint16_t value;
if (!this->read_byte_16(ADS1115_REGISTER_CONVERSION, &value)) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->mark_failed();
return;
}
@@ -58,7 +58,7 @@ void ADS1115Component::setup() {
config |= 0b0000000000000011;
if (!this->write_byte_16(ADS1115_REGISTER_CONFIG, config)) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->mark_failed();
return;
}
this->prev_config_ = config;
@@ -66,6 +66,9 @@ void ADS1115Component::setup() {
void ADS1115Component::dump_config() {
ESP_LOGCONFIG(TAG, "ADS1115:");
LOG_I2C_DEVICE(this);
if (this->is_failed()) {
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
}
}
float ADS1115Component::request_measurement(ADS1115Multiplexer multiplexer, ADS1115Gain gain,
ADS1115Resolution resolution, ADS1115Samplerate samplerate) {
+11 -4
View File
@@ -52,7 +52,8 @@ void AHT10Component::setup() {
break;
}
if (error_code != i2c::ERROR_OK) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
this->mark_failed();
return;
}
uint8_t cal_attempts = 0;
@@ -60,17 +61,20 @@ void AHT10Component::setup() {
while (data & AHT10_STATUS_BUSY) {
delay(AHT10_DEFAULT_DELAY);
if (this->read(&data, 1) != i2c::ERROR_OK) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
this->mark_failed();
return;
}
++cal_attempts;
if (cal_attempts > AHT10_INIT_ATTEMPTS) {
this->mark_failed(LOG_STR("Initialization timed out"));
ESP_LOGE(TAG, "Initialization timed out");
this->mark_failed();
return;
}
}
if ((data & 0x68) != 0x08) { // Bit[6:5] = 0b00, NORMAL mode and Bit[3] = 0b1, CALIBRATED
this->mark_failed(LOG_STR("Initialization failed"));
ESP_LOGE(TAG, "Initialization failed");
this->mark_failed();
return;
}
}
@@ -148,6 +152,9 @@ void AHT10Component::update() {
void AHT10Component::dump_config() {
ESP_LOGCONFIG(TAG, "AHT10:");
LOG_I2C_DEVICE(this);
if (this->is_failed()) {
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
}
LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
LOG_SENSOR(" ", "Humidity", this->humidity_sensor_);
}
+6 -1
View File
@@ -10,7 +10,8 @@ ESPHOME_LOG_TAG(TAG, "aic3204");
#define ERROR_CHECK(err, msg) \
if (!(err)) { \
this->mark_failed(LOG_STR(msg)); \
ESP_LOGE(TAG, msg); \
this->mark_failed(); \
return; \
}
@@ -107,6 +108,10 @@ void AIC3204::setup() {
void AIC3204::dump_config() {
ESP_LOGCONFIG(TAG, "AIC3204:");
LOG_I2C_DEVICE(this);
if (this->is_failed()) {
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
}
}
bool AIC3204::set_mute_off() {
+22 -6
View File
@@ -42,18 +42,21 @@ bool AM2315C::reset_register_(uint8_t reg) {
data[2] = 0;
ESP_LOGD(TAG, "Reset register: 0x%02x", reg);
if (this->write(data, 3) != i2c::ERROR_OK) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
ESP_LOGE(TAG, "Write failed!");
this->mark_failed();
return false;
}
delay(5);
if (this->read(data, 3) != i2c::ERROR_OK) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
ESP_LOGE(TAG, "Read failed!");
this->mark_failed();
return false;
}
delay(10);
data[0] = 0xB0 | reg;
if (this->write(data, 3) != i2c::ERROR_OK) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
ESP_LOGE(TAG, "Write failed!");
this->mark_failed();
return false;
}
delay(5);
@@ -73,7 +76,8 @@ void AM2315C::setup() {
// get status
uint8_t status = 0;
if (this->read(&status, 1) != i2c::ERROR_OK) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
ESP_LOGE(TAG, "Read failed!");
this->mark_failed();
return;
}
@@ -82,9 +86,18 @@ void AM2315C::setup() {
// never required during testing
if ((status & 0x18) != 0x18) {
ESP_LOGD(TAG, "Resetting AM2315C registers");
// reset_register_() marks the component failed with its own reason
if (!this->reset_register_(0x1B) || !this->reset_register_(0x1C) || !this->reset_register_(0x1E))
if (!this->reset_register_(0x1B)) {
this->mark_failed();
return;
}
if (!this->reset_register_(0x1C)) {
this->mark_failed();
return;
}
if (!this->reset_register_(0x1E)) {
this->mark_failed();
return;
}
}
}
@@ -155,6 +168,9 @@ void AM2315C::update() {
void AM2315C::dump_config() {
ESP_LOGCONFIG(TAG, "AM2315C:");
LOG_I2C_DEVICE(this);
if (this->is_failed()) {
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
}
LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
LOG_SENSOR(" ", "Humidity", this->humidity_sensor_);
}
+4 -1
View File
@@ -37,13 +37,16 @@ void AM2320Component::setup() {
data[0] = 0;
data[1] = 4;
if (!this->read_data_(data)) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->mark_failed();
return;
}
}
void AM2320Component::dump_config() {
ESP_LOGD(TAG, "AM2320:");
LOG_I2C_DEVICE(this);
if (this->is_failed()) {
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
}
LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
LOG_SENSOR(" ", "Humidity", this->humidity_sensor_);
}
+2 -2
View File
@@ -5,8 +5,8 @@
namespace esphome::animation {
Animation::Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count,
image::ImageType type, image::Transparency transparent, bool big_endian)
: Image(data_start, width, height, type, transparent, big_endian),
image::ImageType type, image::Transparency transparent)
: Image(data_start, width, height, type, transparent),
animation_data_start_(data_start),
current_frame_(0),
animation_frame_count_(animation_frame_count),
+1 -1
View File
@@ -6,7 +6,7 @@ namespace esphome::animation {
class Animation final : public image::Image {
public:
Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count, image::ImageType type,
image::Transparency transparent, bool big_endian = false);
image::Transparency transparent);
uint32_t get_animation_frame_count() const;
int get_current_frame() const;
+1 -2
View File
@@ -1,6 +1,6 @@
from esphome import automation
import esphome.codegen as cg
from esphome.components.const import CONF_BYTE_ORDER, CONF_LOOP
from esphome.components.const import CONF_LOOP
from esphome.components.file import image as file_image
from esphome.components.file.image import image_schema, write_image
from esphome.components.image import Image_, validate_settings
@@ -90,7 +90,6 @@ async def setup_animation(config: ConfigType) -> None:
frame_count,
image_type,
trans_value,
config.get(CONF_BYTE_ORDER) == "BIG_ENDIAN",
)
if loop_config := config.get(CONF_LOOP):
start = loop_config[CONF_START_FRAME]
+21 -4
View File
@@ -34,7 +34,8 @@ enum { // APDS9306 registers
#define APDS9306_ERROR_CHECK(func, error) \
if (!(func)) { \
this->mark_failed(LOG_STR(error)); \
ESP_LOGE(TAG, error); \
this->mark_failed(); \
return; \
}
#define APDS9306_WARNING_CHECK(func, warning) \
@@ -47,19 +48,21 @@ enum { // APDS9306 registers
ESP_LOGV(TAG, "Writing 0x%02x to 0x%02x", value, reg); \
if (!this->write_byte(reg, value)) { \
ESP_LOGE(TAG, "Failed writing 0x%02x to 0x%02x", value, reg); \
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); \
this->mark_failed(); \
return; \
}
void APDS9306::setup() {
uint8_t id;
if (!this->read_byte(APDS9306_PART_ID, &id)) { // Part ID register
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->error_code_ = COMMUNICATION_FAILED;
this->mark_failed();
return;
}
if (id != 0xB1 && id != 0xB3) { // 0xB1 for APDS9306 0xB3 for APDS9306-065
this->mark_failed(LOG_STR("APDS9306 has invalid id"));
this->error_code_ = WRONG_ID;
this->mark_failed();
return;
}
@@ -86,6 +89,20 @@ void APDS9306::dump_config() {
LOG_SENSOR("", "APDS9306", this);
LOG_I2C_DEVICE(this);
if (this->is_failed()) {
switch (this->error_code_) {
case COMMUNICATION_FAILED:
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
break;
case WRONG_ID:
ESP_LOGE(TAG, "APDS9306 has invalid id!");
break;
default:
ESP_LOGE(TAG, "Setting up APDS9306 registers failed!");
break;
}
}
ESP_LOGCONFIG(TAG,
" Gain: %u\n"
" Measurement rate: %u\n"
+6
View File
@@ -50,6 +50,12 @@ class APDS9306 final : public sensor::Sensor, public PollingComponent, public i2
void set_ambient_light_gain(AmbientLightGain gain) { this->gain_ = gain; }
protected:
enum ErrorCode {
NONE = 0,
COMMUNICATION_FAILED,
WRONG_ID,
} error_code_{NONE};
MeasurementBitWidth bit_width_;
MeasurementRate measurement_rate_;
AmbientLightGain gain_;
+19 -3
View File
@@ -8,7 +8,7 @@ ESPHOME_LOG_TAG(TAG, "apds9960");
#define APDS9960_ERROR_CHECK(func) \
if (!(func)) { \
this->mark_failed(LOG_STR("Setting up APDS9960 registers failed")); \
this->mark_failed(); \
return; \
}
#define APDS9960_WRITE_BYTE(reg, value) APDS9960_ERROR_CHECK(this->write_byte(reg, value));
@@ -16,12 +16,14 @@ ESPHOME_LOG_TAG(TAG, "apds9960");
void APDS9960::setup() {
uint8_t id;
if (!this->read_byte(0x92, &id)) { // ID register
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->error_code_ = COMMUNICATION_FAILED;
this->mark_failed();
return;
}
if (id != 0xAB && id != 0x9C && id != 0xA8 && id != 0x9E) { // APDS9960 all should have one of these IDs
this->mark_failed(LOG_STR("APDS9960 has invalid id"));
this->error_code_ = WRONG_ID;
this->mark_failed();
return;
}
@@ -133,6 +135,20 @@ void APDS9960::dump_config() {
LOG_SENSOR(" ", "Clear channel", this->clear_sensor_);
LOG_SENSOR(" ", "Proximity", this->proximity_sensor_);
#endif
if (this->is_failed()) {
switch (this->error_code_) {
case COMMUNICATION_FAILED:
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
break;
case WRONG_ID:
ESP_LOGE(TAG, "APDS9960 has invalid id!");
break;
default:
ESP_LOGE(TAG, "Setting up APDS9960 registers failed!");
break;
}
}
}
#define APDS9960_WARNING_CHECK(func, warning) \
+5
View File
@@ -58,6 +58,11 @@ class APDS9960 final : public PollingComponent, public i2c::I2CDevice {
uint8_t gesture_gain_;
uint8_t gesture_wait_time_;
enum ErrorCode {
NONE = 0,
COMMUNICATION_FAILED,
WRONG_ID,
} error_code_{NONE};
bool gesture_up_started_{false};
bool gesture_down_started_{false};
bool gesture_left_started_{false};
+5 -3
View File
@@ -23,7 +23,7 @@ static const uint8_t REGISTER_MAGNITUDE = 0x1B; // 16 bytes / R
void AS5600Component::setup() {
if (!this->read_byte(REGISTER_STATUS).has_value()) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->mark_failed();
return;
}
@@ -54,7 +54,7 @@ void AS5600Component::setup() {
// write config to config register
if (!this->write_byte_16(REGISTER_CONF, config)) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->mark_failed();
return;
}
@@ -87,8 +87,10 @@ void AS5600Component::dump_config() {
ESP_LOGCONFIG(TAG, "AS5600:");
LOG_I2C_DEVICE(this);
if (this->is_failed())
if (this->is_failed()) {
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
return;
}
ESP_LOGCONFIG(TAG,
" Watchdog: %d\n"
+6 -2
View File
@@ -14,13 +14,14 @@ void AS7341Component::setup() {
this->read_byte(AS7341_ID, &id);
ESP_LOGCONFIG(TAG, " Read ID: 0x%X", id);
if ((id & 0xFC) != (AS7341_CHIP_ID << 2)) {
this->mark_failed(LOG_STR("Wrong chip ID"));
this->mark_failed();
return;
}
// Power on (enter IDLE state)
if (!this->enable_power(true)) {
this->mark_failed(LOG_STR("Power on failed"));
ESP_LOGE(TAG, " Power on failed!");
this->mark_failed();
return;
}
@@ -34,6 +35,9 @@ void AS7341Component::setup() {
void AS7341Component::dump_config() {
ESP_LOGCONFIG(TAG, "AS7341:");
LOG_I2C_DEVICE(this);
if (this->is_failed()) {
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
}
LOG_UPDATE_INTERVAL(this);
ESP_LOGCONFIG(TAG,
" Gain: %u\n"
+3
View File
@@ -355,6 +355,9 @@ void AS734XComponent::dump_config() {
#ifdef USE_AS734X_RGB
LOG_TEXT_SENSOR(" ", "RGB hex", this->rgb_hex_sensor_);
#endif
if (this->is_failed()) {
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
}
}
void AS734XComponent::enable_led(bool enable) {
+1 -1
View File
@@ -93,7 +93,7 @@ def _megahertz(value: float) -> int:
def _microamps(value: float) -> int:
return round(value * 1000000)
return int(value * 1000000)
RADAR_SETTINGS_SCHEMA = cv.Schema(
+7 -6
View File
@@ -4,13 +4,14 @@ import esphome.config_validation as cv
from esphome.const import DEVICE_CLASS_SWITCH, ICON_WIFI
from esphome.types import ConfigType
from .. import CONF_AT581X_ID, AT581XComponent
from .. import CONF_AT581X_ID, AT581XComponent, at581x_ns
DEPENDENCIES = ["at581x"]
RFSwitch = at581x_ns.class_("RFSwitch", switch.Switch)
CONFIG_SCHEMA = switch.switch_schema(
switch.ApplySwitch,
RFSwitch,
device_class=DEVICE_CLASS_SWITCH,
icon=ICON_WIFI,
).extend(
@@ -23,7 +24,7 @@ CONFIG_SCHEMA = switch.switch_schema(
async def to_code(config: ConfigType) -> None:
hub = await cg.get_variable(config[CONF_AT581X_ID])
await switch.sub_switches(config, parent=hub).create(
config, hub.set_rf_power_switch, apply="set_rf_mode(state)", publish="before"
)
at581x_component = await cg.get_variable(config[CONF_AT581X_ID])
s = await switch.new_switch(config)
await cg.register_parented(s, config[CONF_AT581X_ID])
cg.add(at581x_component.set_rf_power_switch(s))
@@ -0,0 +1,10 @@
#include "rf_switch.h"
namespace esphome::at581x {
void RFSwitch::write_state(bool state) {
this->publish_state(state);
this->parent_->set_rf_mode(state);
}
} // namespace esphome::at581x
@@ -0,0 +1,13 @@
#pragma once
#include "esphome/components/switch/switch.h"
#include "../at581x.h"
namespace esphome::at581x {
class RFSwitch final : public switch_::Switch, public Parented<AT581XComponent> {
protected:
void write_state(bool state) override;
};
} // namespace esphome::at581x
+6 -3
View File
@@ -52,7 +52,7 @@ void ATM90E26Component::setup() {
uint16_t read = this->read16_(ATM90E26_REGISTER_LASTDATA);
if (read != 0x0030) {
ESP_LOGW(TAG, "Could not initialize ATM90E26 IC, check SPI settings: %d", read);
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->mark_failed();
return;
}
// TODO: 100 * <nominal voltage, e.g. 230> * sqrt(2) * <fraction of nominal, e.g. 0.9> / (4 * gain_voltage/32768)
@@ -120,18 +120,21 @@ void ATM90E26Component::setup() {
ESP_LOGW(TAG, "Could not initialize ATM90E26 IC: CS1 was incorrect, expected: 0x%04X",
this->read16_(ATM90E26_REGISTER_CS1));
this->mark_failed(LOG_STR("Checksum mismatch"));
this->mark_failed();
}
if (sys_status & 0x3000) { // Checksum 2 Error
ESP_LOGW(TAG, "Could not initialize ATM90E26 IC: CS2 was incorrect, expected: 0x%04X",
this->read16_(ATM90E26_REGISTER_CS2));
this->mark_failed(LOG_STR("Checksum mismatch"));
this->mark_failed();
}
}
void ATM90E26Component::dump_config() {
ESP_LOGCONFIG("", "ATM90E26:");
LOG_PIN(" CS Pin: ", this->cs_);
if (this->is_failed()) {
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
}
LOG_UPDATE_INTERVAL(this);
LOG_SENSOR(" ", "Voltage A", this->voltage_sensor_);
LOG_SENSOR(" ", "Current A", this->current_sensor_);
+4 -1
View File
@@ -168,7 +168,7 @@ void ATM90E32Component::setup() {
this->write16_(ATM90E32_REGISTER_CFGREGACCEN, 0x55AA); // enable register config access
if (!this->validate_spi_read_(0x55AA, "setup()")) {
ESP_LOGW(TAG, "Could not initialize ATM90E32 IC, check SPI settings");
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->mark_failed();
return;
}
@@ -411,6 +411,9 @@ void ATM90E32Component::log_calibration_status_() {
void ATM90E32Component::dump_config() {
ESP_LOGCONFIG("", "ATM90E32:");
LOG_PIN(" CS Pin: ", this->cs_);
if (this->is_failed()) {
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
}
LOG_UPDATE_INTERVAL(this);
LOG_SENSOR(" ", "Voltage A", this->phase_[PHASEA].voltage_sensor_);
LOG_SENSOR(" ", "Current A", this->phase_[PHASEA].current_sensor_);
+4 -1
View File
@@ -65,7 +65,7 @@ MTreg:
void BH1750Sensor::setup() {
uint8_t turn_on = BH1750_COMMAND_POWER_ON;
if (this->write(&turn_on, 1) != i2c::ERROR_OK) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->mark_failed();
return;
}
this->state_ = IDLE;
@@ -74,6 +74,9 @@ void BH1750Sensor::setup() {
void BH1750Sensor::dump_config() {
LOG_SENSOR("", "BH1750", this);
LOG_I2C_DEVICE(this);
if (this->is_failed()) {
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL_FOR, this->get_name().c_str());
}
LOG_UPDATE_INTERVAL(this);
}
@@ -62,8 +62,7 @@ void BluedroidGattClient::loop() {
auto ret = esp_ble_gattc_app_register(this->app_id);
if (ret) {
ESP_LOGE(TAG, "gattc app register failed: app_id=%d code=%d", this->app_id, ret);
this->mark_failed(
LOG_STR("Registration failed; if the error was ESP_GATT_NO_RESOURCES, reduce the connection slots"));
this->mark_failed();
}
// Do not wait for REG_EVT; connect() rejects until it lands.
this->set_idle_();
@@ -109,7 +108,12 @@ void BluedroidGattClient::ble_before_disabled_event_handler() {
this->enable_loop();
}
void BluedroidGattClient::dump_config() { ESP_LOGCONFIG(TAG, "Bluedroid GATT client %d", this->connection_index_); }
void BluedroidGattClient::dump_config() {
ESP_LOGCONFIG(TAG, "Bluedroid GATT client %d", this->connection_index_);
if (this->is_failed()) {
ESP_LOGE(TAG, " Registration failed; if the error was ESP_GATT_NO_RESOURCES, reduce the connection slots");
}
}
// ---- contract ops ----
@@ -676,8 +680,7 @@ bool BluedroidGattClient::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga
this->gattc_if_ = esp_gattc_if;
} else {
ESP_LOGE(TAG, "[%d] gattc app registration failed, status=%d", this->connection_index_, param->reg.status);
this->mark_failed(
LOG_STR("Registration failed; if the error was ESP_GATT_NO_RESOURCES, reduce the connection slots"));
this->mark_failed();
}
break;
}
@@ -76,14 +76,16 @@ void RP2GattClient::setup() {
// Pre-create every pool entry so the packet handlers' allocate() calls are
// always a free-list pop -- the IRQ path must never reach malloc().
if (!this->event_pool_.warm() || !this->notify_pool_.warm()) {
this->mark_failed(LOG_STR("GATT event pool warm-up failed"));
ESP_LOGE(TAG, "GATT event pool warm-up failed");
this->mark_failed();
return;
}
// Register this engine for IRQ-context event routing.
if (instance_count >= ESPHOME_BLE_GATT_CLIENT_COUNT) {
// Cannot happen with codegen-sized storage; refuse loudly if it ever does.
this->mark_failed(LOG_STR("GATT client registry full"));
ESP_LOGE(TAG, "GATT client registry full");
this->mark_failed();
return;
}
{
+4 -1
View File
@@ -21,7 +21,7 @@ static constexpr uint32_t MAX_TIMER_DURATION_S = 255 * 60;
void BM8563::setup() {
if (!this->write_byte_16(CONTROL_STATUS_1_REG, 0)) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->mark_failed();
return;
}
}
@@ -31,6 +31,9 @@ void BM8563::update() { this->read_time(); }
void BM8563::dump_config() {
ESP_LOGCONFIG(TAG, "BM8563:");
LOG_I2C_DEVICE(this);
if (this->is_failed()) {
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
}
}
void BM8563::start_timer(uint32_t duration_s) {
+16 -1
View File
@@ -7,6 +7,8 @@
#include <esphome/components/sensor/sensor.h>
#include <esphome/core/component.h>
#define BME280_ERROR_WRONG_CHIP_ID "Wrong chip ID or no response"
namespace esphome::bme280_base {
ESPHOME_LOG_TAG(TAG, "bme280.sensor");
@@ -98,11 +100,13 @@ void BME280Component::setup() {
}
if (!this->read_byte(BME280_REGISTER_CHIPID, &chip_id)) {
this->error_code_ = COMMUNICATION_FAILED;
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
return;
}
if (chip_id != 0x60) {
this->mark_failed(LOG_STR("Wrong chip ID or no response"));
this->error_code_ = WRONG_CHIP_ID;
this->mark_failed(LOG_STR(BME280_ERROR_WRONG_CHIP_ID));
return;
}
@@ -178,6 +182,17 @@ void BME280Component::setup() {
}
void BME280Component::dump_config() {
ESP_LOGCONFIG(TAG, "BME280:");
switch (this->error_code_) {
case COMMUNICATION_FAILED:
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
break;
case WRONG_CHIP_ID:
ESP_LOGE(TAG, BME280_ERROR_WRONG_CHIP_ID);
break;
case NONE:
default:
break;
}
ESP_LOGCONFIG(TAG, " IIR Filter: %s", iir_filter_to_str(this->iir_filter_));
LOG_UPDATE_INTERVAL(this);
@@ -101,6 +101,11 @@ class BME280Component : public PollingComponent {
sensor::Sensor *temperature_sensor_{nullptr};
sensor::Sensor *pressure_sensor_{nullptr};
sensor::Sensor *humidity_sensor_{nullptr};
enum ErrorCode {
NONE = 0,
COMMUNICATION_FAILED,
WRONG_CHIP_ID,
} error_code_{NONE};
};
} // namespace esphome::bme280_base
+35 -22
View File
@@ -72,24 +72,22 @@ constexpr float BME680_GAS_LOOKUP_TABLE_2[16] PROGMEM = {0.0, 0.0, 0.0, 0.0, 0.
}
void BME680Component::setup() {
if (!this->setup_registers_())
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
}
bool BME680Component::setup_registers_() {
uint8_t chip_id;
if (!this->read_byte(BME680_REGISTER_CHIPID, &chip_id) || chip_id != 0x61) {
return false;
this->mark_failed();
return;
}
// Read calibration
uint8_t coeff1[25];
if (!this->read_bytes(BME680_REGISTER_COEFF1, coeff1, 25)) {
return false;
this->mark_failed();
return;
}
uint8_t coeff2[16];
if (!this->read_bytes(BME680_REGISTER_COEFF2, coeff2, 16)) {
return false;
this->mark_failed();
return;
}
this->calibration_.t1 = coeff2[9] << 8 | coeff2[8];
@@ -121,17 +119,20 @@ bool BME680Component::setup_registers_() {
uint8_t temp_var = 0;
if (!this->read_byte(0x02, &temp_var)) {
return false;
this->mark_failed();
return;
}
this->calibration_.res_heat_range = ((temp_var & 0x30) / 16);
if (!this->read_byte(0x00, &temp_var)) {
return false;
this->mark_failed();
return;
}
this->calibration_.res_heat_val = (int8_t) temp_var;
if (!this->read_byte(0x04, &temp_var)) {
return false;
this->mark_failed();
return;
}
this->calibration_.range_sw_err = ((int8_t) temp_var & (int8_t) 0xf0) / 16;
@@ -140,35 +141,41 @@ bool BME680Component::setup_registers_() {
// Config register
uint8_t config_register;
if (!this->read_byte(BME680_REGISTER_CONFIG, &config_register)) {
return false;
this->mark_failed();
return;
}
config_register &= ~0b00011100;
config_register |= (this->iir_filter_ & 0b111) << 2;
if (!this->write_byte(BME680_REGISTER_CONFIG, config_register)) {
return false;
this->mark_failed();
return;
}
// Humidity control register
uint8_t hum_control;
if (!this->read_byte(BME680_REGISTER_CONTROL_HUMIDITY, &hum_control)) {
return false;
this->mark_failed();
return;
}
hum_control &= ~0b00000111;
hum_control |= this->humidity_oversampling_ & 0b111;
if (!this->write_byte(BME680_REGISTER_CONTROL_HUMIDITY, hum_control)) {
return false;
this->mark_failed();
return;
}
// Gas 1 control register
uint8_t gas1_control;
if (!this->read_byte(BME680_REGISTER_CONTROL_GAS1, &gas1_control)) {
return false;
this->mark_failed();
return;
}
gas1_control &= ~0b00011111;
gas1_control |= 1 << 4;
gas1_control |= 0; // profile 0
if (!this->write_byte(BME680_REGISTER_CONTROL_GAS1, gas1_control)) {
return false;
this->mark_failed();
return;
}
const bool heat_off = this->heater_temperature_ == 0 || this->heater_duration_ == 0;
@@ -176,34 +183,40 @@ bool BME680Component::setup_registers_() {
// Gas 0 control register
uint8_t gas0_control;
if (!this->read_byte(BME680_REGISTER_CONTROL_GAS0, &gas0_control)) {
return false;
this->mark_failed();
return;
}
gas0_control &= ~0b00001000;
gas0_control |= heat_off << 3;
if (!this->write_byte(BME680_REGISTER_CONTROL_GAS0, gas0_control)) {
return false;
this->mark_failed();
return;
}
if (!heat_off) {
// Gas Heater Temperature
uint8_t temperature = this->calc_heater_resistance_(this->heater_temperature_);
if (!this->write_byte(BME680_REGISTER_HEATER_HEAT0, temperature)) {
return false;
this->mark_failed();
return;
}
// Gas Heater Duration
uint8_t duration = this->calc_heater_duration_(this->heater_duration_);
if (!this->write_byte(BME680_REGISTER_HEATER_WAIT0, duration)) {
return false;
this->mark_failed();
return;
}
}
return true;
}
void BME680Component::dump_config() {
ESP_LOGCONFIG(TAG, "BME680:");
LOG_I2C_DEVICE(this);
if (this->is_failed()) {
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
}
ESP_LOGCONFIG(TAG, " IIR Filter: %s", iir_filter_to_str(this->iir_filter_));
LOG_UPDATE_INTERVAL(this);
-2
View File
@@ -101,8 +101,6 @@ class BME680Component final : public PollingComponent, public i2c::I2CDevice {
void update() override;
protected:
/// Configure the sensor registers; false on an I2C failure.
bool setup_registers_();
/// Calculate the heater resistance value to send to the BME680 register.
uint8_t calc_heater_resistance_(uint16_t temperature);
/// Calculate the heater duration value to send to the BME680 register.
+17 -13
View File
@@ -117,21 +117,18 @@ const uint8_t BMI160_REGISTER_DATA_TEMP_MSB = 0x21;
const float GRAVITY_EARTH = 9.80665f;
void BMI160Component::internal_setup_(int stage) {
if (!this->setup_stage_(stage))
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
}
bool BMI160Component::setup_stage_(int stage) {
switch (stage) {
case 0:
uint8_t chipid;
if (!this->read_byte(BMI160_REGISTER_CHIPID, &chipid) || (chipid != 0b11010001)) {
return false;
this->mark_failed();
return;
}
ESP_LOGV(TAG, " Bringing accelerometer out of sleep");
if (!this->write_byte(BMI160_REGISTER_CMD, (uint8_t) Cmd::ACCL_SET_PMU_MODE | (uint8_t) AcclPmuMode::NORMAL)) {
return false;
this->mark_failed();
return;
}
ESP_LOGV(TAG, " Waiting for accelerometer to wake up");
// need to wait (max delay in datasheet) because we can't send commands while another is in progress
@@ -142,7 +139,8 @@ bool BMI160Component::setup_stage_(int stage) {
case 1:
ESP_LOGV(TAG, " Bringing gyroscope out of sleep");
if (!this->write_byte(BMI160_REGISTER_CMD, (uint8_t) Cmd::GYRO_SET_PMU_MODE | (uint8_t) GyroPmuMode::NORMAL)) {
return false;
this->mark_failed();
return;
}
ESP_LOGV(TAG, " Waiting for gyroscope to wake up");
// wait between 51 & 81ms, doing 100 to be safe
@@ -154,13 +152,15 @@ bool BMI160Component::setup_stage_(int stage) {
uint8_t gyro_config = (uint8_t) GyroBandwidth::OSR4 | (uint8_t) GyroOuputDataRate::HZ_25;
ESP_LOGV(TAG, " Output gyro_config: 0b" BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(gyro_config));
if (!this->write_byte(BMI160_REGISTER_GYRO_CONFIG, gyro_config)) {
return false;
this->mark_failed();
return;
}
ESP_LOGV(TAG, " Setting up Gyro Range");
uint8_t gyro_range = (uint8_t) GyroRange::RANGE_2000_DPS;
ESP_LOGV(TAG, " Output gyro_range: 0b" BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(gyro_range));
if (!this->write_byte(BMI160_REGISTER_GYRO_RANGE, gyro_range)) {
return false;
this->mark_failed();
return;
}
ESP_LOGV(TAG, " Setting up Accel Config");
@@ -168,24 +168,28 @@ bool BMI160Component::setup_stage_(int stage) {
(uint8_t) AcclFilterMode::PERF | (uint8_t) AcclBandwidth::RES_AVG16 | (uint8_t) AccelOutputDataRate::HZ_25;
ESP_LOGV(TAG, " Output accel_config: 0b" BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(accel_config));
if (!this->write_byte(BMI160_REGISTER_ACCEL_CONFIG, accel_config)) {
return false;
this->mark_failed();
return;
}
ESP_LOGV(TAG, " Setting up Accel Range");
uint8_t accel_range = (uint8_t) AccelRange::RANGE_16G;
ESP_LOGV(TAG, " Output accel_range: 0b" BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(accel_range));
if (!this->write_byte(BMI160_REGISTER_ACCEL_RANGE, accel_range)) {
return false;
this->mark_failed();
return;
}
this->setup_complete_ = true;
}
return true;
}
void BMI160Component::setup() { this->internal_setup_(0); }
void BMI160Component::dump_config() {
ESP_LOGCONFIG(TAG, "BMI160:");
LOG_I2C_DEVICE(this);
if (this->is_failed()) {
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
}
LOG_UPDATE_INTERVAL(this);
LOG_SENSOR(" ", "Acceleration X", this->accel_x_sensor_);
LOG_SENSOR(" ", "Acceleration Y", this->accel_y_sensor_);
-2
View File
@@ -31,8 +31,6 @@ class BMI160Component final : public PollingComponent, public i2c::I2CDevice {
sensor::Sensor *gyro_z_sensor_{nullptr};
void internal_setup_(int stage);
/// Run one setup stage; false on an I2C failure.
bool setup_stage_(int stage);
bool setup_complete_{false};
/** reads `len` 16-bit little-endian integers from the given i2c register */
+15 -11
View File
@@ -80,26 +80,28 @@ void BMI270Component::setup() {
// 1. Verify chip ID
uint8_t chip_id = 0;
if (!this->read_byte(BMI270_REG_CHIP_ID, &chip_id)) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
ESP_LOGE(TAG, "Failed to read chip ID – check wiring / address");
this->mark_failed();
return;
}
if (chip_id != BMI270_CHIP_ID_VALUE) {
ESP_LOGE(TAG, "Wrong chip ID: 0x%02X (expected 0x%02X)", chip_id, BMI270_CHIP_ID_VALUE);
this->mark_failed(LOG_STR("Wrong chip ID"));
this->mark_failed();
return;
}
ESP_LOGD(TAG, "Chip ID: 0x%02X", chip_id);
// 2. Soft-reset via CMD register (0x7E = 0xB6)
if (!this->write_byte(BMI270_REG_CMD, BMI270_CMD_SOFT_RESET)) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->mark_failed();
return;
}
delay(20);
// 4. Upload the configuration blob
if (!load_config_file_()) {
this->mark_failed(LOG_STR("Config file upload failed"));
ESP_LOGE(TAG, "Config file upload failed");
this->mark_failed();
return;
}
ESP_LOGD(TAG, "Config blob uploaded ✓");
@@ -109,11 +111,11 @@ void BMI270Component::setup() {
uint8_t acc_conf =
(uint8_t) (accel_odr_) | (BMI270_CONF_BWP_NORMAL << BMI270_CONF_BWP_SHIFT) | BMI270_ACC_CONF_PERF_MODE;
if (!this->write_byte(BMI270_REG_ACC_CONF, acc_conf)) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->mark_failed();
return;
}
if (!this->write_byte(BMI270_REG_ACC_RANGE, (uint8_t) accel_range_)) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->mark_failed();
return;
}
@@ -122,18 +124,18 @@ void BMI270Component::setup() {
uint8_t gyr_conf = (uint8_t) (gyro_odr_) | (BMI270_CONF_BWP_NORMAL << BMI270_CONF_BWP_SHIFT) |
BMI270_GYR_CONF_NOISE_PERF | BMI270_GYR_CONF_FILTER_PERF;
if (!this->write_byte(BMI270_REG_GYR_CONF, gyr_conf)) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->mark_failed();
return;
}
if (!this->write_byte(BMI270_REG_GYR_RANGE, (uint8_t) gyro_range_)) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->mark_failed();
return;
}
// 7. Enable accelerometer, gyroscope, and temperature sensor
// PWR_CTRL bits: temp_en[3] | gyr_en[2] | acc_en[1]
if (!this->write_byte(BMI270_REG_PWR_CTRL, BMI270_PWR_CTRL_IMU)) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->mark_failed();
return;
}
delay(5);
@@ -141,7 +143,7 @@ void BMI270Component::setup() {
// 8. Re-enable advanced power save (optional; keeps current low between reads)
// Disabled here for simplicity – leave in performance mode
if (!this->write_byte(BMI270_REG_PWR_CONF, BMI270_PWR_CONF_FIFO_SELF_WAKEUP)) { // bit1 = fifo_self_wakeup
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->mark_failed();
return;
}
@@ -270,8 +272,10 @@ bool BMI270Component::setup_magnetometer_() {
void BMI270Component::dump_config() {
ESP_LOGCONFIG(TAG, "BMI270 IMU:");
LOG_I2C_DEVICE(this);
if (this->is_failed())
if (this->is_failed()) {
ESP_LOGE(TAG, " Communication failed!");
return;
}
ESP_LOGCONFIG(TAG, " Accel range : %s",
LOG_STR_ARG(AccelRangeStrings::get_log_str(this->accel_range_, AccelRangeStrings::LAST_INDEX)));
+4 -1
View File
@@ -24,7 +24,7 @@ void BMP085Component::update() {
void BMP085Component::setup() {
uint8_t data[22];
if (!this->read_bytes(BMP085_REGISTER_AC1_H, data, 22)) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->mark_failed();
return;
}
@@ -44,6 +44,9 @@ void BMP085Component::setup() {
void BMP085Component::dump_config() {
ESP_LOGCONFIG(TAG, "BMP085:");
LOG_I2C_DEVICE(this);
if (this->is_failed()) {
ESP_LOGE(TAG, "Connection with BMP085 failed!");
}
LOG_UPDATE_INTERVAL(this);
LOG_SENSOR(" ", "Temperature", this->temperature_);
+17 -1
View File
@@ -2,6 +2,8 @@
#include "esphome/core/hal.h"
#include "esphome/core/log.h"
#define BMP280_ERROR_WRONG_CHIP_ID "Wrong chip ID or no response"
namespace esphome::bmp280_base {
ESPHOME_LOG_TAG(TAG, "bmp280.sensor");
@@ -63,15 +65,18 @@ void BMP280Component::setup() {
// Read the chip id twice, to work around a bug where the first read is 0.
// https://community.st.com/t5/stm32-mcus-products/issue-with-reading-bmp280-chip-id-using-spi/td-p/691855
if (!this->bmp_read_byte(0xD0, &chip_id)) {
this->error_code_ = COMMUNICATION_FAILED;
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
return;
}
if (!this->bmp_read_byte(0xD0, &chip_id)) {
this->error_code_ = COMMUNICATION_FAILED;
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
return;
}
if (chip_id != 0x58) {
this->mark_failed(LOG_STR("Wrong chip ID or no response"));
this->error_code_ = WRONG_CHIP_ID;
this->mark_failed(LOG_STR(BMP280_ERROR_WRONG_CHIP_ID));
return;
}
@@ -125,6 +130,17 @@ void BMP280Component::setup() {
}
void BMP280Component::dump_config() {
ESP_LOGCONFIG(TAG, "BMP280:");
switch (this->error_code_) {
case COMMUNICATION_FAILED:
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
break;
case WRONG_CHIP_ID:
ESP_LOGE(TAG, BMP280_ERROR_WRONG_CHIP_ID);
break;
case NONE:
default:
break;
}
ESP_LOGCONFIG(TAG, " IIR Filter: %s", iir_filter_to_str(this->iir_filter_));
LOG_UPDATE_INTERVAL(this);
@@ -85,6 +85,11 @@ class BMP280Component : public PollingComponent {
BMP280IIRFilter iir_filter_{BMP280_IIR_FILTER_OFF};
sensor::Sensor *temperature_sensor_{nullptr};
sensor::Sensor *pressure_sensor_{nullptr};
enum ErrorCode {
NONE = 0,
COMMUNICATION_FAILED,
WRONG_CHIP_ID,
} error_code_{NONE};
};
} // namespace esphome::bmp280_base
+38 -8
View File
@@ -43,27 +43,35 @@ static const LogString *iir_filter_to_str(IIRFilter filter) {
}
void BMP3XXComponent::setup() {
this->error_code_ = NONE;
// Call the Device base class "initialise" function
if (!reset()) {
this->mark_failed(LOG_STR("Failed to reset"));
return;
ESP_LOGE(TAG, "Failed to reset");
this->error_code_ = ERROR_SENSOR_RESET;
this->mark_failed();
}
if (!read_byte(BMP388_CHIP_ID, &this->chip_id_.reg)) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
ESP_LOGE(TAG, "Can't read chip id");
this->error_code_ = ERROR_COMMUNICATION_FAILED;
this->mark_failed();
return;
}
ESP_LOGCONFIG(TAG, "Chip %s Id 0x%X", LOG_STR_ARG(chip_type_to_str(this->chip_id_.reg)), this->chip_id_.reg);
if (chip_id_.reg != BMP388_ID && chip_id_.reg != BMP390_ID) {
this->mark_failed(LOG_STR("Wrong chip ID - please check if you are really using a BMP 388 or BMP 390"));
ESP_LOGE(TAG, "Unknown chip id - is this really a BMP388 or BMP390?");
this->error_code_ = ERROR_WRONG_CHIP_ID;
this->mark_failed();
return;
}
// set sensor in sleep mode
stop_conversion();
// Read the calibration parameters into the params structure
if (!read_bytes(BMP388_TRIM_PARAMS, (uint8_t *) &compensation_params_, sizeof(compensation_params_))) {
this->mark_failed(LOG_STR("Can't read calibration data"));
ESP_LOGE(TAG, "Can't read calibration data");
this->error_code_ = ERROR_COMMUNICATION_FAILED;
this->mark_failed();
return;
}
compensation_float_params_.param_T1 =
@@ -84,7 +92,9 @@ void BMP3XXComponent::setup() {
// Initialise the BMP388 IIR filter register
if (!set_iir_filter(this->iir_filter_)) {
this->mark_failed(LOG_STR("Failed to set IIR filter"));
ESP_LOGE(TAG, "Failed to set IIR filter");
this->error_code_ = ERROR_COMMUNICATION_FAILED;
this->mark_failed();
return;
}
@@ -103,7 +113,9 @@ void BMP3XXComponent::setup() {
}
// Initialise the BMP388 oversampling register
if (!set_oversampling_register(this->pressure_oversampling_, this->temperature_oversampling_)) {
this->mark_failed(LOG_STR("Failed to set oversampling register"));
ESP_LOGE(TAG, "Failed to set oversampling register");
this->error_code_ = ERROR_COMMUNICATION_FAILED;
this->mark_failed();
return;
}
}
@@ -113,6 +125,23 @@ void BMP3XXComponent::dump_config() {
"BMP3XX:\n"
" Type: %s (0x%X)",
LOG_STR_ARG(chip_type_to_str(this->chip_id_.reg)), this->chip_id_.reg);
switch (this->error_code_) {
case NONE:
break;
case ERROR_COMMUNICATION_FAILED:
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
break;
case ERROR_WRONG_CHIP_ID:
ESP_LOGE(TAG, "Wrong chip ID (reported id: 0x%X) - please check if you are really using a BMP 388 or BMP 390",
this->chip_id_.reg);
break;
case ERROR_SENSOR_RESET:
ESP_LOGE(TAG, "Failed to reset");
break;
default:
ESP_LOGE(TAG, "Error code %d", (int) this->error_code_);
break;
}
ESP_LOGCONFIG(TAG, " IIR Filter: %s", LOG_STR_ARG(iir_filter_to_str(this->iir_filter_)));
LOG_UPDATE_INTERVAL(this);
if (this->temperature_sensor_) {
@@ -136,7 +165,8 @@ void BMP3XXComponent::update() {
meas_time += 2.02f * oversampling_to_time(this->pressure_oversampling_) + 0.392f;
meas_time += 0.234f;
if (!set_mode(FORCED_MODE)) {
this->mark_failed(LOG_STR("Failed start forced mode"));
ESP_LOGE(TAG, "Failed start forced mode");
this->mark_failed();
return;
}
@@ -124,6 +124,13 @@ class BMP3XXComponent : public PollingComponent {
OperationMode operation_mode_{FORCED_MODE};
sensor::Sensor *temperature_sensor_{nullptr};
sensor::Sensor *pressure_sensor_{nullptr};
enum ErrorCode {
NONE = 0,
ERROR_COMMUNICATION_FAILED,
ERROR_WRONG_CHIP_ID,
ERROR_SENSOR_STATUS,
ERROR_SENSOR_RESET,
} error_code_{NONE};
struct { // The BMP388 compensation trim parameters (coefficients)
uint16_t param_T1;
+64 -10
View File
@@ -38,6 +38,29 @@ static const LogString *iir_filter_to_str(IIRFilter filter) {
void BMP581Component::dump_config() {
ESP_LOGCONFIG(TAG, "BMP581:");
switch (this->error_code_) {
case NONE:
break;
case ERROR_COMMUNICATION_FAILED:
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
break;
case ERROR_WRONG_CHIP_ID:
ESP_LOGE(TAG, "Unknown chip ID");
break;
case ERROR_SENSOR_RESET:
ESP_LOGE(TAG, "Reset failed");
break;
case ERROR_SENSOR_STATUS:
ESP_LOGE(TAG, "Get status failed");
break;
case ERROR_PRIME_IIR_FAILED:
ESP_LOGE(TAG, "IIR Filter failed to prime with initial measurement");
break;
default:
ESP_LOGE(TAG, "Error %d", (int) this->error_code_);
break;
}
LOG_UPDATE_INTERVAL(this);
ESP_LOGCONFIG(TAG, " Measurement conversion time: %ums", this->conversion_time_);
@@ -73,13 +96,17 @@ void BMP581Component::setup() {
* 6) Configure and prime IIR Filter(s), if enabled
*/
this->error_code_ = NONE;
////////////////////
// 1) Soft reboot //
////////////////////
// Power-On-Reboot bit is asserted if sensor successfully reset
if (!this->reset_()) {
this->mark_failed(LOG_STR("Reset failed"));
ESP_LOGE(TAG, "Reset failed");
this->error_code_ = ERROR_SENSOR_RESET;
this->mark_failed();
return;
}
@@ -92,14 +119,20 @@ void BMP581Component::setup() {
// read chip id from sensor
if (!this->bmp_read_byte(BMP581_CHIP_ID, &chip_id)) {
this->mark_failed(LOG_STR("Read chip ID failed"));
ESP_LOGE(TAG, "Read chip ID failed");
this->error_code_ = ERROR_COMMUNICATION_FAILED;
this->mark_failed();
return;
}
// verify id
if (chip_id != BMP581_ASIC_ID && chip_id != BMP585_ASIC_ID) {
this->mark_failed(LOG_STR("Unknown chip ID"));
ESP_LOGE(TAG, "Unknown chip ID");
this->error_code_ = ERROR_WRONG_CHIP_ID;
this->mark_failed();
return;
}
@@ -109,21 +142,30 @@ void BMP581Component::setup() {
////////////////////////////////////////////////////
if (!this->bmp_read_byte(BMP581_STATUS, &this->status_.reg)) {
this->mark_failed(LOG_STR("Failed to read status register"));
ESP_LOGE(TAG, "Failed to read status register");
this->error_code_ = ERROR_COMMUNICATION_FAILED;
this->mark_failed();
return;
}
// verify status_nvm_rdy bit (it is asserted if boot was successful)
if (!(this->status_.bit.status_nvm_rdy)) {
this->mark_failed(LOG_STR("NVM not ready"));
ESP_LOGE(TAG, "NVM not ready");
this->error_code_ = ERROR_SENSOR_STATUS;
this->mark_failed();
return;
}
// verify status_nvm_err bit (it is asserted if an error is detected)
if (this->status_.bit.status_nvm_err) {
this->mark_failed(LOG_STR("NVM error detected"));
ESP_LOGE(TAG, "NVM error detected");
this->error_code_ = ERROR_SENSOR_STATUS;
this->mark_failed();
return;
}
@@ -134,7 +176,10 @@ void BMP581Component::setup() {
// enable the data ready interrupt source
if (!this->write_interrupt_source_settings_(true)) {
this->mark_failed(LOG_STR("Failed to write interrupt source register"));
ESP_LOGE(TAG, "Failed to write interrupt source register");
this->error_code_ = ERROR_COMMUNICATION_FAILED;
this->mark_failed();
return;
}
@@ -153,7 +198,10 @@ void BMP581Component::setup() {
// write oversampling settings
if (!this->write_oversampling_settings_(this->temperature_oversampling_, this->pressure_oversampling_)) {
this->mark_failed(LOG_STR("Failed to write oversampling register"));
ESP_LOGE(TAG, "Failed to write oversampling register");
this->error_code_ = ERROR_COMMUNICATION_FAILED;
this->mark_failed();
return;
}
@@ -170,13 +218,19 @@ void BMP581Component::setup() {
if ((this->iir_temperature_level_ != IIR_FILTER_OFF) || (this->iir_pressure_level_ != IIR_FILTER_OFF)) {
if (!this->write_iir_settings_(this->iir_temperature_level_, this->iir_pressure_level_)) {
this->mark_failed(LOG_STR("Failed to write IIR configuration registers"));
ESP_LOGE(TAG, "Failed to write IIR configuration registers");
this->error_code_ = ERROR_COMMUNICATION_FAILED;
this->mark_failed();
return;
}
if (!this->prime_iir_filter_()) {
this->mark_failed(LOG_STR("Failed to prime the IIR filter with an initial measurement"));
ESP_LOGE(TAG, "Failed to prime the IIR filter with an initial measurement");
this->error_code_ = ERROR_PRIME_IIR_FAILED;
this->mark_failed();
return;
}
@@ -133,6 +133,15 @@ class BMP581Component : public PollingComponent {
// Sets the power mode on the BMP581 by writing to the ODR register
bool write_power_mode_(OperationMode mode);
enum ErrorCode {
NONE = 0,
ERROR_COMMUNICATION_FAILED,
ERROR_WRONG_CHIP_ID,
ERROR_SENSOR_STATUS,
ERROR_SENSOR_RESET,
ERROR_PRIME_IIR_FAILED
} error_code_{NONE};
// BMP581's interrupt source register (address 0x15) to configure which interrupts are enabled (page 54 of datasheet)
union {
struct {
@@ -0,0 +1,25 @@
#pragma once
#include "esphome/core/defines.h"
#ifdef USE_BUTTON
#include "bq25186.h"
#include "esphome/components/button/button.h"
namespace esphome::bq25186 {
/// Writes one SHIP_RST field when pressed
class BQ25186Button final : public button::Button, public Parented<BQ25186Component> {
public:
BQ25186Button(uint8_t mask, uint8_t value) : mask_(mask), value_(value) {}
protected:
void press_action() override { this->parent_->write_ship_rst(this->mask_, this->value_); }
const uint8_t mask_;
const uint8_t value_;
};
} // namespace esphome::bq25186
#endif // USE_BUTTON
+7 -4
View File
@@ -1,3 +1,4 @@
import esphome.codegen as cg
from esphome.components import button
import esphome.config_validation as cv
from esphome.const import (
@@ -9,10 +10,11 @@ from esphome.const import (
)
from esphome.types import ConfigType
from . import BQ25186_CHILD_SCHEMA, CONF_BQ25186_ID
from . import BQ25186_CHILD_SCHEMA, CONF_BQ25186_ID, bq25186_ns
DEPENDENCIES = ["bq25186"]
BQ25186Button = bq25186_ns.class_("BQ25186Button", button.Button)
# SHIP_RST: bit 7 is the software reset, bits 6:5 the shutdown, ship and hardware reset codes
SOFTWARE_RESET_MASK = 0x80
@@ -31,7 +33,7 @@ CONFIG_SCHEMA = cv.All(
BQ25186_CHILD_SCHEMA.extend(
{
cv.Optional(key): button.button_schema(
button.ApplyButton,
BQ25186Button,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=icon,
device_class=device_class,
@@ -44,6 +46,7 @@ CONFIG_SCHEMA = cv.All(
async def to_code(config: ConfigType) -> None:
buttons = button.sub_buttons(config, parent=config[CONF_BQ25186_ID])
for key, mask, value, _, _ in _BUTTONS:
await buttons(key, None, apply=f"write_ship_rst({mask:#04x}, {value:#04x})")
if (conf := config.get(key)) is not None:
var = await button.new_button(conf, mask, value)
await cg.register_parented(var, config[CONF_BQ25186_ID])
+4 -1
View File
@@ -48,7 +48,7 @@ void BQ27220Component::setup() {
}
if (device_number != DEVICE_NUMBER) {
ESP_LOGE(TAG, "Unexpected device number 0x%04X (expected 0x%04X)", device_number, DEVICE_NUMBER);
this->mark_failed(LOG_STR("Unexpected device number"));
this->mark_failed();
}
}
@@ -76,6 +76,9 @@ void BQ27220Component::update() {
void BQ27220Component::dump_config() {
ESP_LOGCONFIG(TAG, "BQ27220 Battery Fuel Gauge:");
LOG_I2C_DEVICE(this);
if (this->is_failed()) {
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
}
LOG_UPDATE_INTERVAL(this);
LOG_SENSOR(" ", "Voltage", this->voltage_sensor_);
LOG_SENSOR(" ", "Current", this->current_sensor_);
+2 -7
View File
@@ -18,7 +18,6 @@ from esphome.const import (
)
from esphome.core import CORE, ID, CoroPriority, coroutine_with_priority
from esphome.core.entity_helpers import (
ApplyEntity,
SubEntities,
entity_duplicate_validator,
queue_entity_register,
@@ -42,7 +41,6 @@ DEVICE_CLASSES = [
button_ns = cg.esphome_ns.namespace("button")
Button = button_ns.class_("Button", cg.EntityBase)
ButtonPtr = Button.operator("ptr")
ApplyButton = button_ns.class_("ApplyButton", Button)
validate_device_class = cv.one_of(*DEVICE_CLASSES, lower=True, space="_")
@@ -118,14 +116,11 @@ async def new_button(config: ConfigType, *args: SafeExpType) -> MockObj:
return var
APPLY_ENTITY = ApplyEntity(ApplyButton, ((ButtonPtr, "entity"),))
def sub_buttons(
config: ConfigType, *, parent: MockObj | ID | None = None
) -> SubEntities:
"""Return a SubEntities bound to new_button; ``apply`` statements can use ``entity``."""
return SubEntities(new_button, config, parent, APPLY_ENTITY)
"""Return a SubEntities bound to new_button."""
return SubEntities(new_button, config, parent)
BUTTON_PRESS_SCHEMA = maybe_simple_id(
-10
View File
@@ -46,14 +46,4 @@ class Button : public EntityBase {
LazyCallbackManager<void()> press_callback_{};
};
/// Calls the codegen-generated Fn(this) on a press; the hub and any publish are baked into Fn.
template<auto Fn> class ApplyButton final : public Button {
public:
// Not "= default": placement new would zero-fill .bss that is already zero.
ApplyButton() {}
protected:
void press_action() override { Fn(this); }
};
} // namespace esphome::button
+11 -1
View File
@@ -37,7 +37,8 @@ void CAP1188Component::finish_setup_() {
this->read_byte(CAP1188_REVISION, &this->cap1188_revision_);
if ((this->cap1188_product_id_ != 0x50) || (this->cap1188_manufacture_id_ != 0x5D)) {
this->mark_failed(LOG_STR("Product ID or Manufacture ID of the connected device does not match a known CAP1188"));
this->error_code_ = COMMUNICATION_FAILED;
this->mark_failed();
return;
}
@@ -69,6 +70,15 @@ void CAP1188Component::dump_config() {
this->cap1188_product_id_, this->cap1188_manufacture_id_, this->cap1188_revision_);
LOG_I2C_DEVICE(this);
LOG_PIN(" Reset Pin: ", this->reset_pin_);
switch (this->error_code_) {
case COMMUNICATION_FAILED:
ESP_LOGE(TAG, "Product ID or Manufacture ID of the connected device does not match a known CAP1188.");
break;
case NONE:
default:
break;
}
}
void CAP1188Component::loop() {
+5
View File
@@ -59,6 +59,11 @@ class CAP1188Component final : public Component, public i2c::I2CDevice {
uint8_t cap1188_product_id_{0};
uint8_t cap1188_manufacture_id_{0};
uint8_t cap1188_revision_{0};
enum ErrorCode {
NONE = 0,
COMMUNICATION_FAILED,
} error_code_{NONE};
};
} // namespace esphome::cap1188
+31 -7
View File
@@ -10,28 +10,29 @@ ESPHOME_LOG_TAG(TAG, "ccs811");
// based on
// - https://cdn.sparkfun.com/datasheets/BreakoutBoards/CCS811_Programming_Guide.pdf
#define CHECK_TRUE(f, message) \
#define CHECK_TRUE(f, error_code) \
if (!(f)) { \
this->mark_failed(LOG_STR(message)); \
this->mark_failed(); \
this->error_code_ = (error_code); \
return; \
}
#define CHECKED_IO(f) CHECK_TRUE(f, ESP_LOG_MSG_COMM_FAIL)
#define CHECKED_IO(f) CHECK_TRUE(f, COMMUNICATION_FAILED)
void CCS811Component::setup() {
// page 9 programming guide - hwid is always 0x81
uint8_t hw_id;
CHECKED_IO(this->read_byte(0x20, &hw_id))
CHECK_TRUE(hw_id == 0x81, "Sensor reported an invalid ID. Is this a CCS811?")
CHECK_TRUE(hw_id == 0x81, INVALID_ID)
// software reset, page 3 - allowed to fail
this->write_bytes(0xFF, {0x11, 0xE5, 0x72, 0x8A});
delay(5);
// page 10, APP_START
CHECK_TRUE(!this->status_has_error_(), "Sensor reported internal error")
CHECK_TRUE(this->status_app_is_valid_(), "Sensor reported invalid APP installed")
CHECK_TRUE(this->write_bytes(0xF4, {}), "Sensor reported APP start failed")
CHECK_TRUE(!this->status_has_error_(), SENSOR_REPORTED_ERROR)
CHECK_TRUE(this->status_app_is_valid_(), APP_INVALID)
CHECK_TRUE(this->write_bytes(0xF4, {}), APP_START_FAILED)
// App setup, wait for it to load
delay(1);
@@ -159,6 +160,29 @@ void CCS811Component::dump_config() {
} else {
ESP_LOGCONFIG(TAG, " Baseline: NOT SET");
}
if (this->is_failed()) {
switch (this->error_code_) {
case COMMUNICATION_FAILED:
ESP_LOGW(TAG, ESP_LOG_MSG_COMM_FAIL);
break;
case INVALID_ID:
ESP_LOGW(TAG, "Sensor reported an invalid ID. Is this a CCS811?");
break;
case SENSOR_REPORTED_ERROR:
ESP_LOGW(TAG, "Sensor reported internal error");
break;
case APP_INVALID:
ESP_LOGW(TAG, "Sensor reported invalid APP installed.");
break;
case APP_START_FAILED:
ESP_LOGW(TAG, "Sensor reported APP start failed.");
break;
case UNKNOWN:
default:
ESP_LOGW(TAG, "Unknown setup error!");
break;
}
}
}
} // namespace esphome::ccs811
+9
View File
@@ -31,6 +31,15 @@ class CCS811Component final : public PollingComponent, public i2c::I2CDevice {
bool status_has_data_() { return this->read_status_().value_or(0) & (1 << 3); }
void send_env_data_();
enum ErrorCode {
UNKNOWN,
COMMUNICATION_FAILED,
INVALID_ID,
SENSOR_REPORTED_ERROR,
APP_INVALID,
APP_START_FAILED,
} error_code_{UNKNOWN};
sensor::Sensor *co2_{nullptr};
sensor::Sensor *tvoc_{nullptr};
text_sensor::TextSensor *version_{nullptr};
+4 -1
View File
@@ -18,7 +18,7 @@ void CH422GComponent::setup() {
// Set mode and check for errors
if (!this->set_mode_(this->mode_value_) || !this->read_inputs_()) {
ESP_LOGE(TAG, "CH422G not detected at 0x%02X", this->address_);
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->mark_failed();
return;
}
@@ -34,6 +34,9 @@ void CH422GComponent::loop() {
void CH422GComponent::dump_config() {
ESP_LOGCONFIG(TAG, "CH422G:");
LOG_I2C_DEVICE(this)
if (this->is_failed()) {
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
}
}
void CH422GComponent::pin_mode(uint8_t pin, gpio::Flags flags) {
+8 -2
View File
@@ -24,7 +24,8 @@ void CH423Component::setup() {
success = this->read_inputs_();
}
if (!success) {
this->mark_failed(LOG_STR("CH423 not detected"));
ESP_LOGE(TAG, "CH423 not detected");
this->mark_failed();
return;
}
@@ -37,7 +38,12 @@ void CH423Component::loop() {
this->pin_read_flags_ = 0x00;
}
void CH423Component::dump_config() { ESP_LOGCONFIG(TAG, "CH423:"); }
void CH423Component::dump_config() {
ESP_LOGCONFIG(TAG, "CH423:");
if (this->is_failed()) {
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
}
}
void CH423Component::pin_mode(uint8_t pin, gpio::Flags flags) {
if (pin < 8) {
+5 -1
View File
@@ -27,7 +27,8 @@ uint8_t cm1106_checksum(const uint8_t *response, size_t len) {
void CM1106Component::setup() {
uint8_t response[8] = {0};
if (!this->cm1106_write_command_(C_M1106_CMD_GET_CO2, sizeof(C_M1106_CMD_GET_CO2), response, sizeof(response))) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
this->mark_failed();
return;
}
@@ -138,6 +139,9 @@ void CM1106Component::dump_config() {
" ABC baseline: %uppm",
ONOFF(this->abc_boot_logic_ == CM1106_ABC_ENABLED), this->abc_cycle_, this->abc_baseline_);
}
if (this->is_failed()) {
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
}
}
} // namespace esphome::cm1106
-1
View File
@@ -54,7 +54,6 @@ CONF_ON_STATE_CHANGE = "on_state_change"
CONF_ON_STOP = "on_stop"
CONF_OUT_PIN_LEVEL = "out_pin_level"
CONF_PARITY = "parity"
CONF_QUERY_PARAMS = "query_params"
CONF_RECEIVER_FREQUENCY = "receiver_frequency"
CONF_RECONNECT_INTERVAL = "reconnect_interval"
CONF_RED_CHANNEL = "red_channel"
+4 -1
View File
@@ -67,12 +67,15 @@ void CSE7761Component::setup() {
ESP_LOGD(TAG, "CSE7761 found");
this->data_.ready = true;
} else {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->mark_failed();
}
}
void CSE7761Component::dump_config() {
ESP_LOGCONFIG(TAG, "CSE7761:");
if (this->is_failed()) {
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
}
ESP_LOGCONFIG(TAG, " Current input: %s",
LOG_STR_ARG(this->is_current_transformer_() ? LOG_STR("current transformer") : LOG_STR("shunt")));
LOG_UPDATE_INTERVAL(this);
@@ -23,7 +23,8 @@ void DAC7678Output::setup() {
// Reset device
if (!this->write_byte_16(DAC7678_REG_SOFTWARE_RESET, 0x0000)) {
this->mark_failed(LOG_STR("Reset failed"));
ESP_LOGE(TAG, "Reset failed");
this->mark_failed();
return;
} else {
ESP_LOGV(TAG, "Reset succeeded");
@@ -34,7 +35,8 @@ void DAC7678Output::setup() {
// Set internal reference
if (this->internal_reference_) {
if (!this->write_byte_16(DAC7678_REG_INTERNAL_REF_0, 1 << 4)) {
this->mark_failed(LOG_STR("Set internal reference failed"));
ESP_LOGE(TAG, "Set internal reference failed");
this->mark_failed();
return;
} else {
ESP_LOGV(TAG, "Internal reference enabled");
@@ -43,7 +45,9 @@ void DAC7678Output::setup() {
}
void DAC7678Output::dump_config() {
if (!this->is_failed()) {
if (this->is_failed()) {
ESP_LOGE(TAG, "Setting up DAC7678 failed!");
} else {
ESP_LOGCONFIG(TAG, "DAC7678 initialised");
}
}
@@ -26,22 +26,17 @@ class DfrobotSen0395SettingsAction final : public Action<Ts...>, public Parented
TEMPLATABLE_VALUE(float, det_min4)
TEMPLATABLE_VALUE(float, det_max4)
void play(const Ts &...x) override {
void play(const Ts &...x) {
this->parent_->enqueue(make_unique<PowerCommand>(0));
if (this->factory_reset_.has_value() && this->factory_reset_.value(x...) == true) {
this->parent_->enqueue(make_unique<FactoryResetCommand>());
}
if (this->det_min1_.has_value() && this->det_max1_.has_value()) {
// Each segment is read once, so the guard and the command see the same values.
const float min1 = this->det_min1_.value(x...);
if (min1 >= 0) {
const float max1 = this->det_max1_.value(x...);
if (max1 >= 0) {
this->parent_->enqueue(make_unique<DetRangeCfgCommand>(
min1, max1, this->det_min2_.value_or(x..., -1), this->det_max2_.value_or(x..., -1),
this->det_min3_.value_or(x..., -1), this->det_max3_.value_or(x..., -1),
this->det_min4_.value_or(x..., -1), this->det_max4_.value_or(x..., -1)));
}
if (this->det_min1_.value() >= 0 && this->det_max1_.value() >= 0) {
this->parent_->enqueue(make_unique<DetRangeCfgCommand>(
this->det_min1_.value_or(-1), this->det_max1_.value_or(-1), this->det_min2_.value_or(-1),
this->det_max2_.value_or(-1), this->det_min3_.value_or(-1), this->det_max3_.value_or(-1),
this->det_min4_.value_or(-1), this->det_max4_.value_or(-1)));
}
}
if (this->delay_after_detect_.has_value() && this->delay_after_disappear_.has_value()) {
@@ -1,57 +0,0 @@
import esphome.codegen as cg
from esphome.components import button
from esphome.components.const import CONF_QUERY_PARAMS
import esphome.config_validation as cv
from esphome.const import (
CONF_FACTORY_RESET,
CONF_ID,
CONF_RESTART,
DEVICE_CLASS_RESTART,
ENTITY_CATEGORY_CONFIG,
ENTITY_CATEGORY_DIAGNOSTIC,
ICON_DATABASE,
ICON_RESTART,
ICON_RESTART_ALERT,
)
from esphome.types import ConfigType
from .. import CONF_DFROBOT_SEN0609_ID, DFRobotSEN0609Component, dfrobot_sen0609_ns
DFRobotSEN0609Button = dfrobot_sen0609_ns.class_("DFRobotSEN0609Button", button.Button)
ButtonAction = dfrobot_sen0609_ns.enum("ButtonAction")
CONFIG_SCHEMA = {
cv.GenerateID(CONF_ID): cv.declare_id(cg.EntityBase),
cv.GenerateID(CONF_DFROBOT_SEN0609_ID): cv.use_id(DFRobotSEN0609Component),
cv.Optional(CONF_FACTORY_RESET): button.button_schema(
DFRobotSEN0609Button,
device_class=DEVICE_CLASS_RESTART,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_RESTART_ALERT,
),
cv.Optional(CONF_QUERY_PARAMS): button.button_schema(
DFRobotSEN0609Button,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
icon=ICON_DATABASE,
),
cv.Optional(CONF_RESTART): button.button_schema(
DFRobotSEN0609Button,
device_class=DEVICE_CLASS_RESTART,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
icon=ICON_RESTART,
),
}
async def to_code(config: ConfigType) -> None:
hub = await cg.get_variable(config[CONF_DFROBOT_SEN0609_ID])
buttons = button.sub_buttons(config, parent=hub)
await buttons(
CONF_FACTORY_RESET,
hub.set_factory_reset_button,
ButtonAction.BUTTON_FACTORY_RESET,
)
await buttons(
CONF_QUERY_PARAMS, hub.set_query_button, ButtonAction.BUTTON_QUERY_PARAMS
)
await buttons(CONF_RESTART, hub.set_restart_button, ButtonAction.BUTTON_RESTART)
@@ -1,30 +0,0 @@
#pragma once
#include "esphome/components/button/button.h"
#include "../dfrobot_sen0609.h"
namespace esphome::dfrobot_sen0609 {
class DFRobotSEN0609Button final : public button::Button, public Parented<DFRobotSEN0609Component> {
public:
explicit DFRobotSEN0609Button(ButtonAction action) : action_(action) {}
protected:
void press_action() override {
switch (this->action_) {
case BUTTON_RESTART:
this->parent_->restart();
break;
case BUTTON_FACTORY_RESET:
this->parent_->factory_reset();
break;
case BUTTON_QUERY_PARAMS:
this->parent_->query_params();
break;
}
}
ButtonAction action_;
};
} // namespace esphome::dfrobot_sen0609
@@ -21,9 +21,6 @@ static constexpr uint32_t COMMAND_GAP_MS = 100;
static constexpr uint32_t COALESCE_MS = 1000;
static constexpr uint32_t DEFAULT_TIMEOUT_MS = 1000;
static constexpr uint32_t LONG_TIMEOUT_MS = 2000;
static constexpr uint32_t FACTORY_RESET_TIMEOUT_MS = 3000;
// resetSystem has no answer; this is how long the module takes to boot again
static constexpr uint32_t RESTART_MS = 1500;
static constexpr uint32_t GIVE_UP_BACKOFF_MS = 30000;
// Presence frames come every second (setUartOutput period); this long without one means the module lost them
static constexpr uint32_t FRAME_TIMEOUT_MS = 10000;
@@ -116,10 +113,6 @@ static const LogString *operation_to_str(Operation operation) {
return LOG_STR("stop");
case Operation::OPERATION_START:
return LOG_STR("start");
case Operation::OPERATION_RESTART:
return LOG_STR("restart");
case Operation::OPERATION_FACTORY_RESET:
return LOG_STR("factory reset");
case Operation::OPERATION_WRITE:
return LOG_STR("write");
case Operation::OPERATION_SAVE:
@@ -168,11 +161,6 @@ void DFRobotSEN0609Component::dump_config() {
#ifdef USE_SELECT
LOG_SELECT(" ", "OutPinLevel", this->out_pin_level_select_);
#endif
#ifdef USE_BUTTON
LOG_BUTTON(" ", "FactoryReset", this->factory_reset_button_);
LOG_BUTTON(" ", "Query", this->query_button_);
LOG_BUTTON(" ", "Restart", this->restart_button_);
#endif
}
void DFRobotSEN0609Component::setup() {
@@ -448,21 +436,6 @@ void DFRobotSEN0609Component::request_write_(Param param) {
this->hold_(COALESCE_MS);
}
void DFRobotSEN0609Component::restart() {
this->restart_pending_ = true;
this->hold_(COMMAND_GAP_MS);
}
void DFRobotSEN0609Component::factory_reset() {
this->factory_reset_pending_ = true;
this->hold_(COMMAND_GAP_MS);
}
void DFRobotSEN0609Component::query_params() {
this->pending_reads_ |= this->wanted_reads_();
this->hold_(COMMAND_GAP_MS);
}
#ifdef USE_NUMBER
void DFRobotSEN0609Component::control_number(NumberSetting setting, float value) {
// The module needs min_range <= trigger_range <= max_range; a value not read yet is NAN and passes
@@ -538,42 +511,20 @@ void DFRobotSEN0609Component::hold_(uint32_t duration_ms) {
void DFRobotSEN0609Component::run_sequencer_() {
const uint32_t now = App.get_loop_component_start_time();
if (this->operation_ != Operation::OPERATION_NONE) {
uint32_t timeout = DEFAULT_TIMEOUT_MS;
switch (this->operation_) {
case Operation::OPERATION_RESTART:
timeout = RESTART_MS;
break;
case Operation::OPERATION_FACTORY_RESET:
timeout = FACTORY_RESET_TIMEOUT_MS;
break;
case Operation::OPERATION_STOP:
case Operation::OPERATION_SAVE:
timeout = LONG_TIMEOUT_MS;
break;
default:
break;
}
if (now - this->sent_ms_ < timeout)
const bool slow = this->operation_ == Operation::OPERATION_STOP || this->operation_ == Operation::OPERATION_SAVE;
if (now - this->sent_ms_ < (slow ? LONG_TIMEOUT_MS : DEFAULT_TIMEOUT_MS))
return;
if (this->operation_ == Operation::OPERATION_RESTART) {
this->finish_operation_();
} else {
ESP_LOGD(TAG, "No answer to '%s'", this->command_);
this->fail_operation_();
}
ESP_LOGD(TAG, "No answer to '%s'", this->command_);
this->fail_operation_();
return;
}
if (now - this->hold_start_ms_ < this->hold_ms_)
return;
const bool work_pending =
this->factory_reset_pending_ || this->save_pending_ || this->pending_writes_ != 0 || this->pending_reads_ != 0;
const bool work_pending = this->save_pending_ || this->pending_writes_ != 0 || this->pending_reads_ != 0;
Operation operation;
Param param = PARAM_COUNT;
if (this->restart_pending_) {
// The reboot drops a write the module took but did not save; writes not sent yet are kept for after it
operation = this->stopped_ && this->save_pending_ ? Operation::OPERATION_SAVE : Operation::OPERATION_RESTART;
} else if (!work_pending) {
if (!work_pending) {
if (!this->stopped_) {
this->check_frames_(now);
// Work given up on is tried again in a later sequence, so the sensor runs in between
@@ -588,8 +539,6 @@ void DFRobotSEN0609Component::run_sequencer_() {
operation = Operation::OPERATION_START;
} else if (!this->stopped_) {
operation = Operation::OPERATION_STOP;
} else if (this->factory_reset_pending_) {
operation = Operation::OPERATION_FACTORY_RESET;
} else if (this->pending_writes_ != 0) {
operation = Operation::OPERATION_WRITE;
param = static_cast<Param>(__builtin_ctz(this->pending_writes_));
@@ -662,12 +611,6 @@ bool DFRobotSEN0609Component::build_command_(Operation operation, Param param) {
case Operation::OPERATION_START:
ESPHOME_strncpy_P(buf, ESPHOME_PSTR("sensorStart"), len);
return true;
case Operation::OPERATION_RESTART:
ESPHOME_strncpy_P(buf, ESPHOME_PSTR("resetSystem"), len);
return true;
case Operation::OPERATION_FACTORY_RESET:
ESPHOME_strncpy_P(buf, ESPHOME_PSTR("resetCfg"), len);
return true;
case Operation::OPERATION_SAVE:
ESPHOME_strncpy_P(buf, ESPHOME_PSTR("saveConfig"), len);
return true;
@@ -842,16 +785,6 @@ void DFRobotSEN0609Component::finish_operation_() {
this->status_clear_warning();
this->sequence_failed_ = false;
break;
case Operation::OPERATION_RESTART:
// The module starts sensing on its own after a reboot
this->restart_pending_ = false;
this->stopped_ = false;
this->queue_configuration_();
break;
case Operation::OPERATION_FACTORY_RESET:
this->factory_reset_pending_ = false;
this->queue_configuration_();
break;
case Operation::OPERATION_WRITE:
this->deferred_writes_ &= ~param_bit(this->param_);
if (PERSISTENT_PARAMS & param_bit(this->param_))
@@ -913,12 +846,6 @@ void DFRobotSEN0609Component::fail_operation_() {
ESP_LOGW(TAG, "Giving up on %s '%s'", LOG_STR_ARG(operation_to_str(operation)), this->command_);
this->sequence_failed_ = true;
switch (operation) {
case Operation::OPERATION_RESTART:
this->restart_pending_ = false;
break;
case Operation::OPERATION_FACTORY_RESET:
this->factory_reset_pending_ = false;
break;
case Operation::OPERATION_WRITE:
#ifdef USE_SWITCH
if (is_led(this->param_)) {
@@ -21,9 +21,6 @@
#ifdef USE_SELECT
#include "esphome/components/select/select.h"
#endif
#ifdef USE_BUTTON
#include "esphome/components/button/button.h"
#endif
#include "esphome/components/uart/uart.h"
#include <array>
@@ -61,12 +58,6 @@ enum SwitchSetting : uint8_t {
SWITCH_COUNT,
};
enum ButtonAction : uint8_t {
BUTTON_RESTART,
BUTTON_FACTORY_RESET,
BUTTON_QUERY_PARAMS,
};
/// Module parameters; a write or read of each is one command. Pending work runs in this order.
enum Param : uint8_t {
PARAM_RUN_APP,
@@ -90,8 +81,6 @@ enum class Operation : uint8_t {
OPERATION_NONE,
OPERATION_STOP,
OPERATION_START,
OPERATION_RESTART,
OPERATION_FACTORY_RESET,
OPERATION_WRITE,
OPERATION_SAVE,
OPERATION_READ,
@@ -113,11 +102,6 @@ class DFRobotSEN0609Component final : public Component, public uart::UARTDevice
#ifdef USE_SELECT
SUB_SELECT(out_pin_level)
#endif
#ifdef USE_BUTTON
SUB_BUTTON(factory_reset)
SUB_BUTTON(query)
SUB_BUTTON(restart)
#endif
public:
explicit DFRobotSEN0609Component(RunMode mode);
@@ -137,12 +121,6 @@ class DFRobotSEN0609Component final : public Component, public uart::UARTDevice
#ifdef USE_SELECT
void control_out_pin_level(size_t index);
#endif
/// Reboot the module, then apply the configuration and read the settings again.
void restart();
/// Restore the module's factory settings, then apply the configuration and read the settings again.
void factory_reset();
/// Read all settings shown by entities from the module.
void query_params();
protected:
void readline_(uint8_t c);
@@ -229,8 +207,6 @@ class DFRobotSEN0609Component final : public Component, public uart::UARTDevice
bool stopped_{false};
bool save_pending_{false};
bool deferred_save_{false};
bool restart_pending_{false};
bool factory_reset_pending_{false};
bool sequence_failed_{false};
};
+4 -1
View File
@@ -35,13 +35,16 @@ void DHT12Component::update() {
void DHT12Component::setup() {
uint8_t data[5];
if (!this->read_data_(data)) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->mark_failed();
return;
}
}
void DHT12Component::dump_config() {
ESP_LOGD(TAG, "DHT12:");
LOG_I2C_DEVICE(this);
if (this->is_failed()) {
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
}
LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
LOG_SENSOR(" ", "Humidity", this->humidity_sensor_);
}
+11 -50
View File
@@ -57,17 +57,17 @@ void Display::line_at_angle(int x, int y, int angle, int start_radius, int stop_
// -Os stops inlining it once there are two call sites, which costs a call and
// spills per pixel. Without PSRAM there is one call site and it changes
// nothing, and draw_pixel_at() stays a virtual call either way.
// HIGH_BYTE_FIRST (big endian) only matters for 565; as a template argument its test leaves the pixel loop.
template<ColorBitness BITNESS, bool HIGH_BYTE_FIRST = false>
static void __attribute__((flatten)) draw_packed_pixels(Display *display, int x_start, int y_start, int w, int h,
const uint8_t *ptr, int x_offset, int y_offset, int x_pad) {
template<ColorBitness BITNESS>
static void __attribute__((flatten))
draw_packed_pixels(Display *display, int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorOrder order,
bool big_endian, int x_offset, int y_offset, int x_pad) {
const size_t line_stride = x_offset + w + x_pad; // length of each source line in pixels
// BITNESS is a constant here, so to_color()'s three per pixel divisions
// become a multiply and shift and its bitness switch folds.
const auto draw_source_pixel = [&](int x, int y, size_t source_idx) ESPHOME_ALWAYS_INLINE {
display->draw_pixel_at(
x + x_start, y + y_start,
ColorUtil::to_color(ColorUtil::read_packed<BITNESS>(ptr, source_idx, HIGH_BYTE_FIRST), BITNESS));
ColorUtil::to_color(ColorUtil::read_packed<BITNESS>(ptr, source_idx, big_endian), order, BITNESS));
};
// The source and frame buffers are row-major, so walking rows keeps the read
// and the write sequential. When the display swaps the axes before writing,
@@ -94,59 +94,20 @@ static void __attribute__((flatten)) draw_packed_pixels(Display *display, int x_
}
}
// Remove before 2027.5.0. Draws a block in the deprecated BGR or GRB order, pixel by pixel. Not inlined, so
// the RGB loops above compile as tightly as before.
static void __attribute__((noinline))
draw_ordered_pixels(Display *display, int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorOrder order,
ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) {
const size_t line_stride = x_offset + w + x_pad;
for (int y = 0; y != h; y++) {
size_t source_idx = (y_offset + y) * line_stride + x_offset;
for (int x = 0; x != w; x++, source_idx++) {
uint32_t code;
if (bitness == COLOR_BITNESS_565) {
code = ColorUtil::read_packed<COLOR_BITNESS_565>(ptr, source_idx, big_endian);
} else if (bitness == COLOR_BITNESS_888) {
code = ColorUtil::read_packed<COLOR_BITNESS_888>(ptr, source_idx, big_endian);
} else {
code = ColorUtil::read_packed<COLOR_BITNESS_332>(ptr, source_idx, big_endian);
}
display->draw_pixel_at(x + x_start, y + y_start, apply_color_order(ColorUtil::to_color(code, bitness), order));
}
}
}
void Display::draw_pixels_internal(int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorBitness bitness,
bool big_endian, int x_offset, int y_offset, int x_pad) {
// Through the deprecated form, so a driver that still overrides only that one keeps its fast path.
// Remove before 2027.5.0, when the per pixel drawing below moves here.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
this->draw_pixels_at(x_start, y_start, w, h, ptr, COLOR_ORDER_RGB, bitness, big_endian, x_offset, y_offset, x_pad);
#pragma GCC diagnostic pop
}
// Must not call draw_pixels_at() without a color order or draw_pixels_internal(): those call this, and a legacy
// override's fallback ends up here.
void Display::draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorOrder order,
ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) {
if (order != COLOR_ORDER_RGB) {
draw_ordered_pixels(this, x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset, x_pad);
return;
}
switch (bitness) {
case COLOR_BITNESS_565:
if (big_endian) {
draw_packed_pixels<COLOR_BITNESS_565, true>(this, x_start, y_start, w, h, ptr, x_offset, y_offset, x_pad);
} else {
draw_packed_pixels<COLOR_BITNESS_565, false>(this, x_start, y_start, w, h, ptr, x_offset, y_offset, x_pad);
}
draw_packed_pixels<COLOR_BITNESS_565>(this, x_start, y_start, w, h, ptr, order, big_endian, x_offset, y_offset,
x_pad);
break;
case COLOR_BITNESS_888:
draw_packed_pixels<COLOR_BITNESS_888>(this, x_start, y_start, w, h, ptr, x_offset, y_offset, x_pad);
draw_packed_pixels<COLOR_BITNESS_888>(this, x_start, y_start, w, h, ptr, order, big_endian, x_offset, y_offset,
x_pad);
break;
default:
draw_packed_pixels<COLOR_BITNESS_332>(this, x_start, y_start, w, h, ptr, x_offset, y_offset, x_pad);
draw_packed_pixels<COLOR_BITNESS_332>(this, x_start, y_start, w, h, ptr, order, big_endian, x_offset, y_offset,
x_pad);
break;
}
}
+6 -40
View File
@@ -346,6 +346,8 @@ class Display : public PollingComponent {
virtual void draw_pixel_at(int x, int y, Color color) = 0;
/** Given an array of pixels encoded in the nominated format, draw these into the display's buffer.
* The naive implementation here will work in all cases, but can be overridden by sub-classes
* in order to optimise the procedure.
* The parameters describe a rectangular block of pixels, potentially within a larger buffer.
*
* \param x_start The starting destination x position
@@ -353,49 +355,23 @@ class Display : public PollingComponent {
* \param w the width of the pixel block
* \param h the height of the pixel block
* \param ptr A pointer to the start of the data to be copied
* \param bitness Defines the number of bits and their format for each pixel. Red is always in the
* most significant bits.
* \param order The ordering of the colors
* \param bitness Defines the number of bits and their format for each pixel
* \param big_endian True if 16 bit values are stored big-endian. Ignored for 888, which is always b,g,r
* in memory, as LVGL and ESPHome images store it.
* in memory for RGB order, as LVGL and ESPHome images store it.
* \param x_offset The initial x-offset into the source buffer.
* \param y_offset The initial y-offset into the source buffer.
* \param x_pad How many pixels are in each line after the end of the pixels to be copied.
*
* The length of each source buffer line (stride) will be x_offset + w + x_pad.
* The block must lie on the screen. A driver that can copy blocks itself overrides draw_pixels_internal().
*/
void draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorBitness bitness, bool big_endian,
int x_offset, int y_offset, int x_pad) {
this->draw_pixels_internal(x_start, y_start, w, h, ptr, bitness, big_endian, x_offset, y_offset, x_pad);
}
/// Convenience overload for base case where the pixels are packed into the buffer with no gaps (e.g. suits LVGL.)
void draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorBitness bitness,
bool big_endian) {
this->draw_pixels_internal(x_start, y_start, w, h, ptr, bitness, big_endian, 0, 0, 0);
}
// Remove before 2027.5.0
/// The block form above with a color order. The base version draws per pixel and honors the order;
/// a driver that still overrides this one keeps receiving every block, since draw_pixels_internal() calls it.
/// Such a driver needs `using display::Display::draw_pixels_at;` so the forms above stay visible through it,
/// and its fallback must call Display::draw_pixels_at() with the order: Display::draw_pixels_internal() would
/// call the override again.
ESPDEPRECATED(
"Pixels are always RGB: call draw_pixels_at() without the ColorOrder, and override draw_pixels_internal() "
"to copy blocks. Removed in 2027.5.0",
"2026.11.0")
virtual void draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorOrder order,
ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad);
// Remove before 2027.5.0
ESPDEPRECATED("Pixels are always RGB, drop the ColorOrder argument. Removed in 2027.5.0", "2026.11.0")
/// Convenience overload for base case where the pixels are packed into the buffer with no gaps (e.g. suits LVGL.)
void draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorOrder order,
ColorBitness bitness, bool big_endian) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
this->draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, 0, 0, 0);
#pragma GCC diagnostic pop
}
/// Draw a straight line from the point [x1,y1] to [x2,y2] with the given color.
@@ -816,16 +792,6 @@ class Display : public PollingComponent {
void show_test_card() { this->show_test_card_ = true; }
protected:
/** Draws a block for draw_pixels_at(); the parameters are the same. The base version draws it per pixel
* through draw_pixel_at(), so it works on any display.
*
* A driver can override it to copy blocks that are already laid out the way its own draw_pixel_at()
* writes, and must send any other format, byte order, a software rotation or an active clipping
* rectangle through Display::draw_pixels_internal(), which draws per pixel. Do not also override the
* deprecated draw_pixels_at() with a color order: Display::draw_pixels_internal() calls it.
*/
virtual void draw_pixels_internal(int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorBitness bitness,
bool big_endian, int x_offset, int y_offset, int x_pad);
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);
void vprintf_(int x, int y, BaseFont *font, Color color, Color background, TextAlign align, const char *format,
+78 -102
View File
@@ -9,38 +9,6 @@ enum ColorOrder : uint8_t { COLOR_ORDER_RGB = 0, COLOR_ORDER_BGR = 1, COLOR_ORDE
enum ColorBitness : uint8_t { COLOR_BITNESS_888 = 0, COLOR_BITNESS_565 = 1, COLOR_BITNESS_332 = 2 };
inline static uint8_t esp_scale(uint8_t i, uint8_t scale, uint8_t max_value = 255) { return (max_value * i / scale); }
/// esp_scale(value, (1 << bits) - 1) for a field of 2, 3, 5, 6 or 8 bits, as a multiply and shift that gives the
/// same result for every field value. With bits a constant this avoids a division.
constexpr uint8_t expand_field(uint8_t value, uint8_t bits) {
switch (bits) {
case 2:
return (value * 170) >> 1;
case 3:
return (value * 583) >> 4;
case 5:
return (value * 1053) >> 7;
case 6:
return (value * 4145) >> 10;
case 8:
return value;
default:
return esp_scale(value, (1 << bits) - 1);
}
}
// Remove before 2027.5.0, with the forms that take a color order. Maps a color read in RGB order to the
// given order, by moving its channels.
inline Color apply_color_order(Color color, ColorOrder order) {
switch (order) {
case COLOR_ORDER_BGR:
return Color(color.b, color.g, color.r);
case COLOR_ORDER_GRB:
return Color(color.g, color.r, color.b);
default:
return color;
}
}
class ColorUtil {
public:
/// Reads one packed pixel of the given bitness from a source buffer into the
@@ -55,7 +23,7 @@ class ColorUtil {
return (ptr[idx] << 8) + ptr[idx + 1];
return ptr[idx] + (ptr[idx + 1] << 8);
} else if constexpr (BITNESS == COLOR_BITNESS_888) {
// Always the LVGL RGB888 layout, b,g,r in memory; byte order applies to 565 only
// Always the LVGL RGB888 layout, b,g,r in memory for RGB order; byte order applies to 565 only
const size_t idx = index * 3;
return ptr[idx + 0] + (ptr[idx + 1] << 8) + (ptr[idx + 2] << 16);
} else {
@@ -63,9 +31,9 @@ class ColorUtil {
}
}
/// Unpacks a color of the given bitness, red in the most significant bits.
static Color to_color(uint32_t colorcode, ColorBitness color_bitness = ColorBitness::COLOR_BITNESS_888,
bool right_bit_aligned = true) {
static Color to_color(uint32_t colorcode, ColorOrder color_order,
ColorBitness color_bitness = ColorBitness::COLOR_BITNESS_888, bool right_bit_aligned = true) {
uint8_t first_color, second_color, third_color;
uint8_t first_bits = 0;
uint8_t second_bits = 0;
uint8_t third_bits = 0;
@@ -88,66 +56,74 @@ class ColorUtil {
break;
}
const uint8_t red =
right_bit_aligned
? expand_field((colorcode >> (second_bits + third_bits)) & ((1 << first_bits) - 1), first_bits)
: esp_scale(((colorcode >> 16) & 0xFF), (1 << first_bits) - 1);
first_color = right_bit_aligned ? esp_scale(((colorcode >> (second_bits + third_bits)) & ((1 << first_bits) - 1)),
((1 << first_bits) - 1))
: esp_scale(((colorcode >> 16) & 0xFF), (1 << first_bits) - 1);
const uint8_t green = right_bit_aligned
? expand_field((colorcode >> third_bits) & ((1 << second_bits) - 1), second_bits)
: esp_scale(((colorcode >> 8) & 0xFF), ((1 << second_bits) - 1));
second_color = right_bit_aligned
? esp_scale(((colorcode >> third_bits) & ((1 << second_bits) - 1)), ((1 << second_bits) - 1))
: esp_scale(((colorcode >> 8) & 0xFF), ((1 << second_bits) - 1));
const uint8_t blue = right_bit_aligned ? expand_field(colorcode & ((1 << third_bits) - 1), third_bits)
: esp_scale(((colorcode >> 0) & 0xFF), (1 << third_bits) - 1);
third_color = (right_bit_aligned ? esp_scale(((colorcode >> 0) & ((1 << third_bits) - 1)), ((1 << third_bits) - 1))
: esp_scale(((colorcode >> 0) & 0xFF), (1 << third_bits) - 1));
return Color(red, green, blue);
}
// Remove before 2027.5.0
ESPDEPRECATED("Packed colors are always RGB, drop the ColorOrder argument. Removed in 2027.5.0", "2026.11.0")
static Color to_color(uint32_t colorcode, ColorOrder color_order,
ColorBitness color_bitness = ColorBitness::COLOR_BITNESS_888, bool right_bit_aligned = true) {
return apply_color_order(to_color(colorcode, color_bitness, right_bit_aligned), color_order);
Color color_return;
switch (color_order) {
case COLOR_ORDER_RGB:
color_return.r = first_color;
color_return.g = second_color;
color_return.b = third_color;
break;
case COLOR_ORDER_BGR:
color_return.b = first_color;
color_return.g = second_color;
color_return.r = third_color;
break;
case COLOR_ORDER_GRB:
color_return.g = first_color;
color_return.r = second_color;
color_return.b = third_color;
break;
}
return color_return;
}
static inline Color rgb332_to_color(uint8_t rgb332_color) {
return to_color((uint32_t) rgb332_color, COLOR_BITNESS_332);
return to_color((uint32_t) rgb332_color, COLOR_ORDER_RGB, COLOR_BITNESS_332);
}
static uint8_t color_to_332(Color color) {
const uint16_t red_color = esp_scale8(color.red, ((1 << 3) - 1));
const uint16_t green_color = esp_scale8(color.green, ((1 << 3) - 1));
const uint16_t blue_color = esp_scale8(color.blue, (1 << 2) - 1);
return red_color << 5 | green_color << 2 | blue_color;
}
// Remove before 2027.5.0
ESPDEPRECATED("Packed colors are always RGB, drop the ColorOrder argument. Removed in 2027.5.0", "2026.11.0")
static uint8_t color_to_332(Color color, ColorOrder color_order) {
if (color_order == COLOR_ORDER_RGB)
return color_to_332(color);
// The other orders move the 2 bit field, so they cannot reuse the RGB packing
const uint16_t red_color = esp_scale8(color.red, ((1 << 3) - 1));
const uint16_t green_color = esp_scale8(color.green, ((1 << 3) - 1));
if (color_order == COLOR_ORDER_BGR)
return esp_scale8(color.blue, (1 << 2) - 1) << 6 | green_color << 3 | red_color;
return green_color << 5 | red_color << 2 | esp_scale8(color.blue, (1 << 2) - 1);
}
static uint16_t color_to_565(Color color) {
const uint16_t red_color = esp_scale8(color.red, ((1 << 5) - 1));
const uint16_t green_color = esp_scale8(color.green, ((1 << 6) - 1));
const uint16_t blue_color = esp_scale8(color.blue, (1 << 5) - 1);
return red_color << 11 | green_color << 5 | blue_color;
}
// Remove before 2027.5.0
ESPDEPRECATED("Packed colors are always RGB, drop the ColorOrder argument. Removed in 2027.5.0", "2026.11.0")
static uint16_t color_to_565(Color color, ColorOrder color_order) {
static uint8_t color_to_332(Color color, ColorOrder color_order = ColorOrder::COLOR_ORDER_RGB) {
uint16_t red_color, green_color, blue_color;
red_color = esp_scale8(color.red, ((1 << 3) - 1));
green_color = esp_scale8(color.green, ((1 << 3) - 1));
blue_color = esp_scale8(color.blue, (1 << 2) - 1);
switch (color_order) {
case COLOR_ORDER_RGB:
return red_color << 5 | green_color << 2 | blue_color;
case COLOR_ORDER_BGR:
return color_to_565(Color(color.b, color.g, color.r));
return blue_color << 6 | green_color << 3 | red_color;
case COLOR_ORDER_GRB:
// Green moves to the 5 bit field at the top, so it cannot reuse the RGB packing
return esp_scale8(color.green, (1 << 6) - 1) << 10 | esp_scale8(color.red, (1 << 5) - 1) << 5 |
esp_scale8(color.blue, (1 << 5) - 1);
default:
return color_to_565(color);
return green_color << 5 | red_color << 2 | blue_color;
}
return 0;
}
static uint16_t color_to_565(Color color, ColorOrder color_order = ColorOrder::COLOR_ORDER_RGB) {
uint16_t red_color, green_color, blue_color;
red_color = esp_scale8(color.red, ((1 << 5) - 1));
green_color = esp_scale8(color.green, ((1 << 6) - 1));
blue_color = esp_scale8(color.blue, (1 << 5) - 1);
switch (color_order) {
case COLOR_ORDER_RGB:
return red_color << 11 | green_color << 5 | blue_color;
case COLOR_ORDER_BGR:
return blue_color << 11 | green_color << 5 | red_color;
case COLOR_ORDER_GRB:
return green_color << 10 | red_color << 5 | blue_color;
}
return 0;
}
static uint32_t color_to_grayscale4(Color color) {
uint32_t gs4 = esp_scale8(color.white, 15);
@@ -220,23 +196,17 @@ constexpr uint8_t color_to_mono(Color color) { return rec601_luma(color) >= 128
*/
class Rgb565ToMono {
public:
Rgb565ToMono() { this->fill_tables_(REC601_LUMA_R, REC601_LUMA_G, REC601_LUMA_B); }
// Remove before 2027.5.0
ESPDEPRECATED("Packed colors are always RGB, drop the ColorOrder argument. Removed in 2027.5.0", "2026.11.0")
explicit Rgb565ToMono(ColorOrder order) {
// The weight of the channel each 5, 6 and 5 bit field holds in this order
const Color weights = apply_color_order(Color(REC601_LUMA_R, REC601_LUMA_G, REC601_LUMA_B), order);
this->fill_tables_(weights.r, weights.g, weights.b);
}
uint8_t operator()(uint16_t value) const {
const uint32_t weighted = this->high_[value >> 11] + this->middle_[(value >> 5) & 0x3F] + this->low_[value & 0x1F];
return ((weighted + 128u) >> 8) >= 128 ? 1 : 0;
}
protected:
// Each field value scaled to 0..255, then weighted
void fill_tables_(uint16_t high, uint16_t middle, uint16_t low) {
// Rec.601 weight of the 5-bit, 6-bit and 5-bit fields, by the channel each one holds in this order
uint16_t high = REC601_LUMA_R, middle = REC601_LUMA_G, low = REC601_LUMA_B;
if (order == COLOR_ORDER_BGR) {
high = REC601_LUMA_B;
low = REC601_LUMA_R;
} else if (order == COLOR_ORDER_GRB) {
high = REC601_LUMA_G;
middle = REC601_LUMA_R;
}
// Each field value scaled to 0..255, then weighted
for (unsigned i = 0; i != 32; i++) {
this->high_[i] = high * esp_scale(i, 31);
this->low_[i] = low * esp_scale(i, 31);
@@ -245,6 +215,12 @@ class Rgb565ToMono {
this->middle_[i] = middle * esp_scale(i, 63);
}
uint8_t operator()(uint16_t value) const {
const uint32_t weighted = this->high_[value >> 11] + this->middle_[(value >> 5) & 0x3F] + this->low_[value & 0x1F];
return ((weighted + 128u) >> 8) >= 128 ? 1 : 0;
}
protected:
// Weighted contribution of each value of each field
std::array<uint16_t, 32> high_{};
std::array<uint16_t, 64> middle_{};
+21 -15
View File
@@ -9,17 +9,13 @@ ESPHOME_LOG_TAG(TAG, "dps310");
static constexpr uint32_t READ_RETRY_TIMEOUT_ID = 0;
void DPS310Component::setup() {
if (!this->setup_registers_())
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
}
bool DPS310Component::setup_registers_() {
uint8_t coef_data_raw[DPS310_NUM_COEF_REGS];
auto timer = DPS310_INIT_TIMEOUT;
uint8_t reg = 0;
// first, reset the sensor
if (!this->write_byte(DPS310_REG_RESET, DPS310_CMD_RESET)) {
return false;
this->mark_failed();
return;
}
delay(10);
// wait for the sensor and its coefficients to be ready
@@ -29,32 +25,40 @@ bool DPS310Component::setup_registers_() {
}
if (!(reg & DPS310_BIT_SENSOR_RDY) || !(reg & DPS310_BIT_COEF_RDY)) { // the flags were not set in time
return false;
this->mark_failed();
return;
}
// read device ID
if (!this->read_byte(DPS310_REG_PROD_REV_ID, &this->prod_rev_id_)) {
return false;
this->mark_failed();
return;
}
// read in coefficients used to calculate the compensated pressure and temperature values
if (!this->read_bytes(DPS310_REG_COEF, coef_data_raw, DPS310_NUM_COEF_REGS)) {
return false;
this->mark_failed();
return;
}
// read in coefficients source register, too -- we need this a few lines down
if (!this->read_byte(DPS310_REG_TMP_COEF_SRC, &reg)) {
return false;
this->mark_failed();
return;
}
// set up operational stuff
if (!this->write_byte(DPS310_REG_PRS_CFG, DPS310_VAL_PRS_CFG)) {
return false;
this->mark_failed();
return;
}
if (!this->write_byte(DPS310_REG_TMP_CFG, DPS310_VAL_TMP_CFG | (reg & DPS310_BIT_TMP_COEF_SRC))) {
return false;
this->mark_failed();
return;
}
if (!this->write_byte(DPS310_REG_CFG, DPS310_VAL_REG_CFG)) {
return false;
this->mark_failed();
return;
}
if (!this->write_byte(DPS310_REG_MEAS_CFG, 0x07)) { // enable background mode
return false;
this->mark_failed();
return;
}
this->c0_ = // we only ever use c0/2, so just divide by 2 here to save time later
@@ -78,7 +82,6 @@ bool DPS310Component::setup_registers_() {
this->c20_ = int16_t(((uint16_t) coef_data_raw[12] << 8) | (uint16_t) coef_data_raw[13]);
this->c21_ = int16_t(((uint16_t) coef_data_raw[14] << 8) | (uint16_t) coef_data_raw[15]);
this->c30_ = int16_t(((uint16_t) coef_data_raw[16] << 8) | (uint16_t) coef_data_raw[17]);
return true;
}
void DPS310Component::dump_config() {
@@ -88,6 +91,9 @@ void DPS310Component::dump_config() {
" Revision ID: %u",
this->prod_rev_id_ & 0x0F, (this->prod_rev_id_ >> 4) & 0x0F);
LOG_I2C_DEVICE(this);
if (this->is_failed()) {
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
}
LOG_UPDATE_INTERVAL(this);
LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
LOG_SENSOR(" ", "Pressure", this->pressure_sensor_);
-2
View File
@@ -45,8 +45,6 @@ class DPS310Component final : public PollingComponent, public i2c::I2CDevice {
void set_pressure_sensor(sensor::Sensor *pressure_sensor) { pressure_sensor_ = pressure_sensor; }
protected:
/// Configure the sensor; false on a failure.
bool setup_registers_();
void read_();
void read_pressure_();
void read_temperature_();
+4 -1
View File
@@ -10,7 +10,7 @@ ESPHOME_LOG_TAG(TAG, "ds1307");
void DS1307Component::setup() {
if (!this->read_rtc_()) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->mark_failed();
}
}
@@ -19,6 +19,9 @@ void DS1307Component::update() { this->read_time(); }
void DS1307Component::dump_config() {
ESP_LOGCONFIG(TAG, "DS1307:");
LOG_I2C_DEVICE(this);
if (this->is_failed()) {
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
}
RealTimeClock::dump_config();
}
+4
View File
@@ -29,6 +29,10 @@ void DS3231Component::setup() {
void DS3231Component::dump_config() {
ESP_LOGCONFIG(TAG, "DS3231:");
LOG_I2C_DEVICE(this);
if (this->is_failed()) {
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
return;
}
}
bool DS3231Component::read_temperature(float &out) {
+4 -1
View File
@@ -60,7 +60,7 @@ void Emc2101Component::setup() {
uint8_t chip_id = reg(EMC2101_REGISTER_WHOAMI).get();
if ((chip_id != EMC2101_CHIP_ID) && (chip_id != EMC2101_ALT_CHIP_ID)) {
ESP_LOGE(TAG, "Wrong chip ID %02X", chip_id);
this->mark_failed(LOG_STR("Wrong chip ID"));
this->mark_failed();
return;
}
@@ -90,6 +90,9 @@ void Emc2101Component::setup() {
void Emc2101Component::dump_config() {
ESP_LOGCONFIG(TAG, "Emc2101 component:");
LOG_I2C_DEVICE(this);
if (this->is_failed()) {
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
}
ESP_LOGCONFIG(TAG, " Mode: %s", this->dac_mode_ ? LOG_STR_LITERAL("DAC") : LOG_STR_LITERAL("PWM"));
if (this->dac_mode_) {
ESP_LOGCONFIG(TAG, " DAC Conversion Rate: %X", this->dac_conversion_rate_);
+49 -15
View File
@@ -62,17 +62,20 @@ void ENS160Component::setup() {
// check part_id
uint16_t part_id;
if (!this->read_bytes(ENS160_REG_PART_ID, reinterpret_cast<uint8_t *>(&part_id), 2)) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->error_code_ = COMMUNICATION_FAILED;
this->mark_failed();
return;
}
if (part_id != ENS160_PART_ID) {
this->mark_failed(LOG_STR("Sensor reported an invalid ID. Is this a ENS160?"));
this->error_code_ = INVALID_ID;
this->mark_failed();
return;
}
// set mode to reset
if (!this->write_byte(ENS160_REG_OPMODE, ENS160_OPMODE_RESET)) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->error_code_ = WRITE_FAILED;
this->mark_failed();
return;
}
delay(ENS160_BOOTING);
@@ -80,44 +83,51 @@ void ENS160Component::setup() {
// check status
uint8_t status_value;
if (!this->read_byte(ENS160_REG_DATA_STATUS, &status_value)) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->error_code_ = READ_FAILED;
this->mark_failed();
return;
}
this->validity_flag_ = static_cast<ValidityFlag>((ENS160_DATA_STATUS_VALIDITY & status_value) >> 2);
if (this->validity_flag_ == INVALID_OUTPUT) {
this->mark_failed(LOG_STR("Invalid Device Status - No valid output"));
this->error_code_ = VALIDITY_INVALID;
this->mark_failed();
return;
}
// set mode to idle
if (!this->write_byte(ENS160_REG_OPMODE, ENS160_OPMODE_IDLE)) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->error_code_ = WRITE_FAILED;
this->mark_failed();
return;
}
delay(ENS160_BOOTING);
// clear command
if (!this->write_byte(ENS160_REG_COMMAND, ENS160_COMMAND_NOP)) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->error_code_ = WRITE_FAILED;
this->mark_failed();
return;
}
if (!this->write_byte(ENS160_REG_COMMAND, ENS160_COMMAND_CLRGPR)) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->error_code_ = WRITE_FAILED;
this->mark_failed();
return;
}
delay(ENS160_BOOTING);
// read firmware version
if (!this->write_byte(ENS160_REG_COMMAND, ENS160_COMMAND_GET_APPVER)) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->error_code_ = WRITE_FAILED;
this->mark_failed();
return;
}
delay(ENS160_BOOTING);
uint8_t version_data[3];
if (!this->read_bytes(ENS160_REG_GPR_READ_4, version_data, 3)) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->error_code_ = READ_FAILED;
this->mark_failed();
return;
}
this->firmware_ver_major_ = version_data[0];
@@ -126,19 +136,22 @@ void ENS160Component::setup() {
// set mode to standard
if (!this->write_byte(ENS160_REG_OPMODE, ENS160_OPMODE_STD)) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->error_code_ = WRITE_FAILED;
this->mark_failed();
return;
}
// read opmode and check standard mode is achieved before finishing Setup
uint8_t op_mode;
if (!this->read_byte(ENS160_REG_OPMODE, &op_mode)) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->error_code_ = READ_FAILED;
this->mark_failed();
return;
}
if (op_mode != ENS160_OPMODE_STD) {
this->mark_failed(LOG_STR("Device failed to achieve Standard Operating Mode"));
this->error_code_ = STD_OPMODE_FAILED;
this->mark_failed();
return;
}
}
@@ -278,8 +291,29 @@ void ENS160Component::send_env_data_() {
void ENS160Component::dump_config() {
ESP_LOGCONFIG(TAG, "ENS160:");
if (!this->is_failed()) {
ESP_LOGD(TAG, "Setup successful");
switch (this->error_code_) {
case COMMUNICATION_FAILED:
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
break;
case READ_FAILED:
ESP_LOGE(TAG, "Error reading from register");
break;
case WRITE_FAILED:
ESP_LOGE(TAG, "Error writing to register");
break;
case INVALID_ID:
ESP_LOGE(TAG, "Sensor reported an invalid ID. Is this a ENS160?");
break;
case VALIDITY_INVALID:
ESP_LOGE(TAG, "Invalid Device Status - No valid output");
break;
case STD_OPMODE_FAILED:
ESP_LOGE(TAG, "Device failed to achieve Standard Operating Mode");
break;
case NONE:
ESP_LOGD(TAG, "Setup successful");
break;
}
ESP_LOGI(TAG, "Firmware Version: %d.%d.%d", this->firmware_ver_major_, this->firmware_ver_minor_,
this->firmware_ver_build_);
@@ -21,6 +21,16 @@ class ENS160Component : public PollingComponent, public sensor::Sensor {
protected:
void send_env_data_();
enum ErrorCode {
NONE = 0,
COMMUNICATION_FAILED,
INVALID_ID,
VALIDITY_INVALID,
READ_FAILED,
WRITE_FAILED,
STD_OPMODE_FAILED,
} error_code_{NONE};
enum ValidityFlag {
NORMAL_OPERATION = 0,
WARMING_UP,
+13 -7
View File
@@ -55,6 +55,8 @@ static const LogString *ens210_status_to_human(int status) {
return LOG_STR("Invalid data");
case ENS210Component::ENS210_STATUS_OK:
return LOG_STR("Status OK");
case ENS210Component::ENS210_WRONG_CHIP_ID:
return LOG_STR("ENS210 has wrong chip ID! Is it a ENS210?");
default:
return LOG_STR("Unknown");
}
@@ -91,7 +93,8 @@ void ENS210Component::setup() {
// Reset
if (!this->write_byte(ENS210_REGISTER_SYS_CTRL, 0x80)) {
this->write_byte(ENS210_REGISTER_SYS_CTRL, 0x80);
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->error_code_ = ENS210_STATUS_I2C_ERROR;
this->mark_failed();
return;
}
// Wait to boot after reset
@@ -100,24 +103,24 @@ void ENS210Component::setup() {
if (!set_low_power_(false)) {
// Try to go back to default mode (low power enabled)
set_low_power_(true);
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->error_code_ = ENS210_STATUS_I2C_ERROR;
this->mark_failed();
return;
}
// Read the PART_ID
if (!this->read_bytes(ENS210_REGISTER_PART_ID, data, 2)) {
// Try to go back to default mode (low power enabled)
set_low_power_(true);
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->error_code_ = ENS210_STATUS_I2C_ERROR;
this->mark_failed();
return;
}
// Pack bytes into partid
part_id = data[1] * 256U + data[0] * 1U;
// Check expected part id of the ENS210
if (part_id != ENS210_PART_ID) {
// Try to go back to default mode (low power enabled)
set_low_power_(true);
this->mark_failed(LOG_STR("Wrong chip ID"));
return;
this->error_code_ = ENS210_WRONG_CHIP_ID;
this->mark_failed();
}
// Set default power mode (low power enabled)
set_low_power_(true);
@@ -126,6 +129,9 @@ void ENS210Component::setup() {
void ENS210Component::dump_config() {
ESP_LOGCONFIG(TAG, "ENS210:");
LOG_I2C_DEVICE(this);
if (this->is_failed()) {
ESP_LOGE(TAG, "%s", LOG_STR_ARG(ens210_status_to_human(this->error_code_)));
}
LOG_UPDATE_INTERVAL(this);
LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
LOG_SENSOR(" ", "Humidity", this->humidity_sensor_);
+2 -1
View File
@@ -22,7 +22,8 @@ class ENS210Component final : public PollingComponent, public i2c::I2CDevice {
// not yet finished)
ENS210_STATUS_CRC_ERROR, // The value was read, but the CRC over the payload (valid and data) does not match
ENS210_STATUS_I2C_ERROR, // There was an I2C communication error
};
ENS210_WRONG_CHIP_ID // The read PART_ID is not the expected part id of the ENS210
} error_code_{ENS210_STATUS_OK};
protected:
bool set_low_power_(bool enable);
+6 -7
View File
@@ -399,7 +399,7 @@ void HOT write_rgb565_row(uint8_t *byte, uint8_t mask, int step, size_t row_widt
// Each source column maps to one buffer coordinate and each source row to the other, each moving by 1 per pixel, so
// the visible part of a block and its dirty area are worked out once for the whole block.
void HOT EPaperBase::draw_rgb565_block_(uint8_t *buffer, int x_start, int y_start, int w, int h, const uint8_t *ptr,
bool big_endian, int x_offset, int y_offset, int x_pad) {
ColorOrder order, bool big_endian, int x_offset, int y_offset, int x_pad) {
const bool swap = this->effective_transform_ & SWAP_XY;
const bool mirror_x = this->effective_transform_ & MIRROR_X;
const bool mirror_y = this->effective_transform_ & MIRROR_Y;
@@ -432,7 +432,7 @@ void HOT EPaperBase::draw_rgb565_block_(uint8_t *buffer, int x_start, int y_star
const int x_high = x_low + (swap ? rows : columns);
const int y_high = y_low + (swap ? columns : rows);
const Rgb565ToMono to_mono;
const Rgb565ToMono to_mono(order);
const size_t line_stride = x_offset + w + x_pad;
const size_t row_width = this->row_width_;
const int step = column_mirrored ? -1 : 1;
@@ -464,17 +464,16 @@ void HOT EPaperBase::draw_rgb565_block_(uint8_t *buffer, int x_start, int y_star
// Writes an RGB565 block of pixels, as LVGL sends them, straight into a 1 bit per pixel buffer that is one block (the
// usual case): the same result as draw_pixel_at() for each pixel. Anything else goes through draw_pixel_at().
void HOT EPaperBase::draw_pixels_internal(int x_start, int y_start, int w, int h, const uint8_t *ptr,
ColorBitness bitness, bool big_endian, int x_offset, int y_offset,
int x_pad) {
void HOT EPaperBase::draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorOrder order,
ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) {
size_t contiguous_length;
uint8_t *contiguous = this->buffer_.get_span(0, contiguous_length);
if (!this->buffer_is_mono_() || this->get_clipping().is_set() || bitness != COLOR_BITNESS_565 ||
contiguous_length != this->buffer_length_) {
Display::draw_pixels_internal(x_start, y_start, w, h, ptr, bitness, big_endian, x_offset, y_offset, x_pad);
Display::draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset, x_pad);
return;
}
this->draw_rgb565_block_(contiguous, x_start, y_start, w, h, ptr, big_endian, x_offset, y_offset, x_pad);
this->draw_rgb565_block_(contiguous, x_start, y_start, w, h, ptr, order, big_endian, x_offset, y_offset, x_pad);
}
void EPaperBase::dump_config() {
+4 -5
View File
@@ -111,15 +111,14 @@ class EPaperBase : public Display,
int get_height() override { return this->effective_transform_ & SWAP_XY ? this->width_ : this->height_; }
bool pixel_axes_swapped() const override { return this->effective_transform_ & SWAP_XY; }
void draw_pixel_at(int x, int y, Color color) override;
void draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorOrder order,
ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) override;
// Make the next update a full one. Applied when that update starts, so one in progress is not affected.
void request_full_update() { this->full_update_requested_ = true; }
// True from the start of an update until the display has refreshed and gone back to sleep.
bool is_updating() const { return this->state_ != EPaperState::IDLE; }
protected:
void draw_pixels_internal(int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorBitness bitness,
bool big_endian, int x_offset, int y_offset, int x_pad) override;
int get_height_internal() override { return this->height_; };
int get_width_internal() override { return this->width_; };
bool is_using_partial_update_() const { return this->full_update_every_ > 1; }
@@ -136,8 +135,8 @@ class EPaperBase : public Display,
bool init_buffer_(size_t buffer_length);
void update_effective_transform_();
bool rotate_coordinates_(int &x, int &y);
void draw_rgb565_block_(uint8_t *buffer, int x_start, int y_start, int w, int h, const uint8_t *ptr, bool big_endian,
int x_offset, int y_offset, int x_pad);
void draw_rgb565_block_(uint8_t *buffer, int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorOrder order,
bool big_endian, int x_offset, int y_offset, int x_pad);
// Whether the buffer is a single plane of 1 bit per pixel, as draw_pixel_at() writes it
bool buffer_is_mono_() const { return this->bits_per_pixel_ == 1 && this->planes_ == 1; }
+6 -1
View File
@@ -13,7 +13,7 @@ static const size_t MCLK_DIV_FRE = 256;
// Mark the component as failed; use only in setup
#define ES7210_ERROR_FAILED(func) \
if (!(func)) { \
this->mark_failed(LOG_STR("Failed to initialize")); \
this->mark_failed(); \
return; \
}
@@ -31,6 +31,11 @@ void ES7210::dump_config() {
" Channel Gains: %.1f dB, %.1f dB, %.1f dB, %.1f dB",
this->bits_per_sample_, this->sample_rate_, this->channel_gains_[0], this->channel_gains_[1],
this->channel_gains_[2], this->channel_gains_[3]);
if (this->is_failed()) {
ESP_LOGE(TAG, " Failed to initialize");
return;
}
}
void ES7210::setup() {
+9 -2
View File
@@ -13,7 +13,7 @@ ESPHOME_LOG_TAG(TAG, "es7243e");
// Mark the component as failed; use only in setup
#define ES7243E_ERROR_FAILED(func) \
if (!(func)) { \
this->mark_failed(LOG_STR("Failed to initialize")); \
this->mark_failed(); \
return; \
}
@@ -23,7 +23,14 @@ ESPHOME_LOG_TAG(TAG, "es7243e");
return false; \
}
void ES7243E::dump_config() { ESP_LOGCONFIG(TAG, "ES7243E audio ADC:"); }
void ES7243E::dump_config() {
ESP_LOGCONFIG(TAG, "ES7243E audio ADC:");
if (this->is_failed()) {
ESP_LOGE(TAG, " Failed to initialize");
return;
}
}
void ES7243E::setup() {
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_CLOCK_MGR_REG01, 0x3A));
+9 -2
View File
@@ -11,7 +11,7 @@ ESPHOME_LOG_TAG(TAG, "es8156");
// Mark the component as failed; use only in setup
#define ES8156_ERROR_FAILED(func) \
if (!(func)) { \
this->mark_failed(LOG_STR("Failed to initialize")); \
this->mark_failed(); \
return; \
}
@@ -74,7 +74,14 @@ void ES8156::setup() {
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG25_ANALOG_SYS5, 0x20));
}
void ES8156::dump_config() { ESP_LOGCONFIG(TAG, "ES8156 Audio Codec:"); }
void ES8156::dump_config() {
ESP_LOGCONFIG(TAG, "ES8156 Audio Codec:");
if (this->is_failed()) {
ESP_LOGCONFIG(TAG, " Failed to initialize");
return;
}
}
bool ES8156::set_volume(float volume) {
volume = clamp(volume, 0.0f, 1.0f);
+6 -1
View File
@@ -11,7 +11,7 @@ ESPHOME_LOG_TAG(TAG, "es8311");
// Mark the component as failed; use only in setup
#define ES8311_ERROR_FAILED(func) \
if (!(func)) { \
this->mark_failed(LOG_STR("Failed to initialize")); \
this->mark_failed(); \
return; \
}
// Return false; use outside of setup
@@ -56,6 +56,11 @@ void ES8311::dump_config() {
" DAC Bits per Sample: %" PRIu8 "\n"
" Sample Rate: %" PRIu32,
YESNO(this->use_mclk_), YESNO(this->use_mic_), this->resolution_out_, this->sample_frequency_);
if (this->is_failed()) {
ESP_LOGCONFIG(TAG, " Failed to initialize!");
return;
}
}
bool ES8311::set_volume(float volume) {
+6 -1
View File
@@ -11,7 +11,7 @@ ESPHOME_LOG_TAG(TAG, "es8388");
// Mark the component as failed; use only in setup
#define ES8388_ERROR_FAILED(func) \
if (!(func)) { \
this->mark_failed(LOG_STR("Failed to initialize")); \
this->mark_failed(); \
return; \
}
@@ -154,6 +154,11 @@ void ES8388::dump_config() {
LOG_SELECT(" ", "DacOutputSelect", this->dac_output_select_);
LOG_SELECT(" ", "ADCInputMicSelect", this->adc_input_mic_select_);
#endif
if (this->is_failed()) {
ESP_LOGCONFIG(TAG, " Failed to initialize");
return;
}
}
bool ES8388::set_volume(float volume) {
+5 -9
View File
@@ -28,12 +28,14 @@ ADC_INPUT_MIC_OPTIONS = {
}
ADC_INPUT_MIC_OPTION_NAMES = list(ADC_INPUT_MIC_OPTIONS)
DacOutputSelect = es8388_ns.class_("DacOutputSelect", select.Select)
ADCInputMicSelect = es8388_ns.class_("ADCInputMicSelect", select.Select)
CONFIG_SCHEMA = cv.All(
{
cv.GenerateID(CONF_ES8388_ID): cv.use_id(ES8388),
cv.Optional(CONF_DAC_OUTPUT): select.select_schema(
select.ApplySelect,
DacOutputSelect,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_CHIP,
).extend(
@@ -44,7 +46,7 @@ CONFIG_SCHEMA = cv.All(
}
),
cv.Optional(CONF_ADC_INPUT_MIC): select.select_schema(
select.ApplySelect,
ADCInputMicSelect,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_CHIP,
).extend(
@@ -63,18 +65,12 @@ async def to_code(config: ConfigType) -> None:
hub = await cg.get_variable(config[CONF_ES8388_ID])
selects = select.sub_selects(config, parent=hub)
await selects(
CONF_DAC_OUTPUT,
hub.set_dac_output_select,
options=DAC_OUTPUT_OPTION_NAMES,
apply="set_dac_output(static_cast<es8388::DacOutputLine>(index))",
publish="before",
CONF_DAC_OUTPUT, hub.set_dac_output_select, options=DAC_OUTPUT_OPTION_NAMES
)
await selects(
CONF_ADC_INPUT_MIC,
hub.set_adc_input_mic_select,
options=ADC_INPUT_MIC_OPTION_NAMES,
apply="set_adc_input_mic(static_cast<es8388::AdcInputMicLine>(index))",
publish="before",
)
if (
initial := config.get(CONF_DAC_OUTPUT, {}).get(CONF_INITIAL_OPTION)
@@ -0,0 +1,10 @@
#include "adc_input_mic_select.h"
namespace esphome::es8388 {
void ADCInputMicSelect::control(size_t index) {
this->publish_state(index);
this->parent_->set_adc_input_mic(static_cast<AdcInputMicLine>(index));
}
} // namespace esphome::es8388
@@ -0,0 +1,13 @@
#pragma once
#include "esphome/components/es8388/es8388.h"
#include "esphome/components/select/select.h"
namespace esphome::es8388 {
class ADCInputMicSelect final : public select::Select, public Parented<ES8388> {
protected:
void control(size_t index) override;
};
} // namespace esphome::es8388
@@ -0,0 +1,10 @@
#include "dac_output_select.h"
namespace esphome::es8388 {
void DacOutputSelect::control(size_t index) {
this->publish_state(index);
this->parent_->set_dac_output(static_cast<DacOutputLine>(index));
}
} // namespace esphome::es8388
@@ -0,0 +1,13 @@
#pragma once
#include "esphome/components/es8388/es8388.h"
#include "esphome/components/select/select.h"
namespace esphome::es8388 {
class DacOutputSelect final : public select::Select, public Parented<ES8388> {
protected:
void control(size_t index) override;
};
} // namespace esphome::es8388
@@ -42,7 +42,7 @@ CameraWebServer::~CameraWebServer() {}
void CameraWebServer::setup() {
if (!camera::Camera::instance() || camera::Camera::instance()->is_failed()) {
this->mark_failed(LOG_STR("Camera not available"));
this->mark_failed();
return;
}
@@ -56,7 +56,7 @@ void CameraWebServer::setup() {
config.lru_purge_enable = true;
if (httpd_start(&this->httpd_, &config) != ESP_OK) {
this->mark_failed(LOG_STR("Failed to start the web server"));
mark_failed();
return;
}
@@ -97,6 +97,10 @@ void CameraWebServer::dump_config() {
} else {
ESP_LOGCONFIG(TAG, " Mode: snapshot");
}
if (this->is_failed()) {
ESP_LOGE(TAG, " Setup Failed");
}
}
float CameraWebServer::get_setup_priority() const { return setup_priority::LATE; }
@@ -1,18 +1,20 @@
import esphome.codegen as cg
from esphome.components import button
import esphome.config_validation as cv
from esphome.const import ENTITY_CATEGORY_CONFIG
from esphome.types import ConfigType
from .. import CONF_ESPECTRE_ID, ESPectreComponent
from .. import CONF_ESPECTRE_ID, ESPectreComponent, espectre_ns
DEPENDENCIES = ["espectre"]
RecalibrateButton = espectre_ns.class_("RecalibrateButton", button.Button)
CONFIG_SCHEMA = button.button_schema(
button.ApplyButton, entity_category=ENTITY_CATEGORY_CONFIG
RecalibrateButton, entity_category=ENTITY_CATEGORY_CONFIG
).extend({cv.GenerateID(CONF_ESPECTRE_ID): cv.use_id(ESPectreComponent)})
async def to_code(config: ConfigType) -> None:
buttons = button.sub_buttons(config, parent=config[CONF_ESPECTRE_ID])
await buttons.create(config, None, apply="recalibrate()")
var = await button.new_button(config)
await cg.register_parented(var, config[CONF_ESPECTRE_ID])
@@ -0,0 +1,19 @@
#pragma once
#include "esphome/core/defines.h"
#ifdef USE_ESPECTRE
#include "esphome/components/button/button.h"
#include "../espectre.h"
namespace esphome::espectre {
class RecalibrateButton final : public button::Button, public Parented<ESPectreComponent> {
protected:
void press_action() override { this->parent_->recalibrate(); }
};
} // namespace esphome::espectre
#endif // USE_ESPECTRE
@@ -9,23 +9,24 @@ from .. import (
CONF_ESPECTRE_ID,
DOMAIN,
ESPectreComponent,
espectre_ns,
supported_traffic_generator_modes,
)
DEPENDENCIES = ["espectre"]
TrafficModeSelect = espectre_ns.class_(
"TrafficModeSelect", select.Select, cg.Parented.template(ESPectreComponent)
)
CONFIG_SCHEMA = select.select_schema(
select.ApplySelect, entity_category=ENTITY_CATEGORY_CONFIG
TrafficModeSelect, entity_category=ENTITY_CATEGORY_CONFIG
).extend({cv.GenerateID(CONF_ESPECTRE_ID): cv.use_id(ESPectreComponent)})
async def to_code(config: ConfigType) -> None:
options = supported_traffic_generator_modes(CORE.config[DOMAIN])
hub = await cg.get_variable(config[CONF_ESPECTRE_ID])
await select.sub_selects(config, parent=hub).create(
config,
hub.set_traffic_mode_select,
options=options,
apply="request_traffic_generator_mode(entity->option_at(index))",
)
var = await select.new_select(config, options=options)
await cg.register_parented(var, config[CONF_ESPECTRE_ID])
parent = await cg.get_variable(config[CONF_ESPECTRE_ID])
cg.add(parent.set_traffic_mode_select(var))
@@ -0,0 +1,11 @@
#include "espectre_select.h"
#ifdef USE_ESPECTRE
namespace esphome::espectre {
void TrafficModeSelect::control(size_t index) { this->parent_->request_traffic_generator_mode(this->option_at(index)); }
} // namespace esphome::espectre
#endif // USE_ESPECTRE
@@ -0,0 +1,19 @@
#pragma once
#include "esphome/core/defines.h"
#ifdef USE_ESPECTRE
#include "esphome/components/select/select.h"
#include "../espectre.h"
namespace esphome::espectre {
class TrafficModeSelect final : public select::Select, public Parented<ESPectreComponent> {
protected:
void control(size_t index) override;
};
} // namespace esphome::espectre
#endif // USE_ESPECTRE
+3
View File
@@ -13,6 +13,9 @@ static const char *const EZO_CALIBRATION_TYPE_STRINGS[] = {"LOW", "MID", "HIGH"}
void EZOSensor::dump_config() {
LOG_SENSOR("", "EZO", this);
LOG_I2C_DEVICE(this);
if (this->is_failed()) {
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
}
LOG_UPDATE_INTERVAL(this);
}
+3
View File
@@ -39,6 +39,9 @@ static const std::string DOSING_MODE_CONTINUOUS = "Continuous";
void EzoPMP::dump_config() {
LOG_I2C_DEVICE(this);
if (this->is_failed()) {
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
}
LOG_UPDATE_INTERVAL(this);
}
+1 -7
View File
@@ -254,13 +254,7 @@ async def new_image(config: ConfigType) -> MockObj:
"""
prog_arr, width, height, image_type, trans_value, _ = await write_image(config)
var = cg.new_Pvariable(
config[CONF_ID],
prog_arr,
width,
height,
image_type,
trans_value,
config.get(CONF_BYTE_ORDER) == "BIG_ENDIAN",
config[CONF_ID], prog_arr, width, height, image_type, trans_value
)
add_metadata(
config[CONF_ID], width, height, config[CONF_TYPE], config[CONF_TRANSPARENCY]
+3
View File
@@ -82,6 +82,9 @@ bool GDK101Component::try_reset_() {
void GDK101Component::dump_config() {
ESP_LOGCONFIG(TAG, "GDK101:");
LOG_I2C_DEVICE(this);
if (this->is_failed()) {
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
}
#ifdef USE_SENSOR
LOG_SENSOR(" ", "Average Radaition Dose per 1 minute", this->rad_1m_sensor_);
LOG_SENSOR(" ", "Average Radaition Dose per 10 minutes", this->rad_10m_sensor_);
@@ -23,6 +23,7 @@ bool GroveGasMultichannelV2Component::read_sensor_(uint8_t address, sensor::Sens
uint32_t value = 0;
if (!this->read_bytes(address, (uint8_t *) &value, 4)) {
ESP_LOGW(TAG, "Reading Grove Gas Sensor data failed!");
this->error_code_ = COMMUNICATION_FAILED;
this->status_set_warning();
return false;
}
@@ -33,7 +34,8 @@ bool GroveGasMultichannelV2Component::read_sensor_(uint8_t address, sensor::Sens
void GroveGasMultichannelV2Component::setup() {
// Before reading sensor values, must preheat sensor
if (!(this->write_bytes(GROVE_GAS_MC_V2_HEAT_ON, {}))) {
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
this->mark_failed();
this->error_code_ = APP_START_FAILED;
}
}
@@ -59,6 +61,24 @@ void GroveGasMultichannelV2Component::dump_config() {
LOG_SENSOR(" ", "Ethanol", this->ethanol_sensor_);
LOG_SENSOR(" ", "Carbon Monoxide", this->carbon_monoxide_sensor_);
LOG_SENSOR(" ", "TVOC", this->tvoc_sensor_);
if (this->is_failed()) {
switch (this->error_code_) {
case COMMUNICATION_FAILED:
ESP_LOGW(TAG, ESP_LOG_MSG_COMM_FAIL);
break;
case APP_INVALID:
ESP_LOGW(TAG, "Sensor reported invalid APP installed");
break;
case APP_START_FAILED:
ESP_LOGW(TAG, "Sensor reported APP start failed");
break;
case UNKNOWN:
default:
ESP_LOGW(TAG, "Unknown setup error");
break;
}
}
}
} // namespace esphome::grove_gas_mc_v2
Loaded 100 of 462 files, more files were not shown because too many files have changed in this diff. Show more