Thomas shares makes

2024-01-29

Virtual Solar/Grid power meters

block diagram

I want to keep counters for how much solar panel energy and grid energy my car uses. I have power meters for the Solar, Grid and the car. The power the rest of the house uses is however unknown, and measured by the grid meter. Determining the car's part of grid and solar power requires some calculations.

I created home assistant template sensors to come up with these power numbers, and added integrators to obtain energy meters.

Splitting the power

Scenario's

To end up with two virtual power meters, we need a formula for the solar and grid part of the power mix. Since we are dealing with an unknown part of House power use, I drew vector diagrams for each scenario that is possible:

  • Grid + Solar
  • Grid only
  • Solar only

Every consumer (house, car) and producer (solar, grid) is represented by an arrow. The following abbreviations are used:

  • X: The device, the car in this case
  • H: Devices in the Home
  • S: Solar production
block diagram

Scenario's of production and consumption

With every scenario plotted, the parts of interest can be marked:

  • XS: Device used solar power
  • XG: Device used grid power

Home assistant entities

Working around an integration sensor caveat

The Riemann sum integral integration in Home Assistant can be used to turn the power measured by a home assistant entity into an energy measurement.

I am observing an issue with this however. The algorithm will calculate the area of a geometric shape of the input samples amplitudes and the time between the samples and add these finite sums.

If the power value stays zero for a while the next input value will cause it to report an amount of energy was used in the period that the power value was zero.

block diagram

integration sensor output with error marked.

A workaround that I found online for this is to update the sensor every second and add a dummy attribute containing the current time.

Template sensor

Here is a listing of the template sensor code as I use it:

- trigger:
    - platform: time_pattern
      minutes: "/1"
    - platform: state
      entity_id:
        - sensor.electricity_meter_power_production
        - sensor.electricity_meter_power_consumption
        - sensor.solaredge_ac_power
        - sensor.sdm630_total_system_power
      not_from:
        - "unknown"
        - "unavailable"
      not_to:
        - "unknown"
        - "unavailable"
  sensor:
    - name: car_grid_power
      unique_id: car_grid_power
      unit_of_measurement: W
      device_class: power
      state_class: measurement
      state: >
        {% set production = states('sensor.electricity_meter_power_production')|float %}
        {% set consumption = states('sensor.electricity_meter_power_consumption')|float %}
        {% set g = consumption - production %}
        {% set s = states('sensor.solaredge_ac_power')|float /1000 %}
        {% set d = states('sensor.sdm630_total_system_power')|float /1000%}
        {%- if d < 0.0001 -%}
        0.000
        {%- elif g > 0 and g < d -%}
        {# grid+solar #}
        {{ '%0.3f' | format(g) }}
        {% elif g >= 0 %}
        {# grid only #}
        {{ '%0.3f' | format(d) }}
        {% else %}
        0.000
        {% endif %}
      attributes:
        dummy: "{{ now().minute }}"
    - name: car_solar_power
      unique_id: car_solar_power
      unit_of_measurement: W
      device_class: power
      state_class: measurement
      state: >
        {% set production = states('sensor.electricity_meter_power_production')|float %}
        {% set consumption = states('sensor.electricity_meter_power_consumption')|float %}
        {% set g = consumption - production %}
        {% set s = states('sensor.solaredge_ac_power')|float /1000 %}
        {% set d = states('sensor.sdm630_total_system_power')|float /1000%}
        {%- if d < 0.0001 -%}
        0.000
        {%- elif g > 0 and g < d -%}
        {# grid+solar #}
        {{ '%0.3f' | format(d-g) }}
        {% elif g >= 0 %}
        {# grid only #}
        0.000
        {%- else -%}
        {# solar only #}
        {{ '%0.3f' | format(d) }}
        {%- endif  %}
      attributes:
        dummy: "{{ now().minute }}"

Energy meters

And these are integrated into energy meters by the following old-style sensors:

- platform: integration
  name: total_car_grid_energy
  source: sensor.car_grid_power
  round: 2

- platform: integration
  name: total_car_solar_energy
  source: sensor.car_solar_power
  round: 2

Limitations and conclusion

The code I shared can only be used to track one device in your house in its current form, but I think it is useful nonetheless.

I hope someone finds this useful and can reuse it or use it as inspiration.


Liked something? Worked on something similar? Let me know what you think on Mastodon!
You can use your Mastodon account to reply to this post.

Reply to post

You can respond to this post with an account on the Fediverse or Mastodon. Since Mastodon is decentralized, you can use your existing account or create your account on a server of your choice.

Copy and paste this URL into the search field of your favourite Fediverse app or the web interface of your Mastodon server.

Learn how @carlschwan wrote the code that loads Mastodon posts into this webpage here.

Follow me on Mastodon!