This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm that you accept these cookies being set.

Ondilo spa/pool monitor
#1
Hello,

Please, can anyone help with connecting a Ondilo spa monitor.

Authentication is to difficult for me Wink

Here the api info how to auth: https://interop.ondilo.com/docs/api/cust...entication
And here's the general api info: https://interop.ondilo.com/docs/api/customer/v1/

I have a app username and password but i see nothing in the doc how to get access to the api with that user&pwd
Reply
#2
Ok, i give it a try

my code: 
Code:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
local usr = "my@email.com" local pwd = "mypwd" local uri = "https%3A%2F%2Fyour.app.url%2Fauthorize" -- there's no url redirect, so how to handle this local state = "c7d37ee542c7'" -- random ---------------------------- change nothing after this line ------------------------------- local apiHost = "https://interop.ondilo.com" local apiUrl = apiHost .. "/api/customer/v1" local endpointToken = "/oauth2/token" local endpointAuth = "/oauth2/authorize" -- init if not init then   require('socket.http')   require('ltn12')   require('json')   socket.http.TIMEOUT = 5   init = true end function getAuth()   url = apiHost..endpointAuth..'?client_id=customer_api&response_type=code&redirect_uri='..uri..'&scope=api&state='..state   method = "POST"   local response_body = { }    local payload = '{"login":"'..usr..'","password":"'..pwd..'","locale":"nl","proceed":"Authorize"}'     local res, code, response_headers, status = socket.http.request   {     url = url,     method = method,     headers =     {       ["Accept"] = "application/json",       ["Accept-Charset"] = "utf-8",       ["Accept-Encoding"] = "gzip-deflate",       ["Content-Type"] = "application/json",       ["Content-Length"] = payload:len()     },     source = ltn12.source.string(payload),     sink = ltn12.sink.table(response_body)   }   log(res, code, response_headers, status)   log(response_body) end getAuth()

My return:

Code:
1234567891011121314151617181920212223242526272829303132
* arg: 1   * number: 1 * arg: 2   * number: 200 * arg: 3   * table:    ["server"]     * string: Apache/2.4.29 (Ubuntu)    ["content-type"]     * string: text/html;charset=UTF-8    ["connection"]     * string: close    ["access-control-allow-methods"]     * string: GET, POST, PUT, PATCH, DELETE, OPTIONS    ["access-control-allow-headers"]     * string: X-Requested-With, Content-Type, Accept, Origin, Authorization    ["cache-control"]     * string: no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0    ["pragma"]     * string: no-cache    ["content-length"]     * string: 4047    ["date"]     * string: Wed, 21 Oct 2020 17:45:44 GMT    ["vary"]     * string: Accept-Encoding    ["access-control-allow-origin"]     * string:    ["access-control-allow-credentials"]     * string: true * arg: 4   * string: HTTP/1.1 200 OK

but how to get the code that is normally send to the url given in the var uri (see above) or is my code wrong?

documentation is here: https://interop.ondilo.com/docs/api/cust...entication

if i do the same in a browser, my return url looks like:
https://your.app.url/authorize?code=6440...a88c&state=c7d37ee542c7
Reply
#3
What do you get in response body? You should also remove Accept-Encoding header otherwise body will be compressed with gzip instead of plain text.
Reply
#4
(22.10.2020, 06:30)admin Wrote: What do you get in response body? You should also remove Accept-Encoding header otherwise body will be compressed with gzip instead of plain text.

