Problem Reading PV Forecast via HTTP Binding from API Forecast.Solar

Hi
I am trying to use the forecast of PV power via Forecast.Solar API in Openhab.
Basically the access works via HTTP binding.

things-File:

Thing http:url:Solar_Forecast_East "Solar Forecast East" [
	baseURL="https://api.forecast.solar/estimate/watthours/day/49/13/40/-90/6.46",
	headers="key1=value1", "key2=value2", "key3=value3",
    refresh=3600] 
    {
		Channels:
			Type string : PV_Today_East "PV Today East [%.1f Wh]" [ stateTransformation="JSONPATH:$.result.2022-04-21"]
			Type string : PV_Forecast_East "PV Tomorrow East [%.1f Wh]" [ stateTransformation="JSONPATH:$.result.2022-04-22"]
    }

items-File:

Number PV_Today_East "PV Heute Ost [%.1f Wh]" <solarplant> (gPV) { channel="http:url:Solar_Forecast_East:PV_Today_East" }
Number PV_Forecast_East "PV Morgen Ost [%.1f Wh]" <solarplant> (gPV) { channel="http:url:Solar_Forecast_East:PV_Forecast_East" }

My problem is that in the received JSON file there is always the corresponding date in before the value … for today or tomorrow. For the test I have entered the dates directly in the Thingfile, e.g. 2022-04-21. But this works only today, tomorrow the date is already not correct.

Example JSON-File:

{
   "Result" : {
      "2022-04-21" : 10280,
      "2022-04-22" : 7920,
   }
}

Can anyone give me a tip on how to solve this problem? I have not found a solution so far.
I would like to always read the value after today’s date and the value after tomorrow’s date.

Thanks a lot for your help!

Don’t use the watthours API endpoint. Here’s what I use:

https://api.forecast.solar/estimate/LAT/LON/25/-97/1

And then my transformation in the today Thing Channel

JSONPATH:$.result.watt_hours_day∩REGEX:.*\=(.*)\,.*

And the tomorrow Thing Channel

JSONPATH:$.result.watt_hours_day∩REGEX:.*\=(.*)\}.*

There is a similar problem and solution provided by the following forum entry

i have actually implemented the solution with the rules script that dumps data to influxdb and used the grafana integration visualize it in the OH3 UI

maybe that helps

val String INFLUXDB_WRITE = "http://192.168.1.210:8086/write?db=openhab_db&precision=s"
    //Site = yyy
    //api =  xxxxx
val String SOLCAST ="https://api.solcast.com.au/rooftop_sites/yyy/forecasts?format=json&hours=18&api_key=xxxxx"
var Timer influxWriteTimer = null

rule "SolarForecast"
when
    System started or
    Time is midnight or 
    Item TestRule received update
    //Time cron "0 0 0 ? * MON,TUE,WED,THU,FRI *" or // 6am weekdays
	//Time cron "0 0 0 ? * SUN,SAT *" // 7am weekends
    //Time cron "0 * 0 ? * * *"
then
    //val theString = "testTemp value=" +  value + " " + time
    //logInfo("test", "Value = {}, TIME = {} ", value, time)

	val String forecastJSON = sendHttpGetRequest("https://api.solcast.com.au/rooftop_sites/yyy/forecasts?format=json&hours=144&api_key=xxxxx")
    //val String forecastJSON  = '{"forecasts":[{"pv_estimate":2.1914,"pv_estimate10":1.7015,"pv_estimate90":2.2992,"period_end":"2021-05-07T17:00:00.0000000Z","period":"PT30M"},{"pv_estimate":1.1338,"pv_estimate10":1.0083,"pv_estimate90":1.19049,"period_end":"2021-05-07T17:30:00.0000000Z","period":"PT30M"},{"pv_estimate":0.2838,"pv_estimate10":0.26960999999999996,"pv_estimate90":0.29799000000000003,"period_end":"2021-05-07T18:00:00.0000000Z","period":"PT30M"},{"pv_estimate":0.1597,"pv_estimate10":0.1532,"pv_estimate90":0.16768500000000003,"period_end":"2021-05-07T18:30:00.0000000Z","period":"PT30M"},{"pv_estimate":0.034,"pv_estimate10":0.0205,"pv_estimate90":0.0357,"period_end":"2021-05-07T19:00:00.0000000Z","period":"PT30M"},{"pv_estimate":0,"pv_estimate10":0,"pv_estimate90":0,"period_end":"2021-05-07T19:30:00.0000000Z","period":"PT30M"},{"pv_estimate":0,"pv_estimate10":0,"pv_estimate90":0,"period_end":"2021-05-07T20:00:00.0000000Z","period":"PT30M"},{"pv_estimate":0,"pv_estimate10":0,"pv_estimate90":0,"period_end":"2021-05-07T20:30:00.0000000Z","period":"PT30M"},{"pv_estimate":0,"pv_estimate10":0,"pv_estimate90":0,"period_end":"2021-05-07T21:00:00.0000000Z","period":"PT30M"},{"pv_estimate":0,"pv_estimate10":0,"pv_estimate90":0,"period_end":"2021-05-07T21:30:00.0000000Z","period":"PT30M"},{"pv_estimate":0,"pv_estimate10":0,"pv_estimate90":0,"period_end":"2021-05-07T22:00:00.0000000Z","period":"PT30M"},{"pv_estimate":0,"pv_estimate10":0,"pv_estimate90":0,"period_end":"2021-05-07T22:30:00.0000000Z","period":"PT30M"},{"pv_estimate":0,"pv_estimate10":0,"pv_estimate90":0,"period_end":"2021-05-07T23:00:00.0000000Z","period":"PT30M"},{"pv_estimate":0,"pv_estimate10":0,"pv_estimate90":0,"period_end":"2021-05-07T23:30:00.0000000Z","period":"PT30M"},{"pv_estimate":0,"pv_estimate10":0,"pv_estimate90":0,"period_end":"2021-05-08T00:00:00.0000000Z","period":"PT30M"},{"pv_estimate":0,"pv_estimate10":0,"pv_estimate90":0,"period_end":"2021-05-08T00:30:00.0000000Z","period":"PT30M"},{"pv_estimate":0,"pv_estimate10":0,"pv_estimate90":0,"period_end":"2021-05-08T01:00:00.0000000Z","period":"PT30M"},{"pv_estimate":0,"pv_estimate10":0,"pv_estimate90":0,"period_end":"2021-05-08T01:30:00.0000000Z","period":"PT30M"},{"pv_estimate":0,"pv_estimate10":0,"pv_estimate90":0,"period_end":"2021-05-08T02:00:00.0000000Z","period":"PT30M"},{"pv_estimate":0,"pv_estimate10":0,"pv_estimate90":0,"period_end":"2021-05-08T02:30:00.0000000Z","period":"PT30M"},{"pv_estimate":0,"pv_estimate10":0,"pv_estimate90":0,"period_end":"2021-05-08T03:00:00.0000000Z","period":"PT30M"},{"pv_estimate":0,"pv_estimate10":0,"pv_estimate90":0,"period_end":"2021-05-08T03:30:00.0000000Z","period":"PT30M"},{"pv_estimate":0,"pv_estimate10":0,"pv_estimate90":0,"period_end":"2021-05-08T04:00:00.0000000Z","period":"PT30M"},{"pv_estimate":0.042,"pv_estimate10":0.014,"pv_estimate90":0.04410000000000001,"period_end":"2021-05-08T04:30:00.0000000Z","period":"PT30M"},{"pv_estimate":0.2716,"pv_estimate10":0.1609,"pv_estimate90":0.28518000000000004,"period_end":"2021-05-08T05:00:00.0000000Z","period":"PT30M"},{"pv_estimate":0.7754,"pv_estimate10":0.3928,"pv_estimate90":0.8141700000000001,"period_end":"2021-05-08T05:30:00.0000000Z","period":"PT30M"},{"pv_estimate":1.587,"pv_estimate10":0.8759,"pv_estimate90":1.6429,"period_end":"2021-05-08T06:00:00.0000000Z","period":"PT30M"},{"pv_estimate":2.5945,"pv_estimate10":1.4596,"pv_estimate90":2.8016,"period_end":"2021-05-08T06:30:00.0000000Z","period":"PT30M"},{"pv_estimate":3.6394,"pv_estimate10":2.0661,"pv_estimate90":3.9205,"period_end":"2021-05-08T07:00:00.0000000Z","period":"PT30M"},{"pv_estimate":4.6673,"pv_estimate10":2.613,"pv_estimate90":5.0012,"period_end":"2021-05-08T07:30:00.0000000Z","period":"PT30M"},{"pv_estimate":5.5825,"pv_estimate10":3.1063,"pv_estimate90":5.9794,"period_end":"2021-05-08T08:00:00.0000000Z","period":"PT30M"},{"pv_estimate":6.3346,"pv_estimate10":3.4979,"pv_estimate90":6.8164,"period_end":"2021-05-08T08:30:00.0000000Z","period":"PT30M"},{"pv_estimate":7.0571,"pv_estimate10":3.8471,"pv_estimate90":7.6107,"period_end":"2021-05-08T09:00:00.0000000Z","period":"PT30M"},{"pv_estimate":7.5582,"pv_estimate10":4.1691,"pv_estimate90":8.1399,"period_end":"2021-05-08T09:30:00.0000000Z","period":"PT30M"},{"pv_estimate":8.0941,"pv_estimate10":4.4613,"pv_estimate90":8.6522,"period_end":"2021-05-08T10:00:00.0000000Z","period":"PT30M"},{"pv_estimate":8.4482,"pv_estimate10":4.676,"pv_estimate90":8.9656,"period_end":"2021-05-08T10:30:00.0000000Z","period":"PT30M"}]}'
    //logWarn("rules.SolarForecast", "Solcast: {} ",forecastJSON)
    var valueString =""

	for (var i = 0 ; i < (143) ; i++) {	//for each HH forecast
		var  ForeCastPower = (Double::parseDouble(transform("JSONPATH", "$.forecasts["+i+"].pv_estimate", forecastJSON)))*1000	//extract the rate and convert to a number
        var  ForeCastPower10 = (Double::parseDouble(transform("JSONPATH", "$.forecasts["+i+"].pv_estimate10", forecastJSON)))*1000	//extract the rate and convert to a number
		var  ForeCastPower90 = (Double::parseDouble(transform("JSONPATH", "$.forecasts["+i+"].pv_estimate90", forecastJSON)))*1000	//extract the rate and convert to a number
        val String time =  transform("JSONPATH", "$.forecasts["+i+"].period_end", forecastJSON)
        val MyZonedDateTimeFromString = ZonedDateTime.parse(time).withZoneSameInstant(ZoneId.systemDefault())
		valueString = valueString + "ForeCastPower value=" +  ForeCastPower + " " + (MyZonedDateTimeFromString.toEpochSecond).toString +"\n"
		valueString = valueString + "ForeCastPower10 value=" +  ForeCastPower10 + " " + (MyZonedDateTimeFromString.toEpochSecond).toString +"\n"
		valueString = valueString + "ForeCastPower90 value=" +  ForeCastPower90 + " " + (MyZonedDateTimeFromString.toEpochSecond).toString +"\n"
        //logWarn("rules.SolarForecast", "Power {}: {} at {} ", i, ForeCastPower.toString, (MyZonedDateTimeFromString.toEpochSecond).toString)
	}
    valueString = valueString.substring(0, valueString.length()-2)
    //logInfo("test", "Influx data {}", valueString)
    var responds = sendHttpPostRequest(INFLUXDB_WRITE, "--data-binary", valueString, 3000)
    logInfo("test", "Influx responds {}", responds)
