Solcast Global Solar Power Forecast Integration

I have created a simple Apex-chart showing the estimated production for today and tomorrow:

The following YAML code is used.

type: custom:apexcharts-card
apex_config:
  chart:
    height: 350px
all_series_config:
  unit: ' kWh'
header:
  title: Solar forecast
  show: true
  standard_format: true
  show_states: true
  colorize_states: true
graph_span: 2d
span:
  start: day
  offset: '-0h'
now:
  show: true
  label: Now
yaxis:
  - id: kwh
    min: 0
    apex_config:
      tickAmount: 5
  - id: header_only
    show: false
series:
  - entity: sensor.solcast_forecast_today
    yaxis_id: kwh
    type: area
    name: Today
    color: orange
    data_generator: |
      var today = entity.attributes.forecast.map((start, index) => {
        return [new Date(start["period_start"]).getTime(), entity.attributes.forecast[index]["pv_estimate"]];
      });
      var data = today
      return data;
    show:
      legend_value: false
      in_header: false
    stroke_width: 3
    float_precision: 2
    extend_to: false
  - entity: sensor.solcast_forecast_tomorrow
    yaxis_id: kwh
    type: area
    name: Tomorrow
    color: grey
    data_generator: |
      var today = entity.attributes.forecast.map((start, index) => {
        return [new Date(start["period_start"]).getTime(), entity.attributes.forecast[index]["pv_estimate"]];
      });
      var data = today
      return data;
    show:
      legend_value: false
      in_header: false
    stroke_width: 3
    float_precision: 2
    extend_to: false
  - entity: sensor.solcast_forecast_today
    yaxis_id: header_only
    name: Today
    color: orange
    show:
      legend_value: true
      in_header: true
      in_chart: false
  - entity: sensor.solcast_forecast_remaining_today
    yaxis_id: header_only
    name: Remaining
    color: orange
    show:
      legend_value: true
      in_header: true
      in_chart: false
  - entity: sensor.solcast_forecast_tomorrow
    yaxis_id: header_only
    name: Tomorrow
    color: grey
    show:
      legend_value: true
      in_header: true
      in_chart: false
  - entity: sensor.solcast_api_last_polled
    yaxis_id: header_only
    name: Last update
    unit: ' min.'
    transform: return ((Date.now()) - (new Date(x).getTime())) / 60 / 60 / 24
    show:
      legend_value: true
      in_header: true
      in_chart: false

I hope you find it useful :blush:

16 Likes

Anybody know the difference between the services update_forecast and update_actual_forecasts?
The first one didn’t update my rooftop sensors (4 in total) and the second did update everything but lead to 8 API calls instead of 4?

This is really good and useful staff - Many thanks!

Hi,

I am new in to HA, and have just imported the API from Solcast.

How do I get the display like you have in this image…?

Thanks

this looks realy nice :smiley:
Anyway i have a strange problem.
Maybe you can help out.
grafik
The NA Entities are avileable if I click on them.
Any ideas why its not displaying right?

It’s in the setup of the Energy Dashboard.

Settings / Dashboards / Energy

Then when you enter in details of your Solar PV array you can configure a solar forecast for it:

1 Like

I have a problem with the graphs from solcast. In Home assistant it does not show the same as in Solcast. Please see below pictures.

Some of you already mentioned some issues with timezones, but I have checked all kind of settings and can unfortunately still not match the predicted vs. realised graphs.

I did check the timezone in Home Assistant as well: Amsterdam. This matches with Solcast timezone.

Anyone knows the quickfix to this?

HomeAssistant

Looks good but why all header values are N/A?

I fixed the N/A issues, apparently it was because those entities were filtered out in the database recorder. I added them in the “include”.

  include:
    entities:
    - sensor.solcast_forecast_today
    - sensor.solcast_forecast_remaining_today
    - sensor.solcast_forecast_tomorrow
    - sensor.solcast_api_last_polled
  exclude:
    domains:
    - automation
    - device_tracker        
    - sun
    - zone
    entities:
    - sensor.local_ip
    - sensor.date
    - sensor.time
    entity_globs:
    - sensor.solcast*
