Modbus TCP - Wie die abgefragten Integer-Register-Werte "zusammenbauen" in String, Long, Double, etc...

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 44 Antworten in diesem Thema. Der letzte Beitrag () ist von dive26.

    @BitBrösel

    Wenn ich den anderen Wechselrichter (mit Modbus ID 2) anspreche, der KEINE Optimierer hat,
    Dann erhalte ich 00 00 00 00 00 03 02 80 04 zurück.

    Wenn ich den einen Wechselrichter (mit Modbus ID 3) anspreche, der Optimierer hat,
    Dann erhalte ich 00 00 00 00 00 03 03 80 01 zurück.

    Die drei (oder zwei) an 7. Stelle ist die übergebene Modbus ID. Also wohl doch nur Zufall ;-).
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
    @BitBröselnull
    Huawei hat nach langem hin- und her zumindest die Modbus-Beschreibung geliefert.

    Ich habe mal "klein" angefangen und eine normale Registerabfrage durchgeführt.
    Zur Erklärung des Screenshots:

    VB.NET-Quellcode

    1. Dim frame As Byte() = New Byte(11) {}
    2. 'Transmission Flag (2Bytes) - Generated by client - copy value on answer
    3. frame(0) = 98
    4. frame(1) = 91
    5. 'Protocol Flag (2Bytes) - Generated by client - copy value on answer (0=Modbus protocol)
    6. frame(2) = 0
    7. frame(3) = 0
    8. 'Lenght (2Bytes) - Subsequent Bygtes Count - Generatet by client - Regenerated by the server when responding
    9. frame(4) = 0
    10. frame(5) = 6
    11. 'Unit ID (1Byte) - 100 = collector / 1-~ = modbus ID - Generated by client - Copy value on answer
    12. frame(6) = 3 ' WR2 hat ID 3 (der mit den Optimierern)
    13. 'Function Code (03) = Register Query
    14. frame(7) = 3
    15. 'Register Address (30070) = Modell Number (sollte 429 Dez sein)
    16. frame(8) = 117 ' Hex 75
    17. frame(9) = 118 'Hex 76
    18. 'Register Format
    19. frame(10) = 0
    20. frame(11) = 1


    Request:
    * Byte 0,1,2 und 3: individuell - werden beim Response 1:1 zurückgegeben.
    * Byte 4 und 5 sind die Länge des nachfolgenden Datensatzes (in diesem Fall 6 Bytes)
    * Byte 6 ist die Modbus-Adresse (in meinem Fall 3)
    * Byte 7 ist der Modbus Funktionscode (3 = normale Registerabfrage). Wir brauchen später 65 (spezielle Funktion)
    * Byte 8 und 9 ist die Registeradresse die abgefragt werden soll (30070). In meinem Fall soll da die Modellnummer 429 rauskommen.
    * Byte 10 und 11 sind Registerformat. 1 = nur ein Register abfragen, 2= zwei Register etc...

    Response:
    * Byte 0-7 werden 1:1 zurückgegeben
    * Byte 8 (02) ist die Länge des nachfolgenden Inhalts (2 Bytes)
    * Byte 9 und 10 ist der 16Bit Wert (die Modellnummer 429).

    Wir hatten bisher immer die Rückmeldung 83 in Byte 9 und einen Wert in 10 erhalten.
    83 bedeutet ERROR und der zweite Wert ist der Error-Code ;-).
    Bilder
    • 08112022155727.jpg

      187,44 kB, 519×426, 62 mal angesehen
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „dive26“ ()

    @BitBrösel

    Einen halben Schritt bin ich weiter und habe jetzt die Funktionsweise verstanden.
    In der Modbus-Beschreibung (oben bereits verlinkt - ist öffentlich zugängig, also auch von Huawei ok) auf Seite 91 oben ist das Schema abgebildet.

    1. Man sendet ein Datenpaket (Tabelle 6-15) mit Funktionscode 65 und SubCode 5 und erhält dann ein Response-Datenpaket wie in Tabelle 6-16 beschrieben zurück.
    Das funktioniert bereits ohne Fehlermeldungen (bisher hatten wir beide immer den Wert 83 - was Fehler bedeutet ;-)).

    2. Man sollte im Responsepaket sogenannte "Frame No." erhalten die man dann in einer Schleife abfragt (Tabelle 6-18)
    Nun, da ist das Problem. Im Response von der ersten Abfrage gibt es 4 Bytes die in der Beschreibung als "File length" bezeichnet werden (grün im Screenshot).
    Danach folgt ein Wert mit Data Frame Length (der ist immer 246 - das sind die nettodaten ohne Header jeder Abfrage).
    Und danach folgen je nach Data length mehrere Werte die im Handbuch als "Customized data" beschrieben sind. Bei mir 00 00 FF FF
    Jedoch kann ich aus diesen beiden 4-Byte-Werten keine Rückschlüsse auf eine Frame-No ziehen, welche mit 2 Bytes angegeben werden sollte ;-).

    Bei 34 Optimierern sollten pro Optimierer 26 Bytes an Daten kommen + 12 Bytes pro Frame-Abfrage.
    Also sollten bei einer Frame-Abfrage 9 Optimierer + Header kommen.
    Bei 9 Optimierer sind also 4 Frame-Abfrageschleifen erforderlich.

    Keine Ahnung was ich als Framenummer angeben soll.


    Hier die Anfrage die ich an Huawei geschrieben habe weil es gerade stockt (deutsche Version):


    Leider kann ich einige Werte nicht zuordnen. Vielleicht kannst Du mir dabei helfen. Ich beziehe mich auf den Screenshot und die Modbus-Definition Seite 45-50 und 90-94.

    Wechselrichter-Modbus-Adresse ist "3". Es sind 34 Optimierer auf diesen Wechselrichter installiert.

    In Zeile 1 sende ich die Anfrage für "file upload startup". Die Antwort kommt ohne Fehlermeldung in Zeile 2.

    Im folgenden Schritt sollte ja in jeweils in 246 byte-Blöcken (Wert F6 zwischen grün und blau markierten Werten) solange abgerufen werden bis alle Daten empfangen wurden.

    Jedoch weis ich nicht was ich bei BLAU als Wert für die einzelnen Abfrageschleifen verwenden soll. Die GRÜNEN und ROTEN Werte von der ersten Antwort sind für mich leider nicht schlüssig.

    "File lenght" 4 Bytes: 00 1E AA 8C (green)
    Was bedeuten diese Werte? Sind das mehrere Werte oder ein Int32 Wert?

    Customized data 00 00 FF FF (red)
    Auch diese Werte kann ich nicht interpretieren.

    Können Sie mir helfen, damit ich bei der Frame-Abfrage keine Fehlermeldung (C1 03) erhalte?

    Vielen Dank für Ihre Hilfe.



    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. Dim Datenlaenge As Integer
    3. '######## Schritt 1 "File upload startup" ###############
    4. Dim frame As Byte() = New Byte(10) {}
    5. frame(0) = 98 : frame(1) = 91 : frame(2) = 0 : frame(3) = 0 'immer gleich
    6. frame(4) = 0 'Länge in 2 Bytes
    7. frame(5) = 5 'Länge in 2 Bytes
    8. frame(6) = 3 'Modbus-ID des Wechselrichters
    9. frame(7) = CByte(65) 'Huawei eigener Function Code 0x41
    10. frame(8) = CByte(5) 'Subfunktionscode für "Starting the Upload" 0x05
    11. frame(9) = 1 'Data lenght der nachfolgenden Infos
    12. frame(10) = CByte(68) 'File Type 68 0x44 (4.2 obtaining real-time data)
    13. txtResult.Text += "SEND (Table 6-15): " + Me.Display(frame) ' Zeige zu sendende Bytes im Textfeld
    14. Me.mSocket.Send(frame, frame.Length, SocketFlags.None) ' Send Data
    15. Dim buffRecei As Byte() = New Byte(256) {} ' Received data.
    16. Dim ns As NetworkStream = New NetworkStream(Me.mSocket)
    17. If ns.CanRead Then Dim rs As Integer = Me.mSocket.Receive(buffRecei, buffRecei.Length, SocketFlags.None)
    18. If CInt(buffRecei(7)) = 193 Or CInt(buffRecei(7)) = 194 Then
    19. MsgBox("Fehler: " + buffRecei(7).ToString + " Fehlercode: " + CInt(buffRecei(8)).ToString)
    20. txtResult.Text += vbCrLf + "RECEIVE (Table 6-16): " + Me.Display(buffRecei) ' Zeige alle empfangenen Bytes
    21. Exit Sub
    22. Else
    23. 'alles ok - An stelle 9 steht die länge der nachfolgenden Informationen
    24. Datenlaenge = CInt(buffRecei(9)) + 9
    25. txtResult.Text += vbCrLf + "RECEIVE (Table 6-16): " + Me.Display(buffRecei, Datenlaenge) ' Zeige nur die geforderten empfangenen Bytes
    26. End If
    27. txtResult.Text += vbCrLf
    28. '11,12,13 und 14 =
    29. '00 (File lenght 4 Bytes)
    30. '1E (File lenght 4 Bytes)
    31. 'AA(File lenght 4 Bytes)
    32. '8C (File lenght 4 Bytes)
    33. '15 = Datenframe Länge (immer 246)
    34. '16,17,18,18, ... = Nachfolgende Daten
    35. '00 Customized data =0
    36. '00 Customized data =0
    37. 'FF Customized data =255
    38. 'FF Customized data =255
    39. Dim u32Wert As UInt32 = BitConverter.ToUInt32(buffRecei, 11)
    40. 'MsgBox(u32Wert.ToString) 'ergibt eine sehr hohe Zahl
    41. '######### Schritt 2 "Request for uploading data (frame SN) #########
    42. Dim frameC As Byte() = New Byte(12) {}
    43. Dim FrameNumber As Integer = 1
    44. For i As Integer = CInt(buffRecei(9)) + 6 To Datenlaenge
    45. 'MsgBox(i.ToString + ": " + CInt(buffRecei(i)).ToString)
    46. 'Jede Tranche zu 255 Bytes (246 Datenbytes) abfragen
    47. frameC(0) = 98 : frameC(1) = 91 : frameC(2) = 0 : frameC(3) = 0 'immer gleich
    48. frameC(4) = 0 'Länge in 2 Bytes
    49. frameC(5) = 5 'Länge in 2 Bytes
    50. frameC(6) = 3 'Modbus-ID des Wechselrichters
    51. frameC(7) = CByte(65) 'Huawei eigener Function Code 0x41
    52. frameC(8) = CByte(6) 'Subfunktionscode für "Request Frame Uploading Data" 0x06
    53. frameC(9) = 3 'Data lenght der nachfolgenden Infos
    54. frameC(10) = CByte(68) 'File Type 68 0x44 (4.2 obtaining real-time data)
    55. frameC(11) = CByte(0)
    56. frameC(12) = CByte(FrameNumber)
    57. txtResult.Text += vbCrLf + "SEND (Table 6-18): " + Me.Display(frameC) ' Zeige zu sendende Bytes im Textfeld
    58. Application.DoEvents()
    59. Me.mSocket.Send(frameC, frameC.Length, SocketFlags.None) ' Send Data
    60. Dim buffReceiC As Byte() = New Byte(256) {} ' Received data.
    61. Dim nsC As NetworkStream = New NetworkStream(Me.mSocket)
    62. If nsC.CanRead Then Dim rs As Integer = Me.mSocket.Receive(buffReceiC, buffReceiC.Length, SocketFlags.None)
    63. txtResult.Text += vbCrLf + "RECEIVE (Table 6-18): " + Me.Display(buffReceiC) ' Zeige alle empfangenen Bytes
    64. txtResult.Text += vbCrLf
    65. FrameNumber += 1
    66. Next i
    67. '######### Schritt 3 "Completing the Data Upload" ##########
    68. Dim frameA As Byte() = New Byte(10) {}
    69. frameA(0) = 98 : frameA(1) = 91 : frameA(2) = 0 : frameA(3) = 0 'immer gleich
    70. frameA(4) = 0 'Länge in 2 Bytes
    71. frameA(5) = 5 'Länge in 2 Bytes
    72. frameA(6) = 3 'Modbus-ID des Wechselrichters
    73. frameA(7) = CByte(65) 'Huawei eigener Function Code
    74. frameA(8) = CByte(12) 'Subfunktionscode für "Starting the Upload"
    75. frameA(9) = 1 'Data lenght der nachfolgenden Infos
    76. frameA(10) = 0
    77. txtResult.Text += vbCrLf + "SEND: " + Me.Display(frameA) ' Zeige zu sendende Bytes im Textfeld
    78. Application.DoEvents()
    79. Me.mSocket.Send(frameA, frameA.Length, SocketFlags.None) ' Send Data
    80. Dim buffReceiA As Byte() = New Byte(256) {} ' Received data.
    81. Dim nsA As NetworkStream = New NetworkStream(Me.mSocket)
    82. If nsA.CanRead Then Dim rs As Integer = Me.mSocket.Receive(buffReceiA, buffReceiA.Length, SocketFlags.None)
    83. If CInt(buffReceiA(7)) = 193 Or CInt(buffReceiA(7)) = 194 Then
    84. MsgBox("Fehler: " + buffReceiA(7).ToString + " Fehlercode: " + CInt(buffReceiA(8)).ToString)
    85. txtResult.Text += vbCrLf + "RECEIVE: " + Me.Display(buffReceiA) ' Zeige alle empfangenen Bytes
    86. Exit Sub
    87. Else
    88. 'alles ok - An stelle 9 steht die länge der nachfolgenden Informationen
    89. Datenlaenge = CInt(buffReceiA(9)) + 9
    90. txtResult.Text += vbCrLf + "RECEIVE: " + Me.Display(buffReceiA, Datenlaenge) ' Zeige nur die geforderten empfangenen Bytes
    91. End If
    92. End Sub
    Bilder
    • optimizers.jpg

      312,78 kB, 901×558, 59 mal angesehen
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
    @BitBrösel

    Nach einigem Schriftverkehr mit dem Huawei-Support bin ich nun endlich soweit, dass ich die gewünschten Daten bekomme.


    XML-Quellcode

    1. SEND (Table 6-15): 00 01 00 00 00 05 03 41 05 01 44
    2. RECEIVE (Table 6-16): 00 01 00 00 00 0E 03 41 05 0A 44 00 1F 8E 0C F6 00 00 FF FF
    3. SEND (Table 6-18): 00 02 00 00 00 07 03 41 06 03 44 00 00
    4. RECEIVE (Table 6-18): 00 02 00 00 00 FD 03 41 06 F9 44 00 00 56 31 30 31 04 09 00 00 04 09 00 00 12 7A 6E 63 00 00 00 00 76 03 22 00 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 26 00 00 06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 A9 17 00 00 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 31 18 00 00 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F4 21 00 00 09 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 27 00 00 0A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3A 19 00 00 0B 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 D1 23 00 00 0C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FC 1B 00 00 0D 00 00 00 00 00 00 00 00 00 00 00
    5. SEND: 00 03 00 00 00 05 03 41 0C 01 00
    6. RECEIVE: 00 00 00 00 00 00 00 00 00 00



    Funktion:
    Die erste Anfrage beginnt den Abruf der Daten. Als Response kommt die Datenlänge zurück.
    Dann ruft man in einer Schleife alle Datenframes ab (oben ist testweise nur ein Frame abgebildet).
    Am Ende gibt es eine abschließende "Abschlussmeldung".

    Der zweite Block muss mehrmals abgerufen werden, bis alle Daten heruntergeladen wurden. Wie oft steht oben im ersten Response ​00 1F 8E 0C. Jedes abgerufene Frame enthält 246 Bytes F6 .
    ​00 00 FF FF soll man laut Huawei Support einfach ignorieren ;-).

    Die ersten beiden Bytes jeder Anfrage 00 01 , 00 02 , ... sind Modbus-Transmissionflags. Diese werden einfach bei jeder Anfrage um eins hochgezählt und kommen so auch im Response wieder zurück.
    Ist nicht essentiell, aber laut Modbus Protokoll soll man es so machen.

    Ich werde die nächsten Tage den Code entsprechend sauber zusammenschreiben und den dann hier für alle posten.
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
    Nun wie besprochen der komplette Code.
    Ich habe das Modul soweit umgebaut, dass es die Daten der Modbus-Spezialabfrage in einem Byte-Array übergibt (bei Fehler Nothing).
    Abragen: FileUpload Optimierer Infos und Optimierer Real-time-Data und zusätzlich noch eine ganz normale Modbus-Register-Abfrage.

    Huawei_Modbus_GetOptimizerSysInfo = Funktioniert so einwandfrei und übergibt bei 34 Optimierern 15 Datenframes.
    Huawei_Modbus_GetOptimizerRealtime = Funktioniert ebenfalls, nur werden hier 5-Minutige Optimiererdaten abgerufen (fast 2 MB). Hier gibt es sicher noch einen Filter vorher auszuwählen, mit dem nur Daten eines bestimmten Zeitstempels geladen werden. Aber das ist dann nur noch eine Kleinigkeit die jeder selbst einbauen kann.


    Um den Code Nachzubilden braucht man eine Form mit drei Buttons und eine Textbox.

    VB.NET-Quellcode

    1. Option Strict On
    2. Public Class Hauptform
    3. Private Sub Hauptform_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    4. Try
    5. Huawei_Modbus_Connect() ' Connect to device.
    6. Catch ex As Exception
    7. MessageBox.Show(Me, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
    8. End
    9. End Try
    10. End Sub
    11. ''' <summary>
    12. ''' Beim Schließen der Form die Verbindung in jedem Fall wieder trennen
    13. ''' </summary>
    14. ''' <param name="sender"></param>
    15. ''' <param name="e"></param>
    16. Private Sub Hauptform_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
    17. Huawei_Modbus_Disconnect()
    18. End Sub
    19. ''' <summary>
    20. ''' Optimierer Echtzeit-Daten auslesen
    21. ''' </summary>
    22. ''' <param name="sender"></param>
    23. ''' <param name="e"></param>
    24. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    25. nochmals:
    26. txtResult.Text = ""
    27. Dim OptimiererRealTimeDaten As Byte() = Huawei_Modbus_GetOptimizerRealtime()
    28. If Huawei_Modbus_AbfrageFehlgeschlagen = True Then
    29. Huawei_Modbus_AbfrageFehlgeschlagen = False
    30. Huawei_Modbus_Disconnect()
    31. Huawei_Modbus_Connect()
    32. GoTo Nochmals
    33. End If
    34. End Sub
    35. ''' <summary>
    36. ''' Optimierer System Info holen
    37. ''' </summary>
    38. ''' <param name="sender"></param>
    39. ''' <param name="e"></param>
    40. Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    41. txtResult.Text = ""
    42. Nochmals:
    43. Dim OptimiererSysInfoDaten As Byte() = Huawei_Modbus_GetOptimizerSysInfo()
    44. If Huawei_Modbus_AbfrageFehlgeschlagen = True Then
    45. Huawei_Modbus_AbfrageFehlgeschlagen = False
    46. Huawei_Modbus_Disconnect()
    47. Huawei_Modbus_Connect()
    48. GoTo Nochmals
    49. End If
    50. End Sub
    51. ''' <summary>
    52. ''' Einzelnen Register auslesen (UInt16)
    53. ''' </summary>
    54. ''' <param name="sender"></param>
    55. ''' <param name="e"></param>
    56. Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
    57. txtResult.Text = ""
    58. Dim Wert As Integer = MB_RequestU16(3, 30070)
    59. txtResult.Text += vbCrLf + "Result: " + Wert.ToString
    60. End Sub
    61. End Class


    Quellcode

    1. Option Strict On
    2. Imports System.Net
    3. Imports System.Net.Sockets
    4. Imports System.Threading
    5. Module MDL_HuaweiModbus
    6. Public Huawei_Modbus_Socket As Socket = Nothing
    7. Public Const ModbusIP As String = "192.168.0.188"
    8. Public Const ModbusPort As UShort = 502
    9. Public Huawei_Modbus_Transmissionflag As Integer = 1
    10. Public Huawei_Modbus_AbfrageFehlgeschlagen As Boolean
    11. ''' <summary>
    12. ''' Function: Connect to device.
    13. ''' </summary>
    14. Public Sub Huawei_Modbus_Connect()
    15. Huawei_Modbus_Socket = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) With {
    16. .ReceiveTimeout = 5000,
    17. .SendTimeout = 5000
    18. }
    19. Dim server As New IPEndPoint(IPAddress.Parse(ModbusIP), ModbusPort)
    20. Huawei_Modbus_Socket.Connect(server)
    21. Thread.Sleep(2000) 'Empfehlung von Huawei 2 Sekunden zu warten (später mit warte-Funktion)
    22. End Sub
    23. ''' <summary>
    24. ''' Function: disconnect with device.
    25. ''' </summary>
    26. Public Sub Huawei_Modbus_Disconnect()
    27. If Not IsDBNull(Huawei_Modbus_Socket) Then
    28. Huawei_Modbus_Socket.Close()
    29. End If
    30. End Sub
    31. Public Function BO_BitConverter_ToUInt16(Daten As Byte(), start As Integer) As Integer
    32. Return CInt(Daten(start) * 256) + CInt(Daten(start + 1))
    33. End Function
    34. Public Function BO_BitConverter_ToUInt32(Daten As Byte(), start As Integer) As Integer
    35. Return CInt(Daten(start) * 256 * 256 * 256) + CInt(Daten(start + 1) * 256) * 256 + CInt(Daten(start + 2) * 256) + CInt(Daten(start + 3))
    36. End Function
    37. ''' <summary>
    38. ''' Funktion für die Umwandlung von Intergerwert in ein Byte-Array
    39. ''' </summary>
    40. ''' <param name="int"></param>
    41. ''' <returns></returns>
    42. Public Function ConvertIntToByteArray(ByVal int As Int32) As Byte()
    43. Return BitConverter.GetBytes(int)
    44. End Function
    45. ''' <summary>
    46. ''' Wandelt eine Bytefolge in lesbare Hex-Strings um (für die Ausgabe zur Kontrolle)
    47. ''' </summary>
    48. ''' <param name="data"></param>
    49. ''' <param name="laenge"></param>
    50. ''' <returns></returns>
    51. Private Function BytesToTextForDebug(data As Byte(), Optional laenge As Integer = 4096) As String
    52. Dim Counter As Integer = 0
    53. Dim result As String = String.Empty
    54. For Each item As Byte In data
    55. result += String.Format("{0:X2} ", item)
    56. Counter += 1
    57. If Counter > laenge Then Exit For
    58. Next
    59. Application.DoEvents()
    60. Return result
    61. End Function
    62. ''' <summary>
    63. ''' Gibt die Debug-Informationen in einem Textfeld im Hauptfenster (oder überall anders) aus
    64. ''' </summary>
    65. ''' <param name="Daten"></param>
    66. Public Sub DebugAusgabe(Daten As String, Append As Boolean)
    67. If Append = True Then Hauptform.txtResult.Text += Daten Else Hauptform.txtResult.Text = Daten
    68. Hauptform.txtResult.Select(Hauptform.txtResult.Text.Length - 1, 1)
    69. Hauptform.txtResult.ScrollToCaret()
    70. End Sub
    71. ''' <summary>
    72. ''' Lädt die Optimierer-Informationen laut File Format V103 herunter und übergibt alle Bytes
    73. ''' Wenn ein Fehler aufgetreten ist, dann wird nur nothing zurückgegeben
    74. ''' </summary>
    75. ''' <returns></returns>
    76. Public Function Huawei_Modbus_GetOptimizerSysInfo() As Byte()
    77. If Huawei_Modbus_Socket.Connected = False Then Huawei_Modbus_Connect()
    78. If Huawei_Modbus_Socket.Connected = False Then Return Nothing
    79. Dim Filetype As Byte = CByte(69) 'V102 / V103
    80. Dim Datenlaenge As Integer
    81. Dim GesamtByteArray As Byte() = {}
    82. '######## Schritt 1 "File upload startup" ###############
    83. Dim frame As Byte() = New Byte(10) {}
    84. frame(0) = CByte(Huawei_Modbus_Transmissionflag / 256)
    85. frame(1) = CByte(Huawei_Modbus_Transmissionflag)
    86. frame(2) = 0 : frame(3) = 0 'immer gleich
    87. frame(4) = 0 'Länge in 2 Bytes
    88. frame(5) = 5 'Länge in 2 Bytes
    89. frame(6) = 3 'Modbus-ID des Wechselrichters
    90. frame(7) = CByte(65) 'Huawei eigener Function Code 0x41
    91. frame(8) = CByte(5) 'Subfunktionscode für "Starting the Upload" 0x05
    92. frame(9) = 1 'Data lenght der nachfolgenden Infos
    93. frame(10) = Filetype
    94. DebugAusgabe("SEND (Table 6-15): " + BytesToTextForDebug(frame), True)
    95. Huawei_Modbus_Socket.Send(frame, frame.Length, SocketFlags.None) ' Send Data
    96. Dim buffRecei As Byte() = New Byte(256) {} ' Received data.
    97. Try
    98. Using ns As New NetworkStream(Huawei_Modbus_Socket)
    99. If ns.CanRead Then Dim unused = Huawei_Modbus_Socket.Receive(buffRecei, buffRecei.Length, SocketFlags.None)
    100. End Using
    101. Catch ex As Exception
    102. DebugAusgabe(vbCrLf + ex.Message, True)
    103. Huawei_Modbus_AbfrageFehlgeschlagen = True
    104. Return Nothing
    105. End Try
    106. If CInt(buffRecei(7)) = 193 Or CInt(buffRecei(7)) = 194 Then
    107. MsgBox("Fehler: " + buffRecei(7).ToString + " Fehlercode: " + CInt(buffRecei(8)).ToString)
    108. DebugAusgabe(vbCrLf + "RECEIVE (Table 6-16): " + BytesToTextForDebug(buffRecei) + vbCrLf, True)
    109. Huawei_Modbus_AbfrageFehlgeschlagen = True
    110. Return Nothing
    111. Else
    112. 'alles ok - An stelle 9 steht die länge der nachfolgenden Informationen
    113. Datenlaenge = CInt(buffRecei(9)) + 9
    114. DebugAusgabe(vbCrLf + "RECEIVE (Table 6-16): " + BytesToTextForDebug(buffRecei, Datenlaenge) + vbCrLf, True)
    115. End If
    116. Huawei_Modbus_Transmissionflag += 1
    117. Dim DatensatzLaenge As Integer = BO_BitConverter_ToUInt32(buffRecei, 11)
    118. Dim FrameAnzahl As Integer = CInt(Math.Ceiling(DatensatzLaenge / 246))
    119. DebugAusgabe(vbCrLf + "Lenght of file: " + DatensatzLaenge.ToString + " No. of frames: " + FrameAnzahl.ToString + vbCrLf, True)
    120. Hauptform.ProgressBar1.Maximum = FrameAnzahl
    121. For i As Integer = 1 To FrameAnzahl
    122. Hauptform.ProgressBar1.Value = i
    123. Dim frameC As Byte() = New Byte(12) {}
    124. Dim buffReceiC As Byte() = New Byte(258) {} ' Received data.
    125. frameC(0) = CByte(Huawei_Modbus_Transmissionflag / 256)
    126. frameC(1) = CByte(Huawei_Modbus_Transmissionflag)
    127. frameC(2) = 0 : frameC(3) = 0 'immer gleich
    128. frameC(4) = 0 'Länge in 2 Bytes
    129. frameC(5) = 7 'Länge in 2 Bytes
    130. frameC(6) = 3 'Modbus-ID des Wechselrichters
    131. frameC(7) = CByte(65) 'Huawei eigener Function Code 0x41
    132. frameC(8) = CByte(6) 'Subfunktionscode für "Request Frame Uploading Data" 0x06
    133. frameC(9) = 3 'Data lenght der nachfolgenden Infos
    134. frameC(10) = Filetype 'File Type 68 0x44 (4.2 obtaining real-time data)
    135. frameC(11) = 0
    136. frameC(12) = CByte((i - 1))
    137. DebugAusgabe(vbCrLf + Now().ToString("HH.mm.ss") + " SEND (" + i.ToString + "): " + BytesToTextForDebug(frameC), True)
    138. If Huawei_Modbus_Socket.Connected = False Then Huawei_Modbus_Connect()
    139. Huawei_Modbus_Socket.Send(frameC, frameC.Length, SocketFlags.None) ' Send Data
    140. Try
    141. Using nsC As New NetworkStream(Huawei_Modbus_Socket)
    142. If nsC.CanRead Then Dim unused = Huawei_Modbus_Socket.Receive(buffReceiC, buffReceiC.Length, SocketFlags.None)
    143. End Using
    144. Catch ex As Exception
    145. DebugAusgabe(vbCrLf + ex.Message, True)
    146. Huawei_Modbus_AbfrageFehlgeschlagen = True
    147. Return Nothing
    148. End Try
    149. If CInt(buffReceiC(7)) = 193 Or CInt(buffReceiC(7)) = 194 Then
    150. MsgBox("Fehler: " + buffReceiC(7).ToString + " Fehlercode: " + CInt(buffReceiC(8)).ToString)
    151. DebugAusgabe(vbCrLf + "RECEIVE: " + BytesToTextForDebug(buffReceiC), True)
    152. Huawei_Modbus_AbfrageFehlgeschlagen = True
    153. Return Nothing
    154. Else
    155. 'alles ok - An stelle 9 steht die länge der nachfolgenden Informationen
    156. DebugAusgabe(vbCrLf + Now().ToString("HH.mm.ss") + " RECEIVE (" + i.ToString + "): " + BytesToTextForDebug(buffReceiC), True)
    157. End If
    158. GesamtByteArray.Concat(buffReceiC)
    159. Huawei_Modbus_Transmissionflag += 1
    160. Next i
    161. '######### Schritt 3 "Completing the Data Upload" ##########
    162. Dim buffReceiA As Byte() = New Byte(256) {} ' Received data.
    163. Dim frameA As Byte() = New Byte(10) {}
    164. frameA(0) = 0 ' CByte(Transmissionflag / 256)
    165. frameA(1) = 0 'CByte(Transmissionflag)
    166. frameA(2) = 0 : frameA(3) = 0 'immer gleich
    167. frameA(4) = 0 'Länge in 2 Bytes
    168. frameA(5) = 5 'Länge in 2 Bytes
    169. frameA(6) = 3 'Modbus-ID des Wechselrichters
    170. frameA(7) = CByte(65) 'Huawei eigener Function Code
    171. frameA(8) = CByte(12) 'Subfunktionscode für "End the Upload"
    172. frameA(9) = 1 'Data lenght der nachfolgenden Infos
    173. frameA(10) = Filetype
    174. DebugAusgabe(vbCrLf + "SEND: " + BytesToTextForDebug(frameA), True)
    175. Huawei_Modbus_Socket.Send(frameA, frameA.Length, SocketFlags.None) ' Send Data
    176. Try
    177. Using nsA As New NetworkStream(Huawei_Modbus_Socket)
    178. If nsA.CanRead Then Dim unused = Huawei_Modbus_Socket.Receive(buffReceiA, buffReceiA.Length, SocketFlags.None)
    179. End Using
    180. Catch ex As Exception
    181. DebugAusgabe(vbCrLf + ex.Message, True)
    182. Huawei_Modbus_AbfrageFehlgeschlagen = True
    183. Return Nothing
    184. End Try
    185. If CInt(buffReceiA(7)) = 193 Or CInt(buffReceiA(7)) = 194 Then
    186. MsgBox("Fehler: " + buffReceiA(7).ToString + " Fehlercode: " + CInt(buffReceiA(8)).ToString)
    187. DebugAusgabe(vbCrLf + "RECEIVE: " + BytesToTextForDebug(buffReceiA), True)
    188. Huawei_Modbus_AbfrageFehlgeschlagen = True
    189. Return Nothing
    190. Else
    191. 'alles ok - An stelle 9 steht die länge der nachfolgenden Informationen
    192. Datenlaenge = CInt(buffReceiA(9)) + 9
    193. DebugAusgabe(vbCrLf + "RECEIVE: " + BytesToTextForDebug(buffReceiA, Datenlaenge), True)
    194. End If
    195. Huawei_Modbus_Transmissionflag += 1
    196. Return GesamtByteArray
    197. End Function
    198. ''' <summary>
    199. ''' Lädt die Optimierer-Real-Time-Datean laut File Format V101 herunter und übergibt alle Bytes
    200. ''' Wenn ein Fehler aufgetreten ist, dann wird nur nothing zurückgegeben
    201. ''' </summary>
    202. ''' <returns></returns>
    203. Public Function Huawei_Modbus_GetOptimizerRealtime() As Byte()
    204. If Huawei_Modbus_Socket.Connected = False Then Huawei_Modbus_Connect()
    205. If Huawei_Modbus_Socket.Connected = False Then Return Nothing
    206. Dim Filetype As Byte = CByte(68) 'V101
    207. Dim Datenlaenge As Integer
    208. Dim GesamtByteArray As Byte() = {}
    209. '######## Schritt 1 "File upload startup" ###############
    210. Dim frame As Byte() = New Byte(10) {}
    211. frame(0) = CByte(Huawei_Modbus_Transmissionflag / 256)
    212. frame(1) = CByte(Huawei_Modbus_Transmissionflag)
    213. frame(2) = 0 : frame(3) = 0 'immer gleich
    214. frame(4) = 0 'Länge in 2 Bytes
    215. frame(5) = 5 'Länge in 2 Bytes
    216. frame(6) = 3 'Modbus-ID des Wechselrichters
    217. frame(7) = CByte(65) 'Huawei eigener Function Code 0x41
    218. frame(8) = CByte(5) 'Subfunktionscode für "Starting the Upload" 0x05
    219. frame(9) = 1 'Data lenght der nachfolgenden Infos
    220. frame(10) = Filetype 'File Type 68 0x44 (4.2 obtaining real-time data)
    221. DebugAusgabe("SEND (Table 6-15): " + BytesToTextForDebug(frame), True)
    222. Huawei_Modbus_Socket.Send(frame, frame.Length, SocketFlags.None) ' Send Data
    223. Dim buffRecei As Byte() = New Byte(256) {} ' Received data.
    224. Try
    225. Using ns As New NetworkStream(Huawei_Modbus_Socket)
    226. If ns.CanRead Then Dim unused = Huawei_Modbus_Socket.Receive(buffRecei, buffRecei.Length, SocketFlags.None)
    227. End Using
    228. Catch ex As Exception
    229. DebugAusgabe(vbCrLf + ex.Message, True)
    230. Huawei_Modbus_AbfrageFehlgeschlagen = True
    231. Return Nothing
    232. End Try
    233. If CInt(buffRecei(7)) = 193 Or CInt(buffRecei(7)) = 194 Then
    234. MsgBox("Fehler: " + buffRecei(7).ToString + " Fehlercode: " + CInt(buffRecei(8)).ToString)
    235. DebugAusgabe(vbCrLf + "RECEIVE (Table 6-16): " + BytesToTextForDebug(buffRecei) + vbCrLf, True)
    236. Huawei_Modbus_AbfrageFehlgeschlagen = True
    237. Return Nothing
    238. Else
    239. 'alles ok - An stelle 9 steht die länge der nachfolgenden Informationen
    240. Datenlaenge = CInt(buffRecei(9)) + 9
    241. DebugAusgabe(vbCrLf + "RECEIVE (Table 6-16): " + BytesToTextForDebug(buffRecei, Datenlaenge) + vbCrLf, True)
    242. End If
    243. Huawei_Modbus_Transmissionflag += 1
    244. Dim DatensatzLaenge As Integer = BO_BitConverter_ToUInt32(buffRecei, 11)
    245. Dim FrameAnzahl As Integer = CInt(Math.Ceiling(DatensatzLaenge / 246))
    246. DebugAusgabe(vbCrLf + "Lenght of file: " + DatensatzLaenge.ToString + " No. of frames: " + FrameAnzahl.ToString + vbCrLf, True)
    247. Hauptform.ProgressBar1.Maximum = FrameAnzahl
    248. For i As Integer = 1 To FrameAnzahl
    249. Hauptform.ProgressBar1.Value = i
    250. Dim frameC As Byte() = New Byte(12) {}
    251. Dim buffReceiC As Byte() = New Byte(258) {} ' Received data.
    252. frameC(0) = CByte(Huawei_Modbus_Transmissionflag / 256)
    253. frameC(1) = CByte(Huawei_Modbus_Transmissionflag)
    254. frameC(2) = 0 : frameC(3) = 0 'immer gleich
    255. frameC(4) = 0 'Länge in 2 Bytes
    256. frameC(5) = 7 'Länge in 2 Bytes
    257. frameC(6) = 3 'Modbus-ID des Wechselrichters
    258. frameC(7) = CByte(65) 'Huawei eigener Function Code 0x41
    259. frameC(8) = CByte(6) 'Subfunktionscode für "Request Frame Uploading Data" 0x06
    260. frameC(9) = 3 'Data lenght der nachfolgenden Infos
    261. frameC(10) = Filetype 'File Type 68 0x44 (4.2 obtaining real-time data)
    262. frameC(11) = 0
    263. frameC(12) = CByte((i - 1))
    264. DebugAusgabe(vbCrLf + Now().ToString("HH.mm.ss") + " SEND (" + i.ToString + "): " + BytesToTextForDebug(frameC), True)
    265. If Huawei_Modbus_Socket.Connected = False Then Huawei_Modbus_Connect()
    266. Huawei_Modbus_Socket.Send(frameC, frameC.Length, SocketFlags.None) ' Send Data
    267. Try
    268. Using nsC As New NetworkStream(Huawei_Modbus_Socket)
    269. If nsC.CanRead Then Dim unused = Huawei_Modbus_Socket.Receive(buffReceiC, buffReceiC.Length, SocketFlags.None)
    270. End Using
    271. Catch ex As Exception
    272. DebugAusgabe(vbCrLf + ex.Message, True)
    273. Huawei_Modbus_AbfrageFehlgeschlagen = True
    274. Return Nothing
    275. End Try
    276. If CInt(buffReceiC(7)) = 193 Or CInt(buffReceiC(7)) = 194 Then
    277. MsgBox("Fehler: " + buffReceiC(7).ToString + " Fehlercode: " + CInt(buffReceiC(8)).ToString)
    278. DebugAusgabe(vbCrLf + "RECEIVE: " + BytesToTextForDebug(buffReceiC), True)
    279. Huawei_Modbus_AbfrageFehlgeschlagen = True
    280. Return Nothing
    281. Else
    282. 'alles ok - An stelle 9 steht die länge der nachfolgenden Informationen
    283. DebugAusgabe(vbCrLf + Now().ToString("HH.mm.ss") + " RECEIVE (" + i.ToString + "): " + BytesToTextForDebug(buffReceiC), True)
    284. End If
    285. GesamtByteArray.Concat(buffReceiC)
    286. Huawei_Modbus_Transmissionflag += 1
    287. Next i
    288. '######### Schritt 3 "Completing the Data Upload" ##########
    289. Dim buffReceiA As Byte() = New Byte(256) {} ' Received data.
    290. Dim frameA As Byte() = New Byte(10) {}
    291. frameA(0) = 0 ' CByte(Transmissionflag / 256)
    292. frameA(1) = 0 'CByte(Transmissionflag)
    293. frameA(2) = 0 : frameA(3) = 0 'immer gleich
    294. frameA(4) = 0 'Länge in 2 Bytes
    295. frameA(5) = 5 'Länge in 2 Bytes
    296. frameA(6) = 3 'Modbus-ID des Wechselrichters
    297. frameA(7) = CByte(65) 'Huawei eigener Function Code
    298. frameA(8) = CByte(12) 'Subfunktionscode für "End the Upload"
    299. frameA(9) = 1 'Data lenght der nachfolgenden Infos
    300. frameA(10) = Filetype
    301. DebugAusgabe(vbCrLf + "SEND: " + BytesToTextForDebug(frameA), True)
    302. Huawei_Modbus_Socket.Send(frameA, frameA.Length, SocketFlags.None) ' Send Data
    303. Try
    304. Using nsA As New NetworkStream(Huawei_Modbus_Socket)
    305. If nsA.CanRead Then Dim unused = Huawei_Modbus_Socket.Receive(buffReceiA, buffReceiA.Length, SocketFlags.None)
    306. End Using
    307. Catch ex As Exception
    308. DebugAusgabe(vbCrLf + ex.Message, True)
    309. Huawei_Modbus_AbfrageFehlgeschlagen = True
    310. Return Nothing
    311. End Try
    312. If CInt(buffReceiA(7)) = 193 Or CInt(buffReceiA(7)) = 194 Then
    313. MsgBox("Fehler: " + buffReceiA(7).ToString + " Fehlercode: " + CInt(buffReceiA(8)).ToString)
    314. DebugAusgabe(vbCrLf + "RECEIVE: " + BytesToTextForDebug(buffReceiA), True)
    315. Huawei_Modbus_AbfrageFehlgeschlagen = True
    316. Return Nothing
    317. Else
    318. 'alles ok - An stelle 9 steht die länge der nachfolgenden Informationen
    319. Datenlaenge = CInt(buffReceiA(9)) + 9
    320. DebugAusgabe(vbCrLf + "RECEIVE: " + BytesToTextForDebug(buffReceiA, Datenlaenge), True)
    321. End If
    322. Huawei_Modbus_Transmissionflag += 1
    323. Return GesamtByteArray
    324. End Function
    325. ''' <summary>
    326. ''' Liest ein einzelnes Uint16 Register aus
    327. ''' </summary>
    328. ''' <param name="ModbusID">Modbus-ID des Wechselrichters</param>
    329. ''' <param name="Registernummer">Registernummer die ausgelesen werden soll</param>
    330. ''' <returns>Integer-Wert</returns>
    331. Public Function MB_RequestU16(ModbusID As Integer, Registernummer As Integer) As Integer
    332. If Huawei_Modbus_Socket.Connected = False Then Huawei_Modbus_Connect()
    333. If Huawei_Modbus_Socket.Connected = False Then Return 0
    334. Try
    335. Dim frame As Byte() = New Byte(11) {}
    336. frame(0) = 98 : frame(1) = 91 : frame(2) = 0 : frame(3) = 0 : frame(4) = 0 : frame(5) = 6 'Header + 6 Bytes Länge
    337. frame(6) = CByte(ModbusID) 'Modbus ID
    338. frame(7) = 3
    339. Dim WertByte() As Byte = ConvertIntToByteArray(Registernummer)
    340. frame(8) = WertByte(1)
    341. frame(9) = WertByte(0)
    342. frame(10) = 0
    343. frame(11) = 1 '1 Register auslesen
    344. DebugAusgabe(vbCrLf + "SEND: " + BytesToTextForDebug(frame), True)
    345. Huawei_Modbus_Socket.Send(frame, frame.Length, SocketFlags.None) ' Send Data
    346. Dim buffRecei As Byte() = New Byte(10) {} ' Received data
    347. Using ns As New NetworkStream(Huawei_Modbus_Socket)
    348. If ns.CanRead Then Dim unused = Huawei_Modbus_Socket.Receive(buffRecei, buffRecei.Length, SocketFlags.None)
    349. End Using
    350. DebugAusgabe(vbCrLf + BytesToTextForDebug(buffRecei), True)
    351. Dim Wert As Integer = buffRecei(9) * 256 + buffRecei(10)
    352. Return Wert
    353. Catch ex As Exception
    354. MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
    355. Return 0
    356. End Try
    357. End Function
    358. End Module
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at