Fibaro HomeCenter 3를 받고 사용하고 있던 Hubitat을 안전히 Migration 하기 위해서, 각을 세우고 있다. Zigbee와 Z-wave로 연결되는 디바이스들은 별 문제가 되지 않지만 IP로 연결되는 디바이스들이 문제이다.

ST/HE에서는 이러한 디바이스들을 지원하기 위해 Virtual Device가 있으며, 이러한 디바이스를 생성하기 위해 SmartApp도 있다. 보통 SmartApp은 디바이스 서비스 사업자의 클라우드 서비스에 연동할 수 있도록 계정 연결을 하고 Virtual Device를 생성하도록 작업되어 있다.

ST/HE의 SmartApp과 Device를 간단히 모식도를 그리면 이렇다. SmartApp은 Child SmartApp을 만들 수 있으며, SmartApp은 Device를 가질 수 있다. SmartApp에서 디바이스를 생성할 수도 있고, 삭제할 수도 있으며 attribute뿐만 아니라 이름 등의 정보도 업데이트가 가능하다.
심지어 SmartApp에서 디바이스 목록을 보고 디바이스를 선택하게 된다면 zigbee/z-wave 디바이스들의 attribute에 접근가능하고, 업데이트도 가능하다. (Homebridge 등의 SmartApp이 이러하다.)

ST/HE에서의 Device와 SmartApp은 샌드박스 안에 있는 개념이고, 허브의 글로벌한 값을 가져올 순 없는 것으로 알고 있다. 쉽게 볼 수 있는 예로 WebCore에 전역 변수가 있지만, WebCore에서만의 전역변수이고 WebCore가 아닌 다른 자동화 로직에서 절대 참조할 수 없다. HC3은 이러한 개념이 없다고 봐야하며, 어디서나 Global에 저장한 값을 가져올 수 있다. 또한 어디서나 디바이스의 ID만 안다면 다른 디바이스 가져와 사용할 수 있는 것으로 확인된다.

HC3에는 SmartApp은 없다. HC에는 Device의 영역이 한계가 없기 때문에 그런 것 같다. 제공되는 Plugin도 Device로 추가되지만, 실제적으론 SmartApp과 유사한 동작을 하는 것들이 있다. 마찬가지로 QuickApp에서 디바이스간의 통신도 가능한 것 같고, Scene의 Action으로 구성될 필요가 없어 보인다.

QuickApp 이라는 이름에서도 이것이 App인지 Device인지 헷갈리는 부분이다.

아직 HC3의 공식적으로는 QuickApp을 GUI 설정화면 이외에서 생성하는 방법은 없는 것으로 보이며, Fibaro 포럼의 jgab이라는 유저가 올린 fibaroapiHC3.lua 코드를 참고하면 api로 생성하는 방법이 있다. 포럼의 본 글은 HomeCenter 브라우저 콘솔에서 코딩하지 않도록 하기 위한 SDK 코드와 QuickApp을 잘 만들기 위한 팁들을 공유하고 있는 것이다.
일부분만 봤지만 HC3의 웹 대시보드 역시 HC3 Rest API를 이용해서 구성되어있는 것 같기 때문에 QuickApp API가 문서화만 되지 않았을 수 있다.

아래 설명부터 QD라고 축약해서 사용할 것인데, 이는 QuickApp Device의 축약어이다. QA는 Question and Answer 로 쓰이기 때문이다. (jgab도 그런 이유에 QD라고 쓴다고 한다.)

현재 글을 작성하는 시점으로 fibaroapiHC3.lua 최신 버전 v0.63에서 보면

  local function createQuickApp(args)
    local d = {} -- Our device
    d.name = args.name or "QuickApp"
    d.type = args.type or "com.fibaro.binarySensor"
    local body = args.code or ""
    local UI = args.UI or {}
    local variables = args.quickvars or {}
    local dryRun = args.dryRun or false
    d.apiVersion = "1.0"
    d.initialProperties = makeInitialProperties(body,UI,variables,args.height)
    if dryRun then return d end
    Log(LOG.SYS,"Creating device...")--..json.encode(d)) 
    if not d.initialProperties.uiCallbacks[1] then
      d.initialProperties.uiCallbacks = nil
    end
    local d1,res = api.post("/quickApp/",d)
    if res ~= 201 then 
      Log(LOG.ERROR,"D:%s,RES:%s",json.encode(d1),json.encode(res))
      return nil
    else 
      Log(LOG.SYS,"Device %s created",d1.id or "")
      return d1.id
    end
  end