end

component: widget:Grafana chart with timeranges
config:
  URL: http://192.168.1.210:3000/d-solo/mgJqv2lGz/solar?orgId=1&now-{period}&to=now%2B56h&theme=dark&panelId=6
  height: "400"
  timerange: 1d=1 day,3d=3 day,7d=7 day
1 Like

thanks for this informations

i have try this, but i have an error with this line in thing file

Type string : PV_Today_East "PV Today East [%.1f Wh]" [ stateTransformation="JSONPATH:$.result.watt_hours_day∩REGEX:.*\=(.*)\,.*" ]
Configuration model 'http.things' has errors, therefore ignoring it: [46,80]: mismatched character '=' expecting set null

why the same does not work for me? do you see possibly my error?

Yes - we need to use double-escapes when using Thing files. Here’s the full definition for my location:

//THING
Thing http:url:solar "Solar forecast" [
	baseURL = "https://api.forecast.solar/estimate/LAT/LON/25/-97/1",
	refresh = "1800",
	timeout ="10000",
	ignoreSSLErrors = "true"
]
{
	Channels:
		Type string : raw_data [
			mode = "READONLY"
		]
		Type number : power_today [
			mode = "READONLY",
			stateTransformation = "JSONPATH:$.result.watt_hours_day∩REGEX:.*\\=(.*)\\,.*"
		]
		Type number : power_tomorrow [
			mode = "READONLY",
			stateTransformation = "JSONPATH:$.result.watt_hours_day∩REGEX:.*\\=(.*)\\}.*"
		]
}

These are my items:

String strSolarForecastRawData "Solar forecast raw data" { channel="http:url:solar:raw_data" }
Number nSolarForecastPowerToday "Solar forecast power today" <energy> ["Measurement", "Energy"] { channel="http:url:solar:power_today" }
Number nSolarForecastPowerTomorrow "Solar forecast power tomorrow" <energy> ["Measurement", "Energy"] { channel="http:url:solar:power_tomorrow" }
DateTime dtSolarForecastPowerTodayLastUpdate "Solar forecast power today last update"  { channel="http:url:solar:power_today" [profile="timestamp-update"], stateDescription=""[pattern="%1$tR %1$ta"]}
DateTime dtSolarForecastPowerTomorrowLastUpdate "Solar forecast power tomorrow last update" { channel="http:url:solar:power_tomorrow" [profile="timestamp-update"], stateDescription=""[pattern="%1$tR %1$ta"]}

One caveat with this approach: depending on where you are in the world, the today/tomorrow flip might not happen at midnight…!!

Note that that post is about the service provided by Solcast.com.au, whilst the OP is asking about forecast.solar. The received data is different.

yes agree , i assumed that the existing script can be easily adapted to the Forecast.Solar json responds.

thank you, this was the solution. It works fine :ok_hand:

i have upgraded to trial version of personal plan of forecast.solar.
with this plan i reveive 3 day forecast.

watt_hours_day":{"2022-04-22":16348,"2022-04-23":10996,"2022-04-24":10001,"2022-04-25":9809}

i am a complete newbie with regex and have no idea how to read the 4 values one by one. can someone give me a tip on how to do this?

thanks you very much for your help

This topic was automatically closed 41 days after the last reply. New replies are no longer allowed.