mirror of
https://github.com/esphome/esphome.git
synced 2026-10-23 06:15:58 +00:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e5b5dd52ef | ||
|
|
bf36f7532d | ||
|
|
69f6429728 | ||
|
|
bab99748f0 |
No files matched your search
@@ -163,21 +163,26 @@ void CW2017::update() {
|
||||
if (!this->ready_)
|
||||
return;
|
||||
|
||||
bool ok = true;
|
||||
if (this->battery_level_sensor_ != nullptr) {
|
||||
uint8_t soc = 0;
|
||||
ok = this->read_byte(REG_SOC, &soc) && soc <= 100;
|
||||
if (ok)
|
||||
if (this->read_byte(REG_SOC, &soc) && soc <= 100) {
|
||||
this->battery_level_sensor_->publish_state(soc);
|
||||
} else {
|
||||
this->status_set_warning();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (ok && this->battery_voltage_sensor_ != nullptr) {
|
||||
if (this->battery_voltage_sensor_ != nullptr) {
|
||||
uint16_t raw = 0;
|
||||
ok = this->read_byte_16(REG_VCELL, &raw);
|
||||
if (ok)
|
||||
if (this->read_byte_16(REG_VCELL, &raw)) {
|
||||
this->battery_voltage_sensor_->publish_state((raw & VCELL_MASK) * VCELL_VOLTS_PER_LSB);
|
||||
} else {
|
||||
this->status_set_warning();
|
||||
return;
|
||||
}
|
||||
}
|
||||
this->status_comm_result(ok);
|
||||
this->status_clear_warning();
|
||||
}
|
||||
|
||||
void CW2017::dump_config() {
|
||||
|
||||
@@ -12,8 +12,8 @@ class CW2017 : public PollingComponent, public i2c::I2CDevice {
|
||||
public:
|
||||
explicit CW2017(const uint8_t *profile) : profile_(profile) {}
|
||||
|
||||
SUB_SENSOR(battery_level)
|
||||
SUB_SENSOR(battery_voltage)
|
||||
void set_battery_level_sensor(sensor::Sensor *sensor) { this->battery_level_sensor_ = sensor; }
|
||||
void set_battery_voltage_sensor(sensor::Sensor *sensor) { this->battery_voltage_sensor_ = sensor; }
|
||||
|
||||
void setup() override;
|
||||
void update() override;
|
||||
@@ -29,6 +29,8 @@ class CW2017 : public PollingComponent, public i2c::I2CDevice {
|
||||
void wait_ready_(uint8_t attempt);
|
||||
|
||||
const uint8_t *profile_;
|
||||
sensor::Sensor *battery_level_sensor_{nullptr};
|
||||
sensor::Sensor *battery_voltage_sensor_{nullptr};
|
||||
bool ready_{false};
|
||||
bool restart_pending_{false};
|
||||
uint8_t init_attempts_{0};
|
||||
|
||||
@@ -34,7 +34,10 @@ DFRobotSEN0465Component = dfrobot_sen0465_base_ns.class_(
|
||||
"DFRobotSEN0465Component", cg.PollingComponent
|
||||
)
|
||||
AlarmType = dfrobot_sen0465_base_ns.enum("AlarmType", is_class=True)
|
||||
ALARM_TYPES = AlarmType.options("LOW", "HIGH", prefix="ALARM_TYPE_")
|
||||
ALARM_TYPES = {
|
||||
"LOW": AlarmType.ALARM_TYPE_LOW,
|
||||
"HIGH": AlarmType.ALARM_TYPE_HIGH,
|
||||
}
|
||||
|
||||
# One piece of the temperature compensation from the DFRobot_MultiGasSensor library:
|
||||
# for low < T <= high, compensated = raw / (a * T + b) - (c * T + d)
|
||||
|
||||
@@ -72,7 +72,10 @@ void DFRobotSEN0465Component::dump_config() {
|
||||
if (this->alarm_type_ == AlarmType::ALARM_TYPE_OFF) {
|
||||
ESP_LOGCONFIG(TAG, " Alarm: off");
|
||||
} else {
|
||||
const float threshold = this->alarm_threshold_ / pow10_int(this->alarm_decimals_);
|
||||
float scale = 1.0f;
|
||||
for (uint8_t i = 0; i < this->alarm_decimals_; i++)
|
||||
scale *= 10.0f;
|
||||
const float threshold = this->alarm_threshold_ / scale;
|
||||
ESP_LOGCONFIG(TAG, " Alarm: %s %.*f",
|
||||
this->alarm_type_ == AlarmType::ALARM_TYPE_HIGH ? LOG_STR_LITERAL("above") : LOG_STR_LITERAL("below"),
|
||||
this->alarm_decimals_, threshold);
|
||||
@@ -80,6 +83,9 @@ void DFRobotSEN0465Component::dump_config() {
|
||||
if (this->setup_incomplete_) {
|
||||
ESP_LOGCONFIG(TAG, " Setup incomplete: yes");
|
||||
}
|
||||
if (this->is_failed()) {
|
||||
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
|
||||
}
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
LOG_SENSOR(" ", "Concentration", this->concentration_sensor_);
|
||||
LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
|
||||
@@ -222,14 +228,23 @@ void DFRobotSEN0465Component::handle_data_(const uint8_t *frame) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (frame[5] > 2) {
|
||||
ESP_LOGW(TAG, "Invalid number of decimal places: %u", frame[5]);
|
||||
if (this->concentration_sensor_ != nullptr)
|
||||
this->concentration_sensor_->publish_state(NAN);
|
||||
this->status_set_warning();
|
||||
return;
|
||||
float concentration = encode_uint16(frame[2], frame[3]);
|
||||
switch (frame[5]) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
concentration *= 0.1f;
|
||||
break;
|
||||
case 2:
|
||||
concentration *= 0.01f;
|
||||
break;
|
||||
default:
|
||||
ESP_LOGW(TAG, "Invalid number of decimal places: %u", frame[5]);
|
||||
if (this->concentration_sensor_ != nullptr)
|
||||
this->concentration_sensor_->publish_state(NAN);
|
||||
this->status_set_warning();
|
||||
return;
|
||||
}
|
||||
float concentration = encode_uint16(frame[2], frame[3]) * pow10_int(-frame[5]);
|
||||
|
||||
#ifdef USE_DFROBOT_SEN0465_TEMPERATURE_COMPENSATION
|
||||
if (!this->compensation_.empty())
|
||||
|
||||
@@ -95,6 +95,12 @@ static bool answer_means_done(Operation operation, const char *line) {
|
||||
}
|
||||
}
|
||||
|
||||
static bool parse_float(const char *str, float &value) {
|
||||
char *end;
|
||||
value = strtof(str, &end);
|
||||
return end != str && *end == '\0';
|
||||
}
|
||||
|
||||
static const LogString *operation_to_str(Operation operation) {
|
||||
switch (operation) {
|
||||
case Operation::OPERATION_STOP:
|
||||
@@ -280,6 +286,9 @@ void DFRobotSEN0609Component::handle_frame_(char *line) {
|
||||
return;
|
||||
}
|
||||
char *fields[FRAME_FIELDS];
|
||||
float distance;
|
||||
float speed;
|
||||
float energy;
|
||||
if (split_fields(line + 7, fields, FRAME_FIELDS) < FRAME_FIELDS) {
|
||||
this->log_bad_frame_(LOG_STR("Malformed target frame"), line);
|
||||
return;
|
||||
@@ -299,10 +308,7 @@ void DFRobotSEN0609Component::handle_frame_(char *line) {
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
const optional<float> distance = parse_number<float>(fields[2]);
|
||||
const optional<float> speed = parse_number<float>(fields[3]);
|
||||
const optional<float> energy = parse_number<float>(fields[4]);
|
||||
if (!distance.has_value() || !speed.has_value() || !energy.has_value()) {
|
||||
if (!parse_float(fields[2], distance) || !parse_float(fields[3], speed) || !parse_float(fields[4], energy)) {
|
||||
this->log_bad_frame_(LOG_STR("Malformed target frame"), line);
|
||||
return;
|
||||
}
|
||||
@@ -311,7 +317,7 @@ void DFRobotSEN0609Component::handle_frame_(char *line) {
|
||||
this->has_target_binary_sensor_->publish_state(true);
|
||||
#endif
|
||||
#ifdef USE_SENSOR
|
||||
this->publish_target_(*distance, *speed, *energy);
|
||||
this->publish_target_(distance, speed, energy);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -181,6 +181,16 @@ def get_all_display_metadata() -> dict[str, DisplayMetaData]:
|
||||
return {id_.id: meta for id_, meta in entries}
|
||||
|
||||
|
||||
def config_has_writer(config: ConfigType) -> bool:
|
||||
"""Return True when the display config draws anything."""
|
||||
return (
|
||||
config.get(CONF_AUTO_CLEAR_ENABLED) is True
|
||||
or config.get(CONF_PAGES) is not None
|
||||
or config.get(CONF_LAMBDA) is not None
|
||||
or config.get(CONF_SHOW_TEST_CARD) is True
|
||||
)
|
||||
|
||||
|
||||
def get_display_metadata(display_id: ID) -> DisplayMetaData:
|
||||
"""Get display metadata by ID object
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
#include "init_sequence.h"
|
||||
#include "esphome/core/hal.h"
|
||||
|
||||
namespace esphome::display {
|
||||
|
||||
InitSequenceStep InitSequenceReader::next(InitSequenceEntry &entry, uint8_t max_count) {
|
||||
const size_t remaining = this->length_ - this->index_;
|
||||
if (remaining == 0)
|
||||
return INIT_SEQUENCE_STEP_END;
|
||||
const uint8_t *pos = this->sequence_ + this->index_;
|
||||
if (remaining >= 2) {
|
||||
entry.value = progmem_read_byte(pos);
|
||||
entry.count = progmem_read_byte(pos + 1);
|
||||
entry.args = pos + 2;
|
||||
if (entry.count == INIT_SEQUENCE_DELAY_FLAG) {
|
||||
this->index_ += 2;
|
||||
return INIT_SEQUENCE_STEP_DELAY;
|
||||
}
|
||||
if (entry.count <= max_count && remaining - 2 >= entry.count) {
|
||||
this->index_ += 2 + entry.count;
|
||||
return INIT_SEQUENCE_STEP_COMMAND;
|
||||
}
|
||||
}
|
||||
this->index_ = this->length_;
|
||||
return INIT_SEQUENCE_STEP_MALFORMED;
|
||||
}
|
||||
|
||||
} // namespace esphome::display
|
||||
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace esphome::display {
|
||||
|
||||
/// Count byte that marks a delay entry: the byte before it is the delay in ms.
|
||||
static constexpr uint8_t INIT_SEQUENCE_DELAY_FLAG = 0xFF;
|
||||
|
||||
/// Unscoped so `while (auto step = reader.next(entry))` stops at END.
|
||||
enum InitSequenceStep : uint8_t {
|
||||
INIT_SEQUENCE_STEP_END = 0,
|
||||
INIT_SEQUENCE_STEP_COMMAND,
|
||||
INIT_SEQUENCE_STEP_DELAY,
|
||||
INIT_SEQUENCE_STEP_MALFORMED,
|
||||
};
|
||||
|
||||
/// `value` is the command or the delay in ms; `args` points into the (possibly PROGMEM) sequence.
|
||||
struct InitSequenceEntry {
|
||||
const uint8_t *args;
|
||||
uint8_t value;
|
||||
uint8_t count;
|
||||
};
|
||||
|
||||
/// Walks a mipi.flatten_sequence table (`cmd, count, args...` or `ms, 0xFF`) with progmem reads; resumable.
|
||||
class InitSequenceReader {
|
||||
public:
|
||||
InitSequenceReader(const uint8_t *sequence, size_t length) : sequence_(sequence), length_(length) {}
|
||||
|
||||
/// Fill `entry` with the next entry; a command with more than `max_count` args is MALFORMED.
|
||||
InitSequenceStep next(InitSequenceEntry &entry, uint8_t max_count = 0xFE);
|
||||
|
||||
protected:
|
||||
const uint8_t *sequence_;
|
||||
size_t length_;
|
||||
size_t index_{0};
|
||||
};
|
||||
|
||||
} // namespace esphome::display
|
||||
@@ -38,7 +38,7 @@ void ESP32ULP::setup() {
|
||||
esp_err_t err = ulp_set_wakeup_period(0, this->wakeup_period_us_);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "ulp_set_wakeup_period failed: %s", esp_err_to_name(err));
|
||||
this->mark_failed(LOG_STR("Wakeup period not set"));
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,7 @@ void ESP32ULP::setup() {
|
||||
if (esp_reset_reason() == ESP_RST_DEEPSLEEP && s_program_loaded) {
|
||||
this->loaded_ = true;
|
||||
} else if (this->run_on_boot_ && !this->load_and_run()) {
|
||||
this->mark_failed(LOG_STR("Program did not start"));
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
if (this->wakeup_from_sleep_) {
|
||||
|
||||
@@ -43,9 +43,10 @@ CONF_RATIO_SENSOR = "ratio_sensor"
|
||||
CONF_RS_SENSOR = "rs_sensor"
|
||||
CONF_VOLTAGE_SENSOR = "voltage_sensor"
|
||||
|
||||
CONVERSION_MODELS = ConversionModel.options(
|
||||
"dfrobot", "datasheet", prefix="CONVERSION_MODEL_"
|
||||
)
|
||||
CONVERSION_MODELS = {
|
||||
"dfrobot": ConversionModel.CONVERSION_MODEL_DFROBOT,
|
||||
"datasheet": ConversionModel.CONVERSION_MODEL_DATASHEET,
|
||||
}
|
||||
|
||||
# Divider guard limits (input max, pin max) in volts by target platform. ESP32 and RP2: VDD and
|
||||
# the absolute maximum VDD + 0.3 V; a bare ESP8266 A0 measures 0 - 1 V, boards with an onboard
|
||||
|
||||
@@ -36,9 +36,9 @@ async def to_code(config: ConfigType) -> None:
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await cg.register_component(var, config)
|
||||
|
||||
# The schema only lets a model's own keys through, so unconfigured ones are skipped here
|
||||
text_sensors = text_sensor.sub_text_sensors(config)
|
||||
await text_sensors(CONF_ERROR_CODE, var.set_error_code_text_sensor)
|
||||
if config[CONF_MODEL] == CONF_SYSTASOLAR_AQUA and CONF_ERROR_CODE in config:
|
||||
sens = await text_sensor.new_text_sensor(config[CONF_ERROR_CODE])
|
||||
cg.add(var.set_error_code_text_sensor(sens))
|
||||
|
||||
systa_bus = await cg.get_variable(config[CONF_SYSTA_BUS_ID])
|
||||
await register_systa_bus_listener(systa_bus, var)
|
||||
@@ -32,15 +32,14 @@ VEML6040Component = veml6040_ns.class_(
|
||||
)
|
||||
|
||||
VEML6040IntegrationTime = veml6040_ns.enum("VEML6040IntegrationTime")
|
||||
VEML6040_INTEGRATION_TIMES = VEML6040IntegrationTime.options(
|
||||
"40ms",
|
||||
"80ms",
|
||||
"160ms",
|
||||
"320ms",
|
||||
"640ms",
|
||||
"1280ms",
|
||||
prefix="VEML6040_INTEGRATION_TIME_",
|
||||
)
|
||||
VEML6040_INTEGRATION_TIMES = {
|
||||
"40ms": VEML6040IntegrationTime.VEML6040_INTEGRATION_TIME_40MS,
|
||||
"80ms": VEML6040IntegrationTime.VEML6040_INTEGRATION_TIME_80MS,
|
||||
"160ms": VEML6040IntegrationTime.VEML6040_INTEGRATION_TIME_160MS,
|
||||
"320ms": VEML6040IntegrationTime.VEML6040_INTEGRATION_TIME_320MS,
|
||||
"640ms": VEML6040IntegrationTime.VEML6040_INTEGRATION_TIME_640MS,
|
||||
"1280ms": VEML6040IntegrationTime.VEML6040_INTEGRATION_TIME_1280MS,
|
||||
}
|
||||
|
||||
color_channel_schema = sensor.sensor_schema(
|
||||
icon=ICON_LIGHTBULB,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "veml6040.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
#include <cinttypes>
|
||||
@@ -59,14 +60,25 @@ void VEML6040Component::dump_config() {
|
||||
LOG_SENSOR(" ", "Color temperature", this->color_temperature_sensor_);
|
||||
}
|
||||
|
||||
bool VEML6040Component::read_channel_(uint8_t reg, uint16_t &counts) {
|
||||
uint8_t data[2];
|
||||
if (this->read_register(reg, data, sizeof data) != i2c::ERROR_OK)
|
||||
return false;
|
||||
counts = encode_uint16(data[1], data[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
void VEML6040Component::update() {
|
||||
if (!this->data_ready_)
|
||||
return;
|
||||
|
||||
uint16_t red{0}, green{0}, blue{0}, white{0};
|
||||
if (!this->status_comm_result(this->read_byte_16_le(R_DATA_REG, &red) && this->read_byte_16_le(G_DATA_REG, &green) &&
|
||||
this->read_byte_16_le(B_DATA_REG, &blue) && this->read_byte_16_le(W_DATA_REG, &white)))
|
||||
uint16_t red, green, blue, white;
|
||||
if (!this->read_channel_(R_DATA_REG, red) || !this->read_channel_(G_DATA_REG, green) ||
|
||||
!this->read_channel_(B_DATA_REG, blue) || !this->read_channel_(W_DATA_REG, white)) {
|
||||
this->status_set_warning(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
|
||||
return;
|
||||
}
|
||||
this->status_clear_warning();
|
||||
|
||||
ESP_LOGV(TAG, "Counts: red=%u green=%u blue=%u white=%u", red, green, blue, white);
|
||||
|
||||
|
||||
@@ -29,16 +29,23 @@ class VEML6040Component final : public PollingComponent, public i2c::I2CDevice {
|
||||
void dump_config() override;
|
||||
void update() override;
|
||||
|
||||
SUB_SENSOR(red)
|
||||
SUB_SENSOR(green)
|
||||
SUB_SENSOR(blue)
|
||||
SUB_SENSOR(white)
|
||||
SUB_SENSOR(illuminance)
|
||||
SUB_SENSOR(color_temperature)
|
||||
void set_red_sensor(sensor::Sensor *sensor) { this->red_sensor_ = sensor; }
|
||||
void set_green_sensor(sensor::Sensor *sensor) { this->green_sensor_ = sensor; }
|
||||
void set_blue_sensor(sensor::Sensor *sensor) { this->blue_sensor_ = sensor; }
|
||||
void set_white_sensor(sensor::Sensor *sensor) { this->white_sensor_ = sensor; }
|
||||
void set_illuminance_sensor(sensor::Sensor *sensor) { this->illuminance_sensor_ = sensor; }
|
||||
void set_color_temperature_sensor(sensor::Sensor *sensor) { this->color_temperature_sensor_ = sensor; }
|
||||
|
||||
protected:
|
||||
bool read_channel_(uint8_t reg, uint16_t &counts);
|
||||
uint32_t integration_time_ms_() const { return 40u << this->integration_time_; }
|
||||
|
||||
sensor::Sensor *red_sensor_{nullptr};
|
||||
sensor::Sensor *green_sensor_{nullptr};
|
||||
sensor::Sensor *blue_sensor_{nullptr};
|
||||
sensor::Sensor *white_sensor_{nullptr};
|
||||
sensor::Sensor *illuminance_sensor_{nullptr};
|
||||
sensor::Sensor *color_temperature_sensor_{nullptr};
|
||||
const float glass_attenuation_factor_;
|
||||
const float color_temperature_offset_;
|
||||
const VEML6040IntegrationTime integration_time_;
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "esphome/components/display/init_sequence.h"
|
||||
|
||||
namespace esphome::display::testing {
|
||||
|
||||
TEST(InitSequenceReader, WalksCommandsAndDelays) {
|
||||
static const uint8_t SEQ[] = {0x11, 0x00, 120, 0xFF, 0x3A, 0x01, 0x55, 0x2A, 0x02, 0x00, 0xEF};
|
||||
InitSequenceReader reader(SEQ, sizeof(SEQ));
|
||||
InitSequenceEntry entry{};
|
||||
|
||||
ASSERT_EQ(reader.next(entry), INIT_SEQUENCE_STEP_COMMAND);
|
||||
EXPECT_EQ(entry.value, 0x11);
|
||||
EXPECT_EQ(entry.count, 0);
|
||||
|
||||
ASSERT_EQ(reader.next(entry), INIT_SEQUENCE_STEP_DELAY);
|
||||
EXPECT_EQ(entry.value, 120);
|
||||
|
||||
ASSERT_EQ(reader.next(entry), INIT_SEQUENCE_STEP_COMMAND);
|
||||
EXPECT_EQ(entry.value, 0x3A);
|
||||
ASSERT_EQ(entry.count, 1);
|
||||
EXPECT_EQ(entry.args, &SEQ[6]);
|
||||
|
||||
ASSERT_EQ(reader.next(entry), INIT_SEQUENCE_STEP_COMMAND);
|
||||
EXPECT_EQ(entry.value, 0x2A);
|
||||
ASSERT_EQ(entry.count, 2);
|
||||
EXPECT_EQ(entry.args[0], 0x00);
|
||||
EXPECT_EQ(entry.args[1], 0xEF);
|
||||
|
||||
EXPECT_EQ(reader.next(entry), INIT_SEQUENCE_STEP_END);
|
||||
EXPECT_EQ(reader.next(entry), INIT_SEQUENCE_STEP_END);
|
||||
}
|
||||
|
||||
TEST(InitSequenceReader, EmptySequenceEnds) {
|
||||
InitSequenceReader reader(nullptr, 0);
|
||||
InitSequenceEntry entry{};
|
||||
EXPECT_EQ(reader.next(entry), INIT_SEQUENCE_STEP_END);
|
||||
}
|
||||
|
||||
// A count above 127 is a real length, not a flag bit.
|
||||
TEST(InitSequenceReader, HonoursFullCount) {
|
||||
uint8_t seq[2 + 253 + 2] = {0x32, 253};
|
||||
seq[2 + 253] = 0x29;
|
||||
InitSequenceReader reader(seq, sizeof(seq));
|
||||
InitSequenceEntry entry{};
|
||||
|
||||
ASSERT_EQ(reader.next(entry), INIT_SEQUENCE_STEP_COMMAND);
|
||||
EXPECT_EQ(entry.value, 0x32);
|
||||
EXPECT_EQ(entry.count, 253);
|
||||
ASSERT_EQ(reader.next(entry), INIT_SEQUENCE_STEP_COMMAND);
|
||||
EXPECT_EQ(entry.value, 0x29);
|
||||
EXPECT_EQ(reader.next(entry), INIT_SEQUENCE_STEP_END);
|
||||
}
|
||||
|
||||
TEST(InitSequenceReader, TruncatedHeaderIsMalformed) {
|
||||
static const uint8_t SEQ[] = {0x11, 0x00, 0x29};
|
||||
InitSequenceReader reader(SEQ, sizeof(SEQ));
|
||||
InitSequenceEntry entry{};
|
||||
ASSERT_EQ(reader.next(entry), INIT_SEQUENCE_STEP_COMMAND);
|
||||
EXPECT_EQ(reader.next(entry), INIT_SEQUENCE_STEP_MALFORMED);
|
||||
EXPECT_EQ(reader.next(entry), INIT_SEQUENCE_STEP_END);
|
||||
}
|
||||
|
||||
TEST(InitSequenceReader, ShortArgsAreMalformed) {
|
||||
static const uint8_t SEQ[] = {0x2A, 0x04, 0x00, 0x00, 0x00};
|
||||
InitSequenceReader reader(SEQ, sizeof(SEQ));
|
||||
InitSequenceEntry entry{};
|
||||
EXPECT_EQ(reader.next(entry), INIT_SEQUENCE_STEP_MALFORMED);
|
||||
EXPECT_EQ(reader.next(entry), INIT_SEQUENCE_STEP_END);
|
||||
}
|
||||
|
||||
TEST(InitSequenceReader, CountOverMaxIsMalformed) {
|
||||
static const uint8_t SEQ[] = {10, 0xFF, 0x2A, 0x02, 0x00, 0xEF};
|
||||
InitSequenceReader reader(SEQ, sizeof(SEQ));
|
||||
InitSequenceEntry entry{};
|
||||
ASSERT_EQ(reader.next(entry, 1), INIT_SEQUENCE_STEP_DELAY);
|
||||
EXPECT_EQ(reader.next(entry, 1), INIT_SEQUENCE_STEP_MALFORMED);
|
||||
}
|
||||
|
||||
} // namespace esphome::display::testing
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Tests for display.add_writer."""
|
||||
"""Tests for display.add_writer and display.config_has_writer."""
|
||||
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
@@ -6,7 +6,8 @@ import pytest
|
||||
|
||||
from esphome import codegen as cg
|
||||
from esphome.components import display
|
||||
from esphome.const import CONF_LAMBDA
|
||||
from esphome.components.display import CONF_SHOW_TEST_CARD
|
||||
from esphome.const import CONF_AUTO_CLEAR_ENABLED, CONF_LAMBDA, CONF_PAGES
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -39,3 +40,20 @@ async def test_add_writer_without_lambda_does_nothing() -> None:
|
||||
|
||||
process.assert_not_awaited()
|
||||
add.assert_not_called()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("config", "expected"),
|
||||
[
|
||||
({}, False),
|
||||
({CONF_AUTO_CLEAR_ENABLED: True}, True),
|
||||
({CONF_AUTO_CLEAR_ENABLED: False}, False),
|
||||
({CONF_AUTO_CLEAR_ENABLED: "unspecified"}, False),
|
||||
({CONF_PAGES: []}, True),
|
||||
({CONF_LAMBDA: "x"}, True),
|
||||
({CONF_SHOW_TEST_CARD: True}, True),
|
||||
({CONF_SHOW_TEST_CARD: False}, False),
|
||||
],
|
||||
)
|
||||
def test_config_has_writer(config: dict, expected: bool) -> None:
|
||||
assert display.config_has_writer(config) is expected
|
||||
Reference in new issue
Block a user