POST {HC3-HOST}/api/quickApp 를 통해 QD를 생성하고 있음을 알 수 있다. 요청의 body는 위 부분에서 사용하는 코드를 전체적으로 보면 알 수 있는데, 결과적으로 웹 대쉬보드 Device 설정에서 QuickApp 을 다운로드하면 생기는 fqa 파일 내용이다.
fqa파일을 열어보면 JSON 포맷의 데이터가 있다.

{
  "name": "퀵앱 생성 테스트",
  "type": "com.fibaro.binarySwitch",
  "apiVersion": "1.0",
  "initialProperties": {
    "viewLayout": {
      "$jason": {
        "body": {
          "header": {
            "style": {
              "height": "0"
            },
            "title": "quickApp_device_57"
          },
          "sections": {
            "items": []
          }
        },
        "head": {
          "title": "quickApp_device_57"
        }
      }
    },
    "uiCallbacks": [],
    "mainFunction": "function QuickApp:onInit()\n    self:debug(\"onInit. Binary Switch QuickApp Test\")\nend ",
    "quickAppVariables": [
      {
        "name": "name",
        "value": "value"
      }
    ],
    "typeTemplateInitialized": true
  }
}

파일에는 개행 문자없이 한 줄로 표현되어있기 때문에 보기 좋게 개행을 추가하면 이렇다.
이름, 타입, 디바이스에 표현될 뷰, 뷰를 클릭할때 action (버튼, 슬라이드), lua 코드, variables 를 지정해서 생성한다.

타입은 몇 가지 웹에서 생성해보면 값을 알 수 있다. viewLayout 에 포함되는 quickApp_device_57 이런 값은 숫자에 의미가 있는지 모르겠지만 값이 어떻게 되든 문제는 없어보인다. QuickApp의 핵심인 lua 코드는 mainFunction에 있다. 디바이스에 필요한 코드를 넣어서 생성하면 된다.

POST /api/quickApp을 요청의 응답으로는 생성된 결과 디바이스 정보이며, 여기서 디바이스의 ID를 취득하여 서버에서 통신하면 될 것이다.

생성된 디바이스의 액션을 취하거나, 상태를 업데이트하기 위한 것이 필요할텐데 이것은 callAction api를 사용하면 된다.
POST /api/devices/{id}/action/{actionName} 이다. id는 디바이스 ID이고 actionName은 lua 코드에 있는 함수명을 지정하면 된다.

function QuickApp:setValues(power, energy)
    self:debug("setValues", power, energy)
    self:updateProperty("value", energy) 
    self:updateView("label1", "text", "Power: " .. power .. "W")
    self:updateView("label2", "text", "Energy: " .. energy .. "kWh")
end

위와 같은 코드가 있다면, 10번 QD에 대해서

curl 'http://userId:password@192.168.1.1/api/devices/10/action/setValues' \
  -d '{"args":["162","10"]}'

이렇게 한다면 162W와 10kWh (단위는 코드에서 임의로 표현하면 된다) 데이터를 QD에 업데이트 하도록 한 것이다. args가 함수의 파라메터이며 배열로 순서대로이다. 함수 내부에서 updatePropertyfibaro manual을 참고하면 된다.

분명히 이렇게 구성하다보면, QD를 수정해야할 일이 생길 것이다. 이 것은 /api/devices API를 사용하면 된다. 이 부분은 fibaro의 공식 문서에 있기 때문에 그것을 참고하면 된다.
Lua 코드만을 수정할 수 있는 방법은 없으며 device에 대한 전체 속성을 수정 해야한다.
그래서 수정이 필요하다면, GET /api/devices/{id}를 통해 device에 대한 현재 값을 조회한 후 그 값에서 수정할 lua 코드만 변경하여 PUT /api/devices/{id}로 업데이트하면 될 것이다.

ST/HE의 커넥터에서 직접 DTH를 설치해야하고, 경우에 따라 SmartApp도 업데이트가 필요했던 부분이 HC3는 커넥터 서버에서 모두 일괄 관리가 가능한 장점이 생겼다.

ps. QuickApp 생성할 때, 한글에 대해서 인코딩이 깨지는 것 같지만 추가 테스트가 필요해보인다.
ps. 아직 오픈되지 않은 zigbee에 대해서도 어떻게 수많은 zigbee 디바이스를 지원할지도 기대가 된다.