天天看點

釘釘機器人調用函數計算實作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 硬體安裝

  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網關,便于進行通路、流量控制等。

總結

阿裡雲提供的一系列産品和服務,就像擰開水龍頭一樣,打開即用。通過物聯網平台,使用者可以快速地将原有傳統硬體産品迅速地進行更新改造,實作裝置迅速上雲。