1 Like

Hi, nice was the reason for my problem too :slight_smile:
One more question:


grafik
Time where screens where taken is 19:10
Do you also have the difference between the Last update time shown and the real last update time of the sensor if you click on it?

A couple of improvements to archive the most accurate remaining solar forecast actually (this minute):

Card:

type: custom:apexcharts-card
header:
  show: true
  standard_format: true
  show_states: true
  colorize_states: true
apex_config:
  chart:
    height: 220px
  tooltip:
    enabled: true
    shared: true
    followCursor: true
graph_span: 4d
now:
  show: false
  color: grey
  label: Now
span:
  start: day
  offset: '-1day'
all_series_config:
  type: area
  opacity: 0.3
  stroke_width: 1
series:
  - entity: sensor.battery_state_of_capacity
    name: Battery
    float_precision: 0
    type: line
    color: '#f06292'
    opacity: 0.6
    yaxis_id: capacity
    extend_to: now
    show:
      legend_value: true
      in_header: false
    group_by:
      func: last
      duration: 5m
  - entity: sensor.house_consumption_power
    name: House Power
    float_precision: 3
    type: line
    color: MediumAquaMarine
    opacity: 0.8
    yaxis_id: kWh
    unit: kW
    transform: return x/1000;
    extend_to: now
    show:
      legend_value: true
      in_header: false
    group_by:
      func: avg
      duration: 5m
  - entity: sensor.inverter_input_power
    name: Solar Power
    float_precision: 3
    color: '#ff9800'
    yaxis_id: kWh
    unit: kW
    transform: return x/1000;
    extend_to: now
    show:
      legend_value: true
      in_header: false
    group_by:
      func: avg
      duration: 5m
  - entity: sensor.solcast_forecast_today
    name: Solar Forecast (D1)
    extend_to: false
    color: grey
    opacity: 0.3
    stroke_width: 0
    yaxis_id: kWh
    show:
      legend_value: false
      in_header: false
    data_generator: |
      return entity.attributes.forecast.map((entry) => {
            return [new Date(entry.period_start), entry.pv_estimate];
          });
  - entity: sensor.solcast_forecast_tomorrow
    name: Solar Forecast (D2)
    float_precision: 3
    extend_to: false
    color: grey
    opacity: 0.3
    stroke_width: 0
    yaxis_id: kWh
    show:
      legend_value: false
      in_header: false
    data_generator: |
      return entity.attributes.forecast.map((entry) => {
            return [new Date(entry.period_start), entry.pv_estimate];
          });
  - entity: sensor.solcast_forecast_d3
    name: Solar Forecast (D3)
    float_precision: 3
    extend_to: false
    color: grey
    opacity: 0.3
    stroke_width: 0
    yaxis_id: kWh
    show:
      legend_value: false
      in_header: false
    data_generator: |
      return entity.attributes.forecast.map((entry) => {
            return [new Date(entry.period_start), entry.pv_estimate];
          });
  - entity: sensor.solcast_forecast_today
    yaxis_id: header_only
    name: Solar Forecast (D1)
    color: grey
    show:
      legend_value: true
      in_header: true
      in_chart: false
  - entity: sensor.solcast_forecast_remaining_today_every_minute
    yaxis_id: header_only
    name: Forecast (D1 Remaining)
    color: grey
    show:
      legend_value: true
      in_header: true
      in_chart: false
  - entity: sensor.solcast_forecast_tomorrow
    yaxis_id: header_only
    name: Forecast (D2)
    color: grey
    show:
      legend_value: true
      in_header: true
      in_chart: false
  - entity: sensor.solcast_forecast_d3
    yaxis_id: header_only
    name: Solar Forecast (D3)
    color: grey
    show:
      legend_value: true
      in_header: true
      in_chart: false
  - entity: sensor.solcast_api_last_polled
    yaxis_id: header_only
    name: Forecast (Last Update)
    color: grey
    unit: ' min.'
    transform: return ((Date.now()) - (new Date(x).getTime())) / 60 / 60 / 24
    show:
      legend_value: true
      in_header: true
      in_chart: false
