Skip to content

Commit

Permalink
energy_statistics: add year, add partial update #65
Browse files Browse the repository at this point in the history
  • Loading branch information
dentra committed Jan 14, 2025
1 parent 5ec3ee7 commit 91e438d
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 34 deletions.
41 changes: 24 additions & 17 deletions components/energy_statistics/README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
# Energy Statistics

Gather statistics for:
* today
* yesterday
* week
* month

> You can take a look at sample of usage of Energy* components in configuartion for `ZMAi-90` energy meter based on `TYWE3S`: [zmai90.yaml](../zmai90.yaml)
- today
- yesterday
- week
- month
- year

> You can take a look at sample of usage of Energy\* components in configuartion for `ZMAi-90` energy meter based on `TYWE3S`: [zmai90.yaml](../zmai90.yaml)
```yaml
# Example configuration entry
...
...
external_components:
- source: github://dentra/esphome-components
...
...
sensor:
- platform: "energy_statistics"
total: total
Expand All @@ -25,16 +27,21 @@ sensor:
name: "$name Energy Week"
energy_month:
name: "$name Energy Month"
energy_year:
name: "$name Energy Year"
```
## Configuration variables:
* **id** (*Optional*, [ID](https://esphome.io/guides/configuration-types.html#config-id)): Manually specify the ID used for code generation.
* **total** (**Required**, [ID](https://esphome.io/guides/configuration-types.html#config-id)): The ID of the total power sensor.
* **energy_today** (*Optional*, Sensor):
* Any options from [Sensor](https://esphome.io/components/sensor/index.html#config-sensor).
* **energy_yesterday** (*Optional*, Sensor):
* Any options from [Sensor](https://esphome.io/components/sensor/index.html#config-sensor).
* **energy_week** (*Optional*, Sensor):
* Any options from [Sensor](https://esphome.io/components/sensor/index.html#config-sensor).
* **energy_month** (*Optional*, Sensor):
* Any options from [Sensor](https://esphome.io/components/sensor/index.html#config-sensor).
- **id** (_Optional_, [ID](https://esphome.io/guides/configuration-types.html#config-id)): Manually specify the ID used for code generation.
- **total** (**Required**, [ID](https://esphome.io/guides/configuration-types.html#config-id)): The ID of the total power sensor.
- **energy_today** (_Optional_, Sensor):
- Any options from [Sensor](https://esphome.io/components/sensor/index.html#config-sensor).
- **energy_yesterday** (_Optional_, Sensor):
- Any options from [Sensor](https://esphome.io/components/sensor/index.html#config-sensor).
- **energy_week** (_Optional_, Sensor):
- Any options from [Sensor](https://esphome.io/components/sensor/index.html#config-sensor).
- **energy_month** (_Optional_, Sensor):
- Any options from [Sensor](https://esphome.io/components/sensor/index.html#config-sensor).
- **energy_year** (_Optional_, Sensor):
- Any options from [Sensor](https://esphome.io/components/sensor/index.html#config-sensor).
49 changes: 36 additions & 13 deletions components/energy_statistics/energy_statistics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,45 @@ namespace esphome {
namespace energy_statistics {

static const char *const TAG = "energy_statistics";
static const char *const GAP = " ";

static const char *const PREF_V1 = "energy_statistics";
static const char *const PREF_V2 = "energy_statistics_v2";

void EnergyStatistics::dump_config() {
ESP_LOGCONFIG(TAG, "Energy statistics sensors");
if (this->energy_today_) {
LOG_SENSOR(GAP, "Energy Today", this->energy_today_);
LOG_SENSOR(" ", "Energy Today", this->energy_today_);
}
if (this->energy_yesterday_) {
LOG_SENSOR(GAP, "Energy Yesterday", this->energy_yesterday_);
LOG_SENSOR(" ", "Energy Yesterday", this->energy_yesterday_);
}
if (this->energy_week_) {
LOG_SENSOR(GAP, "Energy Week", this->energy_week_);
LOG_SENSOR(" ", "Energy Week", this->energy_week_);
}
if (this->energy_month_) {
LOG_SENSOR(GAP, "Energy Month", this->energy_month_);
LOG_SENSOR(" ", "Energy Month", this->energy_month_);
}
if (this->energy_year_) {
LOG_SENSOR(" ", "Energy Year", this->energy_year_);
}
}

void EnergyStatistics::setup() {
this->total_->add_on_state_callback([this](float state) { this->process_(state); });

this->pref_ = global_preferences->make_preference<energy_data_t>(fnv1_hash(TAG));

energy_data_t loaded{};
if (this->pref_.load(&loaded)) {
this->energy_ = loaded;
this->pref_ = global_preferences->make_preference<energy_data_t>(fnv1_hash(PREF_V2));
bool loaded = this->pref_.load(&this->energy_);
if (!loaded) {
// migrating from v1 data
loaded = global_preferences->make_preference<energy_data_v1_t>(fnv1_hash(PREF_V1)).load(&this->energy_);
if (loaded) {
this->energy_.start_year = this->energy_.start_month;
// save as v2
this->pref_.save(&this->energy_);
global_preferences->sync();
}
}
if (loaded) {
auto total = this->total_->get_state();
if (!std::isnan(total)) {
this->process_(total);
Expand All @@ -52,6 +65,7 @@ void EnergyStatistics::loop() {
return;
}

// update stats first time or on next day
if (t.day_of_year == this->energy_.current_day_of_year) {
// nothing to do
return;
Expand All @@ -72,6 +86,17 @@ void EnergyStatistics::loop() {
}
}

// Intitialize all sensors. https://github.com/dentra/esphome-components/issues/65
if (this->energy_week_ && std::isnan(this->energy_.start_week)) {
this->energy_.start_week = this->energy_.start_yesterday;
}
if (this->energy_month_ && std::isnan(this->energy_.start_month)) {
this->energy_.start_month = this->energy_.start_yesterday;
}
if (this->energy_year_ && std::isnan(this->energy_.start_year)) {
this->energy_.start_year = this->energy_.start_yesterday;
}

this->energy_.current_day_of_year = t.day_of_year;

this->process_(total);
Expand All @@ -94,10 +119,8 @@ void EnergyStatistics::process_(float total) {
this->energy_month_->publish_state(total - this->energy_.start_month);
}

this->save_();
this->pref_.save(&this->energy_);
}

void EnergyStatistics::save_() { this->pref_.save(&(this->energy_)); }

} // namespace energy_statistics
} // namespace esphome
9 changes: 7 additions & 2 deletions components/energy_statistics/energy_statistics.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class EnergyStatistics : public Component {
void set_energy_yesterday(Sensor *sensor) { this->energy_yesterday_ = sensor; }
void set_energy_week(Sensor *sensor) { this->energy_week_ = sensor; }
void set_energy_month(Sensor *sensor) { this->energy_month_ = sensor; }
void set_energy_year(Sensor *sensor) { this->energy_year_ = sensor; }

protected:
ESPPreferenceObject pref_;
Expand All @@ -38,22 +39,26 @@ class EnergyStatistics : public Component {
Sensor *energy_yesterday_{nullptr};
Sensor *energy_week_{nullptr};
Sensor *energy_month_{nullptr};
Sensor *energy_year_{nullptr};

// start day of week configuration
int energy_week_start_day_{2};
// start day of month configuration
int energy_month_start_day_{1};

struct energy_data_t {
struct energy_data_v1_t {
uint16_t current_day_of_year{0};
float start_today{NAN};
float start_yesterday{NAN};
float start_week{NAN};
float start_month{NAN};
};

struct energy_data_t : public energy_data_v1_t {
float start_year{NAN};
} energy_;

void process_(float total);
void save_();
}; // class EnergyStatistics

} // namespace energy_statistics
Expand Down
12 changes: 10 additions & 2 deletions components/energy_statistics/sensor.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import esphome.config_validation as cv
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor, time
from esphome.const import (
CONF_ID,
CONF_TIME_ID,
CONF_POWER,
CONF_TIME_ID,
CONF_TOTAL,
DEVICE_CLASS_ENERGY,
STATE_CLASS_TOTAL_INCREASING,
Expand All @@ -19,6 +19,7 @@
CONF_ENERGY_YESTERDAY = "energy_yesterday"
CONF_ENERGY_WEEK = "energy_week"
CONF_ENERGY_MONTH = "energy_month"
CONF_ENERGY_YEAR = "energy_year"

energy_statistics_ns = cg.esphome_ns.namespace("energy_statistics")

Expand Down Expand Up @@ -53,6 +54,12 @@
device_class=DEVICE_CLASS_ENERGY,
state_class=STATE_CLASS_TOTAL_INCREASING,
),
cv.Optional(CONF_ENERGY_YEAR): sensor.sensor_schema(
unit_of_measurement=UNIT_KILOWATT_HOURS,
accuracy_decimals=2,
device_class=DEVICE_CLASS_ENERGY,
state_class=STATE_CLASS_TOTAL_INCREASING,
),
}
).extend(cv.COMPONENT_SCHEMA)

Expand Down Expand Up @@ -92,3 +99,4 @@ async def to_code(config):
await setup_sensor(config, CONF_ENERGY_YESTERDAY, var.set_energy_yesterday)
await setup_sensor(config, CONF_ENERGY_WEEK, var.set_energy_week)
await setup_sensor(config, CONF_ENERGY_MONTH, var.set_energy_month)
await setup_sensor(config, CONF_ENERGY_YEAR, var.set_energy_year)

0 comments on commit 91e438d

Please sign in to comment.