1. 程式人生 > >釘釘機器人呼叫函式計算實現serverless web服務:傳統門禁的簡單改造,懶惰癌的福音

釘釘機器人呼叫函式計算實現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元組。裝置三元組是裝置的唯一標示


裝置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 硬體安裝

  1. 首先把門禁遙控器的外殼拆開(大卸八塊)
  2. 用電烙鐵把開門按鈕的4個引腳從電路板上取下來
  3. 把2根公杜邦線的引腳焊接在電路板的2個焊點上,並把另一頭分別接在繼電器A、B端上
  4. 再拿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閘道器,便於進行訪問、流量控制等。

總結

阿里雲提供的一系列產品和服務,就像擰開水龍頭一樣,開啟即用。通過物聯網平臺,使用者可以快速地將原有傳統硬體產品迅速地進行升級改造,實現裝置迅速上雲。