Enphase Envoy - D7 firmware with JWT - A Different Approach

This is excellent, exactly what I was looking for. I’ve had it running for several days to compare to Enlighten and it is accurate:


image

1 Like

Has anyone else experienced blips after updated to 2023.8.4? Since updating to 2023.08.4 this afternoon, I now have these sections of no data like in this screenshot

image

The default timeout for rest integration is 10 seconds.

timeout integer (optional, default: 10)

Defines max time to wait data from the endpoint.

I don’t believe that has changed with the latest update.

Please check your log for something like this

Logger: homeassistant.components.rest.data
Source: components/rest/data.py:116 
Integration: RESTful (documentation, issues) 
First occurred: August 25, 2023 at 6:50:16 PM (9 occurrences) 
Last logged: 2:06:40 AM

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

Have you tried this possible solution as well?

Cheers for the suggestion, however, not entirely what I was thinking.
In an effort to mimic the Enphase App, Energy tab, I’ve stumbled upon the HACS card - energy-period-selector-plus. GitHub - flixlix/energy-period-selector-plus: An upgraded Energy Date Selection Card for Home Assistant, with added customizability, while maintaining the Energy Dashboard's original design.


It looks quite nice, however, changing the date doesn’t affect the Enphase graph span or offset…
Has anyone here persisted through this issue and found a solution?
It would be great to work through this and add more functionality to @del13r 's great work.

Here is the frontend code:

square: false
type: grid
cards:
  - type: custom:energy-period-selector-plus
    card_background: false
    today_button: true
    prev_next_buttons: true
    compare_button_type: icon
    today_button_type: text
    period_buttons:
      - day
      - week
      - month
      - year
      - custom
  - type: custom:apexcharts-card
    graph_span: 24h
    span:
      start: day
    stacked: true
    header:
      show: true
      title: Enphase Solar
    all_series_config:
      group_by:
        func: avg
        duration: 3min
      type: column
    series:
      - entity: sensor.power_production
        name: Produced
        color: '#01B4DE'
      - entity: sensor.power_consumption
        transform: return x *-1 ;
        name: Consumed
        color: '#F37320'
      - entity: sensor.power_net
        name: Imported/Exported
        color: '#545456'
columns: 1

1 Like

Hi @Klaneos, I saw something here that might be a good lead

1 Like

Hi @Klaneous,

I got it working. I am able to choose the day of the graph now.

Note: Recorder only holds 10 days of data by default.
See https://www.home-assistant.io/integrations/recorder/#purge_keep_days

today graph

Yesterday graph

What did I do?

Added input_select helpers

input_select:
  statistics_chart_range:
    initial: day
    options:
      - day
      - week
      - month
      - year

input_datetime:
  statistics_chart_date:
    has_date: true
    has_time: false

Added template sensors

