Solar Forecast PV

The more important it would be to be able to set a time slot for requests in the binding configuration…

I use kind of “brute force” cron-driven script-based disabling/enabling of the binding as workaround.

I run one refresh in the early morning when I get updated forecast for today including conveniently calculated “Today Remaining” so that I can calculate how much/if any charging of the battery should be performed to utilize lower tarrif or prevent over-discharge.

Then I use it during morning to get updates to drive optimization of “export price”.

Once its after noon, the updates kind of don’t bring additional value into my automations.

I still prefer having 5 (indeed 2 calls per update :-() more accurate forrecasts to having more of them but less accurate as it is the accuracy that is driving savings.

    var headers = newHashMap("Authorization" -> "Bearer YOUR_OH_TOKEN_GOES_HERE", "WWW-Authenticate"-> "Basic")
    sendHttpPutRequest("http://localhost:8080/rest/things/solarforecast:sc-site:homeSite/enable", "text/plain","false",headers,1000);

Since upgrading to 4.1.2. I experience no updates in the channels/items, the binding is running:

bundle:list

...
338 │ Active │  80 │ 4.2.0.202402262108     │ openHAB Add-ons :: Bundles :: SolarForecast Binding

But there’s no updates visible:

I was forced to do an update on the binding, as it hasn’t been transferred while upgrading from 4.1.1 to 4.1.2 (the update/upgrade was exactly the time the updates stopped).

@weymann I have a question concerning the solar plane calculations when using Solar Forecast:

Are the calculations done in your own binding Java code? Or are they done remotely on the Solar Forecast server?

The reason why I ask is that I noticed a distinct change in forecast accuracy in the last couple of weeks. Prior to that the Solar Forecast for my roof planes was always too high compared to my actual solar production, so I had to apply a correction factor of 0.8, but now the Solar Forecast for my roof planes has become a more-or-less perfect 100% match (i.e. with a correction factor 1.0).

I can imagine several possible reasons for this improvement…

  1. Perhaps Solar Forecast just improved the accuracy of their cover for where I live (East of England)?
  2. Perhaps something changed in general in the solar plane calculation algorithm since the spring equinox March 20th?
  3. Perhaps something changed in specific in the solar plane calculation algorithm for my north facing roof? About 40% of my panels are on a north facing roof sloped at 31°. During winter the sun never touches those panels, whereas since March 1st the mid-day solar elevation just started to exceed the roof pitch 31°. So I am wondering if the solar plane calculation algorithm may have been wrongly forecasting solar irradiation in the winter time, and yet is now accurately forecasting it.
  4. Or … perhaps it is pure chance?

Hello, with which item and which prediction do I get the expected output per hour? All energy items I’ve seen accumulate the yield over the day.
I would like to create a graph of predicted and generated energy per hour.

Thanks, Heiko

problem still exists, no real entries as “ERROR” in the logs since.
But I caught this:

2024-04-02 11:19:25.891 [INFO ] [.solcast.handler.SolcastPlaneHandler] - New forecast Expiration: 2024-04-02T11:19:24.239566891Z, Valid: true, Data:{2024-03-31T11:30+02:00[Europe/Berlin]=3.0533, 2024-03-31T12:00+02:00[Europe/Berlin]=2.3472, 2024-03-31T12:30+02:00[Europe/Berlin]=4.9742, 2024-03-31T13:00+02:00[Europe/Berlin]=5.7648, 2024-03-31T13:30+02:00[Europe/Berlin]=5.3231, 2024-03-31T14:00+02:00[Europe/Berlin]=4.3295, 2024-03-31T14:30+02:00[Europe/Berlin]=3.004, 2024-03-31T15:00+02:00[Europe/Berlin]=2.462, 2024-03-31T15:30+02:00[Europe/Berlin]=4.8451, 
...
2024-04-09T04:00+02:00[Europe/Berlin]=0.0, 2024-04-09T04:30+02:00[Europe/Berlin]=0.0, 2024-04-09T05:00+02:00[Europe/Berlin]=0.0, 2024-04-09T05:30+02:00[Europe/Berlin]=0.0, 2024-04-09T06:00+02:00[Europe/Berlin]=0.0, 2024-04-09T06:30+02:00[Europe/Berlin]=0.0, 2024-04-09T07:00+02:00[Europe/Berlin]=0.0148, 2024-04-09T07:30+02:00[Europe/Berlin]=0.1375, 2024-04-09T08:00+02:00[Europe/Berlin]=0.504, 2024-04-09T08:30+02:00[Europe/Berlin]=0.9999, 2024-04-09T09:00+02:00[Europe/Berlin]=1.4887, 2024-04-09T09:30+02:00[Europe/Berlin]=2.0223, 2024-04-09T10:00+02:00[Europe/Berlin]=2.6534, 2024-04-09T10:30+02:00[Europe/Berlin]=3.1882, 2024-04-09T11:00+02:00[Europe/Berlin]=3.6326, 2024-04-09T11:30+02:00[Europe/Berlin]=4.0116}

it seems to be correct data, but what bothers me is the “New foracast Expiration date”, which seemingly is the exact timestamp the call was made…?

update
I removed the marketplace binding (with version 4.2.0 org.openhab.binding.solarforecast-4.2.0-SNAPSHOT.jar) and replaced it with the 4.1.x version ( org.openhab.binding.solarforecast-4.1.0-SNAPSHOT.jar)
and now it works as it was.

I think the readme on the marketplace is not correct, @weymann ?
(I’m running 4.1+: 4.1.2-release)

Resources

OH 4.1+ with TimeSeries
org.openhab.binding.solarforecast-4.2.0-SNAPSHOT.jar

OH4.0.x
org.openhab.binding.solarforecast-4.1.0-SNAPSHOT.jar
readme

@AndrewFG

I don’t make any own prediction calculation inside the binding. Server delivers prediction values with granularity 1 hour. To provide smoother values and not hourly jumps I calculate intermediate values.

@LukaNoah

Neither forecast service nor binding is delivering an hourly kWh forecast with granularity of one hour.
You can get the energy value for any given timeframe you want

@binderth

I still don’t think marketplace can distinguish between versions.Seen now too much wrong versions were installed. Therefore I’m pretty sure readme isn’t correct also.
readme before TimeSeries introduction = 4.1.0-SNAPSHOT
readme after TimeSeries introduction = 4.2.0-SNAPSHOT

I’m new to this binding and now trying to setup it under OH4.2M2. I have setup both the Solcast and ForecastSolar accounts. I’m having difficulties with Solcast PV Plane Item (see attached screen copy).

I have checked that the Rooftop Resource ID is correct. Any ideas?

Hey jlikonen!

Because of the 401 error it seems there is something wrong with the authentication.

Bye HFM

Yes, I know there is somthing wrong. I also tried to put

[type or paste code here](https://api.solcast.com.au/rooftop_sites/34ea-2682-9060-593e/forecasts?format=json)

for the Rooftop Resource ID but the Solcast PV Plane Item still shows OFFLINE. Solarcast Site Item shows ONLINE but Solarcast channels show NULL so there is something wrong.

Remove SolarForecast Binding delivered by Milestone build.
Then drop 4.2-SNAPSHOT from top post into addons folder. This will work!

OK, thanks. Now it works. Another error was that I had accidentally used Rooftop Resource ID for the API key in the Solcast Site Item.

1 Like

Hi @weymann,

is there any chance to use the InMemory Persistence Service for the forecast data?

Is it sufficient to change the inmemory.persist file to this, after installing the InMemory Persistence Service?

Items {
        influxdb* : strategy = forecast
}

I understand restoreOnStartup is not supported by the InMemory Persistence Service, but its not really needed for forecast data, no?

Is OH4.1 still sufficient or does the binding need OH4.2 features for the forecast data?

Thanks!

It should do. Why don’t you just try and let us know ?
You won’t need restoreOnStartup.

Hello wars, I have been trying to use your DSL rule. I modified it only very slightly for my purposes:

// import solcast_home_raw_json_response
val forecastJSON = Solcast_PV_Plane_Raw_JSON_Response.state.toString 
//logInfo("Forecast.Solcast", forecastJSON)

// influx uri
val String influxdb_uri = "http://192.168.1.2:8086/write?db=openhab&precision=s"
    
// json parse
var String forecasts_entries = transform("JSONPATH", "$..forecasts", forecastJSON)
forecasts_entries = forecasts_entries.replace("[","").replace("]","").replace("{","").replace("}","NEXT")
var Integer count = forecasts_entries.split("NEXT,").length()
//logInfo("Forecast.Solcast", "-" + forecasts_entries.toString + "-")
//logInfo("Forecast.Solcast", "number of entries: " + count.toString)

var Integer x = 0
var influx_content = ""
while (x < count ) {
  //logInfo("Forecast.Solcast", x.toString)
  var String forecasts = forecasts_entries.split("NEXT,").get(x)
  forecasts = "{" + forecasts.replace("NEXT","") + "}"
  //logInfo("Forecast.Solcast", forecasts.toString)
  
  val period_end = transform("JSONPATH", "$.period_end", forecasts)
  val pv_estimate = transform("JSONPATH", "$.pv_estimate", forecasts)
  val pv_estimate10 = transform("JSONPATH", "$.pv_estimate10", forecasts)
  val pv_estimate90 = transform("JSONPATH", "$.pv_estimate90", forecasts)
  
  //val formatter = java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
  val formatter = java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.'0000000Z'") //2023-05-12T12:00:00.0000000Z
  var period_end_formatted = LocalDateTime.parse(period_end, formatter).atZone(ZoneId.systemDefault())
  
  var int timezoneAdd = 0
  if (period_end_formatted.toString.contains("+01:00")) {
    timezoneAdd = 1
  }
  else if (period_end_formatted.toString.contains("+02:00")) {
    timezoneAdd = 2
  }
  period_end_formatted = period_end_formatted.plusHours(timezoneAdd) // add hour for timezone if not correct
  
  //logInfo("Forecast.Solcast", period_end_formatted.toString + ": " + pv_estimate)
    
  val period_end_formatted_seconds = period_end_formatted.toEpochSecond  
  influx_content = influx_content + "solcast_pv_estimate=" + pv_estimate + " " + period_end_formatted_seconds.toString +"\n"
  influx_content = influx_content + "solcast_pv_estimate10=" + pv_estimate10 + " " + period_end_formatted_seconds.toString +"\n"
  influx_content = influx_content + "solcast_pv_estimate90=" + pv_estimate90 + " " + period_end_formatted_seconds.toString +"\n"
    
  x++
}

logInfo("Forecast.Solcast", influx_content)
  
// send to influx
influx_content = influx_content.substring(0, influx_content.length()-2)
var responds = sendHttpPostRequest(influxdb_uri, "--data-binary", influx_content, 3000)
logInfo("Forecast.Solcast", "Influx responds {}", responds)

Basically I changed forecastJSON in line 2 and the influxdb_uri string.

The script works until the following section:

// send to influx
influx_content = influx_content.substring(0, influx_content.length()-2)
var responds = sendHttpPostRequest(influxdb_uri, "--data-binary", influx_content, 3000)
logInfo("Forecast.Solcast", "Influx responds {}", responds)

I have the following error message in the log:

2024-04-25 17:30:30.261 [ERROR] [enhab.core.model.script.actions.HTTP] - Fatal transport error: java.util.concurrent.ExecutionException: org.eclipse.jetty.client.HttpResponseException: HTTP protocol violation: Authentication challenge without WWW-Authenticate header
2024-04-25 17:30:30.261 [INFO ] [b.core.model.script.Forecast.Solcast] - Influx responds {}

So I think the problem is in line:

var responds = sendHttpPostRequest(influxdb_uri, "--data-binary", influx_content, 3000)

So what is wrong with this line?

:wink:

I’m curious why you transfer the forecast data via DSL rule. There’s no need to parse the json and transfer it inside the rule towards influxdb.

Let’s break it down and please check each step:

  • you have an influxdb server running somewhere, local or remote
  • you have installled influxDB Persistence service installed in OH and configured it correctly (Pic 1)
  • you have influxdb.persist file in folder persistence like described in readme
  • you marked your items which shall be stored in influxdb with influxdb group like described in readme

This is my testing environment and without any rule the data is stored correctly (Pic 2)

Pic 1

Pic 2

Hey everyone, I’m trying this out with the forecast solar and I’m getting my bridge errored out with “unknown “ state. Is the API field mandatory by any chance??

Thanks @weymann. The reason why I tried to use the DSL rule is that it’s really unclear to me how you can persist forecast data into influxdb because my Solcast Items are just numbers, not json strings nor time series (I think). I’m using influxdb for persisting most of my Items so I know how to use it.