[counter] Add persistent counter sensor (#19746)

This commit is contained in:
Clyde Stubbs
2026-09-27 18:25:54 +10:00
committed by GitHub
parent c26f2d28e6
commit b8af6cb005
14 changed files with 485 additions and 0 deletions
+30
View File
@@ -0,0 +1,30 @@
#pragma once
#include <gtest/gtest.h>
#include <cstdint>
#include <limits>
#include <utility>
#include "esphome/core/helpers.h"
#include "esphome/components/counter/counter_sensor.h"
namespace esphome::counter::testing {
constexpr int64_t INT64_MAX_VALUE = std::numeric_limits<int64_t>::max();
constexpr int64_t INT64_MIN_VALUE = std::numeric_limits<int64_t>::min();
/// Stands in for a binary sensor: reports each state to its callbacks.
struct FakeBinarySource {
template<typename F> void add_on_state_callback(F &&callback) { this->callbacks_.add(std::forward<F>(callback)); }
void publish(bool state) { this->callbacks_.call(state); }
CallbackManager<void(bool)> callbacks_;
};
// Restore is off so no preference storage is needed.
class CounterTest : public ::testing::Test {
protected:
CounterSensor counter_{false, 0};
};
} // namespace esphome::counter::testing
+37
View File
@@ -0,0 +1,37 @@
esphome:
on_boot:
then:
- counter.set_value:
id: counter_sensor
value: 100
- counter.increment: counter_sensor
- counter.increment:
id: counter_sensor
value: -5
- counter.increment:
id: counter_sensor
value: !lambda "return 5000000000LL;"
sensor:
- platform: counter
id: counter_sensor
name: Counter
- platform: counter
id: counter_no_restore
name: Counter No Restore
restore: false
initial_value: 10
- platform: template
id: source_sensor
lambda: return 1.0;
update_interval: 1s
- platform: counter
name: Counter Of Sensor
sensor: source_sensor
- platform: counter
name: Counter Of Binary Sensor
binary_sensor: source_binary_sensor
binary_sensor:
- platform: template
id: source_binary_sensor
@@ -0,0 +1,84 @@
#include "../common.h"
namespace esphome::counter::testing {
TEST_F(CounterTest, StartsAtZero) {
this->counter_.setup();
EXPECT_EQ(this->counter_.state, 0.0f);
}
TEST(CounterInitialValue, PublishedAtSetupWhenNotRestoring) {
CounterSensor counter(false, -12);
counter.setup();
EXPECT_EQ(counter.state, -12.0f);
counter.increment();
EXPECT_EQ(counter.state, -11.0f);
}
TEST_F(CounterTest, SetValuePublishesState) {
this->counter_.set_value(42);
EXPECT_EQ(this->counter_.state, 42.0f);
}
TEST_F(CounterTest, IncrementDefaultsToOne) {
this->counter_.increment();
this->counter_.increment();
EXPECT_EQ(this->counter_.state, 2.0f);
}
TEST_F(CounterTest, IncrementAcceptsNegativeAmounts) {
this->counter_.set_value(10);
this->counter_.increment(-25);
EXPECT_EQ(this->counter_.state, -15.0f);
}
TEST_F(CounterTest, ValueBeyondInt32) {
this->counter_.set_value(5000000000LL);
this->counter_.increment(5000000000LL);
EXPECT_EQ(this->counter_.state, 1.0e10f);
}
TEST_F(CounterTest, IncrementWrapsAtInt64Limits) {
this->counter_.set_value(INT64_MAX_VALUE);
this->counter_.increment(1);
EXPECT_EQ(this->counter_.state, static_cast<float>(INT64_MIN_VALUE));
this->counter_.set_value(INT64_MIN_VALUE);
this->counter_.increment(-1);
EXPECT_EQ(this->counter_.state, static_cast<float>(INT64_MAX_VALUE));
}
TEST_F(CounterTest, CountsEachPublishFromSource) {
sensor::Sensor source;
this->counter_.count_updates_from(&source);
// The counted value is unrelated to what the source publishes.
source.publish_state(10.0f);
source.publish_state(10.0f);
source.publish_state(-3.5f);
EXPECT_EQ(this->counter_.state, 3.0f);
}
TEST_F(CounterTest, SourceUpdatesAddToCurrentValue) {
sensor::Sensor source;
this->counter_.count_updates_from(&source);
this->counter_.set_value(100);
source.publish_state(1.0f);
EXPECT_EQ(this->counter_.state, 101.0f);
}
TEST_F(CounterTest, CountsOnlyTrueFromBinarySource) {
FakeBinarySource source;
this->counter_.count_true_from(&source);
source.publish(true);
source.publish(false);
EXPECT_EQ(this->counter_.state, 1.0f);
source.publish(true);
source.publish(false);
source.publish(false);
EXPECT_EQ(this->counter_.state, 2.0f);
}
} // namespace esphome::counter::testing
@@ -0,0 +1,2 @@
packages:
counter: !include common.yaml
@@ -0,0 +1,12 @@
packages:
counter: !include common.yaml
esphome:
on_shutdown:
then:
- counter.set_value:
id: counter_no_restore
value: -9223372036854775807
- counter.increment:
id: counter_no_restore
value: 9223372036854775807