template:
  - sensor:
      - name: statistics_chart_grouping
        unique_id: statistics_chart_grouping
        state: |
          {% set grouping={
            'day':'h',
            'week':'d',
            'month':'d',
            'year':'d'}
          %}
          {% set range = states('input_select.statistics_chart_range') %}
          {{ grouping[range] }}
          
      - name: statistics_chart_span
        unique_id: statistics_chart_span
        state: |
          {% macro last_date_in_range(date_str,range) -%}
            {% set date=as_timestamp(date_str)|timestamp_local()|as_datetime() -%}
            {% if range=='day' -%}
              {% set end_date=date -%}
            {% elif range=='week' -%}
              {% set end_date=date + timedelta(days=(6-date.weekday())) -%}
            {% elif range=='month' -%}
              {% set month=(date.month % 12) + 1 -%}
              {% set year=date.year+iif(date.month==12,1,0) -%}
              {% set end_date=strptime(year|string + '-' + month|string + '-01', '%Y-%m-%d')-timedelta(days=1) -%}
            {% elif range=='year' -%}
              {% set end_date=strptime(date.year|string + '-12-31', '%Y-%m-%d') -%}
            {% endif -%}
            {{ as_timestamp(end_date)|timestamp_local() -}}
          {% endmacro -%}
          {% set range = states('input_select.statistics_chart_range') %}
          {% set date_str = states('input_datetime.statistics_chart_date') %}
          {% set spans={
            'day':'24',
            'week':'7',
            'month':(last_date_in_range (strptime(date_str, '%Y-%m-%d'),range)|as_datetime()).day,
            'year':last_date_in_range (strptime(date_str, '%Y-%m-%d'),range)|as_timestamp(0)|timestamp_custom('%j',0)|int +1}
          %}
          {{ spans[range] }}
          
      - name: statistics_chart_period
        unique_id: statistics_chart_period
        state: |
          {% set periods={
            'day':'hour',
            'week':'day',
            'month':'day',
            'year':'day'}
          %}
          {% set range = states('input_select.statistics_chart_range') %}
          {{ periods[range] }}
          
  - sensor:
      - name: statistics_chart_offset
        unique_id: statistics_chart_offset
        state: |
          {% macro last_date_in_range(date_str,range) -%}
            {% set date=as_timestamp(date_str)|timestamp_local()|as_datetime() -%}
            {% if range=='day' -%}
              {% set end_date = date + timedelta(days=1) -%}
            {% elif range=='week' -%}
              {% set end_date=date + timedelta(days=(6-date.weekday())) -%}
            {% elif range=='month' -%}
              {% set month=(date.month % 12) + 1 -%}
              {% set year=date.year+iif(date.month==12,1,0) -%}
              {% set end_date=strptime(year|string + '-' + month|string + '-01', '%Y-%m-%d')-timedelta(days=1) -%}
            {% elif range=='year' -%}
              {% set end_date=strptime(date.year|string + '-12-31', '%Y-%m-%d') -%}
            {% endif -%}
            {{ as_timestamp(end_date) -}}
          {% endmacro -%}
          {% set range = states('input_select.statistics_chart_range') %}
          {% set date_str = states('input_datetime.statistics_chart_date') %}
          {% set offset = last_date_in_range(strptime(date_str, '%Y-%m-%d'),range)|int - now()|as_timestamp(0) -%}
          {% if states('sensor.statistics_chart_grouping') == 'h' %}
            {% set offset=(offset/60/60)|round(method='ceil') %}
          {% else %}
            {% set offset=(offset/60/60/24)|round(method='ceil') + 1 %}
          {% endif %}
          {{ iif(offset >= 0,'+','') }}{{ offset }}{{ states('sensor.statistics_chart_grouping') }}

added script to
/config/scripts.yaml

alias: statistics_chart_date_browse
sequence:
  - service: input_datetime.set_datetime
    target:
      entity_id: input_datetime.statistics_chart_date
    data:
      datetime: >
        {% set range = states('input_select.statistics_chart_range') %}

        {% set date = states('input_datetime.statistics_chart_date')|as_datetime
        %}

        {% set direction = direction %}

        {% if range == 'day' %}
          {% if direction > 0 %}
            {% set target = date + timedelta(days=1) %}
          {% else %}
            {% set target = date - timedelta(days=1) %}
          {% endif %}
        {% elif range == 'week' -%}
          {% if direction > 0 %}
            {% set target = date + timedelta(days=7) %}
          {% else %}
            {% set target = date - timedelta(days=7) %}
          {% endif %}
        {% elif range == 'month' -%}
          {% if direction > 0 %}
            {% set month=((date.month) % 12) + 1 %}
            {% set year=date.year+iif(date.month==12,1,0) %}
            {% set target=strptime(year|string + '-' + month|string + '-01', '%Y-%m-%d') -%}
          {% else %}
            {% set month=((date.month - 2) % 12) + 1 %}
            {% set year=date.year+iif(date.month==1,-1,0) %}
            {% set target=strptime(year|string + '-' + month|string + '-01', '%Y-%m-%d') -%}
          {% endif %}
        {% elif range=='year' -%}
          {% if direction > 0 %}
            {% set target=strptime((date.year|int + 1)|string + '-01-01', '%Y-%m-%d') -%}
          {% else %}
            {% set target=strptime((date.year|int - 1)|string + '-01-01', '%Y-%m-%d') -%}
          {% endif %}
        {% endif -%}

        {% if direction == 0 %}
            {% set target = now() %}
        {% endif -%}

        {{ target }}
