Enphase Envoy - D7 firmware with JWT - A Different Approach

Sure, I understand.
Introducing a 3rd party method for obtaining energy import (grid consumption) and energy export (return to grid) opens up a whole new topic which could further confuse new users.

Not sure if it will help, but you could try my version in post 116. It retrieves total values from the cloud and others from local endpoints. If your setup is not exactly like mine, you might have to fool with indexes in the code to get the correct values from local endpoints, but the cloud should work if populated in the app. The code is not robust and I do not plan to improve it.

Was wondering if anyone here could help me out, or at least point me in the right direction.

The Energy dashboard in HA provides a nice summary of Off Peak, Shoulder and Peak grid consumption. But what I was hoping to do is create some sensors that would give me the solar usage for those same periods.

At the moment, I can get the result by manually adding up the solar production for those hours, but I wanted a sensor to do it for me. I tried setting up something like this, but I’m drawing a blank on how to get it to calculate the right usage for that particular period.

      - name: Daily OffPeak Solar Usage
        state_class: total
        unit_of_measurement: kWh
        device_class: energy
        state: >
         {% if is_state('sensor.tou_period', 'offpeak') %}
           {{ (states('sensor.energy_import') | float(0) - states('sensor.energy_export') | float(0)) | round(2) }}
         {% endif %} 
         
      - name: Daily Shoulder Solar Usage
        state_class: total
        unit_of_measurement: kWh
        device_class: energy
        state: >
         {% if is_state('sensor.tou_period', 'shoulder') %}
           {{ (states('sensor.energy_import') | float(0) - states('sensor.energy_export') | float(0)) | round(2) | round(2) }}
         {% endif %} 
         
      - name: Daily Peak Solar Usage
        state_class: total
        unit_of_measurement: kWh
        device_class: energy
        state: >
         {% if is_state('sensor.tou_period', 'peak') %}
           {{ (states('sensor.energy_import') | float(0) - states('sensor.energy_export') | float(0)) | round(2) | round(2) }}
         {% endif %} 

Hello @yesterdayshero

  • Any time you are exporting to grid, your panels are producing more than your house is consuming.

  • Anytime you are importing from grid, your house is consuming more than your panels are producing.

  • Anytime your production is > 0W, you are ā€œusing solarā€.

May I ask what do you mean by ā€œsolar usageā€ and what is your motivation/goal in measuring it?

Hi @del13r

I’m trying to get how much solar I’ve used (ie. consumed, not sent back to the grid), but broken out into the specific Off-peak, Shoulder and Peak periods.

For example, if I consumed 10kWh during the Shoulder period, I’d like to know how much of that Shoulder consumption was from Solar. I believe from the Energy dashboard, I can already get the grid consumption. I was looking for a way to easily get the Solar consumption during those periods also.

Perhaps I’m overthinking it though and missing something obvious.

Hi @yesterdayshero

I suppose the basic formula for finding self consumption might look like this for power figures occuring right now:

value_template: >-
  {% if states('sensor.power_production') | int(0) > 0  %}
    {{ states('sensor.power_consumption') | int(0)
          - states('sensor.power_import') | int(0) }}
  {% else %}
    0
  {% endif %}

This formula will not work for accumulated energy in Wh or kWh as your daily consumption starts accumulating before the sun rises and therefore the formula will not yield the results you are after when applying this to daily energy in Wh or kWh.
Instead, you would have to use the Integration - Riemann sum integral to convert the the self consumed power into self consumed energy over time after setting up the above template sensor as it has the IF statement which excludes consumption before sunrise and after sunset.

In energy dashboard, it already calculates and displays self consumption when I roll my mouse over each hour and shows as consumed solar (the yellow bar).

For 4pm-5pm for example, my house consumed 2.4 kWh including the 0.14 kWh imported from the grid. To find consumed solar, energy dashboard subtracts the 0.14 kWh import from the 2.4 kWh total consumption to get 2.26 kWh self consumption (consumed solar).

image

Self consumption for the day is also shown on the right as Self-Consumed solar energy.

image
image

I would not recommend trying to get the data from the above template sensor into Energy Dashboard as this sensor is not intended for that purpose as Energy dashboard already calculates this per hour based on the expected inputs for energy dashboard being Grid consumption(import), Return to grid(export), Solar production.

Here is my energy dashboard config as an example

You can use the following template in the Developer Tools for logic testing.

Consuming:
  {{ states('sensor.power_consumption') | int(0) }}

Importing:
  {{ states('sensor.power_import') | int(0) }}

Self Consuming:
  {% if states('sensor.power_production') | int(0) > 0  %}
    {{ states('sensor.power_consumption') | int(0)
          - states('sensor.power_import') | int(0) }}
  {% else %}
    0
  {% endif %}

Example output on the right of what was happening just before sunset:

Example output on the right of what was happening just after sunset:

1 Like

Thanks for the detailed response @del13r. I’m going through it and seeing what I might be able to do.

Yes, this is actually what I’m doing at the moment. I’m basically hovering over each hour in the Off-Peak/Shoulder/Peak periods to add up my solar consumption for each. I was seeing if there was a way to create a sensor that captures this so I wouldn’t need to manually do it.

Agree. I wasn’t looking to add it to the energy dashboard. Just wanted to see if I could capture it myself for my own usage.

1 Like

Hi @yesterdayshero
Cheers. Yeah I only tested the self consumption sensor in dev tools, but the theory and logic make sense.

Not sure if you know this, but you can get the self consumption for each day as well by zooming out to the week view in energy dashboard.

1 Like

Yeah this would be ideal if the solar usage was grouped similar to how the grid usage is grouped by Peak, Shoulder, OffPeak

It looks like Enphase has changed their API and even the Brian Campbell integration doesn’t work now. I should have figured out a way to restrict Enphase fw updates. Im not on FW 8.2.127

There were more reports like your experience. you may want to try this to see if it helps in your case.

AFAIK the API they changed is for the web api, not the Envoy api.

Edit to correct non working approach.

Hi,
To accommodate for the occasional loss of communication to the Envoy, I modified the sensors to define the Energy Consumption in the REST sensor rather than in a template sensor. I also decided to get the Power information from another API so that I don’t have to calculate Power Consumption:

rest:
  - resource: https://envoy.local/ivp/meters/reports
    headers:
      Authorization: !secret enphase_api
    verify_ssl: False
    scan_interval: 60
    sensor:
      - name: "Solar Power Production"
        value_template: >
          {% set value = value_json[0].cumulative.currW | int(0) %}
          {% if value  <= 5 -%}
              0
          {% elif is_state('sun.sun','below_horizon') %}
              0
          {%- else -%}
              {{ value }}
          {%- endif %}
        device_class: power
        unit_of_measurement: W
        state_class: measurement
        icon: mdi:solar-power-variant

      - name: "Power Consumption"
        value_template: "{{ value_json[2].cumulative.currW | int(0) }}"
        state_class: measurement
        device_class: power
        unit_of_measurement: W
        icon: mdi:home-lightning-bolt

      - name: "Power Net"
        value_template: "{{ value_json[1].cumulative.currW | int(0) }}"
        state_class: measurement
        device_class: power
        unit_of_measurement: W
        icon: mdi:transmission-tower

      - name: Grid Power Import
        # Max (0, Power Net)
        value_template: "{{ [0, value_json[1].cumulative.currW | int(0)] | max }}"
        state_class: measurement
        icon: mdi:transmission-tower
        unit_of_measurement: W
        device_class: power

      - name: Grid Power Export
        # Min (0, Power Net) * -1
        value_template: "{{ -1 * ([0, value_json[1].cumulative.currW | int(0)] | min) }}"
        state_class: measurement
        icon: mdi:transmission-tower
        unit_of_measurement: W
        device_class: power

  - resource: https://envoy.local/ivp/meters/readings
    headers:
      Authorization: !secret enphase_api
    verify_ssl: False
    scan_interval: 900
    sensor:
      - name: "Energy Production"
        value_template: "{{ (value_json[0].actEnergyDlvd / 1000 | float(0)) | round(2) }}"
        device_class: energy
        unit_of_measurement: kWh
        state_class: total_increasing
        icon: mdi:solar-power-variant

      - name: "Grid Energy Import"
        value_template: "{{ (value_json[1].actEnergyDlvd / 1000 | float(0)) | round(2) }}"
        device_class: energy
        unit_of_measurement: kWh
        state_class: total_increasing
        icon: mdi:transmission-tower-import

      - name: "Grid Energy Export"
        value_template: "{{ (value_json[1].actEnergyRcvd / 1000 | float(0)) | round(2) }}"
        device_class: energy
        unit_of_measurement: kWh
        state_class: total_increasing
        icon: mdi:transmission-tower-export

      - name: Energy Consumption
        # Consumption = Production + Import - Export
        value_template: "{{ (value_json[0].actEnergyDlvd + value_json[1].actEnergyDlvd - value_json[1].actEnergyRcvd) / 1000 | float(0) | round(2) }}"
        state_class: total_increasing
        icon: mdi:home-lightning-bolt
        unit_of_measurement: kWh
        device_class: energy