yaxis:
  - id: capacity
    show: true
    opposite: true
    decimals: 0
    max: 100
    min: 0
    apex_config:
      tickAmount: 5
  - id: kWh
    show: true
    min: 0
    apex_config:
      tickAmount: 5
  - id: header_only
    show: false

Template sensor:

#
# Estimation of actual remaining Solcast Forecast (Every Minute)
#
# - Attributes for expected_battery_charge_end_time
# - Attributes for expected_battery_charge_end_energy
#
template:
  - trigger:
      - platform: state
        entity_id: sensor.solcast_forecast_today
        not_from:
          - "unknown"
          - "unavailable"
          - "none"
        not_to:
          - "unknown"
          - "unavailable"
          - "none"
      - platform: time_pattern
        minutes: "/1"
    sensor:
      - name: solcast_forecast_remaining_today_every_minute
        unique_id: solcast_forecast_remaining_today_every_minute
        #friendly_name: "Solcast Forecast Remaining Today (Every Minute)"
        state_class: "total"
        device_class: energy
        unit_of_measurement: "kWh"
        icon: mdi:solar-power
        state: >-
          {%- set forecast_today = state_attr('sensor.solcast_forecast_today', 'detailedForecast') %}

          {%- set var = namespace(total = 0) %}
          {%- set ts_now = ((as_timestamp(now())/1800)|round(0,'floor')|int * 1800) %}

          {%- if now().minute < 30 %}
            {%- set var.ts_actual_period = today_at(now().hour ~ ':00').timestamp() %}
            {%- set var.remaining_minutes_actual_period = 30 - now().minute %}
          {% else %}
            {%- set var.ts_actual_period = today_at(now().hour ~ ':30').timestamp() %}
            {%- set var.remaining_minutes_actual_period = 60 - now().minute %}
          {%- endif %}

          {%- for record in forecast_today %}
            {%- set ts = as_timestamp(record.period_start) %}      
            {%- if ts == var.ts_actual_period %}
              {%- set var.total = var.total + (record.pv_estimate / 30 * var.remaining_minutes_actual_period) %}
            {%- endif %}
            {%- if ts > ts_now %}
              {%- set var.total = var.total + record.pv_estimate %}
            {%- endif %}
          {%- endfor %}
          {{ var.total }}
        attributes:
          expected_battery_charge_end_time: "14:00"
          expected_battery_charge_end_energy: >-
            {%- set forecast_today = state_attr('sensor.solcast_forecast_today', 'detailedForecast') %}
            {%- set ts_expected_charge_end_time = today_at(this.attributes.expected_battery_charge_end_time).timestamp() %}

            {%- set var = namespace(total = 0) %}
            {%- set ts_now = ((as_timestamp(now())/1800)|round(0,'floor')|int * 1800) %}

            {%- if now().minute < 30 %}
              {%- set var.ts_actual_period = today_at(now().hour ~ ':00').timestamp() %}
              {%- set var.remaining_minutes_actual_period = 30 - now().minute %}
            {% else %}
              {%- set var.ts_actual_period = today_at(now().hour ~ ':30').timestamp() %}
              {%- set var.remaining_minutes_actual_period = 60 - now().minute %}
            {%- endif %}

            {%- for record in forecast_today %}
              {%- set ts = as_timestamp(record.period_start) %}      
              {%- if ts == var.ts_actual_period and ts < ts_expected_charge_end_time %}
                {%- set var.total = var.total + (record.pv_estimate / 30 * var.remaining_minutes_actual_period) %}
              {%- endif %}
              {%- if ts > ts_now and ts < ts_expected_charge_end_time %}
                {%- set var.total = var.total + record.pv_estimate %}
              {%- endif %}
            {%- endfor %}
            {{ var.total }}
        availability: >-
          {{ (states('sensor.solcast_forecast_today')|is_number) }}

