使用Node.js、Twilio實現手機控制門鎖
英文原文:Build Your Own Lockitron With Twilio, Arduino, and Node.js
試想一下,如果你忘了帶鑰匙,但你帶手機了,你就可以打開門鎖。或者,你還在往家趕,可你的朋友已經到你家門口,你通過手機遠程把家門打開,讓朋友先自己進去看會兒電視。這不是科幻,也不需要多先進的設備,而是自己動手開發出來的。
本文是基于我在波蘭的 Makerland 大會上的一次研討演講。這篇文章將會指導你如何通過手機控制你家的門鎖,而且是在不需要弄壞或改造門鎖的情況下實現。我們需要使用一個微控制器(Arduino Uno),一個電機,和 Node.js,用它們來實現通過短信遠程開鎖和關鎖。我是受到了 Twilio-powered Lockitron 的啟發。
步驟1:設備
部件
1. 一把門鎖
2. 膠帶,紙板
3. 電機(我使用的是 HS-322HD)
4. 微控制器(Arduino Uno) + 轉接線
準備
1. 從 http://arduino.cc/en/Main/Software 下載和安裝 Arduino IDE。
2. 從 http://nodejs.org/獲取并安裝
3. 從 https://ngrok.com/download 下載并安裝 ngrok (一個內網穿透程序)
我將使用 Arduino IDE 寫代碼并上傳到往微控制器里。我使用 node.js 腳本語言來和 Arduino 微處理器進行通信,利用 Express web 框架發送請求和相應請求。最后,我們使用 ngrok 將這個 Express web Server 暴露到外網,這樣我們就可以通過短信讓 Twilio 通信給你的微控制器。
現在,我們可以開始動手了,將我的微控制器跟門鎖鏈接上。
步驟2:裝配
我們將使用一個伺服電機控制門鎖。它就是一個馬達,動力軸需要能旋轉 180 度的那種,這樣我們才能讓門鎖轉開和閉合。
這個伺服馬達有三根線—火線(紅),零線(黑),控制線(通常是黃色或白色)。微處理器上有很多口,將馬達的火線連接 5v 電力口,零線接入 GND 地線口,控制線接入 Digital Pin 12 口,如下圖:
就這樣,我的馬達和微控制器連接到了一起,我們再將它和門鎖裝配到一起。
我喜歡用家里常用的東西來開發這些設備,但如果你能連接上一個 3D 打印機,你可以設計和打印出自己的鎖扣裝置。
因為是示范,我使用了紙板和膠帶來將電機和門鎖固定到一起。
將兩個金屬棍(或其它堅固的細棍)幫到馬達上,用東西墊一下
使用紙板(或其它比較硬的東西)當做門鎖和電機之間的連接填充物:
用膠帶將電機和門鎖綁到一起,確保是綁在正確的一面,讓電機轉動的方向是開鎖或關鎖的方向:
最后,我們將電動機軸固定到鎖鈕上:
現在我們已經將電機和門鎖死死的固定到一起了:
步驟3:編寫控制程序
電機和微控制器已經連接,Node.js 和 Arduino 等軟件也已經安裝了,現在我們需要運行下面的命令來安裝必要的 node.js 模塊。注意,如果你使用的是 Windows,你需要按照 node-serialport Windows 安裝指令。
npm install serialport twilio express
Node-Serialport 能夠讓你輕松的通過 Arduino 微控制器串口跟 Node.js 程序交互。我們將要使用它從 Twilio 里接受短信請求,并傳遞指令給 Arduino 微控制器讓它關鎖或開鎖。
Express 是一個簡單的 node.js web 框架。而 twilio 模塊能讓我們輕松的和 Twilio API 交互。
首先,我們打開 Arduino IDE,建立一個新的 Arduino 開發框架。第一步我們需要打開一個 9600 波特的串口連接,跟伺服馬達接通(12 口)。
#include Servo myservo;int servoPin = 12;int lock = ;int unlock = 180;void setup () { // initialize serial: Serial.begin (9600); myservo.attach (servoPin); myservo.write (lock); }
我們告訴微處理器,伺服馬達的 0 位置是“鎖住”,180 位置是“解鎖”。跟據你是如何將馬達跟門鎖捆綁的,也許需要交換調整這個位置。當微控制器啟動時,它會告訴馬達移動到“鎖住”位置。
接下來,我們將從串口連接上讀取一個字符,來判定是否應該調動馬達運行。
void loop () { // Recieve data from Node and write it to a String while (Serial.available ()) { char inChar = (char) Serial.read (); if(inChar == 'V'){ // end character for locking if (myservo.read () >= 90) { Serial.println ("L"); myservo.write (lock); delay (3000); } else { Serial.println ("U"); myservo.write (unlock); delay (3000); } } } }
Arduino 用來分析的串口輸入是來自 node.js 腳本的輸出,下面我們會介紹這個腳本。
在 Arduino IDE 開發環境外,我們用一個文本編輯器創建一個新文件,叫做 nodelock.js,文件的開頭是導入前面我們用 npm 安裝的模塊:
var twilio = require ('twilio'), SerialPort = require ("serialport") .SerialPort, express = require ('express');
下面我們將建立新 express web server 和 serialPort 連接:
var app = express ();var serialPort = new SerialPort ("/dev/tty.usbmodem1411", { baudrate: 9600 });
注意,我們指定了要連接的 USB 端口和波特率。你可能需要根據你的計算機的情況修改這個 USB 端口。你可以在 Arduino->Tools->Port 菜單上找到你的可用的 USB 端口號。
下面我們要設定 HTTP 相關信息,調用/sms
:
app.use (express.bodyParser ()); app.post ('/sms', twilio.webhook ('your auth token', { host:'foo.herokuapp.com', protocol:'https' }), function (req, res){ });
我們需要告訴 express 服務器通過/sms
地址接受 POST 請求,使用bodyParser
分析請求內容,獲取來自 Twilio 的短信信息。我們使用 twilio 的webhook
方法來驗證請求來源的可靠性。
現在,我們有了接收短信的地址,在試一下之前,我們應該檢查一下發短信的號碼是否是我們用來控制鎖的號碼。
app.post ('/sms', twilio.webhook ('your auth token', { host:'foo.herokuapp.com', protocol:'https' }), function (req, res){ if (req.body.From == "+12128675309") { console.log ("verified number!"); } else { console.log ("Wrong number!"); sendMessage (res, "Invalid number!"); } });
在驗證號碼的代碼段里,我們可以加入一個處理發送和相應 Arduino 微控制器上串口連接的功能。
serialPort.once ('data', function (data) { if (data.toString () .indexOf ('U') > -1) { //check if the Arduino returned a U for unlocking sendMessage (res, 'Unlocking!'); } else if (data.toString () .indexOf ('L') > -1) { sendMessage (res, 'Locking!'); } else { sendMessage (res, 'ERROR'); } console.log ('data received: ' + data); }); serialPort.write ("V", function (err, results) { if (err) { console.log ('err ' + err); } console.log ('results ' + results); });
這代碼看起來很雜亂,但這是相當直接的寫法。我們設定了事件處理器從微控制器里接受數據。這個事件處理器會檢查 Arduino 微控制器發送的是 “U” 還是 “L” ,我們獲取這個值,并用sendMessage
函數將信息反饋給用戶。
設定了事件處理器后,我們向 Arduino 微控制器里寫入“V”字符,告訴它接收到了短信,它現在應該打開/關閉門鎖。
我們現在往文件中加入sendMessage
函數,它有 2 個參數:res 和 message。
function sendMessage (res, message) { var resp = new twilio.TwimlResponse (); resp.message (message); res.type ('text/xml'); res.send (resp.toString ()); }
調用sendMessage
函數會給用戶發送 TwiML 響應信息。TwiML 是 XML 的子集,Twilio 用它來傳遞短消息指令。在我們這里,我們用它告訴 Twilio 響應我發送的 SMS 信息。用戶也許會發送“unlock”,程序會通過 Twilio SMS 回復 “Unlocking!”
我們已經配置了 SMS 處理器,最后只需要打開 SerialPort,啟動 Express web server,我們的應用就開發完了:
serialPort.open ( function () { app.listen (3000); console.log ('Listening on port 3000'); });
這就是所有我們需要的代碼。現在,如果你上傳我們之前寫的 Arduino 代碼,運行nodelock.js
,方法是在終端里執行node nodelock.js
,程序就啟動了。
如果你在開發的過程中遇到了錯誤,可跟這些代碼對比一下看是什么問題。
在創建并登陸你的 Twilio 帳號后,到 Twilio 控制臺,點擊號碼標簽,選擇你希望用來控制鎖的號碼。你會看到兩個框,語音請求地址(Voice Request URL)和消息請求地址(Messaging Request URL)。我們使用 Messaging Request URL 來傳遞我們的短信文本信息。
因為 Twilio 是通過 HTTP 請求通信的,我們需要有一個能從公網上訪問的地址,當有消息到達時,Twilio 會將信息傳遞跟這個地址。于是我們之前安裝的 ngrok 就起作用了。
等你的 node.js 服務器起來,開一個終端窗口,在你安裝 ngrok 的目錄下輸入./ngrok 3000
,這里你需要指定一個地址,通過它,外部服務能訪問你的本地服務器。在這個地址后面跟上/sms
,填入 Twilio Messaging Request URL 欄里,保存設置,試著發送一個短信!你的門鎖應該隨著短信自動打開或關閉。
祝大家玩的愉快,編程開心!