I have followed all steps from @del13r, everything is looking fine however my sensors keep on saying 0 W

I must be doing something wrong… also what I have noticed is that there are only 3 sensors when searching on ā€œ.power_ā€

All the downloads from /production and /readings looks good. Also the decoding with JWT looks similar.

Maybe the difference could be that my account being used to login to Enphase is an installer account embracing 3 sites. Could this be the case? I don’t think, as the credentials for logging in to Enphase are not used. It’s just the token and the URL…

When looking into the log, I found an Error:

Logger: homeassistant.components.rest.data
Source: components/rest/data.py:114
integration: RESTful (documentation, issues)
First occurred: 13:47:56 (3 occurrences)
Last logged: 13:48:26

Timeout while fetching data: https://192.168.1.192/ivp/meters/readings

I replaced my local IP address for envoy.local, but this doesn’t help.

Actually, when using https://192.168.1.192/ivp/meters/readings nothing happens in my browser. When using https://envoy.local/ivp/meters/readings I get this Enphase screen and I can submit the token. As a result I get the info:

Of course the ā€œBearer ā€ is with quotes.

If anyone has a clue what I’m missing I will be thankful…

What did you do @TerroBladeZ as it seems like I’m at the same wrong track as you were before…

@del13r or anyone else…
with the recent change for bar-card being removed from HACS, is there an alternative to display the inverter(s) data?

There’s a couple options:

  • Keep using your existing bar-card component. Just because it was removed from HACS doesn’t mean you can’t keep it installed (or if uninstalled, re-add it as a custom repo). It hasn’t received updates in a long time (hence the HACS removal). However, if it was working fine for you, no need to stop. Just hit ā€œignoreā€ on the HACS warning.
  • Use a new fork of that component - GitHub - spacerokk/bar-card: Customizable Animated Bar card for Home Assistant Lovelace. The new maintainer has made a bunch of changes to bring it more up-to-date with recent HA changes. That being said, it looks like some functionality (like adding action handlers) was either intentionally removed or broken. For this reason, I’m still using the original one. You can def switch to this and see if your configuration still works. It’s a drop-in replacement so there’s no need to really modify anything. If something breaks (like I saw w/ the lack of action handling), you can always go back to the old one.

so about option #2… (since I already removed the original one).
I noticed it no longer shows the active bar being plotted for energy

Wondering if there are new options/switches that need to be provided for this to work again? Used to see a blue bar representing the wattage present.

