IMG_1598

不久前在 Youtube 上看到一則影片,主角只出一張嘴,就能透過 Siri 讓家裡的電器用品乖乖聽話,就像小時候的科幻片描述未來的居家生活,頗為神奇。只不過影片中並沒有說明實作的方法,只在影片下方留言中提到幾個關鍵字,引起了我的好奇。

從 iOS 開發者的角度來看,原以為是 iOS 10 的 Sirikit 的新功能,於是我嘗試呼叫 Siri ,得到的是以下的結果:

 

IMG_1599

Siri 回答提到「打理這個家」,大概能猜得到,iOS 使用 Homekit 控制家電 ,而 Siri 與 Homekit 整合已經是 iOS 10 內建的功能,所以 Siri 控制家電並非使用 Sirikit ,而是用 Homekit 來實現。換言之,所謂家電用品支援 Homekit 功能,就是除了能透過 iOS 10 內建的「家庭 App」來統一管理,並可自訂使用情境、場景與配件的設定,打造個人專屬的家電運作模式之外,還能透過 iOS 的 Siri 語音助理,「用講的」操控家電的部分功能。「家庭 App 管理家電」與「Siri 語音控制家電」兩項重點功能,就是 iOS 10 的 Homekit 智慧家電平台。

近年來有越來越多新的家電產品標榜「智慧家電」功能,但台灣民眾對這一塊的熱度不夠,目前市面上還不普及,現役家電產品也大多還能用個很多年,除非在裝修新房時就納入智慧家電的規劃,否則只有極少數的人為了享受「智慧家電生活」把家裏的電器產品全部換掉(據說有個社會名人就這樣搞,打造智慧家庭就花了四千萬台幣)。於是換個角度,有沒有辦法讓家裏面的現有家電,透過外掛手段來支援 Homekit 呢?答案是有的,價格也很低廉,只是要達到這樣的目標有一定的技術門檻,雖然不難,但也不算容易,因為不同的電器有不同的動作設定,納入 Homekit 之後更不一定支援家電原有的全部功能。

所以我可以理解為何一堆 Youtube 影片,尤其是中文的,大多沒有教學,畢竟有些實作步驟很有可能卡關,實作方式也會牽涉到特定的知識領域,寫了教學也不可能人人都能淺顯易懂。所以這篇文章並非新手教學,只會概略提出實作方式,除了幫自己做紀錄,也提供已有以下相關基礎知識,並且有興趣想嘗試的人做參考。

  • 會使用 Arduino IDE 撰寫單晶片韌體。
  • 略懂 Linux 終端機操作指令。

目標使用情境:以家裏運作多年的老冷氣機為例,利用 iOS 的 Homekit 功能來控制冷氣的基本功能「開」和「關」。

市售的傳統家用冷氣都有紅外線遙控器,但並不支援無線網路。所以要達到上述目標,實作目標分成兩大部分:

  • 實作一組可支援網路操控的自製紅外線 WIFI 遙控器
  • 在家裡的區域網路內,連接 Homekit 與自製的紅外線WIFI遙控器

一、支援 WIFI 網路操控的紅外線遙控器

這個部分教學就不少了,搜尋「Arduino+IRremote」就會跑出一堆。這裡再細分出兩階段:材料採購與軟體撰寫。

材料相當廉價,甚至於比你去夜市買一隻萬用遙控器還便宜。

  • MCU/SoC 晶片:首先是必須支援聯網功能的單晶片,ESP8266 系列當然是不二人選,直接用 NodeMCU V1.0 就可以了,或是使用體積更小、更便宜的 WEMOS D1 mini 也行。這東西越來越便宜,台灣一個才一百多元,對岸的淘寶更便宜,合台幣不到 80 元,CP 值爆表,屌打一堆動輒千元的物聯網模組。
  • 紅外線發射 LED :一顆才 2 元,台南市區的電子材料店約 10-15 元。因為發射時有方向性,可以併聯個2-3顆,每一顆朝不同的方向。
  • 電晶體:NPN 型,例如 2N3904,作用是放大紅外線發射訊號,一顆也是 2-5 元。

元件接法可參考這個網頁,自製紅外線搖控器的硬體配置就這樣而已,材料費才台幣一百多元。至於運作的電源,找條 Micro-USB 線連接 NodeMCU 與帶電的 USB 埠就行了(電腦/充電器/行動電源…)。

NodeMCU V1.0 電路接法

687474703a2f2f667269747a696e672e6f72672f6d656469612f667269747a696e672d7265706f2f70726f6a656374732f652f657370383236362d69722d7472616e736d69747465722f696d616765732f49522532305472616e736d69747465725f62622e706e67

WEMOS D1 mini 的電路接法,其實與 NodeMCU V1.0 相同,但體積更小。

WEMOS_D1_mini  

再來是軟體撰寫的階段。倘若真的不會寫程式,那…請自行 Google 市面上已整合 WIFI + 紅外線 + 軟體 APP 的產品:Broadlink RM Pro(市價約 NT 980.-),以及如何把這產品掛上 Homekit 的教學,就可以按上一頁離開本文章了。

軟體撰寫使用 Arduino IDE + Arduino Code 開發撰寫,加掛以下三方套件,至於程式碼內容就不說明了,套件範例都有。

  • IRremoteESP8266:ESP8266 驅動紅外線的套件。
  • WiFiManager:ESP8266 超級好用的 Wifi 連線套件。
  • <ESP8266mDNS.h>、<ESP8266WebServer.h>:ESP8266 Arduino Code 內建。讓 ESP8266 變成具備 DNS Name 的 WebServer,負責接收 HTTP Request 內容。

不過一開始我們不知道冷氣的紅外線指令的編碼內容,所以要買一顆紅外線接收器(我是買模組化的這個,理論上可以買更便宜的 LED 型),再用 IRremoteESP8266 提供的標準範例程式寫個 ESP8266 接收紅外線編碼的程式,學習原廠的搖控器就可取得紅外線的編碼內容,存成文字後就可以作為紅外線發射器的資料來源,可參考這篇文章的說明。

這個部分最終的目標為:在家裡的網路中隨便找一台電腦/平板/手機,打開瀏覽器,輸入網址就能驅動自製的紅外線發射器進行指定的動作,例如輸入 http://esp8266.local/airconditioner/on 就能讓自製遙控器發射「開冷氣」的紅外線編碼,http://esp8266.local/airconditioner/off 讓自製遙控器發射「關冷氣」的紅外線編碼。

當這個階段完成之後,只要把自製紅外線 WIFI 遙控器擺在冷氣(家電)可接收紅外線訊號的固定位置,就等於可以在家裡用電腦/平板/手機等裝置,用透過家裡的區域網路來控制家裡的冷氣開關,成功之後就可以寫個簡單的 App ,透過按按鈕或其他操作方式,來呼叫網址就行了。例如以下的幾個範例:

手機端的 Widget 工具:

IMG_1652

macOS 電腦端的應用程式:

2017-08-30-1.19.25

Windows PC 端的應用程式:

Image2 Image

Web 版(將網頁程式上傳到 ESP8266 的 SPIFF 檔案空間)。

esp8266local

其實「用裝置遙控 ESP8266 聯網裝置」的動作不一定要透過 HTTP 協定,有太多方式了,例如使用 MQTT 協定搭配國外免費的 Broker 服務,預設就能直接跨越家裡區網的限制,不論人在世界的哪個地方,拿起手機或平板執行 MQTT 客戶端程式,就能控制家裏的 ESP8266 聯網裝置,但也意味別人也有機會駭入你家,所以使用網路 MQTT 服務要非常小心,這部分就不多提了。

二、連結 iOS Homekit 與自製紅外線WIFI遙控器

這邊就進入重點了。目前雖然有 ESP8266-Homekit 方案,但似乎並沒有 Arduino Code 的形式,所以要客製化周邊設備有不小的難度。現在看到大部分實作的方式是透過一個叫「homebridge」的服務作為橋接器,由這個橋接器負責周邊設備與 Homekit 的溝通,實作重點在軟體服務的安裝與設定。

(1) 安裝 homebridge 橋接器服務

知道上述動作原理之後,實作過程就是找台電腦建立「homebridge 」橋接器,並在橋接器上建立虛擬周邊與包含執行網址的設定(開/關冷氣的動作網址)。網路上大部分的教學是把 homebridge 安裝在「樹莓派(Raspberry Pi)」上,也有少部分教學是安裝在 UbuntumacOS,或 Windows 。每種作業系統安裝 homebridge 方式雖然不太相同,但也是大同小異。

由於我沒有樹莓派(雖然便宜,但一台也要一兩千元),所以我是採用建立 Ubuntu 14.04 (VirtualBox 虛擬機)的方式,來安裝啟動 homebridge 服務。VirtualBoxUbuntu 作業系統也是免費下載,花費 0 元。與 Ubuntu 系出同門的 Debian 作業系統(正確說法為 Ubuntu 是 Debian 的一項分支),在安裝完 sudo 與 設定 sudoers 之後,也能使用以下相同的方式安裝 homebridge 服務。

Ubuntu 作業系統開啟終端機視窗,依序執行指令如下:

1. 執行 sudo apt-get update

如果出現以下的錯誤訊息:
E: 無法將 /var/lib/dpkg/lock 鎖定 - open (11: 資源暫時無法取得)
E: Unable to lock the administration directory (/var/lib/dpkg/), is another process using it?

可執行以下指令
sudo rm -rf /var/lib/dpkg/lock

2. 執行 sudo apt-get upgrade 等一段時間,這邊要等很久,14.04 虛擬機大概會跑10幾分鐘以上,甚至半個多小時。

如果一下子跑完,又說 xx 未被升級的話,可執行
apt-get dist-upgrade

3. 執行以下命令

sudo apt-get install -y samba screen git
sudo apt-get install curl
curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
sudo apt-get install -y nodejs
sudo npm install node-gyp
sudo apt-get install libavahi-compat-libdnssd-dev


4. 安裝 homebridge
執行 sudo npm install -g --unsafe-perm homebridge

不過 Ubuntu 14.04 很可能會遇到以下的錯誤訊息

nas@nas:~$ sudo npm install -g --unsafe-perm homebridge
/usr/bin/homebridge -> /usr/lib/node_modules/homebridge/bin/homebridge

> mdns@2.3.3 install /usr/lib/node_modules/homebridge/node_modules/mdns
> node-gyp rebuild

make: Entering directory `/usr/lib/node_modules/homebridge/node_modules/mdns/build'
CXX(target) Release/obj.target/dns_sd_bindings/src/dns_sd.o
make: g++: Command not found
make: *** [Release/obj.target/dns_sd_bindings/src/dns_sd.o] Error 127
make: Leaving directory `/usr/lib/node_modules/homebridge/node_modules/mdns/build'
gyp ERR! build error
gyp ERR! stack Error: `make` failed with exit code: 2

 

可執行以下五行指令修正問題

sudo rm -rf /usr/lib/node_modules/
sudo apt-get install build-essential
sudo apt-get install libkrb5-dev
sudo apt-get remove nodejs
sudo apt-get install nodejs

之後再執行一次  sudo npm install -g --unsafe-perm homebridge 試試看。


5. 測試 homebridge
輸入homebridge

回應
......
Scan this code with your HomeKit App on your iOS device to pair with Homebridge:

┌────────────┐
│ 031-45-154 │
└────────────┘

[2017-08-02 16:12:05] Homebridge is running on port 43761.

如果出現反白配對碼「 XXX-XX-XXX」的訊息,表示 homebridge 安裝完成。

螢幕快照 2017-08-05 上午12.51.04

這時候就可以打開 iOS 10 手機的「家庭 App」了,一路循指示開啟 iCloud 的「家庭」權限-->新增配件,就能看到有個叫「Homebridge」的裝置顯示在清單上。

IMG_1602

不過這個時候先別急著設定,因為橋接器還沒有掛上虛擬周邊可供選取。先按「取消」離開,回到 Ubuntu 電腦進行操作。

(2) 安裝 homebridge 插件

homebridge 插件的目的,就是建立虛擬周邊設備掛進 homebridge 橋接器服務,並設定虛擬周邊的動作指令。有上百種插件任君挑選,每一種插件都有不同的週邊設備作用方式。要選哪個插件可以到這裡搜尋

homebridge-plugin

插件的功能可說是玲瑯滿目,坦白說要搞懂插件的運作與設定方式實在不容易,因為每一種的作用與目的都不同,甚至超出「周邊家電」的既定印象。例如這個「homebridge-openweathermap-temperature」插件,就是模擬一個溫度計周邊,用來顯示 OpenWeather 天氣服務網站的某指定城市現在氣溫。

先用這個插件為例,安裝的方式為:

A. 開啟終端機,執行命令 sudo npm install -g homebridge-openweathermap-temperature

B. 在 ~/.homebridge/ 建立(或修改)config.json,文字內容如下:

{
  "bridge": {
    "name": "控制中心",
    "username": "AB:CD:EF:12:34:56",
    "port": 51826,
    "pin": "123-45-678"
  },
  "description": "HomeBridge HTTP Status Control",
  "accessories": [
    {
      "accessory": "OpenweathermapTemperature",
      "name": "台南市溫度",
      "url": "http://api.openweathermap.org/data/2.5/weather?q=Tainan&appid=[apikey需註冊OpenWeather帳號取得]"
    }
  ]
}

config_json

C.終端機執行 homebridge 指令

螢幕快照 2017-08-05 上午2.00.46

看到 Load x accessories... 以及配對的 XXX-XX-XX 訊息時,就表示 homebridge 和配件都成功掛載啟動了。

若要讓 homebridge 於每次 Ubuntu 開機時自動執行,請參考這裡

D. 回到 iOS 10 的「家庭 App」,依照畫面指示設定就行了。

IMG_1603

最後就能在「家庭 App」看到一個配件,內容顯示 OpenWeather 查詢的城市溫度。

也可以呼叫 Siri 用講的給你聽。不過因為是「家庭周邊配件」,問 Siri 的時候要問「家裏溫度」才會顯示配件數字,若是只問「溫度」或「室外溫度」,它就會找 iOS 內建的天氣預報服務,而不是 Homekit 。

IMG_1609  

搞懂如何掛載插件的方法後,接著就可以選擇適合的插件,透過 HTTP 網址來執行冷氣的開關動作了。我找到符合有「開」與「關」對應動作網址的插件是「homebridge-http

sudo npm install -g homebridge-http

接著編輯 config.json 內容,在「"accessories"」節點內插入以下內容:

{
  "accessory": "Http",
  "name": "冷氣",
  "switchHandling": "realtime",
  "http_method": "GET",
  "on_url": "http://[開冷氣的網址]",
  "off_url": "http://[關冷氣的網址]",
  "status_on": "ON",
  "status_off": "OFF",
  "service": "Switch",
  "sendimmediately": "",
  "username": "",
  "password": ""
}

螢幕快照 2017-08-05 上午2.52.02

重新執行 homebridge 之後,「家庭 App」就可以看到兩個配件按鈕。可以點擊冷氣配件按鈕進行開或關的動作。

IMG_1613

不過這個插件遇到網路問題時會發生找不到 callback 函數的 BUG 而跳出,修正方式: 

/usr/lib/node_modules/homebridge-http/index.js
從第 11 行加入
    function callback(error){
        if(error){
            console.log('HTTP function failed: %s', error.message);
        }
        else{
            console.log('HTTP function done with No Error...');
        }
    }

插件可以一直加掛進 homebridge 橋接器內,例如再繼續加掛「homebridge-httptemperaturehumidity」就可以透過 HTTP 協定取得家裏的 ESP8266+DHT22 溫濕度數值,並透過 Siri 語音控制這些周邊。

IMG_1598

sudo npm install -g homebridge-http-temperature-humidity

這個插件也有類似的問題,修正方式: 

1. 修改 /usr/lib/node_modules/homebridge-http-temperature-humidity/index.js
在 var res = request(this.http_method, this.url,{}); 與 if(res.statusCode > 400){ 之間加入

        var res = request(this.http_method, this.url,{});
        if (typeof res === 'undefined'){
          this.log('HTTP power function NOT succeeded : undefined');
          this.temperature = -1;
          this.humidity = -1;
          callback(null, this.temperature);
        }
	else if(res.statusCode > 400){

 

2. 修改 /usr/lib/node_modules/homebridge-http-temperature-humidity/node_modules/sync-request/index.js ,目的是修正可能因網路問題造成 Javascript 程式錯誤或 JSON.parse 方法卡死的現象,修改內容重點在「標記 throw error 方法」與「增加 resErr 變數」的判斷,才不至於讓錯誤結果誤進 JSON 解析程序產生其他問題。

'use strict';

var fs = require('fs');
var spawnSync = require('child_process').spawnSync || require('spawn-sync');
var HttpResponse = require('http-response-object');
require('concat-stream');
require('then-request');
var JSON = require('./lib/json-buffer');

Function('', fs.readFileSync(require.resolve('./lib/worker.js'), 'utf8'));

module.exports = doRequest;
function doRequest(method, url, options) {
  var req = JSON.stringify({
    method: method,
    url: url,
    options: options
  });
  var res = spawnSync(process.execPath, [require.resolve('./lib/worker.js')], {input: req});
  var resErr = 0;
  if (res.status !== 0) {
    console.log('doRequest res.stderr.toString: %s',res.stderr.toString());
    resErr = 1;
    //throw new Error(res.stderr.toString());
  }
  if (res.error) {
    if (typeof res.error === 'string') res.error = new Error(res.error);
    console.log('doRequest res.error === string ');
    resErr = 1;
    //throw res.error;
  }
  if (resErr === 0){
  	var response = JSON.parse(res.stdout);
  	if (typeof response === 'undefined'){
  		console.log('httptemperaturehumidity: response JSON is undefined');
  	}
  	else if (response.success) {
  		return new HttpResponse(response.response.statusCode, response.response.headers, response.response.body, response.response.url);
  	} else {
  		console.log('response not success: %s',response.error.message);
  		//throw new Error(response.error.message || response.error || response);
  	}
  }
}

若是 iPhone 6s 以後的設備(支援免插電源線呼叫 Siri),或是家裡擺一台 Homepod ,就能實現完全不需動手,回到家出一張嘴喊個 Siri 就行了,敲方便。

實際運作影片

成本總結:

  • NodeMCU x 1 : NT 120.-
  • 紅外線 LED / NPN 電晶體 x1 : 10元 有找

其他必備條件:

  • Micro USB 連接線
  • 個人電腦一台(撰寫 Arduino Code ,建置 Homebridge 環境)
  • 行動電源 或 USB 充電器 或 電腦的 USB 連接埠(可提供 5V USB 連接埠)
  • iPhone 手機一支或 iPad(需支援 iOS 10,最低要求為 iPhone 5 / iPad 4th / iPad min)
  • 家裡區域網路,與可連上 iCloud 的環境。

補充:

1. 電腦啟動時執行 homebridge(適用於樹莓派)

終端機中執行

$ sudo nano /etc/xdg/autostart/homebridge.desktop

填入以下內容:

[Desktop Entry]
Name=homebridge
Type=Application
Exec=lxterminal -e "homebridge"
Terminal=true
Comment=system monitoring tool.
Categories=Utility;

按 Ctrl + X 存擋離開。

2. 樹莓派升級到 Buster 版本後,nodejs 被強制升級到 10 版,npm 不會隨 nodejs 安裝。用 apt 安裝 npm 的版本是 5.x ,必須升級到 npm 6.x 才能支援 nodejs 10 。

$ sudo apt install npm
$ sudo npm install -g npm@6

3. homebridge 指定網卡服務

以樹莓派 3B/+/4 為例:樹莓派主機上有無線網路和有線網路,homebridge 只能在其中一個網路上啟動。若希望強制在指定的網卡上啟用服務時,必須在 config.json 內指定 mdns 參數,如下

{
  "mdns":{ "interface": "網路卡的 IP 位址,例如 192.168.1.100" },
  "bridge": {
   ... 省略...
  },
}

4. 其他可用插件

4.1 homebridge-http-temperature-sensor (網址)

功能說明:透過網址取得溫度數字。

安裝:
sudo npm install -g homebridge-http-temperature-sensor

config.json 範例

    {
      "accessory": "HTTP-TEMPERATURE",
      "name": "裝置溫度",
      "unit": "celsius",
      "getUrl": "API 網址",
      "pullInterval": 5000
    }

API 網址回應:溫度浮點數

應用:樹莓派的溫度(讀取 /sys/class/thermal/thermal_zone0/temp 內容並轉換為網址服務)。

 

arrow
arrow

    benjenq 發表在 痞客邦 留言(5) 人氣()