mode: single
icon: mdi:arrow-right-bold-outline

Created a new dashboard view

  - theme: Backend-selected
    title: Enphase
    path: enphase
    icon: mdi:solar-power
    type: sidebar
    badges: []
    cards:
      - type: custom:config-template-card
        variables:
          offset: states['sensor.statistics_chart_offset'].state
          span: states['sensor.statistics_chart_span'].state
          period: states['sensor.statistics_chart_period'].state
          grouping: states['sensor.statistics_chart_grouping'].state
        entities:
          - sensor.statistics_chart_offset
          - sensor.statistics_chart_span
          - sensor.statistics_chart_period
          - sensor.statistics_chart_grouping
        card:
          type: custom:apexcharts-card
          graph_span: ${span + period}
          span:
            offset: ${offset}
          stacked: true
          header:
            show: false
            title: Total Power
          series:
            - entity: sensor.power_production
              type: column
              name: Produced
              color: '#01B4DE'
              group_by:
                func: avg
                duration: 5min
            - entity: sensor.power_consumption
              transform: return x *-1 ;
              type: column
              name: Consumed
              color: '#F37320'
              group_by:
                func: avg
                duration: 5min
            - entity: sensor.power_net
              type: column
              name: Imported/Exported
              color: '#545456'
              group_by:
                func: avg
                duration: 5min
          yaxis:
            - min: -7000
              max: 7000
              decimals: 0
      - type: custom:mod-card
        card:
          type: horizontal-stack
          cards:
            - type: entities
              entities:
                - entity: input_datetime.statistics_chart_date
                  name: date
            - type: entities
              entities:
                - entity: input_select.statistics_chart_range
                  name: period
            - type: glance
              show_name: false
              show_state: false
              entities:
                - entity: script.statistics_chart_date_browse
                  icon: mdi:chevron-left
                  tap_action:
                    action: call-service
                    service: script.statistics_chart_date_browse
                    data:
                      direction: -1
                - entity: script.statistics_chart_date_browse
                  icon: mdi:chevron-down
                  tap_action:
                    action: call-service
                    service: script.statistics_chart_date_browse
                    data:
                      direction: 0
                - entity: script.statistics_chart_date_browse
                  icon: mdi:chevron-right
                  tap_action:
                    action: call-service
                    service: script.statistics_chart_date_browse
                    data:
                      direction: 1
2 Likes

This is very nice! Great job @del13r :clap:

1 Like

@del13r Thanks for all this info. Quick question that I haven’t yet seen the answer to (although havent read all the links above). I have 3 phase power which is getting monitored by the Enphase. I can see in the app under LIVE STATUS the current consumption (power) per phase but I am yet to find out whether it is possible to get that info into HA? Anyone know if that is possible?

Hello,
Yes the per phase information is available in the channels section of the json data.
Each channel is a phase.

Have you tried clicking on https://envoy.local/ivp/meters/readings and seeing what information you are presented with?

Thanks. Yes I have. It seems like it might be challenging for me to work out exactly what is what as I have a legacy system also integrated (somewhow by the installer) so I see this:

[
    {
        "eid": 704643328,
        "timestamp": 1694505436,
        "actEnergyDlvd": 7989.564,
        "actEnergyRcvd": 2.219,
        "apparentEnergy": 9051.251,
        "reactEnergyLagg": 275.625,
        "reactEnergyLead": 705.749,
        "instantaneousDemand": 6.532,
        "activePower": 6.532,
        "apparentPower": 281.179,
        "reactivePower": 272.244,
        "pwrFactor": 0.020,
        "voltage": 704.724,
        "current": 1.200,
        "freq": 50.125,
        "channels": [
            {
                "eid": 1778385169,
                "timestamp": 1694505436,
                "actEnergyDlvd": 3705.621,
                "actEnergyRcvd": 1.233,
                "apparentEnergy": 4292.490,
                "reactEnergyLagg": 41.186,
                "reactEnergyLead": 511.417,
                "instantaneousDemand": 4.617,
                "activePower": 4.617,
                "apparentPower": 140.568,
                "reactivePower": 136.269,
                "pwrFactor": 0.040,
                "voltage": 232.250,
                "current": 0.605,
                "freq": 50.125
            },
            {
                "eid": 1778385170,
                "timestamp": 1694505436,
                "actEnergyDlvd": 2933.610,
                "actEnergyRcvd": 0.009,
                "apparentEnergy": 3030.153,
                "reactEnergyLagg": 212.147,
                "reactEnergyLead": 71.271,
                "instantaneousDemand": 1.015,
                "activePower": 1.015,
                "apparentPower": 67.843,
                "reactivePower": 65.011,
                "pwrFactor": 0.000,
                "voltage": 235.256,
                "current": 0.288,
                "freq": 50.125
            },
            {
                "eid": 1778385171,
                "timestamp": 1694505436,
                "actEnergyDlvd": 1350.333,
                "actEnergyRcvd": 0.977,
                "apparentEnergy": 1728.608,
                "reactEnergyLagg": 22.293,
                "reactEnergyLead": 123.060,
                "instantaneousDemand": 0.900,
                "activePower": 0.900,
                "apparentPower": 72.768,
                "reactivePower": 70.964,
                "pwrFactor": 0.000,
                "voltage": 237.219,
                "current": 0.306,
                "freq": 50.125
            }
        ]
    },
    {
        "eid": 704643584,
        "timestamp": 1694505436,
        "actEnergyDlvd": 1033.142,
        "actEnergyRcvd": 6473.965,
        "apparentEnergy": 8830.396,
        "reactEnergyLagg": 297.656,
        "reactEnergyLead": 1519.162,
        "instantaneousDemand": 888.667,
        "activePower": 888.667,
        "apparentPower": 1221.254,
        "reactivePower": -538.591,
        "pwrFactor": 0.722,
        "voltage": 705.145,
        "current": 5.188,
        "freq": 50.125,
        "channels": [
            {
                "eid": 1778385425,
                "timestamp": 1694505436,
                "actEnergyDlvd": 106.408,
                "actEnergyRcvd": 3526.892,
                "apparentEnergy": 4161.063,
                "reactEnergyLagg": 231.862,
                "reactEnergyLead": 317.159,
                "instantaneousDemand": 161.852,
                "activePower": 161.852,
                "apparentPower": 328.418,
                "reactivePower": -265.626,
                "pwrFactor": 0.483,
                "voltage": 232.485,
                "current": 1.412,
                "freq": 50.125
            },
            {
                "eid": 1778385426,
                "timestamp": 1694505436,
                "actEnergyDlvd": 206.388,
                "actEnergyRcvd": 2322.949,
                "apparentEnergy": 2814.684,
                "reactEnergyLagg": 62.558,
                "reactEnergyLead": 383.085,
                "instantaneousDemand": 174.303,
                "activePower": 174.303,
                "apparentPower": 260.982,
                "reactivePower": -124.439,
                "pwrFactor": 0.667,
                "voltage": 235.268,
                "current": 1.109,
                "freq": 50.125
            },
            {
                "eid": 1778385427,
                "timestamp": 1694505436,
                "actEnergyDlvd": 720.347,
                "actEnergyRcvd": 624.124,
                "apparentEnergy": 1854.650,
                "reactEnergyLagg": 3.236,
                "reactEnergyLead": 818.918,
                "instantaneousDemand": 552.512,
                "activePower": 552.512,
                "apparentPower": 631.853,
                "reactivePower": -148.526,
                "pwrFactor": 0.868,
                "voltage": 237.391,
                "current": 2.667,
                "freq": 50.125
            }
        ]
    }
]

Ok, great.
What information did you want HA to record per phase?

For each channel/phase, you would setup the rest sensor like this for example:

Production CT Phase 1:
[0].channels[0].activePower = Production in Watts = 4.617 W
[0].channels[0].current = current in Amps = 0.605 A
[0].channels[0].freq = frequency in Hertz = 50.125 Hz
[0].channels[0].voltage = voltage in Volts = 232.250 V

Production CT Phase 2:
[0].channels[1].activePower = Production in Watts = 1.015 W
[0].channels[1].current = current in Amps = 0.288 A
[0].channels[1].freq = frequency in Hertz = 50.125 Hz
[0].channels[1].voltage = voltage in Volts = 235.256 V