type: vertical-stack
cards:
  - type: custom:bar-card
    entities:
      - entity: sensor.envoy_xxxxxxxxxxx_current_power_production
    title: Enphase Panels
    max: "15.59"
    decimal: "2"
    unit_of_measurement: kW
    positions:
      name: "off"
      indicator: inside
      icon: "off"
    animation:
      speed: "5"
    style: |
      bar-card-currentbar, bar-card-backgroundba
  - type: custom:bar-card
    title: Grid A
    entities:
      - entity: sensor.inverter_1219451xxxx
      - entity: sensor.inverter_1219451xxxx
      - entity: sensor.inverter_1219451xxxx
      - entity: sensor.inverter_1219451xxxx
      - entity: sensor.inverter_1219451xxxx
      - entity: sensor.inverter_1219451xxxx
      - entity: sensor.inverter_1219451xxxx
      - entity: sensor.inverter_1219451xxxx
      - entity: sensor.inverter_1219451xxxx
      - entity: sensor.inverter_1219451xxxx
    positions:
      name: "off"
      indicator: inside
    columns: 5
    direction: up
    max: "420"
    min: "0"
    animation:
      speed: "5"
    decimal: "0"
    icon: "off"
    height: 100
    style: |
      bar-card-currentbar, bar-card-backgroundbar { border-radius:5px; }
 

Visual:

I guess you could open a bug against the new fork (or see if one already exists). Given that the old, removed repo still worked well for me, I opted to go back to it and just hit ignore on the HACS warning.

1 Like

will give that a shot once I have some spare cycles free up. At least it isn’t erroring out for now.

found a nicer alternative approach… an animated progress bar that uses filtering

Bet one of you guys/gals with more time than I have available could push this into a template (declutter) ? The max_value can be adjusted (fine-tuned) to make the bar change color…


