Wee update,
Irridiance on it's own looks like it is not enough from my testing over several different days, due to there are two irridiance values received from OpenWeatherMap.org, one for cloud based and another for clear based which has been difficult to pull into a useable figure that works for all types of weather.
So, I have changed to a hybrid calculation based on irridiance and cloud cover.
I'm pulling hourly irradiance and cloud cover data from the Meteosource API, adjusting the data pulled based on monthly sunrise/sunset as it varies through the year thus only considering the relevant hours for solar energy potential.
Then, the hourly values are are summed to create totals, then hybrid calculating a figure from both Irr & cloud which I can then use for the daily forecast SolarPV.
We'll see how this goes.......but it takes time to experience different weather days!
PS. I did look for another API that gives actual SolarPV predictions, but all the ones I found are very expensive. If you know of one let me know.
New sub in question for those interested.
Ian.
Private Sub MeteosourceIrradiance()
' Meteosource API configuration
Dim MeteosourceAPIKey As String = "###################################"
Dim latitude As String = "########"
Dim longitude As String = "########"
Dim Timezone As String = "###############"
Dim apiUrl As String = $"https://www.meteosource.com/api/v1/flexi/point?lat={latitude}&lon={longitude}§ions=hourly&timezone={Timezone}&language=en&units=auto&key={MeteosourceAPIKey}"
' Ping retry settings
Dim deviceAddress As String = "www.meteosource.com"
Dim maxRetries As Integer = 3
Dim retryDelaySeconds As Double = 0.2
' Check if the checkbox is checked
If CheckBox8.Checked = True Then
' Call Function to check connectivity
If TryPingDevice(deviceAddress, maxRetries, retryDelaySeconds) Then
' Ping was successful
Try
Dim jsonResponse As String = New WebClient().DownloadString(apiUrl)
' Parse the JSON response
Dim data As JObject = JObject.Parse(jsonResponse)
Dim hourlyData As JArray = data("hourly")("data")
' Initialize total variables for today's and tomorrow's irradiance and cloud cover
Dim totalTodayIrradiance As Double = 0
Dim totalTodayCloudCover As Double = 0
Dim todayHours As Integer = 0
Dim totalTomorrowIrradiance As Double = 0
Dim totalTomorrowCloudCover As Double = 0
Dim tomorrowHours As Integer = 0
' Define today and tomorrow's date
Dim today As DateTime = DateTime.Now.Date
Dim tomorrow As DateTime = today.AddDays(1)
' Define start and end hour variables
Dim startHour As Integer
Dim endHour As Integer
' Get the current month
Dim currentMonth As Integer = DateTime.Now.Month
' Adjust based on the month (12 CASE statements for sunrise/sunset adjustment)
Select Case currentMonth
Case 1 ' January
startHour = 10
endHour = 15
Case 2 ' February
startHour = 9
endHour = 16
Case 3 ' March
startHour = 8
endHour = 17
Case 4 ' April
startHour = 7
endHour = 19
Case 5 ' May
startHour = 6
endHour = 20
Case 6 ' June
startHour = 6
endHour = 21
Case 7 ' July
startHour = 6
endHour = 21
Case 8 ' August
startHour = 6
endHour = 20
Case 9 ' September
startHour = 7
endHour = 18
Case 10 ' October
startHour = 8
endHour = 17
Case 11 ' November
startHour = 9
endHour = 15
Case 12 ' December
startHour = 10
endHour = 15
End Select
' Clear the ListBox before adding new data
ListBoxHourlyData.Items.Clear()
ListBoxHourlyData.Items.Add("Forecast = " & DateTime.Now.AddDays(1).ToString("dd-MM-yyyy") & ":" & vbCrLf) ' Add the forecast date header
' Loop through the hourly data and process each entry
For Each hourData As JObject In hourlyData
' Get the date string from the "date" field and split by space
Dim hourDateRaw As String = CStr(hourData("date"))
Dim dateAndTime As String() = hourDateRaw.Split(" "c) ' Split by space
' Get the date and time separately
Dim datePart As String = dateAndTime(0) ' Left part (date)
Dim timePart As String = dateAndTime(1) ' Right part (time)
' Reformat the date part
Dim dateComponents As String() = datePart.Split("/"c) ' Split by "/"
datePart = $"{dateComponents(2)}-{dateComponents(1)}-{dateComponents(0)}"
' Create the full date and time string
Dim fullDateTime As String = datePart & "T" & timePart
' Convert fullDateTime to DateTime
Dim hourDate As DateTime
Try
' Use DateTime.ParseExact to specify the correct format of the fullDateTime
hourDate = DateTime.ParseExact(fullDateTime, "yyyy-dd-MMTHH:mm:ss", System.Globalization.CultureInfo.InvariantCulture)
' Check if the hour is within the valid daytime range
' Both the Irradiance and the Cloud readings per hour are totalled to present a summed value each for the day.
' The hours to consider are dependant on the sunrise to sunset times.
Dim hour As Integer = hourDate.Hour
If hour >= startHour And hour <= endHour Then
' Check if the hour belongs to today or tomorrow
If hourDate.Date = tomorrow Then
totalTomorrowIrradiance += CDbl(hourData("irradiance")) ' sum the irradiance
totalTomorrowCloudCover += CDbl(hourData("cloud_cover")("total")) ' sum the cloud cover
tomorrowHours += 1
' In the 2nd listbox display the hourly Irradiance and Cloud Cover values
Dim timeFormatted As String = $"{hourDate:HH:mm}" ' Format time
Dim irradianceFormatted As String = $"{CDbl(hourData("irradiance"))} W/m²".PadRight(15) ' Ensure consistent width
Dim cloudCoverFormatted As String = $"{CDbl(hourData("cloud_cover")("total"))} %".PadRight(10) ' Ensure consistent width
Dim outputString As String = timeFormatted & vbTab & irradianceFormatted & vbTab & cloudCoverFormatted
ListBoxHourlyData.Items.Add(outputString) ' Add the formatted string to the ListBox
End If
End If
Catch ex As FormatException
' If date parsing fails, print a debug message
'Debug.Print($"Failed to parse date: {fullDateTime} - {ex.Message}")
End Try
Next
' Save contents of ListBoxHourlyData
' Create a StringCollection to hold the ListBox items
Dim itemsToSave As New Specialized.StringCollection()
' Add each item in the ListBox to the StringCollection
For Each item As String In ListBoxHourlyData.Items
itemsToSave.Add(item)
Next
' Save the StringCollection to My.Settings
My.Settings.ListBoxItems = itemsToSave
My.Settings.Save()
' Calculate averages for tomorrow - not used
Dim avgTomorrowIrradiance As Double = If(tomorrowHours > 0, totalTomorrowIrradiance / tomorrowHours, 0)
Dim avgTomorrowCloudCover As Double = If(tomorrowHours > 0, totalTomorrowCloudCover / tomorrowHours, 0)
' Hybrid calculation for tomorrow's irradiance/cloud value
' The hybrid Irr/Cloud value is the total Irradiance value modified my the total cloud cover value.
' No clouds all day then the total Irradiance value all all but unchanged.
' Full clouding all day then the value is brought way, way down.
' The final value goes off to be compared through the ruleset in the Solis dub.
HybridTomorrowIrradianceCloud = totalTomorrowIrradiance * (1 - (totalTomorrowCloudCover / ((endHour - startHour + 1) * 100))) ' Value that will be used to calculate on/off charging times for Solis Sub
' Log the forecast data to a text file
Dim logData As String = $"{DateTime.Now.AddDays(1):dd-MM-yyyy HH:mm}" & vbCrLf &
$" Forecasted Total Irradiance: {totalTomorrowIrradiance} W/m²" & vbCrLf &
$" Forecasted Total Cloud Cover: {totalTomorrowCloudCover} %" & vbCrLf &
$" Hybrid Irr/Cloud Value: {Math.Floor(HybridTomorrowIrradianceCloud).ToString()}" & vbCrLf &
$" Current Battery Level: {BatteryCapacity.Text} %" & vbCrLf &
"------------------------------------------------------------" & vbCrLf
Dim logFileName As String = $"ForecastLog.txt"
Dim logFilePath As String = System.IO.Path.Combine(Application.StartupPath, logFileName) ' Change to your desired log directory
' Append log data to the file
System.IO.File.AppendAllText(logFilePath, logData)
' Update GUI
HybridIrrCloud.Text = CInt(HybridTomorrowIrradianceCloud).ToString()
IrridianceTomorrow.Text = CInt(totalTomorrowIrradiance).ToString() ' Update UI element with the final value
CloudTomorrow.Text = CInt(totalTomorrowCloudCover).ToString() ' Update UI element with the final value
IrradianceCloudForecastDate.Text = DateTime.Now.AddDays(1).ToString("dd-MM-yyyy")
' Hybrid value for GUI
'HybridIrrCloud.Text = CInt(HybridTomorrowIrradianceCloud).ToString() ' Update UI element with the final value
My.Settings.data40 = HybridIrrCloud.Text
My.Settings.data41 = IrridianceTomorrow.Text
My.Settings.data43 = CloudTomorrow.Text
My.Settings.data44 = DateTime.Now.AddDays(1).ToString("dd-MM-yyyy")
My.Settings.Save()
Catch ex As Exception
' Handle any exceptions during data retrieval
Dim currentDateAndTime As DateTime = DateTime.Now
Dim formattedDateTime As String = currentDateAndTime.ToString("dd-MM-yyyy HH:mm", CultureInfo.InvariantCulture)
AddToLogBox(formattedDateTime & " " & "Error fetching data from Meteosource API: " & ex.Message, Color.Red)
IsOkIrridiance = False
LEDirridiance.State = OnOffLed.LedState.OffSmall ' fail RED LED
Exit Sub
End Try
Else
' Ping failed, handle the error
Dim currentDateAndTime As DateTime = DateTime.Now
Dim formattedDateTime As String = currentDateAndTime.ToString("dd-MM-yyyy HH:mm", CultureInfo.InvariantCulture)
AddToLogBox(formattedDateTime & " " & "Error: Unable to reach Meteosource API.", Color.Red)
IsOkIrridiance = False
LEDirridiance.State = OnOffLed.LedState.OffSmall ' fail RED LED
Exit Sub
End If
End If
End Sub