XML-RPC Client

Hey @fishermans,

welche Version von homegear setzt du ein?
Die aktuelle Funktionsreferenz befindet sich hier: https://ref.homegear.eu/

so long,
p

Hallo @pmayer,

ich verwende die neuste Version 0.6. Aber auch hier (https://ref.homegear.eu/)
ist der erste Parameter kein String. Ich verstehe auch nicht, warum die Rückgabe immer von unterschiedlicher Größe ist, mal werden für ein device 16 items zurückgegeben mal 14 oder 13. Ich habe hier nur MAX! devices. Wie kann ich wissen, wo welches Feld in der Rückgabe steht, wenn die Anzahl der Felder nicht dem der Rückgabestruktur entspricht?

Viele Grüße

Also, ich nutze listDevices in einem Webinterface und da gibt es mir immer die gleiche Anzahl Geräten zurück - zugegeben über die PHP-Schnittstelle, sollten aber die gleichen Funktionsaufrufe sein.

pi@homegearpi:~$ sudo homegear -e rc 'print_r($hg->listDevices(false, ["FAMILY", "ID", "ADDRESS", "TYPE", "FIRMWARE"]));'

Die Rückgabe ist bei mir auch immer gleich, aber die Struktur entspricht nicht der in der Dokumentation. Die Parent-Devices sint immer korrekt aber die Channel-devices variiren in der Länge der Struktur.

Viele Grüße

Gib mal ein Beispiel…

So habe einmal nur eine Testausgabe gemacht, hier werden 41 Devices (parents plus channels)
gefunden, dann nur die Anzahl der Einträge pro Device:

Starting call: getVersion()
getVersion: Homegear 0.6.17-902
Version: Homegear 0.6.17-902
Starting call: logLevel()
logLevel: Loglevel is set to 5
Loglevel: 5
Starting call: listDevices()
Array length: 41
Count: 16
Count: 13
Count: 14
Count: 14
Count: 16
Count: 13
Count: 15
Count: 14
Count: 14
Count: 16
Count: 13
Count: 15
Count: 14
Count: 14
Count: 16
Count: 13
Count: 15
Count: 14
Count: 14
Count: 16
Count: 13
Count: 15
Count: 14
Count: 14
Count: 16
Count: 13
Count: 15
Count: 14
Count: 14
Count: 16
Count: 13
Count: 13
Count: 13
Count: 16
Count: 13
Count: 13
Count: 13
Count: 16
Count: 13
Count: 13
Count: 13

Hast du ein Beispiel, wie du die RPC-Methode in deinem Programm aufrufst?

Ist allerdings mein Quälcode, es wird die Methode aufgerufen und die Rückgabe protokolliert:

Function TForm1.listDevices(channels : Boolean; fields : TStrings; familyid : Integer) : Integer;
Var
  hgDevice   : THGDevice;
  RpcResult  : IRpcResult;
  Flags, Rx_Mode,
  i, j, k, l : Integer;
  s : String;
Begin
  FRpcFunction.ObjectMethod := 'listDevices';

  FRpcFunction.AddItem(channels);
  {
  If fields <> NIL Then Begin
    For i := 0 To fields.Count-1 Do
      FRpcFunction.AddItem(fields[i]);
  End Else
    FRpcFunction.AddItem('');
  FRpcFunction.AddItem(familyid);
  }
  AddMessage('Starting call: listDevices()');

  try
    RpcResult := FRpcCaller.Execute(FRpcFunction);
    if RpcResult.IsError then
      AddMessage(Format('Error: (%d) %s',
          [RpcResult.ErrorCode, RpcResult.ErrorMsg]))
    else Begin
      If RpcResult.DataType = dtArray Then Begin
        AddMessage('Array length: '+IntToStr(RpcResult.AsArray.Count));

        For i := 0 To RpcResult.AsArray.Count-1 Do Begin
          {
          if Pos(':', RpcResult.AsArray.Items[i].AsStruct.Items[4].AsString) = 0 Then  // Adresse
            hgDevice := hgd_Parent
          else
            hgDevice := hgd_Channel;
          }
          // AddMessage('-----------------------------------------------------------------');
          AddMessage('Count: '+InttoStr(RpcResult.AsArray.Items[i].AsStruct.Count));
          //
          //  Parent Device
          //
          If hgDevice = hgd_Parent Then Begin
            If RpcResult.AsArray.Items[i].DataType = dtStruct Then Begin // Array 0 = Struct lenth = 11
              For j := 0 To RpcResult.AsArray.Items[i].AsStruct.Count-1 Do Begin
                AddMessage('DataType: '+GetDataTypeStr(RpcResult.AsArray.Items[i].AsStruct.Items[j].DataType));
                // if j = 0 then
                //  AddMessage('Address: '+RpcResult.AsArray.Items[i].AsStruct.Items[j].AsString);
                (*
                Case j OF
                  // FAMILY 	DeviceFamily 	The family the device belongs to (e. g. HomeMatic BidCoS)
                  00 : Begin
                         AddMessage('Family: '+IntToStr(RpcResult.AsArray.Items[i].AsStruct.Items[j].AsInteger));
                       End;
                  // TYPE 	String 	        Type of the device
                  01 : Begin
                         AddMessage('Type: '+RpcResult.AsArray.Items[i].AsStruct.Items[j].AsString);
                       End;
                  // TYPE_ID 	Integer 	The type ID of the device
                  02 : Begin
                         AddMessage('Type_Id: '+RpcResult.AsArray.Items[i].AsStruct.Items[j].AsString);
                       End;
                  // ID 	Integer 	The id of the device(e. g. 131)
                  03 : Begin
                         AddMessage('ID: '+IntToStr(RpcResult.AsArray.Items[i].AsStruct.Items[j].AsInteger));
                       End;
                  // ADDRESS 	String 	        Serialnumber of the device (e. g. JEQ0123456)
                  04 : Begin
                         AddMessage('Adress: '+RpcResult.AsArray.Items[i].AsStruct.Items[j].AsString);
                       End;
                  // CHILDREN 	Array<String> 	For compatibility. Addresses of the channels (e. g. JEQ0123456:1)
                  05 : Begin
                         For k := 0 To RpcResult.AsArray.Items[i].AsStruct.Items[j].AsStruct.Count-1 Do Begin
                           AddMessage('Children: '+RpcResult.AsArray.Items[i].AsStruct.Items[j].AsStruct.Items[k].AsString);
                         End;
                       End;
                  // CHANNELS 	Array<Integer> 	Indexes of all available channels
                  06 : Begin
                         For k := 0 To RpcResult.AsArray.Items[i].AsStruct.Items[j].AsStruct.Count-1 Do Begin
                           AddMessage('Channel: '+IntToStr(RpcResult.AsArray.Items[i].AsStruct.Items[j].AsStruct.Items[k].AsInteger));
                         End;
                       end;
                  // PARENT 	String 	        Empty for parent device
                  07 : Begin
                         AddMessage('Patent: '+RpcResult.AsArray.Items[i].AsStruct.Items[j].AsString);
                       End;
                  // PARAMSETS 	Array<String> 	Names of the available parameter sets (MASTER, VALUES and/or LINK)
                  08 : Begin
                         For k := 0 To RpcResult.AsArray.Items[i].AsStruct.Items[j].AsStruct.Count-1 Do Begin
                           AddMessage('Paramsets: '+RpcResult.AsArray.Items[i].AsStruct.Items[j].AsStruct.Items[k].AsString);
                         End;
                       End;
                  // FIRMWARE 	String 	Optional. Firmware version (e. g. "2.1"). "?" for teams.
                  09 : Begin
                         AddMessage('Firmware: '+RpcResult.AsArray.Items[i].AsStruct.Items[j].AsString);
                       End;
                  // AVAILABLE_FIRMWARE 	String 	Optional. Firmware version available for update (e. g. "2.2"). Only set when a newer firmware version is available.
                  10 : Begin
                         AddMessage('Aviable Firmware: '+RpcResult.AsArray.Items[i].AsStruct.Items[j].AsString);
                       End;
                  // VERSION 	Integer 	Version of the XML file
                  11 : Begin
                         AddMessage('Version: '+IntToStr(RpcResult.AsArray.Items[i].AsStruct.Items[j].AsInteger));
                       End;
                  // FLAGS 	Flags 	        or-linked flags for the GUI
                  12 : Begin
                         // 1 	Visible: Device should be visible to the user
                         // 2 	Internal: Device is only used internally
                         // 8 	Dontdelete: Device can't (or shouldn't) be deleted
                         // ThgFlags  = (hgf_Visible=1,hgf_Internal=2,hgf_Dontdelete=8);

                         Flags := RpcResult.AsArray.Items[i].AsStruct.Items[j].AsInteger;
                         s := '';
                         If GetBit(Flags, chgf_Visible-1) Then
                           s := '-Visible ';
                         If GetBit(Flags, chgf_Internal-1) Then
                           s := s + '-Internal ';
                         If GetBit(Flags, chgf_Dontdelete-1) Then
                           s := s + '-Dontdelete ';
                         AddMessage('Flags ('+IntToStr(Flags)+'): '+s);
                       End;
                  // RF_ADDRESS Integer 	For compatability. Physical address of the device.
                  13 : Begin
                         AddMessage('RF_Adress: '+IntToStr(RpcResult.AsArray.Items[i].AsStruct.Items[j].AsInteger));
                       End;
                  // PHYSICAL_ADDRESS Integer   Physical address of the device
                  14 : Begin
                         AddMessage('Physical Adress: '+IntToStr(RpcResult.AsArray.Items[i].AsStruct.Items[j].AsInteger));
                       End;
                  // RX_MODE 	RXMode 	        The supported RX modes of the device.
                  15 : Begin
                         Rx_Mode := RpcResult.AsArray.Items[i].AsStruct.Items[j].AsInteger;
                         s := '';
                         If GetBit(Flags, chgr_RX_ALWAYS-1) Then
                           s := s + '-RX_ALWAYS ';
                         If GetBit(Flags, chgr_RX_BURST-1) Then
                           s := s + '-RX_BURST ';
                         If GetBit(Flags, chgr_RX_CONFIG-1) Then
                           s := s + '-RX_CONFIG ';
                         If GetBit(Flags, chgr_RX_WAKEUP-1) Then
                           s := s + '-RX_WAKEUP ';
                         If GetBit(Flags, chgr_RX_LAZY_CONFIG-1) Then
                           s := s + '-RX_LAZY_CONFIG ';
                         AddMessage('RX-Mode: ('+IntToStr(Rx_Mode)+'): '+s);
                       End;
                  // INTERFACE 	String 	        Only for compatibility. Serial number of the central.
                  16 : Begin
                         AddMessage('Interface: '+RpcResult.AsArray.Items[i].AsStruct.Items[j].AsString);
                       End;
                end;
                *)
              end;  // For i := ...
            end;  //
          end;

          //
          //  Channel Device
          //
          If hgDevice = hgd_Channel Then Begin
            For j := 0 To RpcResult.AsArray.Items[i].AsStruct.Count-1 Do Begin
              Case j OF
                // FAMILY 	DeviceFamily 	The family the device belongs to (e. g. HomeMatic BidCoS)
                00 : Begin
                       // RpcResult.AsArray.Items[i].AsStruct.Items[j].AsInteger;
                     End;
                // ID 	        Integer 	The id of the device(e. g. 131)
                01 : Begin
                     End;
                // CHANNELS 	Array<Integer> 	Indexes of all available channels
                02 : Begin
                     End;
                // ADDRESS 	String 	        Serialnumber of the device (e. g. JEQ0123456)
                03 : Begin
                     End;
                // PARENT 	String 	        Empty for parent device
                04 : Begin
                     End;
                // PARENT_TYPE 	String 	Type of the parent device
                05 : Begin
                     End;
                // INDEX 	Integer 	Channel number
                06 : Begin
                     End;
                // AES_ACTIVE 	Integer 	"1" when AES handshakes are enabled for the channel otherwise "0". This variable is of type Integer for compatibility.
                07 : Begin
                     End;
                // PARAMSETS 	Array<String> 	Names of the available parameter sets (MASTER, VALUES and/or LINK)
                08 : Begin
                     End;
                // VERSION 	Integer 	Version of the XML file
                09 : Begin
                     End;
                // FLAGS 	Flags 	        or-linked flags for the GUI
                10 : Begin
                     End;
                // LINK_SOURCE_ROLES 	String 	        Source roles defined for this channel in the XML file seperated by space
                11 : Begin
                     End;
                // LINK_TARGET_ROLES 	String 	        Target roles defined for this channel in the XML file seperated by space
                12 : Begin
                     End;
                // DIRECTION 	        Direction 	Direction of the channel (sender or receiver)
                13 : Begin
                     End;
                // GROUP 	        String 	        Optional. Only when device has grouped channels. Serial number and index of the grouped channel (e. g. JEQ0123456:3)
                14 : Begin
                     End;
                // TEAM 	        String 	        Optional. Only when channel supports teams. Serial number of the team (e. g. *JEQ0123456 - note the "*")
                15 : Begin
                     End;
                // TEAM_TAG 	        String 	        Optional. Only when channel supports teams or for teams. Type of the team ("team_tag" attribute of the team's XML file).
                16 : Begin
                     End;
                // TEAM_CHANNELS 	Array<String> 	Optional. Only for teams. Array of peers (serialnumber and channel) paired to this team (e. g. JEQ0234567:1)               end;
                17 : Begin
                     End;
              end;
            end;
          end;
        end;
      end;
    end;
  except
    on E: Exception do
      AddMessage(StringReplace(E.Message, #13#10, ': ', [rfReplaceAll]));
  end;
end;

Sorry, da blicke ich nicht durch.

Bau doch mal einen einfachen Aufruf der Methode listDevices nach.

Ich denke nicht, dass die Funktion in einer Schleife aufgerufen werden sollte. Sie gibt eine Liste der verfügbaren Geräte zurück. Um Info’s für ein einzelnes Gerät zu bekommen wird getDeviceInfo genutzt: https://ref.homegear.eu/rpc.html#getDeviceInfo

Das mit der Schleife sollte eigentlich korrekt sein, die Funktion liefert ja ein Array zurück
Array listDevices()
Das durchlaufe ich und lese die Daten ein. Die entspricht aber nicht der in der Dokumentation.
Mein Ziel ist, die Geräte (MAX!) zu program.ieren.

Ich kann aber kein VisualBasic (glaube, dass du das da programmierst) und kann nicht sehen welche Methode in der Schleife ausgeführt wird.

Also wäre doch der logische Schritt erst mal listDevices “alleine” auszuführen und zu debuggen ob denn die Rückgabe dem Erwarteten entspricht.

Das ist Pascal, ich rufe hier die Methode auf:
FRpcFunction.ObjectMethod := ‘listDevices’;
If RpcResult.DataType = dtArray Then Begin…
Falls nun ein Array zurückgegeben wird werte ich die Daten aus.
In der Dokumentation steht

Name Type Description
FAMILY DeviceFamily The family the device belongs to (e. g. HomeMatic BidCoS)
TYPE String Type of the device

d.h. der erste Eintrag sollte ein Integer Wert sein, da ich nur Max! Devices habe also eine 4.
Die finde ich aber an einer späteren Position. An erster Position wird die Adresse zurückgegeben die aber an Position 4 auftauchen sollte…
???

Gibst du eine Liste der gewünschten Parameter mit?

Nein, das sollte ich vielleicht noch versuchen, ansonsten werte ich die einzelnen Geräte händisch
aus, das ist zwar nicht besonderst schön und funktioniert dann nur mit meinen vorhandenene Geräten, aber sollte klappen. Dann kann leider niemand etwas damit anfangen ausser mir. Inspiriert hat mich dieser Beitrag Homegear Script Editor. Ich würde gerne die devices einlesen und per rpc programmieren.

1 Like

So, wenn ich eine Liste der Parameter angebe, bekomme ich die gewünschten Informationen, allerdings nicht in der Reihnfolge meiner Parameterliste sondern in alphabetischer Reihnfolge:

family: 4
firmware: 1.4
id: 2
type: BC-RT-TRX-CyG
--------------------------------------------
adress: IEQ0184984
family: 4
firmware: 1.4
id: 3
type: BC-RT-TRX-CyG
--------------------------------------------
adress: IEQ0108293
family: 4
firmware: 1.4
id: 4
type: BC-RT-TRX-CyG
--------------------------------------------
adress: IEQ0198096
family: 4
firmware: 1.4
id: 5
type: BC-RT-TRX-CyG
--------------------------------------------
adress: IEQ0196591
family: 4
firmware: 1.4
id: 6
type: BC-RT-TRX-CyG
--------------------------------------------
adress: IEQ0052570
family: 4
firmware: 1.2
id: 7
type: BC-PB-2-WM
--------------------------------------------
adress: IEQ0144688
family: 4
firmware: 1.2
id: 8
type: BC-PB-2-WM
--------------------------------------------
adress: IEQ0144585
family: 4
firmware: 1.2
id: 9
type: BC-PB-2-WM

So komme ich zumindest weiter

Viele Grüße

Das sollte sich @sathya mal angucken…

PS: Nutz doch bitte die Formatierungswerkzeuge des Forums :slight_smile:

@pmayer Das werde ich :slight_smile:

Hallo @fishermans,

die Reihenfolge der Strukturelemente ist zwar konstant aber sie darf nach XML-RPC-Spezifikation variieren. Du kannst also nicht davon ausgehen, dass die Elemente immer an der gleichen Stelle zu finden sind. Die Unterschiede in der Elementezahl kommen zustande, da einige Elemente optional sind. Greif daher am besten über den Namen auf die Elemente zu. Bei optionalen Elementen ist vorher zu prüfen, ob der Schlüssel existiert. Beantwortet das deine Frage?

Viele Grüße

Sathya

Hallo @sathya,

ja das hat meine Frage beantwortet. Das eigentliche Problem lag in dem Verständnis der Komponente, die ich verwendet habe um die Daten einzulesen. Da gibt es ein Feld “Name” was immer leer war, aber der Name steht in einem Feld mit der Bezeichnung “Key”. Nach dem ich das begriffen hatte ging es ganz leicht :-). Vielen Dank für dieses tolle Programm! Ich werde, wenn ich das Programm soweit fertig habe, das Ganze mal hier vorstellen incl. Quälcode, für die die es interesiert.

Viele Grüße

Elmar

1 Like

Sehr gerne ;-).