Created At

Oct 21, 2017

Last Update

Dec 14, 2018

Platforms

HC 2

Views

7354

Download

165

Function

This virtual device allows to see and control the status of a Husqvarna Automower equipped with the Husqvarna Automower Connect hardware (with a GPRS connection). It is based on the official Husqvarna Automower Connect APP. 

It also pushes errors generated by the Automower. 

 

Configuration

  • Create a new LUA scene with the code below. Note down the "Scene ID".
  • Create the Variables. 
  • Import the Virtual Device. Put the Scene ID in the TCP-port configuration of the virtual device. 

Variables

The following variables should be created as "Predefined variables". The values are not important. 

  • mower1Command
  • mower1Status
  • mower1Token

Scene

The scene below is required and contains the real logic behind the virtual device. Scene should be set on "Manual". 

--[[
%% properties
%% events
%% globals
--]]
local usr = "<INSERT YOUR HUSQVARNA ACCOUNT EMAIL>"
local pwd = "<INSERT YOUR HUSQVARNA ACCOUNT PASSWORD"
local mowerindex = 1 -- 1 = first robot in account
local token_url = "https://iam-api.dss.husqvarnagroup.net/api/v3"
local api_url = "https://amc-api.dss.husqvarnagroup.net/v1"


local MowerConnect = net.HTTPClient()
local aHeaders = {['Content-Type'] = 'application/json'}
local mower_id = ""

function Login()
  local req = '{"data": {"attributes": {"password": "'.. pwd .. '","username": "'.. usr .. '"},"type": "token"}}'
  local value, modificationTime = fibaro:getGlobal('mower1Token')
  local result = json.decode(value)
  
  if (result) then
    if (os.time() < (modificationTime + result.data.attributes.expires_in - (60*60))) then
      -- Token not expired, reuse
      aHeaders = {
          ['Content-Type'] = 'application/json',
          ['Authorization'] = 'Bearer ' .. result.data.id,
          ['Authorization-Provider'] = result.data.attributes.provider
        }
      GetRobot()
      req = nil
    else
      -- Token expired, refresh
      req = '{"data":{"type":"token","attributes":{"refresh_token":"'.. result.data.attributes.refresh_token ..'"}}}'
    end
  end

  if (req) then
    -- Request or refresh token
    MowerConnect:request(token_url .. "/token", {
      options = {
        headers = aHeaders,
        method = "POST",
        data = '{"data": {"attributes": {"password": "'.. pwd .. '","username": "'.. usr .. '"},"type": "token"}}'
      }, 
      success = function(status)
        local result = json.decode(status.data)
        fibaro:setGlobal("mower1Token", status.data)
        fibaro:debug(status.data)
        aHeaders = {
            ['Content-Type'] = 'application/json',
            ['Authorization'] = 'Bearer ' .. result.data.id,
            ['Authorization-Provider'] = result.data.attributes.provider
          }
        GetRobot()
      end, --success
      error = function(error)
        fibaro:setGlobal("mower1Token", '')
      end --error
    }) --request
  end --if
end
  
function GetRobot()
  MowerConnect:request(api_url .. "/mowers", {
    options = {
      headers = aHeaders,
      method = "GET"
    }, 
    success = function(status)
      local prevResult = json.decode(fibaro:getGlobalValue("mower1Status"))
      fibaro:setGlobal("mower1Status", status.data)
      local result = json.decode(status.data)

      if result then
          if result[mowerindex] then
            mower_id = result[mowerindex].id
              
            if result[mowerindex].status.mowerStatus == "ERROR" or result[mowerindex].status.mowerStatus == "ERROR_AT_POWER_UP" then
                if prevResult[mowerindex].status.lastErrorCode ~= result[mowerindex].status.lastErrorCode then
                	-- Push once; only if error changes
	                PushError(result[mowerindex].status.lastErrorCode)
                end
            end
              
            fibaro:debug(status.data)
            local cmd = fibaro:getGlobalValue("mower1Command")
            if cmd ~= "" then
                fibaro:debug(cmd)
                DoCommand(cmd)
            end
          end
      end --if result
    end, --success
    error = function(error)
      fibaro:debug(error)
      fibaro:setGlobal("mower1Token", '')
    end --error
  }) --request
end


-- not used
function GetStatus()
  MowerConnect:request(api_url .. "/mowers/" .. mower_id .. "/status" , {
    options = {
      headers = aHeaders,
      method = "GET"
    }, 
    success = function(status)
      fibaro:debug(status.data)
      result = json.decode(status.data)
    end
})
end

function DoCommand(cmd)
  MowerConnect:request(api_url .. "/mowers/" .. mower_id .. "/control", {
    options = {
      headers = aHeaders,
      method = "POST",
      data = '{"action": "' .. cmd ..'"}}'
    }, 
    success = function(status)
        fibaro:debug(status.data)
        fibaro:setGlobal("mower1Command", "")
      end
})
end

function PushError(err)
  -- err 19: bump probleem front
  -- err 18: bump probleem back
  -- err 15: lifted
  -- err 10: Upside down
  -- err 2: Empty battery
  -- err 1: outside mowing area
    HomeCenter.PopupService.publish({
        title = 'Fout met grasmaaier',
        subtitle = '',
        contentBody = 'Grasmaaier heeft fout gegenereerd: ' .. err,
        img = 'http://husqvarnacdn.azureedge.net//qs_mh=680&mw=680&ver=00000000T000000/_$$_/media/dam/husqvarna/garden%20lawnmowers%20and%20ride-on%20mowers/robotic%20lawnmowers/2014/12/08/20/34/h310-0866.ashx',
        type = 'Warning',
        buttons = {
            { caption = 'Ok', sceneId = 0 }
        }
    })  
end

Login()

Icons

 

See http://virtualstuff.org/fibaro/icons/ for original icons.

 

21 Comments,  Want to add comment please login
6abf30f1df1e3c73395c57af736fdd14

Good day and thanks for the VD, Have one issue in the scene: [DEBUG] 15:28:12: line 35: unexpected character @ character: 1 0:1 [V] line: [DEBUG] 15:28:12: V

6b85f09ae1b720f156977b9cc45e6720

Good morning all, first of all thanks to Peter for this great VD and scene. Worked like a charm for several weeks. Suddenly as of 07th May 2018, it fails. Could it be that Husqvarna changed the API? The connection to get a new token still works fine, but sending any command via "https://amc-api.dss.husqvarnagroup.net/v1" fails. I do not even get an error message in the scene, which I have not figured out yet why. When I try to call above link from my browser, I do get a json string back containing "HTTP 404 Not Found". That's why I was guessing they could have changed the link. Anybody with same observation?

0dc6dce5432b46456ffa607540ef80fd

Hello all; I think i had de same problem! in the debug mode (VD), i get this error: [DEBUG] 10:27:34: Wert 1 [ERROR] 10:27:34: line 9: Expected value but found invalid token at character 1 when i try to use the links in my browser i get the following message: Cannot GET /api/v3 and {"status":"404","code":null,"title":"HTTP 404 Not Found","detail":null} . so i think the links can maybe wrong. has anyone a solution? many thanks forwards

0dc6dce5432b46456ffa607540ef80fd

hello, now i had following debug error: [DEBUG] 14:29:55 [fatal] Unknown exception: /usr/share/lua/5.2/json/decode/util.lua:35: unexpected character @ character: 1 0:1 [W] line: [DEBUG] 14:28:55: W can anybody help, pls? i don't understand whats wrong. thanks forwards

De916ec2f79d1ced59638e385f996e9d

Thank you very much for the VD. I'm having the same problem as the people below. Anyone found a solution?