Production CT Phase 3:
[0].channels[2].activePower = Production in Watts = 0.900 W
[0].channels[2].current = current in Amps = 0.306 A
[0].channels[2].freq = frequency in Hertz = 50.125 Hz
[0].channels[2].voltage = voltage in Volts = 237.219 V

Net/Total Consumption CT Phase 1:
[1].channels[0].activePower = Net/Total Consumption in Watts = 161.852 W
[1].channels[0].current = current in Amps = 1.412 A
[1].channels[0].freq = frequency in Hertz = 50.125 Hz
[1].channels[0].voltage = voltage in Volts = 232.485

Net/Total Consumption CT Phase 2:
[1].channels[1].activePower = Net/Total Consumption in Watts = 174.303 W
[1].channels[1].current = current in Amps = 1.109 A
[1].channels[1].freq = frequency in Hertz = 50.125 Hz
[1].channels[1].voltage = voltage in Volts = 235.269 V

Net/Total Consumption CT Phase 3:
[1].channels[2].activePower = Net/Total Consumption in Watts = 552.512 W
[1].channels[2].current = current in Amps = 2.667 A
[1].channels[2].freq = frequency in Hertz = 50.125 Hz
[1].channels[2].voltage = voltage in Volts = 237.391

1 Like

hi @del13r

question for you if you know… in my Energy dashboard i am only getting the options to do Monthly Import & Monthly Export from the utility_meter integration. Do you by chance know why the Daily options are not selectable?

From configuration.yaml:

utility_meter:
  daily_energy:
    source: sensor.energy_import
    name: Daily Import
    cycle: daily
  daily_energy_export:
    source: sensor.energy_export
    name: Daily Export
    cycle: daily
  monthly_energy:
    source: sensor.energy_import
    name: Monthly Import
    cycle: monthly
  monthly_energy_export:
    source: sensor.energy_export
    name: Monthly Export
    cycle: monthly

Here is the Reimann sensors:

  - platform: integration
    name: Energy Export
    source: sensor.power_export
    unit_prefix: k
    unit_time: h
    method: left

  - platform: integration
    name: Energy Import
    source: sensor.power_import
    unit_prefix: k
    unit_time: h
    method: left

And here are the rest sensors pulling data from Enphase:

rest:
  - headers:
      Authorization: !secret enphase_api
    verify_ssl: False
    scan_interval: 15
    resource: https://192.168.1.207/ivp/meters/readings
    sensor:
      - name: "Power Production"
        value_template: >
          {% set value = value_json[0].activePower | 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: >
          {% set newValue = value_json[1].activePower | int(0) %}
          {% set lastValue = states('sensor.power_consumption') | float(0) %}
          {% if newValue == 0 %}
            {{ lastValue }}
          {% else %}
            {{ newValue }}
          {% endif %}
        state_class: measurement
        device_class: power
        unit_of_measurement: W
        icon: mdi:transmission-tower
        
      - name: "Energy Production"
        value_template: >
          {% set newValue = ((value_json[0].actEnergyDlvd - 6300) / 1000 | float(0)) | round(2) %}
          {% set lastValue = states('sensor.energy_production') | float(0) %}
          {% if newValue <= lastValue %}
            {{ lastValue }}
          {% else %}
            {{ newValue }}
          {% endif %}
        device_class: energy
        unit_of_measurement: kWh
        state_class: total_increasing
        icon: mdi:solar-power-variant

      - name: "Energy Consumption"
        value_template: >
          {% set newValue = ((value_json[1].actEnergyDlvd - 600) / 1000 | float(0)) | round(2) %}
          {% set lastValue = states('sensor.energy_consumption') | float(0) %}
          {% if newValue <= lastValue %}
            {{ lastValue }}
          {% else %}
            {{ newValue }}
          {% endif %}
        device_class: energy
        unit_of_measurement: kWh
        state_class: total_increasing
        icon: mdi:home-lightning-bolt

And here is my Energy Dashboard selector options:

I’ve been struggling with this for a few days but had no luck!

Thank you!! :smiley:

developer tools will give you more insight into why you cant see something in energy dashboard

here is my source energy sensor getting data via the rest sensor

rest:
  - headers:
      Authorization: !secret enphase_api
    verify_ssl: False
    scan_interval: 15
    resource: https://192.168.1.114/ivp/meters/readings    
    sensor:

      - name: "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

and here is how that same sensor looks in dev tools / states

here is an example where I have split my utility meter into different tariffs but essentially still the same purpose as what you are trying to do.


please go to dev tools / states and compare what attributes you don’t have for the daily sensor that isnt selectable.

ok, just tracing back, it would appear that your utility meter is using the sensor.energy_import as a source, as is mine too.

where your setup becomes different is that this source: sensor.energy_import is an integration sensor.

what i dont see is where your sensor.power_import is defined.

what i dont understand is that you have setup the rest sensors but are instead choosing to use the integration sensor as as source for your utility meter?

The only possible reason why you would use integration sensors is if your ct clamp is setup as
total-consumption = Load only

Can you please tell me what your measurement type is or show me how sensor.power_import is defined?

I have the same Enphase setup/configuration as @jon102034050 where the json output does not match yours.

My other sensors are templates based on the math from the available data:

  - sensor:
        name: Power Net
        state_class: measurement
        icon: mdi:home-lightning-bolt
        unit_of_measurement: W
        device_class: power
        state: >
          {{ states('sensor.power_production') | int(0) - states('sensor.power_consumption') | int(0) }}
          
  - sensor:
        name: Power Export
        state_class: measurement
        icon: mdi:transmission-tower-export
        unit_of_measurement: W
        device_class: power
        state: >
          {{ [0, states('sensor.power_production') | int(0) - states('sensor.power_consumption') | int(0) ] | max }}
          
  - sensor:
        name: Power Import
        state_class: measurement
        icon: mdi:transmission-tower-import
        unit_of_measurement: W
        device_class: power
        state: >
          {{ [0, states('sensor.power_consumption') | int(0) - states('sensor.power_production') | int(0) ] | max }}

  - sensor:
        name: Energy Net
        state_class: total
        icon: mdi:transmission-tower
        unit_of_measurement: kWh
        device_class: energy
        state: >
          {% set newValue = (states('sensor.energy_production') | float(0) - states('sensor.energy_consumption') | float(0)) | round(2) %}
          {% set lastValue = states('sensor.energy_net') | float(0) %}
          {% if newValue == 0 %}
            {{ lastValue }}
          {% else %}
            {{ newValue }}
          {% endif %}

My utility_meter sensors as seen from Dev Tools:

And lastly, my Enphase measurement type:

[
    {
        "eid": 12345,
        "state": "enabled",
        "measurementType": "production",
        "phaseMode": "split",
        "phaseCount": 2,
        "meteringStatus": "normal",
        "statusFlags": []
    },
    {
        "eid": 12345,
        "state": "enabled",
        "measurementType": "total-consumption",
        "phaseMode": "split",
        "phaseCount": 2,
        "meteringStatus": "normal",
        "statusFlags": []
    }
]

Regarding the utility_meter Daily sensor difference, the only thing I see that diverges is that I don’t have a tariff set… could that matter?

Maybe I’m interpreting the utility_meter incorrectly, but I thought we needed to have Daily sensors for the Energy Dashbaord to operate correctly. If that’s not the case, I’ll get rid of the utility_meter sensors and then point the Energy Dashboard right at the Enphase output sensors.

Edit:
As a test, I set my Energy Dashboard grid sensors to the Enphase rest sensors. Ill monitor it for the next few days.

In your original post, you were trying to search for daily import sensor but you have only provided screenshot of the attributes for your export sensors.

I compared your daily export sensor screenshot with mine and they are the same, so you should be able to choose it, unless you are already using it.

Example of mine already in use
image

Example of it not being available in the list due to it already being in use.
image

Wow this is so bizarre! I can now select Daily Export but cannot select Daily Import. When i look at the Daily Export sensor I see this:


However when I look at the Daily Import sensor I get no statistics found:

I’m wondering if something is messed up with just that sensor now. Also I’m wondering if these sensors need to run for over a day to populate or something before selection. The utility_meter docs haven’t turned up anything so far…

I appreciate your help digging into this!!