Jump to content
Guides for the Forum Read more... ×
Poradniki na Forum Read more... ×

Question

Hi guys,

 

Good news for the happy customers of Nibe! I am sharing the code for the Nibe Uplink scene.

  • This scene can get the telemetry from your Nibe Uplink cloud. You would be able to see any parameter available through the Nibe uplink and use this data for your other systems. For example, I am using the outside temperature sensor to control my markize on the terrace and inform night cooling bypass decisions for the HRV.
  • This scene can also post a defined set of parameters to the Nibe Uplink cloud. For example, Fibaro uses the overall house states (Home, Away, Vacation, etc. ) to put the Nibe system into a corresponding mode. I have also tried creating a virtual thermostat VD (Nest-like)  which can be used by Nibe to change the flow temp and switch between heating and cooling.

 

This scene has to be heavily customized for each user, since there are so many different Nibe products that work with the Uplink cloud. My scene is done for the F1255PC.

So far this code has been used by @perjar, @Allan@lytken.dk - you guys are welcome to share your versions of the code and any improvements!

 

Replace XXXXX with your Auth credentials - Please follow the instructions in STEP2  here https://www.marshflattsfarm.org.uk/wordpress/?page_id=3480

Please, look though the code and create the necessary Global Variables.

 

--[[

%% properties

%% autostart

%% globals

--]]

 

 

local Authorized  = true  --Set to true once you have saved the OAuth data

local access_token

local refresh_token

local JRefresh

local cHM

local http = net.HTTPClient({timeout=5000}) 

-- if scene is started by autorun and is running in the loop then set selfRun to true

-- else if it is called by another scene like Main scene for time based events then

-- set selfRun to false

local selfRun        = true

-- if above selfRun is set to true then set refresh rate in seconds

local refreshloop       = 300

-- DEBUGGING VARIABLES ---------------------------------------------------

-- setup debugging, true is turned on, false turned off. If set to false

-- only ERROR messages will be shown in debug window

local deBug          = true

 

-- debug function

function logbug(color, message)

  if deBug then

    for line in message:gmatch("[^\010\013]+") do

      local txt = line:gsub("([\038\060\062])",

        function(c)

          return "&#"..string.byte(c)..";"

        end)

      fibaro:debug(('<span style="color:%s">%s</span>'):format(color,txt))

    end

  end

end

 

function UpdateNibeTable ()

  fibaro:setGlobal('NibeParameters', json.encode(NibeParameters))

  logbug('green', 'Table updated')

end

 

-- SETUP NIBE ACCOUNT (Please follow the instructions in STEP2  here 

Please login or register to see this link.

)--------------------------------------------------------

local client_id = XXXXX'

local client_secret = 'XXXX'

local redirect_uri = 'https://www.marshflattsfarm.org.uk/nibeuplink/oauth2callback/index.php'

local code = 'XXXX'

local requestAuth = 'grant_type=authorization_code&client_id=' ..client_id..

                         '&client_secret=' ..client_secret..

                         '&code=' ..code..

                         '&redirect_uri=' ..redirect_uri..

                         '&scope=READSYSTEM%20WRITESYSTEM'

 

--Making sure that only one instance of the scene is running.

if (fibaro:countScenes() > 1) then

  fibaro:abort()

end

 

  

--Main function (looping)

