釘釘機器人呼叫函式計算實現serverless web服務:傳統門禁的簡單改造,懶惰癌的福音
本文通過釘釘機器人呼叫函式計算實現的serverless web服務,打通物聯網平臺,和樹莓派實時通訊。實現了將原有傳統的磁吸門禁,改造成可以由釘釘來控制開門的簡單應用。
場景
由於本部門擁有獨立封閉的空間,在大門口配置了磁吸玻璃門,因此規定在工作期間出入需要隨手關門,以保證工作環境的私密性和安全性。但前臺並沒有小妹,這樣對於來訪客人就不是特別方便,往往需要電話通知接待者到大門口來接,要麼接待者向管理員要來無線遙控器來開門(tuo ku zi fang pi)。這對於我這種重度懶惰病患者來說,簡直是種折磨。So...
思路
是否可以由樹莓派模擬按動無線門禁遙控器的按鈕來開門?
經過對無線遙控器的暴力拆解,發現遙控器的開門按鈕是由一個有4個引腳的貼片按鈕構成。經過試驗,只需把這2個介面短路,就相當於按下按鈕的動作。因此可以在上面接駁一個繼電器,由樹莓派控制繼電器來實現遙控器的按鈕接通。圖參考3.1節
目標: 將有經常需要接待的人(重度懶惰病患者)加入到公司某個內部釘釘群中,有來訪者需要開門時,直接向群機器人傳送"開門",門禁就會開啟。
實現方式: 在釘釘群加入一個自定義的outgoing機器人,向機器人傳送指令後,遠端HTTP POST呼叫函式計算服務,函式計算向物聯網平臺的Topic上送訊息,而訂閱此Topic的樹莓派會在收到訊息後開啟繼電器開關,讓無線遙控器的按鈕短路,傳送無線訊號讓門禁開啟。
成本估算
物聯網平臺:
使用基礎版產品免費
函式計算:
呼叫次數:每月前 100 萬次函式呼叫免費。
執行時間:每月前 400000(GB*秒) 費用免費。唯一可能產生費用的就是極少量的網路使用費
準備
物料準備
- 樹莓派
- 一路繼電器
- 門禁無線遙控器
- 母對母杜邦線3根
- 公對公杜邦線2根
阿里雲環境準備
- 物聯網平臺
- 函式計算
- 日誌服務(可選)
操作步驟
1 雲端開發
1.1 物聯網平臺
登入阿里雲控制檯,進入物聯網平臺控制面板
1.1.1 新建產品
進入裝置管理,建立產品,選擇基礎版或高階版都可以,本例項使用基礎版就可以滿足基本要求。
系統會自動建立3個Topic,我們需要使用 /ProductName/${deviceName}/get,作為裝置訂閱訊息的Topic。
1.1.2 裝置管理
在產品中新增裝置,並獲得裝置的3元組,在2.3節的裝置程式碼的編寫時需要使用此3元組。裝置三元組是裝置的唯一標示
1.2 函式計算
函式計算可以通過flask web工程來實現serverless,我們可以直接使用url去訪問和呼叫函式。好處在於,直接在函式計算裡編寫程式碼即可,而省去了購買ECS及搭建相應的執行環境,使用起來非常方便。
通過使用http觸發器,函式計算可提供 http://${account-id}.${region}.fc.aliyuncs.com/2016-08-15/proxy/$(serviceName)/$(functionName)/
來訪問呼叫函式。
1.2.1 新建服務
新建服務 iot-demo,如果需要記錄和回溯函式執行的日誌,則需要開通日誌服務,並配置好日誌倉庫。
1.2.2 新建函式
新建函式,使用模版 flask-web,函式名和觸發器填寫 officegate,執行環境選擇python2.7
1.2.3 函式程式碼
# -*- coding: utf-8 -*-
from flask import Flask
from flask import request
from flask import make_response
import logging
from aliyunsdkcore import client
from aliyunsdkcore.request import RpcRequest
import base64
try:
from urllib.parse import urlparse
except:
from urlparse import urlparse
app = Flask(__name__)
base_path = ''
return_string='''{
"msgtype": "text",
"text": {
"content": "%s"
}
}'''
# 引數定義
options = {
'productKey': '', # 裝置標識三元組
'deviceName': '', # 裝置標識三元組
'accessKeyId': '',
'accessKeySecret': '',
'token': '12345678', # Dingding Outgoing token
}
clt = client.AcsClient(options['accessKeyId'], options['accessKeySecret'], 'cn-shanghai')
# 推送訊息到IoT Hub Topic
def pushMsg(msg):
request = RpcRequest('Iot', '2018-01-20', 'Pub')
request.set_accept_format('json')
request.add_query_param('ProductKey',options['productKey'])
request.add_query_param('TopicFullName','/' + options['productKey'] + '/' + options['deviceName'] +'/get') #訊息傳送到的Topic全名
request.add_query_param('MessageContent',base64.b64encode(msg)) #Base64
request.add_query_param('Qos',0)
result = clt.do_action_with_exception(request)
logging.info('result : ' + result)
# 健康檢查
@app.route('/', methods=['GET', 'POST'])
def home():
resp = make_response('I am ok!', 200)
return resp
# 對應 DingDing outgoing URL
@app.route('/dingbot',methods=['POST'])
def bot_receive() :
token=request.headers.get('token')
data=request.get_json()
logging.debug("token="+token+"\nmessage:"+str(data))
msgtype=data.get("msgtype")
if token != options['token'] and msgtype != "text" :
return make_response("error",403)
content=str(data["text"]["content"])
senderId=data["senderId"]
senderNick=data["senderNick"]
logging.info('%s(%s) talk: %s' % (senderNick,senderId,content))
pushMsg(content.strip())
ret = return_string % "門開了"
resp = make_response(ret,200)
resp.headers['Content-Type']="application/json; charset=utf-8"
return resp
# 函式計算主入口
def handler(environ, start_response):
parsed_tuple = urlparse(environ['fc.request_uri'])
li = parsed_tuple.path.split('/')
global base_path
if not base_path:
base_path = "/".join(li[0:5])
return app(environ, start_response)
程式碼建立完成後,在程式碼編輯框下方的除錯Http觸發器,可以獲得呼叫的url。
注意,我們程式碼里路由入口是/dingbot
因此,實際的訪問網址應該是:https://$(account-id).cn-hangzhou.fc.aliyuncs.com/2016-08-15/proxy/iot-demo/officegate/dingbot
2 釘釘機器人的配置
如圖所示,新增自定義機器人時,需要勾選中 是否開啟Outgoing機制,在POST地址裡,把上一節中的url貼上進來,而Token必須和函式計算程式碼裡引數配置的一致,本例中是12345678
。
新增成功後,嘗試著給釘釘機器人發指令“開門”,如果機器人能迴應“門開了”,那說明函式計算已經可以正常提供服務。
3 裝置端開發
3.1 硬體安裝
- 首先把門禁遙控器的外殼拆開(大卸八塊)
- 用電烙鐵把開門按鈕的4個引腳從電路板上取下來
- 把2根公杜邦線的引腳焊接在電路板的2個焊點上,並把另一頭分別接在繼電器A、B端上
- 再拿3根母杜邦線,VCC、GND、IN分別接到樹莓派GPIO介面的4、6、16引腳上。
3.2 環境準備
我們在樹莓派上使用python2.7作為開發語言。安裝阿里雲物聯網的SDK:
pip install aliyun-python-sdk-iot-client
3.3 程式碼開發
gate-demo.py 內容如下:
# -*- coding: utf-8 -*-
import json
from time import sleep
import RPi.GPIO as GPIO
import aliyunsdkiotclient.AliyunIotMqttClient as iot
# 引數配置
options = {
'productKey':'', # 裝置三元組
'deviceName':'', # 裝置三元組
'deviceSecret':'', # 裝置三元組
'port':1883,
'host':'iot-as-mqtt.cn-shanghai.aliyuncs.com',
'gate_pin':23 #in 接GPIO 23針腳
}
# 訂閱的IoT Hub Topic
SUBSCRIBE_TOPIC = '/'+options['productKey']+'/'+options['deviceName']+'/user/get'
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
# 設定GPIO介面是輸出,預設低電平
GPIO.setup(options['gate_pin'],GPIO.OUT,initial=GPIO.LOW)
# 開門
def openGate() :
GPIO.output(options['gate_pin'],GPIO.HIGH) # 開啟高電平
sleep(0.8)
GPIO.output(options['gate_pin'],GPIO.LOW) # 恢復低電平
# 收到釋出的訊息回撥
def on_message(client, userdata, msg):
print(msg.payload)
if msg.payload=='開門':
openGate()
def on_connect(client, userdata, flags_dict, rc):
print("Connected with result code " + str(rc))
# 訂閱訊息
client.subscribe(topic=SUBSCRIBE_TOPIC)
def on_disconnect(client, userdata, flags_dict, rc):
print("Disconnected.")
if __name__ == '__main__':
# IoT 初始化
client = iot.getAliyunIotMqttClient(options['productKey'], options['deviceName'], options['deviceSecret'], secure_mode=3)
client.on_connect = on_connect
client.on_message = on_message
client.connect(host=options['productKey'] + '.' + options['host'], port=options['port'], keepalive=60)
client.loop_forever()
4 測試執行
4.1 裝置端執行
在py-demo資料夾下執行
python gate-demo.py
4.2 釘釘傳送訊息
在釘釘群上 @機器人,傳送“開門”指令,如果函式計算執行正常,則應能收到機器人“門開了”的應答。
4.3 雲端檢視上送訊息
在函式計算裡的日誌查詢介面中,可以看到程式執行時記錄的日誌:
在物聯網平臺的裝置的Topic列表中,可以看到收到了函式計算髮布的訊息:
4.4 測試結果
樹莓派的python程式打印出日誌,繼電器的訊號燈閃動,同時遙控器發出無線指令,大門磁吸門禁收到訊號後開啟。
後續
本例只是一個基於物聯網的簡單用例,並未考慮過多的安全問題。下一步可以對安全性進一步完善,例如,授權和控制誰能夠進行開門等。此外,提高系統的安全性,還引入API閘道器,便於進行訪問、流量控制等。
總結
阿里雲提供的一系列產品和服務,就像擰開水龍頭一樣,開啟即用。通過物聯網平臺,使用者可以快速地將原有傳統硬體產品迅速地進行升級改造,實現裝置迅速上雲。