Google Ad

Project 027 - Solis Cloud API - VB.NET sample code

DISCLAIMER: This design is experimental, so if you decide to build one yourself then you are on your own, I can't be held responsible for any problems/issues/damage/injury that may occur if you decide to follow this build and make one yourself.

I have a Solis Inverter (non-hybrid) connected to 10.65kWh Lithium-Iron-Phosphate batteries in the house.
I have a VB app running on a web server in the house that I use to monitor and control a whol;e host of energy related hardware including my workshop aircon, and wanted to extend it's functionality to monitor my new Solis Inverter.

I don't offer much of an explanation of how the code works, I just quote it below to give anyone else some ideas since the Solis API is quite a feat to understand when you also consider the API is a 122 page document.

Important: You cannot access the API data unless you have activated it via Solis. You will need to sign a document.

Here's the sample VB.net code, note the real Key and Secret Key are omitted for obvious reasons.

Imports System.Security.Cryptography
Imports System.Text
Imports Newtonsoft.Json.Linq
Imports Newtonsoft.Json
Imports System.Net.Http
Imports System.Globalization
Imports System.Net.Http.Headers

Partial Class FormMain

    Private Sub Battery()

        If CheckBox4.Checked = True Then     ' Solar read must have been done successfully before OB418 read can take place

            Try
                Dim key As String = "###################"
                Dim keySecret As String = "################################"
                Dim map As New Dictionary(Of String, Object)()
                map.Add("pageNo", 1)
                map.Add("pageSize", 10)
                Dim body As String = JsonConvert.SerializeObject(map)
                Dim ContentMd5 As String = GetDigest(body)
                Dim [Date] As String = GetGMTTime()
                'Dim path As String = "/v1/api/userStationList"
                Dim path As String = "/v1/api/inverterList"
                Dim param As String = "POST" & vbLf & ContentMd5 & vbLf & "application/json" & vbLf & [Date] & vbLf & path
                Dim sign As String = HmacSHA1Encrypt(param, keySecret)
                Dim url As String = "https://www.soliscloud.com:13333" & path
                Dim client As New HttpClient()
                Dim requestBody As HttpContent = New StringContent(body, Encoding.UTF8, "application/json")

                ' Set Content-Type and Content-MD5 directly when creating StringContent
                requestBody.Headers.ContentType = New MediaTypeHeaderValue("application/json") With {
                                .CharSet = "UTF-8"
                            }
                requestBody.Headers.ContentMD5 = Convert.FromBase64String(ContentMd5)

                Dim request As New HttpRequestMessage(HttpMethod.Post, url)
                request.Headers.Add("Authorization", "API " & key & ":" & sign)
                request.Headers.Add("Date", [Date])
                request.Content = requestBody

                Dim response As HttpResponseMessage = client.SendAsync(request).Result
                Dim result As String = response.Content.ReadAsStringAsync().Result
                Console.WriteLine(result)


                ' Pull data from JSON string
                ' JSON version (Newtonsoft DLL) of retrieve data
                Dim jsonString As String = result ' Your JSON string
                Dim jsonObject As JObject = JObject.Parse(result) ' Parse the JSON string

                ' Access the "records" array within the "page" property
                Dim recordsArray As JArray = jsonObject.SelectToken("data.page.records")

                ' Check if the "records" array is not null and contains at least one item
                If recordsArray IsNot Nothing AndAlso recordsArray.Any() Then
                    ' Access the first item in the "records" array
                    Dim firstRecord As JObject = recordsArray.First

                    ' Access the "batteryCapacitySoc" property within the first record
                    Dim batteryCapacitySoc As Double = 0
                    If firstRecord.TryGetValue("batteryCapacitySoc", batteryCapacitySoc) Then

                        IsOkBattery = True
                        LEDbattery.State = OnOffLed.LedState.OnSmall

                        BatteryCapacity.Text = Math.Round(batteryCapacitySoc, 0).ToString() ' 0dp
                    Else
                        IsOkBattery = False
                        LEDbattery.State = OnOffLed.LedState.OffSmall
                    End If

                    ' Access the "batterypower" property within the first record, also charging status
                    Dim batteryPower As Double = 0
                    If firstRecord.TryGetValue("batteryPower", batteryPower) Then

                        IsOkBattery = True
                        LEDbattery.State = OnOffLed.LedState.OnSmall

                        If batteryPower > 0 Then
                            BattStatus.Text = "Charging"
                        End If
                        If batteryPower < 0 Then
                            BattStatus.Text = "Discharging"
                        End If
                        If batteryPower = 0 Then
                            BattStatus.Text = "Static"
                        End If
                        batteryPower = batteryPower * 1000        ' kW to W
                        BattChg.Text = Math.Round(batteryPower, 0).ToString() ' 0dp
                    
                    Else
                    
                        IsOkBattery = False
                        LEDbattery.State = OnOffLed.LedState.OffSmall
                    End If

                Else
                    ' Handle the case where "records" array is empty or null
                    'BatteryCapacity.Text = "No 'records' data available"
                    IsOkBattery = False
                    LEDbattery.State = OnOffLed.LedState.OffSmall
                End If

            Catch ex As Exception
                Console.WriteLine(ex.ToString())
            End Try

        End If

    End Sub

    Function HmacSHA1Encrypt(encryptText As String, KeySecret As String) As String
        Dim data As Byte() = Encoding.UTF8.GetBytes(KeySecret)
        Dim secretKey As New HMACSHA1(data)
        Dim text As Byte() = Encoding.UTF8.GetBytes(encryptText)
        Dim result As Byte() = secretKey.ComputeHash(text)
        Return Convert.ToBase64String(result)
    End Function

    Function GetGMTTime() As String
        Return DateTime.UtcNow.ToString("ddd, dd MMM yyyy HH:mm:ss 'GMT'", CultureInfo.InvariantCulture)
    End Function

    Function GetDigest(test As String) As String
        Dim result As String = ""
        Try
            Using md5 As System.Security.Cryptography.MD5 = System.Security.Cryptography.MD5.Create()
                Dim data As Byte() = md5.ComputeHash(Encoding.UTF8.GetBytes(test))
                result = Convert.ToBase64String(data)
            End Using
        Catch ex As Exception
            Console.WriteLine(ex.ToString())
        End Try
        Return result
    End Function
    
End Class