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.

Ebeco floorheat thermostat
#1
Hi.

I have a floorheat brand that has an REST API  that I want to implement into a buildings KNX installation.
is it possible to make this with some script or is it someone that has done this already? I want to control and see status och the floorheating. 
Attach the link to its api information if that’s explains my goal better. 
https://www.ebeco.se/support/ebeco-open-api
Reply
#2
First you need to get the bearer token manually as described in the API link you've provided. Then you can use it to make requests as documented here: https://ebecoconnect.com/swagger/index.html

Topics where you can find example code:
https://forum.logicmachine.net/showthread.php?tid=2185
https://forum.logicmachine.net/showthread.php?tid=3308
https://forum.logicmachine.net/showthread.php?tid=3121
https://forum.logicmachine.net/showthread.php?tid=1786
Reply
#3
Hi.

I ran this in Postman where I got the accessToken with success.
Code:
12345678
curl --location --request POST 'https://ebecoconnect.com/api/TokenAuth/Authenticate' \ --header 'Content-Type: application/json' \ --header 'Abp.TenantId: 1' \ --data-raw '    {     "userNameOrEmailAddress": "xxxxx@xxxxx.com",     "password": "xxxxx"    }'

But in my script I don´t get the response of the connected devices, in fact I dopnt get much at all in response, what is wrong here? 
Code:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
-- Load modules require('json') require('ssl.https') require('ltn12') -- Set credentials for Ebecoconnect API userNameOrEmailAddress = "xxxxx@xxxxx.com" -- your email for Ebecoconnect account password = "xxxxx" -- your password for Ebecoconnect account function GetToken()  request_token_url = 'https://ebecoconnect.com/api/TokenAuth/Authenticate'  local response_body = {}  local request_body = "grant_type=password&username=" .. userNameOrEmailAddress .. "&password=" .. password  local body, code, hdrs, stat = ssl.https.request{    url = request_token_url;    method = "POST";    headers =    {      ["Content-Type"] = "application/x-www-form-urlencoded";       ["Content-Length"] = #request_body;       ["Abp.TenantId"] = 1;    };    source = ltn12.source.string(request_body);    sink = ltn12.sink.table(response_body);  }  if code == 200 then    ret = table.concat(response_body)    ret = json.pdecode(ret)     log(ret)    return ret.access_token -- could be some other field, try to log ret to be sure  end end -- Request token if not API_Token then     API_Token = GetToken() end function RequestFromEbeco(request)  request_url = 'https://api/services/app/Devices/GetUserDevices' .. request  local response_body = {}  local request_body = ""  local body, code, hdrs, stat = ssl.https.request{    url = request_url;    method = "GET";    headers =    {      ["Content-Type"] = "application/json";      ["Authorization"] = "Bearer " .. API_Token;    };    source = ltn12.source.string(request_body);    sink = ltn12.sink.table(response_body);  }  if code == 200 then    ret = table.concat(response_body)    ret = json.pdecode(ret)    return ret  else    API_Token = GetToken() -- request a new token  end end -- Get products products = RequestFromEbeco('products') log(products) -- Checks your Ebeco thermostats

Ebecos API documentation here
https://www.ebeco.se/radgivning/guider/ebeco-oppet-api
Reply
#4
Use this:
Code:
12345678910111213141516171819202122232425262728
function GetToken()   local response_body = {}   local request_body = json.encode({     userNameOrEmailAddress = userNameOrEmailAddress,     password = password,   })   local body, code, hdrs, stat = ssl.https.request{     url = 'https://ebecoconnect.com/api/TokenAuth/Authenticate',     method = 'POST',     headers = {       ['Content-Type'] = 'application/json',       ['Content-Length'] = #request_body,       ['Abp.TenantId'] = 1,     },     source = ltn12.source.string(request_body),     sink = ltn12.sink.table(response_body),   }   if code == 200 then     ret = table.concat(response_body)     ret = json.pdecode(ret)     log(ret)     return ret.access_token -- could be some other field, try to log ret to be sure   else     log('request failed', body, code, hdrs, stat)   end end

The request_url in RequestFromEbeco is wrong, it should be "https://ebecoconnect.com/api/services/app/Devices/GetUserDevices" (without any additional parameters).
Reply
#5
(08.08.2022, 06:04)admin Wrote: Use this:
Code:
12345678910111213141516171819202122232425262728
function GetToken()   local response_body = {}   local request_body = json.encode({     userNameOrEmailAddress = userNameOrEmailAddress,     password = password,   })   local body, code, hdrs, stat = ssl.https.request{     url = 'https://ebecoconnect.com/api/TokenAuth/Authenticate',     method = 'POST',     headers = {       ['Content-Type'] = 'application/json',       ['Content-Length'] = #request_body,       ['Abp.TenantId'] = 1,     },     source = ltn12.source.string(request_body),     sink = ltn12.sink.table(response_body),   }   if code == 200 then     ret = table.concat(response_body)     ret = json.pdecode(ret)     log(ret)     return ret.access_token -- could be some other field, try to log ret to be sure   else     log('request failed', body, code, hdrs, stat)   end end

The request_url in RequestFromEbeco is wrong, it should be "https://ebecoconnect.com/api/services/app/Devices/GetUserDevices" (without any additional parameters).

Thanks, but did´nt get that to work either. But change my script line from having ". . ." to '. . .'
Then I put in log('request failed') and got this in response:
Ebeco REST API copy 08.08.2022 08:48:58
* arg: 1
  * string: request failed
* arg: 2
  * number: 1
* arg: 3
  * number: 415
* arg: 4
  * table:
  ["server"]
    * string: Microsoft-IIS/10.0
  ["connection"]
    * string: close
  ["content-length"]
    * string: 0
  ["x-rate-limit-limit"]
    * string: 60s
  ["x-rate-limit-remaining"]
    * string: 29
  ["request-context"]
    * string: appId=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  ["x-frame-options"]
    * string: SAMEORIGIN
  ["x-rate-limit-reset"]
    * string: 2022-08-08T06:49:58.5482160Z
  ["date"]
    * string: Mon, 08 Aug 2022 06:48:57 GMT
  ["x-xss-protection"]
    * string: 1; mode=block
  ["set-cookie"]
    * string: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxPath=/;HttpOnly;SameSite=None;Secure;Domain=ebecoconnect.com
  ["x-content-type-options"]
    * string: nosniff
* arg: 5
  * string: HTTP/1.1 415 Unsupported Media Type

I added the X:es if it might have been sensitive stuff Smile
Reply
#6
Try adding Accept: application/json or Accept: */* to headers in GetToken function:
Code:
123456
headers = {   ['Content-Type'] = 'application/json',   ['Content-Length'] = #request_body,   ['Abp.TenantId'] = 1,   ['Accept'] = 'application/json', },
Reply
#7
(08.08.2022, 07:06)admin Wrote: Try adding Accept: application/json or Accept: */* to headers in GetToken function:
Code:
123456
headers = {   ['Content-Type'] = 'application/json',   ['Content-Length'] = #request_body,   ['Abp.TenantId'] = 1,   ['Accept'] = 'application/json', },

Now intsted of "HTTP/1.1 415 Unsupported Media Type"

I get "HTTP/1.1 400 Bad Request"
Reply
#8
Have you tried */* instead of application/json?
Reply
#9
(08.08.2022, 07:24)admin Wrote: Have you tried */* instead of application/json?

Yes it´s the same response as well "HTTP/1.1 400 Bad Request"

The response look like this:
* arg: 1
  * string: request failed
* arg: 2
  * number: 1
* arg: 3
  * number: 400
* arg: 4
  * table:
  ["server"]
    * string: Microsoft-IIS/10.0
  ["content-type"]
    * string: application/json; charset=utf-8
  ["connection"]
    * string: close
  ["content-length"]
    * string: 412
  ["x-rate-limit-limit"]
    * string: 60s
  ["x-rate-limit-remaining"]
    * string: 29
  ["request-context"]
    * string: appId=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  ["x-frame-options"]
    * string: SAMEORIGIN
  ["x-rate-limit-reset"]
    * string: 2022-08-08T07:31:10.2468154Z
  ["date"]
    * string: Mon, 08 Aug 2022 07:30:10 GMT
  ["x-xss-protection"]
    * string: 1; mode=block
  ["set-cookie"]
    * string: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxDomain=ebecoconnect.com
  ["x-content-type-options"]
    * string: nosniff
* arg: 5
  * string: HTTP/1.1 400 Bad Request
Reply
#10
Can you send credentials to us via e-mail so we can check locally?
Reply
#11
(08.08.2022, 08:01)admin Wrote: Can you send credentials to us via e-mail so we can check locally?

sure, wich email?
Reply
#12
Send to info@openrb.com
Reply
#13
This works for me using your credentials:
Code:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
require('json') require('ssl.https') require('ltn12') -- Set credentials for Ebecoconnect API userNameOrEmailAddress = '...' -- your email for Ebecoconnect account password = '...' -- your password for Ebecoconnect account function GetToken()   local response_body = {}   local request_body = json.encode({     userNameOrEmailAddress = userNameOrEmailAddress,     password = password,   })   local body, code, hdrs, stat = ssl.https.request{     url = 'https://ebecoconnect.com/api/TokenAuth/Authenticate',     method = 'POST',     headers = {       ['Content-Type'] = 'application/json',       ['Content-Length'] = #request_body,       ['Abp.TenantId'] = 1,     },     source = ltn12.source.string(request_body),     sink = ltn12.sink.table(response_body),   }   if code == 200 then     local ret = table.concat(response_body)     ret = json.pdecode(ret)     if type(ret) == 'table' and type(ret.result) == 'table' then       return ret.result.accessToken     end   else     log('request failed', body, code, hdrs, stat)   end end API_Token = GetToken() function RequestFromEbeco(request, params)   local url = 'https://ebecoconnect.com/api/services/app/Devices/' .. request   local response_body = {}   local request_body = ''   local body, code, hdrs, stat = ssl.https.request{     url = url,     method = 'GET',     headers = {       ['Content-Type'] = 'application/json',       ['Authorization'] = 'Bearer ' .. API_Token,     },     source = ltn12.source.string(request_body),     sink = ltn12.sink.table(response_body),   }   if code == 200 then     local ret = table.concat(response_body)     ret = json.pdecode(ret)     return ret   else     log('request failed', body, code, hdrs, stat)   end end if API_Token then   devices = RequestFromEbeco('GetUserDevices')   log(devices) end
Reply
#14
(08.08.2022, 12:07)admin Wrote: This works for me using your credentials:
Code:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
require('json') require('ssl.https') require('ltn12') -- Set credentials for Ebecoconnect API userNameOrEmailAddress = '...' -- your email for Ebecoconnect account password = '...' -- your password for Ebecoconnect account function GetToken()   local response_body = {}   local request_body = json.encode({     userNameOrEmailAddress = userNameOrEmailAddress,     password = password,   })   local body, code, hdrs, stat = ssl.https.request{     url = 'https://ebecoconnect.com/api/TokenAuth/Authenticate',     method = 'POST',     headers = {       ['Content-Type'] = 'application/json',       ['Content-Length'] = #request_body,       ['Abp.TenantId'] = 1,     },     source = ltn12.source.string(request_body),     sink = ltn12.sink.table(response_body),   }   if code == 200 then     local ret = table.concat(response_body)     ret = json.pdecode(ret)     if type(ret) == 'table' and type(ret.result) == 'table' then       return ret.result.accessToken     end   else     log('request failed', body, code, hdrs, stat)   end end API_Token = GetToken() function RequestFromEbeco(request, params)   local url = 'https://ebecoconnect.com/api/services/app/Devices/' .. request   local response_body = {}   local request_body = ''   local body, code, hdrs, stat = ssl.https.request{     url = url,     method = 'GET',     headers = {       ['Content-Type'] = 'application/json',       ['Authorization'] = 'Bearer ' .. API_Token,     },     source = ltn12.source.string(request_body),     sink = ltn12.sink.table(response_body),   }   if code == 200 then     local ret = table.concat(response_body)     ret = json.pdecode(ret)     return ret   else     log('request failed', body, code, hdrs, stat)   end end if API_Token then   devices = RequestFromEbeco('GetUserDevices')   log(devices) end
Now works fine for me too, thanks!

Looks like the problem was that I had used "..." insted of '...'
for some lines, including username
Reply
#15
(08.08.2022, 12:07)admin Wrote: This works for me using your credentials:
Code:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
require('json') require('ssl.https') require('ltn12') -- Set credentials for Ebecoconnect API userNameOrEmailAddress = '...' -- your email for Ebecoconnect account password = '...' -- your password for Ebecoconnect account function GetToken()   local response_body = {}   local request_body = json.encode({     userNameOrEmailAddress = userNameOrEmailAddress,     password = password,   })   local body, code, hdrs, stat = ssl.https.request{     url = 'https://ebecoconnect.com/api/TokenAuth/Authenticate',     method = 'POST',     headers = {       ['Content-Type'] = 'application/json',       ['Content-Length'] = #request_body,       ['Abp.TenantId'] = 1,     },     source = ltn12.source.string(request_body),     sink = ltn12.sink.table(response_body),   }   if code == 200 then     local ret = table.concat(response_body)     ret = json.pdecode(ret)     if type(ret) == 'table' and type(ret.result) == 'table' then       return ret.result.accessToken     end   else     log('request failed', body, code, hdrs, stat)   end end API_Token = GetToken() function RequestFromEbeco(request, params)   local url = 'https://ebecoconnect.com/api/services/app/Devices/' .. request   local response_body = {}   local request_body = ''   local body, code, hdrs, stat = ssl.https.request{     url = url,     method = 'GET',     headers = {       ['Content-Type'] = 'application/json',       ['Authorization'] = 'Bearer ' .. API_Token,     },     source = ltn12.source.string(request_body),     sink = ltn12.sink.table(response_body),   }   if code == 200 then     local ret = table.concat(response_body)     ret = json.pdecode(ret)     return ret   else     log('request failed', body, code, hdrs, stat)   end end if API_Token then   devices = RequestFromEbeco('GetUserDevices')   log(devices) end

Hi.

I´ve used this script for one device, but how do I get the data from data table 2-5?

Code:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
if API_Token then   devices = RequestFromEbeco('GetUserDevices')   --log(devices) end   if devices and devices.result then     for _, device in ipairs(devices.result) do             -- Enhetsdata 1 grp.checkwrite('32/2/1', device["id"]) -- id (Number) grp.checkwrite('32/2/2', device["relayOn"]) -- relayOn (Bool) grp.checkwrite('32/2/3', device["minutesToTarget"]) -- minutesToTarget (Number) grp.checkwrite('32/2/4', device["temperatureRoom"]) -- temperatureRoom (Number) grp.checkwrite('32/2/5', device["temperatureRoomDecimals"]) -- temperatureRoomDecimals (Number) grp.checkwrite('32/2/6', device["temperatureFloorDecimals"]) -- temperatureFloorDecimals (Number) grp.checkwrite('32/2/7', device["remoteInput"]) -- remoteInput (Bool) grp.checkwrite('32/2/8', device["displayName"]) -- displayName (String) grp.checkwrite('32/2/9', device["temperatureSet"]) -- temperatureSet (Number) -- "errorMessage" ignorerad (userdata: NULL) grp.checkwrite('32/2/10', device["building"]["name"]) -- building name (String) grp.checkwrite('32/2/11', device["building"]["id"]) -- building id (Number) grp.checkwrite('32/2/12', device["programState"]) -- programState (String) grp.checkwrite('32/2/13', device["temperatureFloor"]) -- temperatureFloor (Number) grp.checkwrite('32/2/14', device["hasError"]) -- hasError (Bool) grp.checkwrite('32/2/15', device["installedEffect"]) -- installedEffect (Number) grp.checkwrite('32/2/16', device["powerOn"]) -- powerOn (Bool) grp.checkwrite('32/2/17', device["todaysOnMinutes"]) -- todaysOnMinutes (Number) grp.checkwrite('32/2/18', device["selectedProgram"]) -- selectedProgram (String) -- Enhetsdata 2 grp.checkwrite('32/2/19', device2["id"]) -- id (Number) grp.checkwrite('32/2/20', device2["relayOn"] and 1 or 0) -- relayOn (Bool) grp.checkwrite('32/2/21', device2["minutesToTarget"]) -- minutesToTarget (Number) grp.checkwrite('32/2/22', device2["temperatureRoom"]) -- temperatureRoom (Number) grp.checkwrite('32/2/23', device2["temperatureRoomDecimals"]) -- temperatureRoomDecimals (Number) grp.checkwrite('32/2/24', device2["temperatureFloorDecimals"]) -- temperatureFloorDecimals (Number) grp.checkwrite('32/2/25', device2["remoteInput"] and 1 or 0) -- remoteInput (Bool) grp.checkwrite('32/2/26', device2["displayName"]) -- displayName (String) grp.checkwrite('32/2/27', device2["temperatureSet"]) -- temperatureSet (Number) -- "errorMessage" ignorerad (userdata: NULL) grp.checkwrite('32/2/28', device2["building"]["name"]) -- building name (String) grp.checkwrite('32/2/29', device2["building"]["id"]) -- building id (Number) grp.checkwrite('32/2/30', device2["programState"]) -- programState (String) grp.checkwrite('32/2/31', device2["temperatureFloor"]) -- temperatureFloor (Number) grp.checkwrite('32/2/32', device2["hasError"] and 1 or 0) -- hasError (Bool) grp.checkwrite('32/2/33', device2["installedEffect"]) -- installedEffect (Number) grp.checkwrite('32/2/34', device2["powerOn"] and 1 or 0) -- powerOn (Bool) grp.checkwrite('32/2/35', device2["todaysOnMinutes"]) -- todaysOnMinutes (Number) grp.checkwrite('32/2/36', device2["selectedProgram"]) -- selectedProgram (String)
Reply
#16
Remove the for loop and try this:
Code:
1234567
if devices and devices.result then   device = devices.result[1]   device2 = devices.result[2]   device3 = devices.result[3]   ... end
Reply
#17
(31.10.2023, 07:57)admin Wrote: Remove the for loop and try this:
Code:
1234567
if devices and devices.result then   device = devices.result[1]   device2 = devices.result[2]   device3 = devices.result[3]   ... end

Thanks
It seems to work without the loop.
Reply


Forum Jump: