Calculate a device's theoretical power comsumption by the time it's on

ok, I believe I have figured out how to do this - my solution is probably incredibly scruffy, but at least it seems to get the job done.

First I made a template sensor that will output the kW of the device (in my case a heater with 1kW rating)

  - platform: template
    sensors:

      sz_h_current_power_draw:
        friendly_name: "Schlafzimmer Heizung momentaner Stromverbrauch"
        unit_of_measurement: 'kW'
        value_template: >
          {% if is_state('switch.osram_smartplug_01_switch', 'on') %}
              {{ states.input_number.sz_h_on.state }}
          {% else %}
              {{ (states.input_number.sz_h_off.state)|float / 2 }}
          {% endif %}

as you can see I use input numbers:

sz_h_on:
    name: sz_h_on
    min: 0
    max: 3
    step: 1

sz_h_off:
    name: sz_h_off
    min: 0
    max: 0.001
    step: 0.001

The reason is, that only when the value changes, the following integration sensor

  - platform: integration
    source: sensor.sz_h_current_power_draw
    name: sz_h_power_draw
    round: 5

updates. (without that it will allways assume the used energy is the average between on and off - the last two values it knows. so no matter if you turn the switch on or off, it will return the same kWh used)

To prevent this, we need 4 automations:

- id: 'sz heater power refresh_1'
  alias: sz_heater_power_refresh_1
  trigger:
  - platform: state
    entity_id: switch.osram_smartplug_01_switch
    to: 'on'
  action:
  - service: automation.turn_off
    entity_id: automation.sz_heater_power_refresh_off
  - service: automation.turn_on
    entity_id: automation.sz_heater_power_refresh_on

- id: 'sz heater power refresh_0'
  alias: sz_heater_power_refresh_0
  trigger:
  - platform: state
    entity_id: switch.osram_smartplug_01_switch
    to: 'off'
  action:
  - service: automation.turn_off
    entity_id: automation.sz_heater_power_refresh_on
  - service: automation.turn_on
    entity_id: automation.sz_heater_power_refresh_off



- id: 'sz heater power refresh on '
  alias: sz_heater_power_refresh_on
  trigger:
  - platform: time_pattern
    seconds: '/10'
  action:
  - service: input_number.set_value
    data_template:
      entity_id: input_number.sz_h_on
      value: "0.99"
  - delay: 00:00:04
  - service: input_number.set_value
    data_template:
      entity_id: input_number.sz_h_on
      value: "1.01"

- id: 'sz heater power refresh off '
  alias: sz_heater_power_refresh_off
  trigger:
  - platform: time_pattern
    seconds: '/10'
  action:
  - service: input_number.set_value
    data_template:
      entity_id: input_number.sz_h_off
      value: "0.001"
  - delay: 00:00:04
  - service: input_number.set_value
    data_template:
      entity_id: input_number.sz_h_off
      value: "0"

The first two are here to trigger the last two according to the power state of the switch.

The last two automations change the input_numbers that are tied to the power sensor minimally, so that the integration sensor gets regular readings it can work with.

Basically, the automations loop every 5sec between 0.99 and 1.01kW if the device is on (which results in 1kW in average) and between 0 and 0.001kW when it’s off (unfortunately 0.001 is the lowest number the input_number supports, which results in 0.5W as the lowest power consumption (the plug uses 0.1-0.3 when in standby) - as you can see, I divided the sz_heater_power_refresh_off value in the template sensor by 2, which results in 0.25W standby power consumption )

Like I said - it works, but I’m sure there is a much simlper way to do that. Probably a script or something, but I have no idea how to approach that…

It seems that I’ve managed to find a very simple solution - only “downside” is that it works with Node Red.

Basically Node Red calculates the kWh by looking at the duration of the last state (on or off) of a switch, sends this value via MQTT to a sensor in Home Assistant, which gets read by the Utility Meter and added up.

First you need to make a flow like that :

Here’s the flow to copy:

[
    {
        "id": "82770b78.c61bb8",
        "type": "server-state-changed",
        "z": "3c74f436.9e051c",
        "name": "XYZ ON",
        "server": "938bbb0d.d39038",
        "version": 1,
        "exposeToHomeAssistant": false,
        "haConfig": [
            {
                "property": "name",
                "value": ""
            },
            {
                "property": "icon",
                "value": ""
            }
        ],
        "entityidfilter": "switch.xyz",
        "entityidfiltertype": "exact",
        "outputinitially": false,
        "state_type": "str",
        "haltifstate": "",
        "halt_if_type": "str",
        "halt_if_compare": "is",
        "outputs": 1,
        "output_only_on_state_change": true,
        "x": 100,
        "y": 1500,
        "wires": [
            [
                "451731a4.89d82"
            ]
        ]
    },
    {
        "id": "2ef96586.96ce9a",
        "type": "interval-length",
        "z": "3c74f436.9e051c",
        "format": "mills",
        "bytopic": false,
        "minimum": "",
        "maximum": "",
        "window": "",
        "timeout": false,
        "msgTimeout": "",
        "minimumunit": "msecs",
        "maximumunit": "msecs",
        "windowunit": "msecs",
        "msgTimeoutUnit": "msecs",
        "reset": false,
        "startup": false,
        "msgField": "payload",
        "timestampField": "timestamp",
        "repeatTimeout": false,
        "name": "",
        "x": 480,
        "y": 1500,
        "wires": [
            [
                "3b31d530.44a95a",
                "afc1d974.630488"
            ],
            []
        ]
    },
    {
        "id": "3b31d530.44a95a",
        "type": "api-current-state",
        "z": "3c74f436.9e051c",
        "name": "OFF",
        "server": "938bbb0d.d39038",
        "version": 1,
        "outputs": 2,
        "halt_if": "off",
        "halt_if_type": "str",
        "halt_if_compare": "is",
        "override_topic": false,
        "entity_id": "switch.xyz",
        "state_type": "str",
        "state_location": "",
        "override_payload": "none",
        "entity_location": "",
        "override_data": "none",
        "blockInputOverrides": false,
        "x": 670,
        "y": 1440,
        "wires": [
            [
                "caf894a8.d73fb8",
                "bbd5ce79.d3dfe"
            ],
            []
        ]
    },
    {
        "id": "afc1d974.630488",
        "type": "api-current-state",
        "z": "3c74f436.9e051c",
        "name": "ON",
        "server": "938bbb0d.d39038",
        "version": 1,
        "outputs": 2,
        "halt_if": "on",
        "halt_if_type": "str",
        "halt_if_compare": "is",
        "override_topic": false,
        "entity_id": "switch.xyz",
        "state_type": "str",
        "state_location": "",
        "override_payload": "none",
        "entity_location": "",
        "override_data": "none",
        "blockInputOverrides": false,
        "x": 670,
        "y": 1560,
        "wires": [
            [
                "ce50d3fe.fae1c",
                "579fecb9.d13fd4"
            ],
            []
        ]
    },
    {
        "id": "451731a4.89d82",
        "type": "switch",
        "z": "3c74f436.9e051c",
        "name": "",
        "property": "payload",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "on",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "off",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "unavailable",
                "vt": "str"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 3,
        "x": 310,
        "y": 1500,
        "wires": [
            [
                "2ef96586.96ce9a"
            ],
            [
                "2ef96586.96ce9a"
            ],
            []
        ]
    },
    {
        "id": "d3430473.57f0a8",
        "type": "function",
        "z": "3c74f436.9e051c",
        "name": "kWh",
        "func": "\nmsg.payload = (msg.payload[1] * 0.00000027777778) * (msg.payload[0] / 1000);\n\nreturn msg;\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 1430,
        "y": 1440,
        "wires": [
            [
                "683e95e4.7b8e0c",
                "fe4ed983.e12f48"
            ]
        ]
    },
    {
        "id": "4deac3b8.2f902c",
        "type": "join",
        "z": "3c74f436.9e051c",
        "name": "",
        "mode": "custom",
        "build": "array",
        "property": "payload",
        "propertyType": "msg",
        "key": "topic",
        "joiner": "\\n",
        "joinerType": "str",
        "accumulate": false,
        "timeout": "",
        "count": "2",
        "reduceRight": false,
        "reduceExp": "",
        "reduceInit": "",
        "reduceInitType": "",
        "reduceFixup": "",
        "x": 1270,
        "y": 1440,
        "wires": [
            [
                "d3430473.57f0a8"
            ]
        ]
    },
    {
        "id": "caf894a8.d73fb8",
        "type": "api-current-state",
        "z": "3c74f436.9e051c",
        "name": "XYZ Watt",
        "server": "938bbb0d.d39038",
        "version": 1,
        "outputs": 1,
        "halt_if": "",
        "halt_if_type": "str",
        "halt_if_compare": "is",
        "override_topic": false,
        "entity_id": "input_number.xyz_watt",
        "state_type": "num",
        "state_location": "payload",
        "override_payload": "msg",
        "entity_location": "data",
        "override_data": "msg",
        "blockInputOverrides": false,
        "x": 1060,
        "y": 1400,
        "wires": [
            [
                "4deac3b8.2f902c"
            ]
        ]
    },
    {
        "id": "bbd5ce79.d3dfe",
        "type": "delay",
        "z": "3c74f436.9e051c",
        "name": "",
        "pauseType": "delay",
        "timeout": "5",
        "timeoutUnits": "milliseconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "x": 1050,
        "y": 1460,
        "wires": [
            [
                "4deac3b8.2f902c"
            ]
        ]
    },
    {
        "id": "f46f070a.905bb8",
        "type": "function",
        "z": "3c74f436.9e051c",
        "name": "kWh",
        "func": "\nmsg.payload = (msg.payload[1] * 0.00000027777778) * (msg.payload[0] / 1000);\n\nreturn msg;\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 1430,
        "y": 1560,
        "wires": [
            [
                "683e95e4.7b8e0c",
                "82898f2c.ddf6d"
            ]
        ]
    },
    {
        "id": "c55b5515.fe1ba8",
        "type": "join",
        "z": "3c74f436.9e051c",
        "name": "",
        "mode": "custom",
        "build": "array",
        "property": "payload",
        "propertyType": "msg",
        "key": "topic",
        "joiner": "\\n",
        "joinerType": "str",
        "accumulate": false,
        "timeout": "",
        "count": "2",
        "reduceRight": false,
        "reduceExp": "",
        "reduceInit": "",
        "reduceInitType": "",
        "reduceFixup": "",
        "x": 1270,
        "y": 1560,
        "wires": [
            [
                "f46f070a.905bb8"
            ]
        ]
    },
    {
        "id": "ce50d3fe.fae1c",
        "type": "api-current-state",
        "z": "3c74f436.9e051c",
        "name": "Switch standby Watt",
        "server": "938bbb0d.d39038",
        "version": 1,
        "outputs": 1,
        "halt_if": "",
        "halt_if_type": "str",
        "halt_if_compare": "is",
        "override_topic": false,
        "entity_id": "input_number.switch_standby_watt",
        "state_type": "num",
        "state_location": "payload",
        "override_payload": "msg",
        "entity_location": "data",
        "override_data": "msg",
        "blockInputOverrides": false,
        "x": 1040,
        "y": 1540,
        "wires": [
            [
                "c55b5515.fe1ba8"
            ]
        ]
    },
    {
        "id": "579fecb9.d13fd4",
        "type": "delay",
        "z": "3c74f436.9e051c",
        "name": "",
        "pauseType": "delay",
        "timeout": "5",
        "timeoutUnits": "milliseconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "x": 1050,
        "y": 1600,
        "wires": [
            [
                "c55b5515.fe1ba8"
            ]
        ]
    },
    {
        "id": "683e95e4.7b8e0c",
        "type": "mqtt out",
        "z": "3c74f436.9e051c",
        "name": "",
        "topic": "power_consumption/kWh/xyz",
        "qos": "0",
        "retain": "true",
        "broker": "bda1e0cb.3e2458",
        "x": 1840,
        "y": 1500,
        "wires": []
    },
    {
        "id": "fe4ed983.e12f48",
        "type": "delay",
        "z": "3c74f436.9e051c",
        "name": "",
        "pauseType": "delay",
        "timeout": "50",
        "timeoutUnits": "milliseconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "x": 1590,
        "y": 1400,
        "wires": [
            [
                "eaf71cf9.23401"
            ]
        ]
    },
    {
        "id": "eaf71cf9.23401",
        "type": "change",
        "z": "3c74f436.9e051c",
        "name": "back to zero",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "0",
                "tot": "num"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1790,
        "y": 1400,
        "wires": [
            [
                "683e95e4.7b8e0c"
            ]
        ]
    },
    {
        "id": "82898f2c.ddf6d",
        "type": "delay",
        "z": "3c74f436.9e051c",
        "name": "",
        "pauseType": "delay",
        "timeout": "50",
        "timeoutUnits": "milliseconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "x": 1590,
        "y": 1600,
        "wires": [
            [
                "fb35bf26.9afc1"
            ]
        ]
    },
    {
        "id": "fb35bf26.9afc1",
        "type": "change",
        "z": "3c74f436.9e051c",
        "name": "back to zero",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "0",
                "tot": "num"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1790,
        "y": 1600,
        "wires": [
            [
                "683e95e4.7b8e0c"
            ]
        ]
    },
    {
        "id": "d70f995d.901bc8",
        "type": "comment",
        "z": "3c74f436.9e051c",
        "name": "Theoretical Power Consumption",
        "info": "",
        "x": 170,
        "y": 1340,
        "wires": []
    },
    {
        "id": "938bbb0d.d39038",
        "type": "server",
        "z": "",
        "name": "Home Assistant"
    },
    {
        "id": "bda1e0cb.3e2458",
        "type": "mqtt-broker",
        "z": "",
        "name": "[email protected]",
        "broker": "10.127.20.238",
        "port": "1883",
        "clientid": "",
        "usetls": false,
        "compatmode": true,
        "keepalive": "60",
        "cleansession": true,
        "birthTopic": "",
        "birthQos": "0",
        "birthPayload": "",
        "closeTopic": "",
        "closeQos": "0",
        "closePayload": "",
        "willTopic": "",
        "willQos": "0",
        "willPayload": ""
    }
]

EDIT: You have to insert an rbe node between the switch and the interval length, so if the switch goes to unavailable and back to the previous state, it is not taken into the calculation

The reason I set the kWh back to zero imediately in the flow is because the utility meter only adds positive changes from a sensor. So only this way the difference from the last value to the current is the actual consumption

Now you need a MQTT sensor to recieve the values:

  - platform: mqtt
    name: "XYZ Power Consumption"
    state_topic: "power_consumption/kWh/xyz"
    unit_of_measurement: 'kWh'
    icon: 'mdi:flash'

and of course a Utility Meter:

  xyz_month_energy_draw:
    source: sensor.xyz_power_consumption
    cycle: monthly

The input numbers are not a necessity - I just like to be able to quickly change them (don’t even know why, because they shouldn’t ever change anyway)

One for the standby consumption of the switch

switch_standby_watt:
  name: 'Switch Standby Watt'
  min: 0
  max: 10
  step: 0.01
  mode: box

and one for the wattage of the device

xyz_watt:
  name: 'XYZ Watt'
  min: 0
  max: 3600
  step: 1
  mode: box

If you don’t use the input numbers, you can simply remove the part of the flow between OFF/ON and the functions, and in the function instead of

msg.payload = (msg.payload[1] * 0.00000027777778) * (msg.payload[0] / 1000);

