API Version 8

Einklappen
X
 
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge
  • Gast

    API Version 8

    Hallo zusammen

    Ich möchte ein bisschen mit der API von Loxone herumspielen, schaffe es aber nicht mich anzumelden.
    Ich benutzte POSTMAN als Client zum Testen. Ich gehe wie folgt vor:
    - http://{{loxone_server}}:{{loxone_port}}/jdev/sys/getkey => erhalte einen Key"value": "4639393231433643413837453945353742433336313443393 7333342423239434331333539344641",
    - Danach versuche ich über die Seite https://caligatio.github.io/jsSHA/ mithilfe dieses keys einen hash für admin:admin zu generieren (Input Type Text, Key Type Hex, Output Type Hex, SHA-1
    - danach gebe ich den Key über http://{{loxone_server}}:{{loxone_port}}/authenticate/C759EAF09E4638954F63ACE0CE1B53B40F62CCB7 ein

    Ich bekomme aber immer die Meldung
    <html>
    <head>
    <title>error</title>
    </head>
    <body>
    <errorcode>401</errorcode>
    <errordetail>Unauthorized</errordetail>
    </body>
    </html>

    Kann mir hier jemand helfen.
  • Gast

    #2
    Ich brauche jetzt die Webservice schnittstelle, geht einfach für meinen Gebrauch.
    Mit den Loxone Webservices kann man mit einfachen http-Befehlen Informationen abrufen, Einstellungen vornehmen und schalten.


    Gibt es eigentlich eine Möglichkeit den Miniserver mit https zu nutzten anstelle von http?

    Kommentar

    • maxw
      Lox Guru
      • 26.08.2015
      • 1351

      #3
      Nein, leider nicht unterstützt.

      Kommentar

      • Aleq
        Smart Home'r
        • 04.05.2016
        • 52

        #4
        Maybe this helps - this is a snippet of a my Java (Android) code which authenticates @ loxone via WebSocket (first version, it may be far from perfect, nevertheless useful for start):

        Code:
            final String url = "ws://" + address + "/ws/rfc6455";
            WebSocket ws = new WebSocketFactory()
                    .setConnectionTimeout(TIMEOUT)
                    .createSocket(url)
                    .addListener(new WebSocketAdapter() {
                        // A text message arrived from the server.
                        public void onTextMessage(WebSocket websocket, String message) {
                            try {
                                String reply = LoxoneComm.getInstance().received(websocket, message);
                                if (reply != null) {
                                    websocket.sendText(reply);
                                } else {
                                    websocket.disconnect();
                                }
                            } catch (LoxoneAuthorizationException e) {
                                invalidCredentials = true;
                                websocket.disconnect();
                            }
        
                        }
                    })
                    .addExtension(WebSocketExtension.PERMESSAGE_DEFLATE)
                    .connect();
            ws.sendText("jdev/sys/getkey");
        and


        Code:
            public String received(WebSocket websocket, String input) throws LoxoneAuthorizationException {
                String reply = null;
                try {
                    JSONObject jsonObject = new JSONObject(input);
                    JSONObject jsonLL = jsonObject.getJSONObject("LL");
                    String control = (jsonLL.has("control") ? jsonLL.getString("control") : "");
                    String value = (jsonLL.has("value") ? jsonLL.getString("value") : "");
                    final int code = jsonLL.getInt("Code");
                    switch (code) {
                        case 200:
                            // OK
                            reply = processControl(control, value, jsonLL);
        
                        case 400:
                            // Not authorized
                            throw new LoxoneAuthorizationException(code);
        
                        case 401:
                            // Invalid credentials
                            Log.w("LoxoneComm", "Invalid username or password");
        
                        case 420:
                            // Authorization Time-out
        
                        case 4003:
                            // Access Denied due to too many failed attempts
                    }
                    Log.d("LoxoneComm", jsonObject.getJSONObject("LL").toString(4));
                } catch (JSONException e) {
                    Log.w("LoxoneComm", "Invalid input: ''" + input + "''", e);
                }
                return reply;
            }
        
            @Nullable
            private String processControl(String control, String value, JSONObject jsonLLObject) {
                Log.d("LoxoneComm", "Processing CONTROL = " + control + "; VALUE = " + value);
                if (control.equals("jdev/sys/getkey")) {
                    currentKey = value;
                    Log.d("LoxoneComm", "We have a key = " + currentKey);
        
                    return "authenticate/" + calculateHash();
        
                } else {
                    return null;
                }
            }
        
            private String calculateHash() {
                String result = null;
                try {
                    SecretKeySpec keySpec = new SecretKeySpec(hexStringToByteArray(currentKey), "HmacSHA1");
                    Mac mac = Mac.getInstance("HmacSHA1");
                    mac.init(keySpec);
                    byte[] bytes = mac.doFinal((username + ":" + password).getBytes("UTF-8"));
                    result = byteArrayToHexString(bytes);
                } catch (UnsupportedEncodingException e) {
                    Log.e("LOX", "SHA1", e);
                } catch (NoSuchAlgorithmException e) {
                    Log.e("LOX", "SHA1", e);
                } catch (InvalidKeyException e) {
                    Log.e("LOX", "SHA1", e);
                }
                return result;
            }
        
            private static byte[] hexStringToByteArray(String input) {
                int len = input.length();
                byte[] result = new byte[len / 2];
        
                for (int i = 0; i < len; i += 2) {
                    result[i / 2] = (byte) ((Character.digit(input.charAt(i), 16) << 4) + Character.digit(input.charAt(i + 1), 16));
                }
                return result;
            }
        
            @NonNull
            private static String byteArrayToHexString(byte[] bytes)
            {
                StringBuffer buffer = new StringBuffer();
                for (int i = 0; i < bytes.length; i++)
                {
                    if (((int) bytes[i] & 0xff) < 0x10) {
                        buffer.append("0");
                    }
                    buffer.append(Long.toString((int) bytes[i] & 0xff, 16));
                }
                return buffer.toString();
            }
        Good luck and sorry for English post in German part, it would be disaster if I have written this in Deutsch

        Kommentar

        • Prof.Mobilux
          Supermoderator
          • 25.08.2015
          • 4590

          #5
          Useful example code - thanks!

          Gast: Kennst Du den Link? http://www.loxone.com/dede/service/d...erung/api.html
          🇺🇦 Hilfe für die Menschen der Ukraine: https://www.loxforum.com/forum/proje...Cr-die-ukraine


          LoxBerry - Beyond the Limits

          Kommentar

          • Gast

            #6
            Gast Ich würde/habe es auch so versucht. Bisher auch ohne Erfolg. Bekomme auch immer den 401 als Antwort.

            Kommentar

            • Aleq
              Smart Home'r
              • 04.05.2016
              • 52

              #7
              Orson, are you trying it as a human or programatically? At least for WebSocket, there is a time limit of few (I believe 2?) seconds, until when you need to respond with your hash, otherwise you get denied automatically. I don't know if this applies to you, though. Also check the way how you format the resulting hash - see my source code, I believe it will be similar.

              Kommentar


              • Gast
                Gast kommentierte
                Kommentar bearbeiten
                As a human. My Goal was, to use the string with iftttt. There's nothing about a time limit in documentation-pdf. How long can i use a valid string, is there an limitation too ?

                thx
                Zuletzt geändert von Gast; 15.11.2016, 08:36.
            • Aleq
              Smart Home'r
              • 04.05.2016
              • 52

              #8
              It is described in http://www.loxone.com/tl_files/loxon...miniserver.pdf but it really seems to be relevant for WebSockets only. Also I just noticed you would get 420 and not 401 in case of a timeout.

              But I wonder (I may be very well wrong, I'm also new to this area) aren't you mixing two aproaches? WebSocket API is a stateful aproach, requires two-sided communication - [j]dev/sys/getkey request and consecutive authenticate/{hash} response. The connection stays open after this and you are authenticated for all the actions. I think issuing jdev/sys/getkey via HTTP GET is not correct. even though miniserver responds to that. It may be a glitch. What you want and will work is WebServices RESTFul API: http://www.loxone.com/enen/service/d...bservices.html I think.

              Try in your browser:
              http://admin:admin@<miniserverIP>/jdev/sps/state
              and then enumerate the inputs
              .../jdev/sps/enumin
              pick one, temperature sensor in my case and query the value:
              /jdev/sps/io/prádelna%20(Hlavní%20rozváděč)%20Senzor%20teploty/astate
              (%20 gets encoded instead of spaces automatically by browser). I get:
              Code:
               
               {"LL": { "control": "dev/sps/io/prádelna (Hlavní rozváděč) Senzor teploty/astate", "value": "19.3°", "Code": "200"}}
              To control the lights, you may need to evaluate the structure JSON obtained from .../data/LoxAPP3.json, but that's are where I'm lost a bit too. I only found it it's possible to manipulate the light by taking the ID/name of a subcontrol in a LightController. This is what I found in the LoxAPP3.json:
              Code:
                      "0eb22d79-02c6-710c-fffffae984b19f22":{  
                          "name":"Ovládání osvětlení",
                          "type":"LightController",
                          "uuidAction":"0eb22d79-02c6-710c-fffffae984b19f22",
                          "room":"0d745096-0051-03ed-fffffae984b19f22",
                          "cat":"0d745096-0013-030d-fffffae984b19f22",
                          "defaultRating":0,
                          "isFavorite":false,
                          "isSecured":false,
                          "details":{  
                              "movementScene":1
                          },
                          "states":{  
                              "activeScene":"0eb22d79-02c6-7109-ffffa6ea96de1476",
                              "sceneList":"0eb22d79-02c6-70cb-ffffa6ea96de1476"
                          },
                          "subControls":{  
                              "0eb22d79-02c6-710c-fffffae984b19f22/AI1":{  
                                  "name":"Světlo prádelna",
                                  "type":"Switch",
                                  "uuidAction":"0eb22d79-02c6-710c-fffffae984b19f22/AI1",
                                  "defaultRating":0,
                                  "isFavorite":false,
                                  "isSecured":false,
                                  "states":{  
                                      "active":"0eb22d79-02c6-70fd-ffffa6ea96de1476"
                                  }
                              }
                          }
                      },
                      "0d7afacb-024f-1d69-fffffae984b19f22":{  
                          "name":"Světlo prádelna O",
                          "type":"InfoOnlyDigital",
                          "uuidAction":"0d7afacb-024f-1d69-fffffae984b19f22",
                          "room":"0d745096-0051-03ed-fffffae984b19f22",
                          "cat":"0d745096-0013-030d-fffffae984b19f22",
                          "defaultRating":10,
                          "isFavorite":true,
                          "isSecured":false,
                          "details":{  
                              "text":{  
                                  "off":"Off",
                                  "on":"On"
                              },
                              "color":{  
                                  "off":"#BE1624",
                                  "on":"#73BA1B"
                              }
                          },
                          "states":{  
                              "active":"0d7afacb-024f-1d69-fffffae984b19f22"
                          }
                      },
              and from there, I found out that it can be turned on/off:
              If the command is accepted, you get something like this (Code 200 is important):
              Code:
               
               {"LL": { "control": "dev/sps/io/0eb22d79-02c6-710c-fffffae984b19f22/AI1/on", "value": "1", "Code": "200"}}
              To get the light, that's a different story. I haven't figured out any better way than to take the Miniserver/Extension Digital output itself (I am not able to determine programatically from the structure file the associated output). In my case, as per following screenshot:
              Loxone Config


              it is:
              Code:
                      "0d7afacb-024f-1d69-fffffae984b19f22":{  
                          "name":"Světlo prádelna O",
              which can be requested by

              returning value "value" carries the state:
              Code:
               
               {"LL": { "control": "dev/sps/io/0d7afacb-024f-1d69-fffffae984b19f22/astate", "value": "0", "Code": "200"}}
              or
              Code:
               
               {"LL": { "control": "dev/sps/io/0d7afacb-024f-1d69-fffffae984b19f22/astate", "value": "1", "Code": "200"}}
              Hope this helps. And if there's anyone willing to share some more light to this, I'd be also glad to read his/her experience.

              Kommentar


              • Gast
                Gast kommentierte
                Kommentar bearbeiten
                Hi Aleq,

                thx for your explanation. The Documentation says that the miniserver cpu is to weak to support secured conversation (SSL), thats why they implemented the secured command with the salted hash. for my opinion a trustable way.

                -- from the docu

                Secured Commands
                We have the possibility to use a “visualization password” for Controls (set in Loxone Config),
                those passwords are added to the commands as described below:
                1. request the visualization password from the user
                2. request a Hashing-Key from the Miniserver (“jdev/sys/getkey”)
                3. hash the password (see Hashing)
                ​4. send “jdev/sps/ios/{hash}/{uuid}/{command}”
            • Aleq
              Smart Home'r
              • 04.05.2016
              • 52

              #9
              Oh, I see! You meant his part. You are absolutely right, I remember that part in the documentation. I just deliberately skipped that as I decided not to use the encryption for starters and get back to it later, when everything else is working.

              At least I have prepared a tool for you which uses the same hash mechanism I validated while using WebSockets to be working. You need java to run it: "java.exe -jar LoxoneAuth.jar <login>:<pass> <secret>".
              Executable JAR and source attached. Good luck and let us know if you get it solved.
              Angehängte Dateien

              Kommentar


              • Gast
                Gast kommentierte
                Kommentar bearbeiten
                Thx,

                i used on Onlinedecoder to create a salted hash, same result as with your tool. but the ms wants credentials or sends a 401 error.

                Thats my command

                http://<my external ms -ip>:12345/jdev/sps/ios/3fe1fefaf57f42fae7e3afbd374be450476eecfa/Eingang%20VI4/pulse

                I will ask loxone what the problem is.
            • Aleq
              Smart Home'r
              • 04.05.2016
              • 52

              #10
              Good luck. I've seen a statement somewhere in the Docu that they don't support API...

              Kommentar


              • Gast
                Gast kommentierte
                Kommentar bearbeiten
                I've read this. But no support means not does it shouldn't work. ;-)
            • Aleq
              Smart Home'r
              • 04.05.2016
              • 52

              #11
              Any news? Did you solve it?

              Kommentar


              • Aleq
                Aleq kommentierte
                Kommentar bearbeiten
                Only for about 2 seconds, but that's via WebSocket. Don't know if such strict limit applies to RESTful API as well. My personal guess would be not.
                It was impossible to test the WebSocket as a human via some kind of interactive WebSocket tool (chrome addon for instance) as before I managed to cut'n paste the key to the hash tools, I received the error already. I'm able to make it in time only programatically.

              • Gast
                Gast kommentierte
                Kommentar bearbeiten
                That's would i ask you. You did it programatically. Perhaps it would be possible to use a raspberry/loxberry as a proxy and execute a script/java-applets as an url, which can later use with ifttt.

              • Aleq
                Aleq kommentierte
                Kommentar bearbeiten
                Possibly, if the timing is really an issue here.
            • Christian Fenzl
              Lebende Foren Legende
              • 31.08.2015
              • 11200

              #12
              Hi,

              in the LightController, the API says that a sceneList is provided as a json list including the scene names:
              ● sceneList ○ Returns a JSON-Object in the following format
              ○ uuid -> the UUID of the LightControl
              ○ uuidIcon -> This is only used by the Status Control
              ○ text -> This is an array of Scenes separated by a “,”
              ■ "1="Szene1",2="Szene2",7="Szene7""
              In reality, it is another ID:
              Code:
              "states" : {
                              "activeScene" : "0e4fbd25-005c-945b-ffff862894cb65ca",
                              "sceneList" : "0e4fbd25-005c-9420-ffff862894cb65ca"
                          },
              Anybody an idea, how to query this sceneList id , or the scene list of the light controller id?

              Thanks and regards,
              Christian
              Hilfe für die Menschen der Ukraine: https://www.loxforum.com/forum/proje...Cr-die-ukraine

              Kommentar

              • Aleq
                Smart Home'r
                • 04.05.2016
                • 52

                #13
                Seems to be forgotten. Neither I have found anything. Sad.

                Kommentar

                Lädt...