With the advanced attributes within the sensor you can define:
expected_battery_charge_end_time: 14:00

expected_battery_charge_end_energy attribute will calculate every minute the remaining solar forecast until 14:00.

With this hack it is possible to control your battery charging in a most efficient and reliable way as you can see in the graph for yesterday morning.

9 Likes

New to HA and been trying to integrate solcast. My main issue is the reported solar array capacity is a lot higher in HA than in reality (roof east 26.81 vs 5.95 kwh, roof west 11.25 vs 3.4 kwh) .Atributes look correct and identical to solcast. Where are those figures coming from? I have deleted solcast intregration several times but it’s not making any difference. What am I doing wrong?

The integration is HA is telling you what to expect to be produced from your Solar array today based on the Solcast Forecast, so the 26.81kWh is the forecast production today from your 5.95kW array (that’s if I’m reading your setup correctly from the attributes)

Your Roof East array capacity is measured in kW not kWh. 5.95 kW is the theoretical power that can be generated at a single point in time.
Solcast is giving you an estimated forecast of 26.81 kWh (Energy) given todays expected conditions.
Energy kWh is measured as Power kW over Time.

That makes a lot more sense now and thanks for the correction (KWh vs KW).

1 Like

Great card. Thanks for sharing. Just so I understand correctly expected_battery_charge_end_energy is the expected solar available to charge the battery up until the charge end time?

Yes - you are right.

expected_battery_charge_end
Parameter A: time => in my example 14:00 local time
Parameter B: energy => remaining estimated solar energy until the charge end time

Hey all,
Im trying to make use of Solcast for my PV string. It has 8x535 Longi panels on Deye inverter (total 4250w)
So i put my location to the api, enter my real inclanation of 15 degree (flat roof mount)
my azimuth is 200 angle southwest
and have some strange data, in the morning i have a little of production and Solcast shows great production, in the evening i have more than predicted. For me it looks like to have it shifted a few hours ahead that forecast.
I tried making some changes of abnormal settings (changes to inclanation 0 to 45, azimuth -160 +160, with effitiency adjustments) and i just dont get the forecast nearly acceptable

Hello I’m having trouble getting the Solcast prediction to work.
I installed ‘Solcast Solar’ via HACS. I got a Solcast API key from the Solcast website. Unfortunately I can’t make a query. 0 is displayed for all entities.
Can you help me? What information do you still need?
My API Key (somewhat blurred)
https://api.solcast.com.au/rooftop_sites/xxxx-xxxx-xxxx-xxxx/estimated_actuals?format=json

Dieser Fehler wurde von einer benutzerdefinierten Integration verursacht

Logger: custom_components.solcast_solar.solcastapi
Source: custom_components/solcast_solar/solcastapi.py:110
Integration: Solcast PV Forecast (documentation, issues)
First occurred: 17:23:55 (1 occurrences)
Last logged: 17:23:55

SOLCAST - sites_data http status Error 404 - Gathering rooftop sites data.
Dieser Fehler wurde von einer benutzerdefinierten Integration verursacht

Logger: custom_components.solcast_solar.solcastapi
Source: custom_components/solcast_solar/solcastapi.py:121
Integration: Solcast PV Forecast (documentation, issues)
First occurred: 17:23:55 (1 occurrences)
Last logged: 17:23:55

SOLCAST - sites_data sites_data error: Traceback (most recent call last): File "/config/custom_components/solcast_solar/solcastapi.py", line 113, in sites_data raise Exception(f"SOLCAST - HTTP sites_data error: Solcast Error gathering rooftop sites data.") Exception: SOLCAST - HTTP sites_data error: Solcast Error gathering rooftop sites data.

Did you get an email from them confirming your account is active? Did you check your log for errors?