使用Node.js、Twilio實現手機控制門鎖
試想一下,如果你忘了帶鑰匙,但你帶手機了,你就可以打開門鎖。或者,你還在往家趕,可你的朋友已經到你家門口,你通過手機遠程把家門打開,讓朋友先自己進去看會兒電視。這不是科幻,也不需要多先進的設備,而是自己動手開發出來的。
本文是基於我在波蘭的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-serialportWindows安裝指令。
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 = 0; 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欄裏,保存設置,試着發送一個短信!你的門鎖應該隨着短信自動打開或關閉。
祝大家玩的愉快,編程開心!