Code: (UPDATED)
added shimmer effect and changed icon to (icon: mdi:solar-power)

      - type: custom:vertical-stack-in-card
        cards:
          - type: custom:mushroom-title-card
            subtitle: ''
            title: Enphase Panels
            alignment: center
          - type: custom:entity-progress-card
            bar_effect: shimmer
            max_value: 13
            bar_size: medium
            entity: sensor.envoy_2023xxxxxxxxx_current_power_production
            name: Current Power Production
            theme: optimal_when_high
            icon: mdi:solar-power-variant
            icon_tap_action:
              action: more-info
            layout: vertical
            badge_icon: >-
               {% if states('sensor.envoy_2023xxxxxx_current_power_production') |  float < 1 %}
               mdi:moon-waning-crescent
               {% else %}
               mdi:sun-wireless
               {% endif %}
            badge_color: >-
               {% if states('sensor.envoy_2023xxxxx_current_power_production') | float  < 1 %}
               blue
              {% else %}
               orange
              {% endif %}
          - type: custom:mushroom-title-card
            subtitle: ''
            title: Grid A
            alignment: center
          - type: custom:auto-entities
            filter:
              include:
                - options:
                    type: custom:entity-progress-card
                    bar_effect: shimmer
                    decimal: 0
                    max_value: 350
                    bar_size: medium
                    icon: mdi:solar-panel
                    theme: optimal_when_high
                    icon_tap_action:
                      action: more-info
                    card_mod:
                      style:
                        .: |-
                          :host {
                            --ha-card-border-width: 0px !important; /* Force border removal */
                            box-shadow: none !important; /* Delete shadow to remove any outline */
                          }
                          .icon {
                          animation: boing 3s ease infinite;
                          transform-origin: 50% 90%;
                          }
                          @keyframes boing {
                            0% { transform: scale3d(1, 1, 1); }
                            7% { transform: scale3d(1.25, 0.75, 1); }
                            10% { transform: scale3d(0.75, 1.25, 1); }
                            12% { transform: scale3d(1.15, 0.85, 1); }
                            16% { transform: scale3d(0.95, 1.05, 1); }
                            19% { transform: scale3d(1.05, 0.95, 1); }
                            25% { transform: scale3d(1, 1, 1); }
                          }
                  entity_id: sensor.inverter_*
                  label: grid_a
            sort:
              method: friendly_name
            card:
              square: false
              type: grid
              columns: 2
            card_param: cards
          - type: custom:mushroom-title-card
            subtitle: ''
            title: Grid B
            alignment: center
          - type: custom:auto-entities
            filter:
              include:
                - options:
                    type: custom:entity-progress-card
                    bar_effect: shimmer
                    decimal: 0
                    max_value: 350
                    bar_size: medium
                    icon: mdi:solar-panel
                    theme: optimal_when_high
                    icon_tap_action:
                      action: more-info
                    card_mod:
                      style:
                        .: |-
                          :host {
                            --ha-card-border-width: 0px !important; /* Force border removal */
                            box-shadow: none !important; /* Delete shadow to remove any outline */
                          }
                          .icon {
                          animation: boing 3s ease infinite;
                          transform-origin: 50% 90%;
                          }
                          @keyframes boing {
                            0% { transform: scale3d(1, 1, 1); }
                            7% { transform: scale3d(1.25, 0.75, 1); }
                            10% { transform: scale3d(0.75, 1.25, 1); }
                            12% { transform: scale3d(1.15, 0.85, 1); }
                            16% { transform: scale3d(0.95, 1.05, 1); }
                            19% { transform: scale3d(1.05, 0.95, 1); }
                            25% { transform: scale3d(1, 1, 1); }
                          }
                  entity_id: sensor.inverter_*
                  label: grid_b
            sort:
              method: friendly_name
            card:
              square: false
              type: grid
              columns: 2
            card_param: cards
          - type: custom:mushroom-title-card
            subtitle: ''
            title: Grid C
            alignment: center
          - type: custom:auto-entities
            filter:
              include:
                - options:
                    type: custom:entity-progress-card
                    bar_effect: shimmer
                    decimal: 0
                    max_value: 350
                    bar_size: medium
                    icon: mdi:solar-panel
                    theme: optimal_when_high
                    icon_tap_action:
                      action: more-info
                    card_mod:
                      style:
                        .: |-
                          :host {
                            --ha-card-border-width: 0px !important; /* Force border removal */
                            box-shadow: none !important; /* Delete shadow to remove any outline */
                          }
                          .icon {
                          animation: boing 3s ease infinite;
                          transform-origin: 50% 90%;
                          }
                          @keyframes boing {
                            0% { transform: scale3d(1, 1, 1); }
                            7% { transform: scale3d(1.25, 0.75, 1); }
                            10% { transform: scale3d(0.75, 1.25, 1); }
                            12% { transform: scale3d(1.15, 0.85, 1); }
                            16% { transform: scale3d(0.95, 1.05, 1); }
                            19% { transform: scale3d(1.05, 0.95, 1); }
                            25% { transform: scale3d(1, 1, 1); }
                          }
                  entity_id: sensor.inverter_*
                  label: grid_c
            sort:
              method: friendly_name
            card:
              square: false
              type: grid
              columns: 2
            card_param: cards
          - type: custom:mushroom-title-card
            subtitle: ''
            title: Grid D
            alignment: center
          - type: custom:auto-entities
            filter:
              include:
                - options:
                    type: custom:entity-progress-card
                    bar_effect: shimmer
                    decimal: 0
                    max_value: 350
                    bar_size: medium
                    icon: mdi:solar-panel
                    theme: optimal_when_high
                    icon_tap_action:
                      action: more-info
                    card_mod:
                      style:
                        .: |-
                          :host {
                            --ha-card-border-width: 0px !important; /* Force border removal */
                            box-shadow: none !important; /* Delete shadow to remove any outline */
                          }
                          .icon {
                          animation: boing 3s ease infinite;
                          transform-origin: 50% 90%;
                          }
                          @keyframes boing {
                            0% { transform: scale3d(1, 1, 1); }
                            7% { transform: scale3d(1.25, 0.75, 1); }
                            10% { transform: scale3d(0.75, 1.25, 1); }
                            12% { transform: scale3d(1.15, 0.85, 1); }
                            16% { transform: scale3d(0.95, 1.05, 1); }
                            19% { transform: scale3d(1.05, 0.95, 1); }
                            25% { transform: scale3d(1, 1, 1); }
                          }
                  entity_id: sensor.inverter_*
                  label: grid_d
            sort:
              method: friendly_name
            card:
              square: false
              type: grid
              columns: 2
            card_param: cards
2 Likes