I see the plain website, i think the form is not filled and executed. But how to do this.
same source as: 
https://interop.ondilo.com/oauth2/author...d44ef532c5
Code:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
* table: [1]   * string: <!DOCTYPE html> <html>     <head>         <meta charset="utf-8"/>         <title>Ondilo authorization page</title>         <style>             * {                 margin: 10px 4px 10px 4px;             }             .box {                 width: 340px;                 margin: auto;                 border: 1px solid rgb(41, 165, 155);             }             .banner {                 margin: 0px;                 background-color: rgb(41, 165, 155);                 height: 50px;                 position: relative;             }             .ico {                 position: absolute;                 top: 3px;                 left: 4px;             }             .ondilo {                 position: absolute;                 top: -1px;                 right: 4px;             }             strong {                 margin: 0px;             }             label {                 margin-top: 8px;                 margin-bottom: 0px;                 display: block;                 font-size: 0.8em;                 color: gray;             }             input, select {                 font-size: 1.2em;             }             input[type=text], input[type=password], select {                 width: 312px;             }             input[type=submit] {                 width: 322px;                 display: block;                 margin-bottom: 25px;             }             .authorize {                 color: white;                 background-color: rgb(41, 165, 155);                 margin-bottom: 10px;                 margin-top: 25px;                 border-color: rgb(41, 165, 155);             }             p {                 text-align: center;                 margin-top: 25px;                 margin-bottom: 25px;             }             .warning p, .warning ul {                 margin: 0 0 0 0;                 line-height: 15px;             }         </style>     </head>     <body>         <div class="box">             <div class="banner">                 <img src="/images/ico.png" alt="ICO" title="ICO" class="ico"/ [2]   * string: >                 <img src="/images/ondilo.png" alt="Ondilo" title="Ondilo" class="ondilo"/>             </div>                         <form method="post">                 <p>Sign in to allow <strong>customer_api</strong> to connect to your <strong>Ondilo</strong> account and access the related data</p>                 <label for="login">Your email address</label><input type="text" name="login" ><br/>                 <label for="pasword">Your password</label><input type="password" name="password">                 <label for="locale">Your language</label><select id="locale" name="locale">                     <option value="en">English</option>                     <option value="fr">Français</option>                     <option value="es">Español</option>                     <option value="de">Deutsch</option>                     <option value="pt">Português</option>                     <option value="nl">Nederlands</option>                     <option value="it">Italiano</option>                     <option value="cs"eština</option>                     <option value="hu">Magyar</option>                     <option value="sv">Svenska</option>                     <option value="ro">Română</option>                 </select>                 <div class="warning">                     <p>                         We remind that ICO takes measures every hour.</br>                         In order to avoid excessive load of our servers, the requests to the Ondilo Customer API are limited to the following per user quotas :                         <ul>                             <li>5 requests per second</li>                             <li>30 requests per hour</li>                         </ul>                     </p>                                </div>                 <input type="submit" name="proceed" value="Authorize" class="authorize">                 <input type="submit" name="proceed" value="Cancel">             </form>         </div>     </body> </html>
Reply
#5
For auth you need to use standard POST, not JSON:
Code:
1234567891011121314151617
function encodepost(t)   local res = {}   local esc = require('socket.url').escape   for k, v in pairs(t) do     res[ #res + 1 ] = esc(k) .. '=' .. esc(v)   end   return table.concat(res, '&') end payload = encodepost({   login = usr,   password = pwd,   locale = "nl",   proceed = "Authorize", })

For this request Accept/Content-Type headers are not needed. Add redirect = false to the request table to catch the redirect URL instead of following it.
Reply
#6
(22.10.2020, 07:14)admin Wrote: For auth you need to use standard POST, not JSON:

For this request Accept/Content-Type headers are not needed. Add redirect = false to the request table to catch the redirect URL instead of following it.
 
mmm same result with changed code

Code:
1234567891011121314151617181920212223242526272829303132333435363738
function getAuth()   function encodepost(t)     local res = {}     local esc = require('socket.url').escape     for k, v in pairs(t) do       res[ #res + 1 ] = esc(k) .. '=' .. esc(v)     end     return table.concat(res, '&')   end     url = apiHost..endpointAuth..'?client_id=customer_api&response_type=code&redirect_uri='..uri..'&scope=api&state='..state   method = "POST"   local response_body = {}    local payload = encodepost({     login = usr,     password = pwd,     locale = "nl",     proceed = "Authorize",   })   local res, code, response_headers, status = socket.http.request   {     url = url,     method = method,     redirect = false,     headers =     {       ["Content-Length"] = #payload     },     source = ltn12.source.string(payload),     sink = ltn12.sink.table(response_body)   }   if res and code == 200 then     log(response_body)     log(res, code, response_headers, status)   else     log(res, code, response_headers, status)   end end
Reply
#7
Header is missing:
Code:
1
["Content-Type"] = "application/x-www-form-urlencoded"
Reply
#8
(22.10.2020, 08:23)admin Wrote: Header is missing:
Code:
1
["Content-Type"] = "application/x-www-form-urlencoded"

 yes, now i get the authorization code (authCode).

Next is exchaging the authorization code for an access token, see my code try below.
Doc: https://interop.ondilo.com/docs/api/cust...n-exchange
Code:
123456789101112131415161718
-- exchange the authorization code for an access token   if authCode then     url = apiHost..endpointToken..'?code='..authCode..'&grant_type=authorization_code&client_id=customer_api&redirect_uri='..uri     method = "POST"     local response_body = {}     local res, code, response_headers, status = socket.http.request     {       url = url,       method = method,       headers =       {         ["Content-Type"] = "application/x-www-form-urlencoded"       },       source = ltn12.source.string(''),       sink = ltn12.sink.table(response_body)     }     log(res, code, response_headers, status)   end

but as usually i received an error  Big Grin
Code:
123456789101112131415161718192021222324252627282930
* arg: 1   * number: 1 * arg: 2   * number: 400 * arg: 3   * table:    ["server"]     * string: Apache/2.4.29 (Ubuntu)    ["content-type"]     * string: application/json    ["connection"]     * string: close    ["access-control-allow-methods"]     * string: GET, POST, PUT, PATCH, DELETE, OPTIONS    ["access-control-allow-headers"]     * string: X-Requested-With, Content-Type, Accept, Origin, Authorization    ["cache-control"]     * string: no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0    ["pragma"]     * string: no-cache    ["date"]     * string: Thu, 22 Oct 2020 11:14:32 GMT    ["content-length"]     * string: 97    ["access-control-allow-origin"]     * string: *    ["access-control-allow-credentials"]     * string: true * arg: 4   * string: HTTP/1.1 400 Bad Request
Reply
#9
You must provide "Content-Length" header for POST requests. Move your GET variables to POST payload:
Code:
1234567
url = apiHost..endpointToken payload = encodepost({   code = authCode,   grant_type = 'authorization_code',   client_id = 'customer_api',   redirect_uri = uri, })
Reply
#10
many thanks to admin for the support.

here my first version to get the latest sensor readings for one pool/spa.

We remind that ICO takes measures every hour.
In order to avoid excessive load of our servers, the requests to the Ondilo Customer API
are limited to the following per user quotas :
5 requests per second
30 requests per hour

Access tokens have a lifetime of one hour, while refresh tokens are non-expiring.

Attached Files
.lua   ondilo.lua (Size: 4.25 KB / Downloads: 28)
Reply
#11
One small improvement, you should use the whole table instead of only the first element. If the JSON response is large enough then the response table will have more than 1 element. Use this instead:
Code:
1
data = json.decode(table.concat(response_body))
Reply
#12
Hello

Could you give some instructions with examples how to get sensors data please  Shy
I am not familiar with scripting, but can multiply solution from example.

Thank you
Reply
#13
First you need to set usr and pwd variables in the script. Then run this function to get the ID of your pool:
Code:
1
log( getPoolInfo() )

Then you can request the sensor state by calling getSensorInfo:
Code:
12
data = getSensorInfo() log(data)
When the data format is known the script can be modified to write sensor state to objects.
Reply
#14
(24.05.2021, 09:38)admin Wrote: First you need to set usr and pwd variables in the script. Then run this function to get the ID of your pool:
Code:
1
log( getPoolInfo() )

Then you can request the sensor state by calling getSensorInfo:
Code:
12
data = getSensorInfo() log(data)
When the data format is known the script can be modified to write sensor state to objects.

Hello

I have got sensors data, thank you, could you make example of a function for the PUT method?

Thank you
Reply
#15
PUT is the same as POST, just change the method field accordingly
Reply


Forum Jump: