[tmp102] Add text sensor for diagnostics (#20629)

Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
techdregs
2026-10-13 17:06:56 -10:00
committed by GitHub
co-authored by J. Nick Koston
parent 40e12cd0d8
commit 5718e4b779
11 changed files with 339 additions and 12 deletions
+31
View File
@@ -0,0 +1,31 @@
"""TMP102 threshold status entity."""
import esphome.codegen as cg
from esphome.components import text_sensor
import esphome.config_validation as cv
from esphome.const import ENTITY_CATEGORY_DIAGNOSTIC
from esphome.types import ConfigType
from . import CONF_TMP102_ID, TMP102Component, validate_unique_child
CONFIG_SCHEMA = text_sensor.text_sensor_schema(
entity_category=ENTITY_CATEGORY_DIAGNOSTIC
).extend(
{
cv.GenerateID(CONF_TMP102_ID): cv.use_id(TMP102Component),
}
)
def _final_validate(config: ConfigType) -> ConfigType:
return validate_unique_child(config, "text_sensor")
FINAL_VALIDATE_SCHEMA = _final_validate
async def to_code(config: ConfigType) -> None:
cg.add_define("USE_TMP102_TEXT_SENSOR")
parent = await cg.get_variable(config[CONF_TMP102_ID])
var = await text_sensor.new_text_sensor(config)
cg.add(parent.set_threshold_status_text_sensor(var))
+98 -7
View File
@@ -1,8 +1,14 @@
#include "tmp102.h"
#include "esphome/core/log.h"
#include "esphome/core/hal.h"
#ifdef USE_TMP102_TEXT_SENSOR
#include "esphome/core/progmem.h"
#endif
#include <cmath>
#ifdef USE_TMP102_TEXT_SENSOR
#include <cstdio>
#endif
namespace esphome::tmp102 {
@@ -12,6 +18,30 @@ static constexpr uint32_t READ_TEMP_TIMEOUT_ID = 0;
static constexpr uint8_t TMP102_REGISTER_TEMPERATURE = 0x00;
static constexpr float TMP102_CONVERSION_FACTOR = 0.0625f;
enum TMP102ThresholdStatus : uint8_t {
TMP102_THRESHOLD_STATUS_NOT_CONFIGURED,
TMP102_THRESHOLD_STATUS_SETUP_FAILED,
TMP102_THRESHOLD_STATUS_OK,
TMP102_THRESHOLD_STATUS_RESTORE_RESET,
TMP102_THRESHOLD_STATUS_RESTORE_RESET_SAVE_FAILED,
TMP102_THRESHOLD_STATUS_PREFERENCE_SAVE_FAILED,
TMP102_THRESHOLD_STATUS_RECOVERY_FAILED,
TMP102_THRESHOLD_STATUS_RECOVERED,
TMP102_THRESHOLD_STATUS_WRITE_HIGH_FAILED,
TMP102_THRESHOLD_STATUS_WRITE_LOW_FAILED,
TMP102_THRESHOLD_STATUS_SENSOR_SETUP_FAILED,
TMP102_THRESHOLD_STATUS_COUNT,
};
#ifdef USE_TMP102_TEXT_SENSOR
PROGMEM_STRING_TABLE(ThresholdStatusStrings, "Not configured", "Setup failed", "OK", "Restored thresholds reset",
"Restore reset; save failed", "Preference save failed", "Configuration recovery failed",
"Configuration restored", "Write failed: high threshold", "Write failed: low threshold",
"Rejected: sensor setup failed");
static_assert(ThresholdStatusStrings::COUNT == TMP102_THRESHOLD_STATUS_COUNT);
#endif
#if defined(USE_TMP102_CONFIGURE) || defined(USE_TMP102_BINARY_SENSOR)
static constexpr uint8_t TMP102_REGISTER_CONFIGURATION = 0x01;
static constexpr uint16_t TMP102_ALERT_BIT = 0x0020;
@@ -42,15 +72,30 @@ static uint16_t encode_temperature(float temperature, bool extended) {
return static_cast<uint16_t>(static_cast<uint32_t>(static_cast<uint16_t>(steps)) << (extended ? 3 : 4));
}
#endif
#endif
#if defined(USE_TMP102_CONFIGURE) || defined(USE_TMP102_TEXT_SENSOR)
void TMP102Component::setup() {
if (!this->configure_)
#ifdef USE_TMP102_CONFIGURE
if (this->configure_) {
this->setup_configured_();
return;
}
#endif
this->publish_threshold_status_(TMP102_THRESHOLD_STATUS_NOT_CONFIGURED);
}
#endif
#ifdef USE_TMP102_CONFIGURE
void TMP102Component::setup_configured_() {
bool corrected = false;
#ifdef USE_TMP102_NUMBER
float restored[2]{};
this->prepare_number_limits_(restored);
bool restore_corrected[2]{};
corrected = this->prepare_number_limits_(restored, restore_corrected);
#endif
if (!this->write_configuration_()) {
this->publish_threshold_status_(TMP102_THRESHOLD_STATUS_SETUP_FAILED);
this->mark_failed();
return;
}
@@ -61,14 +106,17 @@ void TMP102Component::setup() {
if (control == nullptr)
continue;
const float value = this->get_limit_temperature_(static_cast<TMP102LimitType>(limit));
if (value != restored[limit])
if (restore_corrected[limit] || value != restored[limit])
saved &= control->save_value_(value);
control->publish_state(value);
}
if (!saved) {
ESP_LOGW(TAG, "Failed to save threshold preferences");
this->publish_threshold_status_(TMP102_THRESHOLD_STATUS_RESTORE_RESET_SAVE_FAILED);
return;
}
#endif
this->publish_threshold_status_(corrected ? TMP102_THRESHOLD_STATUS_RESTORE_RESET : TMP102_THRESHOLD_STATUS_OK);
}
#endif
@@ -83,6 +131,9 @@ void TMP102Component::dump_config() {
#ifdef USE_TMP102_BINARY_SENSOR
LOG_BINARY_SENSOR(" ", "Alert", this->alert_binary_sensor_);
#endif
#ifdef USE_TMP102_TEXT_SENSOR
LOG_TEXT_SENSOR(" ", "Threshold Status", this->threshold_status_text_sensor_);
#endif
#ifdef USE_TMP102_CONFIGURE
if (!this->configure_)
return;
@@ -203,6 +254,9 @@ bool TMP102Component::check_configuration_() {
this->set_warning_and_invalidate_alert_();
if (!this->write_configuration_()) {
ESP_LOGW(TAG, "Failed to restore configuration and thresholds");
this->publish_threshold_status_(TMP102_THRESHOLD_STATUS_RECOVERY_FAILED);
} else {
this->publish_threshold_status_(TMP102_THRESHOLD_STATUS_RECOVERED);
}
return false;
}
@@ -228,22 +282,25 @@ void TMP102Component::set_limit_control(TMP102LimitNumber *number) {
this->limit_controls_[number->limit_type_] = number;
}
void TMP102Component::prepare_number_limits_(float *restored) {
bool TMP102Component::prepare_number_limits_(float *restored, bool *restore_corrected) {
const bool extended = this->config_ & TMP102_EXTENDED_MODE_BIT;
uint16_t raw[2] = {this->low_limit_, this->high_limit_};
bool corrected = false;
for (uint8_t limit = 0; limit < 2; ++limit) {
TMP102LimitNumber *control = this->limit_controls_[limit];
if (control == nullptr)
continue;
restored[limit] = control->load_value_(decode_temperature(raw[limit], extended));
restored[limit] = control->load_value_(decode_temperature(raw[limit], extended), restore_corrected[limit]);
corrected |= restore_corrected[limit];
raw[limit] = encode_temperature(restored[limit], extended);
}
if (static_cast<int16_t>(raw[TMP102_LIMIT_LOW]) > static_cast<int16_t>(raw[TMP102_LIMIT_HIGH])) {
ESP_LOGW(TAG, "Restored thresholds are inverted; using configured values");
return;
return true;
}
this->low_limit_ = raw[TMP102_LIMIT_LOW];
this->high_limit_ = raw[TMP102_LIMIT_HIGH];
return corrected;
}
float TMP102Component::get_limit_temperature_(TMP102LimitType limit) const {
@@ -261,10 +318,13 @@ bool TMP102Component::set_limit_temperature_(TMP102LimitType limit, float temper
ESP_LOGW(TAG, "Rejected %s threshold %.4f°C: crosses %s threshold %.4f°C",
high ? LOG_STR_LITERAL("high") : LOG_STR_LITERAL("low"), decode_temperature(raw, extended),
high ? LOG_STR_LITERAL("low") : LOG_STR_LITERAL("high"), decode_temperature(other, extended));
this->publish_threshold_rejection_(high, decode_temperature(raw, extended), decode_temperature(other, extended));
return false;
}
if (!this->write_register_(static_cast<uint8_t>(TMP102_REGISTER_LOW_LIMIT + limit), raw)) {
this->status_set_warning();
this->publish_threshold_status_(high ? TMP102_THRESHOLD_STATUS_WRITE_HIGH_FAILED
: TMP102_THRESHOLD_STATUS_WRITE_LOW_FAILED);
return false;
}
(high ? this->high_limit_ : this->low_limit_) = raw;
@@ -273,6 +333,32 @@ bool TMP102Component::set_limit_temperature_(TMP102LimitType limit, float temper
#endif
#endif
#ifdef USE_TMP102_TEXT_SENSOR
void TMP102Component::publish_threshold_status_(uint8_t status) {
if (this->threshold_status_text_sensor_ == nullptr)
return;
char text[40];
ESPHOME_strncpy_P(
text,
reinterpret_cast<ESPHOME_PGM_P>(ThresholdStatusStrings::get_progmem_str(status, TMP102_THRESHOLD_STATUS_OK)),
sizeof(text));
text[sizeof(text) - 1] = '\0';
this->threshold_status_text_sensor_->publish_state(text);
}
void TMP102Component::publish_threshold_rejection_(bool high, float value, float other) {
if (this->threshold_status_text_sensor_ == nullptr)
return;
char text[96];
if (high) {
ESPHOME_snprintf_P(text, sizeof(text), ESPHOME_PSTR("Rejected: high %.4f°C crosses low %.4f°C"), value, other);
} else {
ESPHOME_snprintf_P(text, sizeof(text), ESPHOME_PSTR("Rejected: low %.4f°C crosses high %.4f°C"), value, other);
}
this->threshold_status_text_sensor_->publish_state(text);
}
#endif
#ifdef USE_TMP102_BINARY_SENSOR
void TMP102Component::invalidate_alert_() {
if (this->alert_binary_sensor_ != nullptr)
@@ -294,7 +380,7 @@ bool TMP102Component::read_alert_state_() {
#endif
#ifdef USE_TMP102_NUMBER
float TMP102LimitNumber::load_value_(float fallback) {
float TMP102LimitNumber::load_value_(float fallback, bool &corrected) {
float value = fallback;
if (this->restore_value_) {
this->pref_ = this->make_entity_preference<float>();
@@ -303,6 +389,7 @@ float TMP102LimitNumber::load_value_(float fallback) {
if (!std::isfinite(value) || value < this->traits.get_min_value() || value > this->traits.get_max_value()) {
ESP_LOGW(TAG, "Invalid restored threshold; using configured value");
value = fallback;
corrected = true;
}
return value;
}
@@ -313,6 +400,7 @@ void TMP102LimitNumber::control(float value) {
// A chip that failed setup holds nothing the entity could show
if (this->parent_->is_failed()) {
ESP_LOGW(TAG, "Rejected threshold change: sensor setup failed");
this->parent_->publish_threshold_status_(TMP102_THRESHOLD_STATUS_SENSOR_SETUP_FAILED);
return;
}
const bool accepted = this->parent_->set_limit_temperature_(this->limit_type_, value);
@@ -320,6 +408,9 @@ void TMP102LimitNumber::control(float value) {
this->publish_state(value);
if (accepted && !this->save_value_(value)) {
ESP_LOGW(TAG, "Failed to save threshold preference");
this->parent_->publish_threshold_status_(TMP102_THRESHOLD_STATUS_PREFERENCE_SAVE_FAILED);
} else if (accepted) {
this->parent_->publish_threshold_status_(TMP102_THRESHOLD_STATUS_OK);
}
}
#endif
+28 -4
View File
@@ -12,11 +12,20 @@
#include "esphome/core/preferences.h"
#endif
#include "esphome/components/sensor/sensor.h"
#ifdef USE_TMP102_TEXT_SENSOR
#include "esphome/components/text_sensor/text_sensor.h"
#endif
#include <cstdint>
namespace esphome::tmp102 {
#ifdef USE_HOST
namespace testing {
class TMP102Test;
}
#endif
#ifdef USE_TMP102_NUMBER
enum TMP102LimitType : uint8_t {
TMP102_LIMIT_LOW = 0,
@@ -31,8 +40,13 @@ class TMP102Component final : public PollingComponent, public i2c::I2CDevice, pu
#ifdef USE_TMP102_BINARY_SENSOR
SUB_BINARY_SENSOR(alert)
#endif
#ifdef USE_TMP102_CONFIGURE
#ifdef USE_TMP102_TEXT_SENSOR
SUB_TEXT_SENSOR(threshold_status)
#endif
#if defined(USE_TMP102_CONFIGURE) || defined(USE_TMP102_TEXT_SENSOR)
void setup() override;
#endif
#ifdef USE_TMP102_CONFIGURE
void set_configuration(uint16_t config, uint16_t high_limit, uint16_t low_limit) {
this->config_ = config;
this->high_limit_ = high_limit;
@@ -47,6 +61,13 @@ class TMP102Component final : public PollingComponent, public i2c::I2CDevice, pu
void update() override;
protected:
#ifdef USE_TMP102_TEXT_SENSOR
void publish_threshold_status_(uint8_t status);
void publish_threshold_rejection_(bool high, float value, float other);
#else
void publish_threshold_status_(uint8_t) {}
void publish_threshold_rejection_(bool, float, float) {}
#endif
void set_warning_and_invalidate_alert_() {
this->status_set_warning();
#ifdef USE_TMP102_BINARY_SENSOR
@@ -58,6 +79,7 @@ class TMP102Component final : public PollingComponent, public i2c::I2CDevice, pu
void invalidate_alert_();
#endif
#ifdef USE_TMP102_CONFIGURE
void setup_configured_();
bool write_register_(uint8_t reg, uint16_t value);
bool write_configuration_();
bool check_configuration_();
@@ -67,11 +89,10 @@ class TMP102Component final : public PollingComponent, public i2c::I2CDevice, pu
friend class TMP102LimitNumber;
bool set_limit_temperature_(TMP102LimitType limit, float temperature);
float get_limit_temperature_(TMP102LimitType limit) const;
void prepare_number_limits_(float *restored);
bool prepare_number_limits_(float *restored, bool *restore_corrected);
TMP102LimitNumber *limit_controls_[2]{};
#endif
uint16_t config_{0};
uint16_t high_limit_{0};
uint16_t low_limit_{0};
@@ -87,7 +108,10 @@ class TMP102LimitNumber final : public number::Number, public Parented<TMP102Com
protected:
friend class TMP102Component;
float load_value_(float fallback);
#ifdef USE_HOST
friend class testing::TMP102Test;
#endif
float load_value_(float fallback, bool &corrected);
bool save_value_(float value);
void control(float value) override;
+1
View File
@@ -272,6 +272,7 @@
#define USE_TMP102_BINARY_SENSOR
#define USE_TMP102_CONFIGURE
#define USE_TMP102_NUMBER
#define USE_TMP102_TEXT_SENSOR
#define USE_TOUCHSCREEN
#define USE_UART_DEBUGGER
#define USE_UART_WAKE_LOOP_ON_RX
@@ -0,0 +1,23 @@
---
esphome:
name: tmp102-test
esp32:
board: esp32dev
i2c:
sda: GPIO21
scl: GPIO22
sensor:
- platform: tmp102
id: parent_sensor
name: Temperature
text_sensor:
- platform: tmp102
tmp102_id: parent_sensor
name: First Status
- platform: tmp102
tmp102_id: parent_sensor
name: Second Status
@@ -0,0 +1,20 @@
---
esphome:
name: tmp102-test
esp32:
board: esp32dev
i2c:
sda: GPIO21
scl: GPIO22
sensor:
- platform: tmp102
id: parent_sensor
name: Temperature
text_sensor:
- platform: tmp102
tmp102_id: parent_sensor
name: Threshold Status
@@ -58,6 +58,30 @@ def test_duplicate_alert_entities_are_rejected(
)
def test_status_entity_is_read_only(
generate_main: Callable[[Path], str],
component_config_path: Callable[[str], Path],
) -> None:
source = generate_main(component_config_path("status.yaml"))
assert "set_threshold_status_text_sensor" in source
assert "set_configuration" not in source
defines = " ".join(define.name for define in CORE.defines)
assert "USE_TMP102_TEXT_SENSOR" in defines
assert "USE_TMP102_CONFIGURE" not in defines
def test_duplicate_status_entities_are_rejected(
component_config_path: Callable[[str], Path],
capsys: pytest.CaptureFixture[str],
) -> None:
CORE.config_path = component_config_path("duplicate_status.yaml")
assert read_config({}) is None
assert (
"Only one TMP102 text_sensor may reference each temperature sensor"
in capsys.readouterr().out
)
def test_threshold_numbers_enable_configuration_once(
generate_main: Callable[[Path], str],
component_config_path: Callable[[str], Path],
+3 -1
View File
@@ -6,11 +6,12 @@ from tests.testing_helpers import ComponentManifestOverride
def override_manifest(manifest: ComponentManifestOverride) -> None:
async def to_code_testing(config: ConfigType) -> None:
for platform in ("sensor", "binary_sensor", "number"):
for platform in ("sensor", "binary_sensor", "number", "text_sensor"):
CORE.testing_ensure_platform_registered(platform)
cg.add_define("USE_TMP102_CONFIGURE")
cg.add_define("USE_TMP102_BINARY_SENSOR")
cg.add_define("USE_TMP102_NUMBER")
cg.add_define("USE_TMP102_TEXT_SENSOR")
manifest.to_code = to_code_testing
manifest.dependencies = manifest.dependencies + [
@@ -18,4 +19,5 @@ def override_manifest(manifest: ComponentManifestOverride) -> None:
"sensor",
"binary_sensor",
"number",
"text_sensor",
]
+5
View File
@@ -30,3 +30,8 @@ binary_sensor:
- platform: tmp102
tmp102_id: tmp102_extended_temperature
name: TMP102 Alert
text_sensor:
- platform: tmp102
tmp102_id: tmp102_extended_temperature
name: TMP102 Threshold Status
@@ -0,0 +1,12 @@
packages:
i2c: !include ../../test_build_components/common/i2c/esp32-idf.yaml
sensor:
- platform: tmp102
id: tmp102_text_sensor_parent
name: TMP102 Temperature
text_sensor:
- platform: tmp102
tmp102_id: tmp102_text_sensor_parent
name: TMP102 Threshold Status
+94
View File
@@ -4,6 +4,7 @@
#include <array>
#include <cmath>
#include <functional>
#include <utility>
#include "esphome/components/host/preferences.h"
#include "esphome/components/tmp102/tmp102.h"
@@ -29,6 +30,7 @@ class RegisterBus final : public i2c::I2CBus {
unsigned transactions{0};
unsigned writes{0};
uint8_t pointer{0};
std::function<void()> on_write;
i2c::ErrorCode write_readv(uint8_t address, const uint8_t *data, size_t size, uint8_t *out,
size_t out_size) override {
@@ -42,6 +44,10 @@ class RegisterBus final : public i2c::I2CBus {
return i2c::ERROR_NOT_ACKNOWLEDGED;
++this->writes;
this->registers[this->pointer] = (uint16_t(data[1]) << 8) | data[2];
if (this->on_write) {
auto callback = std::move(this->on_write);
callback();
}
}
}
if (out_size != 0) {
@@ -59,6 +65,7 @@ class TMP102Test : public ::testing::Test {
RegisterBus bus_;
TMP102Component chip_;
binary_sensor::BinarySensor alert_;
text_sensor::TextSensor status_;
TMP102LimitNumber high_{TMP102_LIMIT_HIGH};
TMP102LimitNumber low_{TMP102_LIMIT_LOW};
unsigned publications_{0};
@@ -122,6 +129,8 @@ class TMP102Test : public ::testing::Test {
static void save(TMP102LimitNumber &number, float value) {
ASSERT_TRUE(number.make_entity_preference<float>().save(&value));
}
static void fail_saves(TMP102LimitNumber &number) { number.pref_ = {}; }
};
TEST_F(TMP102Test, LegacySetupAndContinuousReadDoNotWriteRegisters) {
@@ -136,6 +145,24 @@ TEST_F(TMP102Test, LegacySetupAndContinuousReadDoNotWriteRegisters) {
EXPECT_EQ(this->bus_.registers, original);
}
TEST_F(TMP102Test, ReadOnlyStatusDoesNotConfigureOrWriteRegisters) {
this->chip_.set_threshold_status_text_sensor(&this->status_);
const auto original = this->bus_.registers;
this->chip_.setup();
EXPECT_EQ(this->bus_.transactions, 0);
EXPECT_EQ(this->bus_.registers, original);
ASSERT_TRUE(this->status_.has_state());
EXPECT_EQ(this->status_.state, "Not configured");
}
TEST_F(TMP102Test, ConfiguredSetupPublishesStatus) {
this->chip_.set_threshold_status_text_sensor(&this->status_);
this->configure();
this->chip_.setup();
ASSERT_TRUE(this->status_.has_state());
EXPECT_EQ(this->status_.state, "OK");
}
TEST_F(TMP102Test, SampleFormatOverridesConfiguredModeInBothDirections) {
for (bool configured_extended : {false, true}) {
this->configure(configured_extended ? 0x0010 : 0, configured_extended ? 0x2800 : 0x5000,
@@ -408,6 +435,7 @@ TEST_F(TMP102Test, FailureOfAnySetupWriteMarksComponentFailed) {
}
TEST_F(TMP102Test, InvalidRestoredPairIsRepairedAfterSuccessfulSetup) {
this->chip_.set_threshold_status_text_sensor(&this->status_);
this->numbers_();
save(this->high_, 20);
save(this->low_, 35);
@@ -416,30 +444,53 @@ TEST_F(TMP102Test, InvalidRestoredPairIsRepairedAfterSuccessfulSetup) {
EXPECT_FLOAT_EQ(this->low_.state, 25);
EXPECT_FLOAT_EQ(saved(this->high_), 30);
EXPECT_FLOAT_EQ(saved(this->low_), 25);
EXPECT_EQ(this->status_.state, "Restored thresholds reset");
}
TEST_F(TMP102Test, InvalidRestoredPairAndSaveFailurePublishCombinedStatus) {
this->chip_.set_threshold_status_text_sensor(&this->status_);
this->numbers_();
save(this->high_, 20);
save(this->low_, 35);
this->bus_.on_write = [this]() {
fail_saves(this->high_);
fail_saves(this->low_);
};
this->chip_.setup();
EXPECT_FLOAT_EQ(this->high_.state, 30);
EXPECT_FLOAT_EQ(this->low_.state, 25);
EXPECT_EQ(this->status_.state, "Restore reset; save failed");
}
TEST_F(TMP102Test, InvalidRestoredValuesAreRepaired) {
this->chip_.set_threshold_status_text_sensor(&this->status_);
this->numbers_();
save(this->high_, NAN);
save(this->low_, INFINITY);
this->chip_.setup();
EXPECT_FLOAT_EQ(this->high_.state, 30);
EXPECT_FLOAT_EQ(this->low_.state, 25);
EXPECT_FLOAT_EQ(saved(this->high_), 30);
EXPECT_FLOAT_EQ(saved(this->low_), 25);
EXPECT_EQ(this->status_.state, "Restored thresholds reset");
}
TEST_F(TMP102Test, FailedSetupDoesNotOverwritePreferences) {
this->chip_.set_threshold_status_text_sensor(&this->status_);
this->numbers_();
save(this->high_, 90);
save(this->low_, 85);
this->bus_.fail_write = 3;
this->chip_.setup();
EXPECT_TRUE(this->chip_.is_failed());
EXPECT_EQ(this->status_.state, "Setup failed");
EXPECT_FALSE(this->high_.has_state());
EXPECT_FLOAT_EQ(saved(this->high_), 90);
EXPECT_FLOAT_EQ(saved(this->low_), 85);
}
TEST_F(TMP102Test, FailedSetupRejectsThresholdChanges) {
this->chip_.set_threshold_status_text_sensor(&this->status_);
this->numbers_();
save(this->high_, 90);
this->bus_.fail_write = 3;
@@ -450,6 +501,7 @@ TEST_F(TMP102Test, FailedSetupRejectsThresholdChanges) {
EXPECT_FALSE(this->high_.has_state());
EXPECT_EQ(this->bus_.writes, writes);
EXPECT_FLOAT_EQ(saved(this->high_), 90);
EXPECT_EQ(this->status_.state, "Rejected: sensor setup failed");
}
TEST_F(TMP102Test, SetupOnlySavesChangedThresholds) {
@@ -464,6 +516,7 @@ TEST_F(TMP102Test, SetupOnlySavesChangedThresholds) {
}
TEST_F(TMP102Test, FailedNumberWriteKeepsAcceptedState) {
this->chip_.set_threshold_status_text_sensor(&this->status_);
this->numbers_();
save(this->high_, 90);
save(this->low_, 85);
@@ -475,6 +528,47 @@ TEST_F(TMP102Test, FailedNumberWriteKeepsAcceptedState) {
EXPECT_FLOAT_EQ(this->high_.state, 90);
EXPECT_EQ(publications, 1);
EXPECT_FLOAT_EQ(saved(this->high_), 90);
EXPECT_EQ(this->status_.state, "Write failed: high threshold");
this->bus_.fail_write = 2;
this->low_.make_call().set_value(80).perform();
EXPECT_FLOAT_EQ(this->low_.state, 85);
EXPECT_FLOAT_EQ(saved(this->low_), 85);
EXPECT_EQ(this->status_.state, "Write failed: low threshold");
}
TEST_F(TMP102Test, PreferenceSaveFailurePublishesStatus) {
this->chip_.set_threshold_status_text_sensor(&this->status_);
this->numbers_();
this->chip_.setup();
fail_saves(this->high_);
this->high_.make_call().set_value(35).perform();
EXPECT_FLOAT_EQ(this->high_.state, 35);
EXPECT_EQ(this->status_.state, "Preference save failed");
}
TEST_F(TMP102Test, RejectedNumberWritePublishesStatus) {
this->chip_.set_threshold_status_text_sensor(&this->status_);
this->numbers_();
this->chip_.setup();
this->high_.make_call().set_value(20).perform();
EXPECT_EQ(this->status_.state, "Rejected: high 20.0000°C crosses low 25.0000°C");
this->high_.make_call().set_value(35).perform();
EXPECT_EQ(this->status_.state, "OK");
}
TEST_F(TMP102Test, ConfigurationRecoveryPublishesStatus) {
this->chip_.set_threshold_status_text_sensor(&this->status_);
this->configure();
this->chip_.setup();
this->bus_.registers[1] = 0;
this->chip_.update();
EXPECT_EQ(this->status_.state, "Configuration restored");
this->bus_.registers[1] = 0;
this->bus_.fail_write = 1;
this->chip_.update();
EXPECT_EQ(this->status_.state, "Configuration recovery failed");
}
TEST_F(TMP102Test, RestoreDisabledNeverChangesSavedValue) {