Created At

Oct 21, 2017

Last Update

Dec 14, 2018

Platforms

HC 2

Views

5391

Download

109

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.

 

19 Comments,  Want to add comment please login
De916ec2f79d1ced59638e385f996e9d

Hi, I get it to work by using the Lars Hultqvist trick. Use Variables insted of Predifined Variables. Anyone know what the slider does? /Oscar

204e33f4c63dbb959e6bb6a50ef29497

Can someone tell me what to do, to get it work? And be more specific if it something i dont do.. I have followed the instructions but i cant get it to work =(

204e33f4c63dbb959e6bb6a50ef29497

Hello! I am a total newbie and i dont get it to work, i have tried to do exactly as described but when i try to enter the scene number in tcp port at the virtual unit it says: "unable to create button - selected id already exists"

6839fd2885a10bb01ffeb31bd0e6453c

I had the same problem as Dominik. I removed mower1Command, mower1Status, mower1Token from "Predefined variables" and created new empty ones as "Variables". Then I restarted the virtual divice and everything works. Husqvarna Automover 430x 2017

D51f15045800db206626b8f2447d4595

fo couple of days I have this error : [DEBUG] 18:27:59: 2019-04-02 18:27:59.655530 [ fatal] LUA error: /usr/share/lua/5.2/json/decode/util.lua:35: unexpected character @ character: 1 0:1 [<] line: [DEBUG] 18:27:59: <