you use:

msg.payload = (msg.payload * 0.00000027777778) * ( [INSERT POWER CONSUMPTION IN WATT] * 1000);

The biggest issue right now it, that “unavailable” status is being ignored - this doen’t matter as long as they are powered and just lose connection for a moment - just think about it, if you want to unplug them for some time the easiest workaround would be to treat OFF an UNAVAILABLE the same way and assume both are 0 consumption … I don’t like this solution so I’ll look into it furthrer

Hope some of you like this

2 Likes

Any ideas how you use the integration sensor twice?

sensor:
  - platform: integration
    source: sensor.current_power
    name: energy_spent
    unit_prefix: k
    round: 2

I have two plugs i’d like to measure the kWh, i can get one working with:

sensor:
  - platform: integration
    source: sensor.outdoor_tree_lights_mss310_power_sensor_w_0
    name: energy_spent
    unit_prefix: k
    round: 2

But once i had the second source, neither sensor then works:

sensor:
  - platform: integration
    source: sensor.outdoor_tree_lights_mss310_power_sensor_w_0
    name: energy_spent
    unit_prefix: k
    round: 2
  - platform: integration
    source: sensor.smart_plug_2_mss310_power_sensor_w_0
    name: Server_Rack_Plug_Power_Total
    unit_prefix: k
    round: 2

Do i need to keep them separate, and use sensor twice?

everyone still trying to do that - there’s a custom component in HACS called “Powercalc” - it works flawlessly and is very simple to use … I found out about it a month ago and it now calculates pretty much every lamps and switches theoretical power consumption in my house.

5 Likes