function OAuth(nextFunction)

  if not Authorized then

    http:request('https://api.nibeuplink.com/oauth/token', { 

      options={ 

        headers = {

          ['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'

        }, 

        data = requestAuth, 

        method = 'POST', 

        timeout = 20000 

      }, 

      success = function(Oauth)

        logbug('green', 'Initial authorisation response '..Oauth.status)

        fibaro:setGlobal("NibeOauth", Oauth.data)

        Authorized = true

        fibaro:debug('Variables ok')

      end, 

      error = function(error) 

        print "Initial Auth ERROR" 

        print(error) 

      end 

    })

  else

    local Oauth = fibaro:getGlobalValue("NibeOauth")

    local JOauth = json.decode(Oauth)

    local refresh_token = JOauth.refresh_token

    local refreshAuth = 'grant_type=refresh_token&client_id=' ..client_id..

                         '&client_secret=' ..client_secret..

                         '&refresh_token=' ..refresh_token

    http:request('https://api.nibeuplink.com/oauth/token', { 

      options={ 

        headers = {

          ['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'

        }, 

        data = refreshAuth, 

        method = 'POST', 

        timeout = 20000 

      }, 

      success = function(Refresh)

          logbug('green', 'Refresh response '..Refresh.status)

          JRefresh = json.decode(Refresh.data)

          access_token = JRefresh.access_token

          refresh_token = JRefresh.refresh_token

          if refresh_token == nil then

            logbug ("red","Error: No Refresh Token Found")

          else

            logbug("green","Refresh token obtained from Nibe")

            fibaro:setGlobal("NibeOauth", Refresh.data)

            NibeParameters = json.decode(fibaro:getGlobalValue("NibeParameters"))

            setTimeout(UpdateNibeTable, 20000)

            ConnectionStatus ()

            CategoryStatus ()

            Parameters ()

            GSHPStatus ()

            GSHPMode ()

            fibaro:debug('Variables ok')

          end

      end, 

      error = function(error) 

        print "Refresh auth ERROR" 

        print(error) 

      end 

    })

  end

  if selfRun then 

    logbug("violet", "Wait "..refreshloop.." seconds for next run")

    setTimeout(OAuth, refreshloop*1000)

  end

end

 

-- Checks Nibe Uplink connection

function ConnectionStatus (NextFunction)

http:request('https://api.nibeuplink.com/api/v1/systems/35842', { 

      options={ 

        headers = {

          ['Authorization'] = 'Bearer '..access_token,

        },  

        method = 'GET', 

        timeout = 5000 

      }, 

      success = function(NibeData)

        local JNibeData = json.decode(NibeData.data)

        cHM = os.date("%H:%M")

        if JNibeData.connectionStatus ~= nil then

          NibeConnectionStatus = JNibeData.connectionStatus..' в '..cHM

          logbug('yellow', JNibeData.connectionStatus)

          fibaro:setGlobal("NibeConnectStatus", NibeConnectionStatus)

          NibeParameters.connectionStatus = NibeConnectionStatus

        end

    end, 

      error = function(error) 

        print "Connection status request - ERROR" 

        print(error) 

      end 

    })

end

 

-- Updates main parameters as in Service Info/Status

function CategoryStatus (NextFunction)

http:request('https://api.nibeuplink.com/api/v1/systems/35842/serviceinfo/categories/status', { 

      options={ 

        headers = {

          ['Authorization'] = 'Bearer '..access_token,

        },  

        method = 'GET', 

        timeout = 5000 

      }, 

      success = function(NibeData)

        local JNibeData = json.decode(NibeData.data)

        for i = 1, #JNibeData do

          if JNibeData.title == 'outdoor temp.' then

            logbug('yellow',JNibeData.title..' '..JNibeData.rawValue)

            OutsideTemp = tonumber(JNibeData.rawValue)/10

            gui_weather = {id=3, properties={Temperature=OutsideTemp}}

            api.put("/devices", gui_weather)

            logbug("green", "GUI Weather temp updated")

          end

          if JNibeData.rawValue ~= nil then

            NibeParameters[JNibeData.title] = JNibeData.rawValue

          end

        end

    end, 

      error = function(error) 

        print "Category status request - ERROR" 

        print(error) 

      end 

    })

end

 

-- Get room temperature

function Parameters ()

  http:request('https://api.nibeuplink.com/api/v1/systems/35842/parameters?parameterIds=hot_water_boost', { 

      options={ 

        headers = {

          ['Authorization'] = 'Bearer '..access_token,},

        method = 'GET', 

        timeout = 5000 

      }, 

      success = function(NibeData)

        local JNibeData = json.decode(NibeData.data)

        for i = 1,#JNibeData do

          if JNibeData.title == 'Temporary Lux' then

            logbug('yellow',JNibeData.title..' '..JNibeData.displayValue)

            fibaro:setGlobal("LuxWater", JNibeData.displayValue)

            NibeParameters[JNibeData.title] = JNibeData.displayValue

          end

        end

    end, 

      error = function(error) 

        print "Parameters request - ERROR" 

        print(error) 

      end 

    })

end

 

--Set heat pump mode (Home/Vacation)

function GSHPStatus ()

  SmartHomeMode = fibaro:getGlobalValue("GSHPStatus")

  if SmartHomeMode == 'Home'  then body = json.encode({mode="DEFAULT_OPERATION"})

  elseif SmartHomeMode == 'Away'  then body = json.encode({mode="AWAY_FROM_HOME"})

  elseif SmartHomeMode == 'Vacation' then body = json.encode({mode="VACATION"})

  end 

    http:request('https://api.nibeuplink.com/api/v1/systems/35842/smarthome/mode', { 

      options={ 

        headers = {

        ['Authorization'] = 'Bearer '..access_token,

        ['Content-Type'] = 'application/json'},

        data = body,  

        method = 'PUT', 

        timeout = 5000 

      }, 

      success = function(Response)

      logbug('yellow', 'SmartHome Response '..Response.status)

    end, 

      error = function(error) 

        print "GSHPStatus setting - ERROR" 

        print(error) 

      end 

    })  

end

 

-- Updates Heat Pump Mode (Nil/Heating/Cooling/Hot water)

function GSHPMode (NextFunction)

http:request('https://api.nibeuplink.com/api/v1/systems/35842/status/system', { 

      options={ 

        headers = {

          ['Authorization'] = 'Bearer '..access_token,

        },  

        method = 'GET', 

        timeout = 5000 

      }, 

      success = function(NibeData)

        --fibaro:debug(NibeData.data)

        local JNibeData = json.decode(NibeData.data)

        if fibaro:getGlobalValue("GSHPStatus") == 'Home'

          then

          if (JNibeData[1] == nil) then fibaro:setGlobal('NibeMode', 'Idle')

          elseif (JNibeData[1].image.name == 'Supply') then fibaro:setGlobal('NibeMode', 'Idle')

          elseif (JNibeData[1].image.name == 'Heating') then fibaro:setGlobal('NibeMode', 'Heating')

          elseif (JNibeData[1].image.name == 'Cooling') then fibaro:setGlobal('NibeMode', 'Cooling')

          elseif (JNibeData[1].image.name == 'Drop') then fibaro:setGlobal('NibeMode', 'Hot Water')

          end   

        else

          if (JNibeData[2] == nil) then fibaro:setGlobal('NibeMode', 'Idle')

          elseif (JNibeData[2].image.name == 'Heating') then fibaro:setGlobal('NibeMode', 'Heating')

          elseif (JNibeData[2].image.name == 'Cooling') then fibaro:setGlobal('NibeMode', 'Cooling')

          elseif (JNibeData[2].image.name == 'Drop') then fibaro:setGlobal('NibeMode', 'Hot Water')

          end

        end

        Compressor = false

        for i = 1,#JNibeData do

          if JNibeData.image.name == 'Compressor' then

            Compressor = true

            NibeParameters.compressorFrequency = JNibeData.parameters[4].rawValue

          end

        end

        if Compressor == false then  NibeParameters.compressorFrequency = nil end

    end, 

      error = function(error) 

        print "GSHPMode request - ERROR" 

        print(error) 

      end 

    })

end

 

--Main part launching the loop

OAuth()

 

 

 

Edited by Ros

Share this post


Link to post
Share on other sites

12 answers to this question

Recommended Posts

  • 0

The topic has been moved from "

Please login or register to see this link.

" to "

Please login or register to see this link.

".

 

Temat został przeniesiony z "

Please login or register to see this link.

" do "

Please login or register to see this link.

".

Share this post


Link to post
Share on other sites
  • 0
  • Inquirer
  • Ок. Seems no one has a Nibe... 

    I would like to access their API and get just one parameter. I need to start with authentication, which is described like this:

    Users are authenticated via the 

    Please login or register to see this link.

     protocol. NIBE Uplink currently supports the Authorization Code Grant flow and the Implicit Grant flow. The Authorization Code Grant flow targets clients which the OAuth 2 specification deems confidential, such as web applications and mobile apps while the Implicit Grant flow is a shorter flow which targets public clients that can't keep the confidentiality of the OAuth credentials, such as browser based JavaScript applications.

    Under no circumstances is the client allowed to process or handle a user's secret login credentials.

    The following URL:s are used for the OAuth 2 requests

    • Authorize endpoint 

      Please login or register to see this link.

    • Token endpoint 

      Please login or register to see this link.

    Could you guys please point me to the right place to see a similar code? Which code should I use for OAuth2? I have an identifier, a secret  and authorization code... How do I get an access token?

    Edited by Ros

    Share this post


    Link to post
    Share on other sites
    • 0

    Hi @Ros,

     

    Check Netatmo weather station scene since it uses same OAuth 2 authentication system:

    It might be of help to you.

    Share this post


    Link to post
    Share on other sites
    • 0
  • Inquirer
  • Hi guys,

    I've almost gotten this to work. Apparently there is a private api, that does not need oauth2.

    This API works fine via the POSTMAN  plugin in Chrome, but I am unable to achieve the same result in a Fibaro scene? What am I doing wrong? What is the right code for this in LUA?

    This is the request to authorize with API. When I launch this is Postman, I get Status 200.

     

    POST /LogIn HTTP/1.1
    Host: www.nibeuplink.com
    Cache-Control: no-cache
    Postman-Token: 4def48a9-e5f7-3797-4296-53247897663d
    Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW

    ------WebKitFormBoundary7MA4YWxkTrZu0gW
    Content-Disposition: form-data; name="email"

    myemail@gmail.com
    ------WebKitFormBoundary7MA4YWxkTrZu0gW
    Content-Disposition: form-data; name="password"

    mypassword
    ------WebKitFormBoundary7MA4YWxkTrZu0gW--

     

    This is the code I'm using for this in a Lua Scene. Is this correct? When I launch this, I get status 302... I think the API authorizes me, because I get redirected to the right link.

     

    local http = net.HTTPClient({timeout=5000}) 

    local requestAuth = 'email=myemail@gmail.com&password=mypassword'
    http:request('https://www.nibeuplink.com/LogIn', { 
    options={ 
    headers = {
      ['Content-Type'] = 'application/x-www-form-urlencoded'
      }, 
    data = requestAuth, 
    method = 'POST', 
    timeout = 5000 
    }, 

    success = function(status) 
    print(status.status)
         print(status.data)      


     
    end, 
    error = function(error) 
    print "ERROR" 
    print(error) 
    end 
    })

     

    However, then I need to do a second POST to get the variables. And now the API returns trash, like I have not authorised... is there any way to make the API think this request is part of the same session as above?

     

    local requestVariables = 'hpid=35842&variables=40033'

    http:request('https://www.nibeuplink.com/PrivateAPI/Values', {

    options={

    headers = {

      ['Content-Type'] = 'application/x-www-form-urlencoded'

      },

    data = requestVariables,

    method = 'POST',

    timeout = 10000

    },

     

    success = function(status)

    print(status.status)

          print(status)     

     

     

    end,

    error = function(error)

    print "ERROR"

    print(error)

    end

    })

     

    Edited by Ros

    Share this post


    Link to post
    Share on other sites
    • 0
  • Inquirer
  • @Sankotronic

    Thanks man! I've looked into your code for the Netatmo and was able to replicate the OAuth2 part! Now I've got the set of parameters back from the API. I am unable to parse the JSON file...

    What I would like to do is to set a global variable to a displayValue of a specific parameterID.  Can anyone help?

     

    The data comes in the following format

    Please login or register to see this code.

    Share this post


    Link to post
    Share on other sites
    • 0
  • Inquirer
  • Ok. I've figured out the JSON issue!

     

    I have a working VD and Scene for the Nibe heat pump products. Fibaro has access to the Nibe telemetry via the public API (oAuth2) and is able to manage the heat pump via IFTTT.

     

    If anyone has a Nibe heat pump and wants the code - please, feel free to reach out to me!

    Share this post


    Link to post
    Share on other sites
    • 0
    On 2017-08-08 at 1:45 PM, mekis_9 said:

    Hi

     

    I gladly test your Nibe VD and bring feedback to you.

    :-)

     

    bump :-)

     

    Share this post


    Link to post
    Share on other sites
    • 0
    On 2017-08-08 at 1:21 PM, Ros said:

    Ok. I've figured out the JSON issue!

     

    I have a working VD and Scene for the Nibe heat pump products. Fibaro has access to the Nibe telemetry via the public API (oAuth2) and is able to manage the heat pump via IFTTT.

     

    If anyone has a Nibe heat pump and wants the code - please, feel free to reach out to me!

    Hi,

     

    I would love to try it. I have just finished building an integration between the HC2 and my Verisure alarm API and was ready to get going with the Nibe API.

     

    My thinking was to build something in Python and run it on a Raspberry Pi. There is a library for the Nibe API on Github I was thinking of using. But if I can skip that step and call the Nibe API directly from a VD in the HC2 that's even better!

     

    I tried the Chrome Postman approach just to see if I could get anything back from the API but my call is just returning the login page.

    All in all, I would be happy to run your code, it will save me some time. :-)

     

    Regards,

    Per

     

     

     

    Share this post


    Link to post
    Share on other sites
    • 0

    Hi

     

    If you can share the code I can test that on HC2 with Nibe 1245 heatpump.

    Thanks.

    Share this post


    Link to post
    Share on other sites
    • 0
  • Inquirer
  • 2 hours ago, laurit said:

    Hi

     

    If you can share the code I can test that on HC2 with Nibe 1245 heatpump.

    Thanks.

     Please, look at the first post in this thread

    Share this post


    Link to post
    Share on other sites
    • 0

    Ah, ok. I thought it was just tryout or smth.

    Thanks, I'll look into it.

    Share this post


    Link to post
    Share on other sites

    Create an account or sign in to comment

    You need to be a member in order to leave a comment

    Create an account

    Sign up for a new account in our community. It's easy!

    Register a new account

    Sign in

    Already have an account? Sign in here.

    Sign In Now

    ×