Actions on Google から SLACK へ ②

GoogleNest(Home) に話しかけた内容を、オリジナルデバイスへの指示としてサーバで受取り、SLACKへコマンドとして投稿を行う部分を作成する。
以下の図の赤枠の部分。

スマートホームサービス用サーバの立上げ

前の記事 からの続き。
Action on GoogleHome からデバイスの操作指示を受けて、その内容をslackに書込みするサーバの作成。
本来であれば、自社の製品等をコントロールするサーバとして動作させるのだと思います。
今回は、ソースコードはpythonで書くこととして、flaskを使用してサーバを立てることとします。

サーバ処理のソースコード

サーバの処理用のサンプルコードです。
さしあたり、動かすだけならこれで大丈夫です。
config.cfg ファイルの内容は、ソースから必要な項目を設定してください。
ソースコードは、コメントを参考にしていただければ、ある程度わかると思います。
詳細は、こちらのページ がわかりやすいと思います。

<main.py>

import sys
import json
import io
import requests
from flask import Flask, request, jsonify

app = Flask(__name__)
app.config["JSON_AS_ASCII"] = False  #文字コードをUTF8に
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')

# 設定ファイルの読み込み
app.config.from_pyfile('config.cfg')

#SLACK WebHook URL
SLACK_URL = app.config['SLACK_URL']

### SLACK に送る ###
def goSlack( str ):
    requests.post(SLACK_URL, data=json.dumps({
        "text" : str,
    }))

#########################################
###  動作定義をGoogleに送るJSON読込み ###
#########################################
# 電気
with open('light.json', 'r', encoding='utf-8') as f:
    denki_sync = json.load(f, strict=False)   
# テレビ
with open('tv.json', 'r', encoding='utf-8') as f:
    tv_sync = json.load(f, strict=False)

#デバイスの定義
DEV_LIGHT     = "10"
DEV_TV        = "20"

# デバイスリスト登録
dev = [ denki_sync, tv_sync ]

##########################
###  実行のメイン処理  ###
##########################
def executecmd( device_id, execute ):

    ### 電気 ###
    if device_id == DEV_LIGHT:
        if execute["command"] == "action.devices.commands.OnOff":   # つける / 消す
            if execute["params"]["on"]:
                goSlack( "電気をつけて" )
            else:
                goSlack( "電気を消して" )

    ### テレビ ###
    elif device_id == DEV_TV:
        if execute["command"] == "action.devices.commands.OnOff":   # つける / 消す
            if execute["params"]["on"]:
                goSlack( "テレビをつけて" )
            else:
                goSlack( "テレビを消して" )
        elif execute["command"] == "action.devices.commands.selectChannel":  # チャンネル
            ch = execute["params"]["channelNumber"]
            goSlack( "テレビのチャンネルを" + ch + "にして" )
        elif execute["command"] ==  "action.devices.commands.volumeRelative":  # 音量  調整
            lv = execute["params"]["relativeSteps"]
            if lv > 0:
                goSlack("テレビの音量を" + str(lv) + "上げて")
            else:
                goSlack("テレビの音量を" + str(abs(lv)) + "下げて")

    return


############################
###  Googleとの通信処理  ###
############################
@app.route("/your_service/gran/")
def gran():
    # 認証したことにして、必要なリダイレクトだけ行えるようにする
    # 本来は、何らかの認証を行うべき
    req = request.args
    redirecturi = req.get('redirect_uri') + "?code=" + app.config['CODEX']  + "&state=" + req.get('state')
    ret_str = "<!DOCTYPE html><html lang=\"ja\">"
    ret_str += "<BODY><A HREF=\"" + redirecturi + "\">redirecturi</A></BODY></HTML>"
    return ret_str

@app.route("/your_service/talken/", methods=["POST"])
def talken():
    # 適当にトークンぽいものを返しておく
    if request.form['grant_type'] == "authorization_code":
        ret_str = {"token_type": "Bearer","access_token": app.config['CODEX'] , "refresh_token": app.config['CODEXRE'], "expires_in": app.config['EXPIREIN'] }
    if request.form['grant_type'] == "refresh_token":
        ret_str = {"token_type": "Bearer", "access_token": app.config['CODEX'] , "expires_in": app.config['EXPIREIN'] }
    return jsonify(ret_str)

@app.route("/your_service/intent/", methods=["GET","POST"])
def intent():

    requestId = request.json['requestId']
    inputs = request.json['inputs']
    intent = inputs[0]["intent"]

    # SYNC
    if intent == "action.devices.SYNC":
        return jsonify( {'requestId': requestId, "payload": { "agentUserId": app.config['AGENTUSERID'], "devices": dev } })
    
    # EXECUTE
    elif intent == "action.devices.EXECUTE":
        command = inputs[0]["payload"]["commands"][0]
        device_id = command["devices"][0]["id"]
        execute = command["execution"][0]

        executecmd( device_id, execute )

        return jsonify({'requestId': requestId, "payload": { "commands":  [{"ids": [device_id], "status": "SUCCESS", "states":{"online":True}}]}})

    # QUERY
    if intent == "action.devices.QUERY":
        # onlineであることだけを返す
        devicelist = {}
        for deviceinfo in inputs[0]["payload"]['devices']:
            devicelist |= { deviceinfo["id"] : { "online": True, "on": True }} 
        return jsonify({'requestId': requestId, "payload": { "devices": devicelist } })
    

##################
### FLASK 実行 ###
##################
if __name__ == "__main__":
    app.run(debug=False)
<light.json>

{
    "id": "10",
    "type": "action.devices.types.LIGHT",
    "traits": [
        "action.devices.traits.OnOff"
         ],	
    "name": {
        "defaultNames": [
            "電気"
        ],
        "name": "電気",
        "nicknames": [
            "ライト"
            ] 
    },
    "willReportState": false,
    "roomHint": "リビング",
    "attributes": {
        "commandOnlyOnOff": true,
        "commandOnlyBrightness": true
    },
    "deviceInfo": {
        "manufacturer": "サンプル",
        "model": "light",
        "hwVersion": "1.0",
        "swVersion": "1.0"
    },	
    "customData": {}
}
<tv.json>

{
    "id": "20",
    "type": "action.devices.types.TV",
    "traits": [
        "action.devices.traits.OnOff",
        "action.devices.traits.Channel",
        "action.devices.traits.Volume"
    ],
    "name": {
        "name": "テレビ",
        "defaultNames": [
            "テレビ"
        ],
        "nicknames": [
            "テレビ"
        ] 
    },
    "roomHint": "リビング",
    "willReportState": false,
    "attributes": {
        "availableChannels": [
            {
                "number": "0"
            },
            {
                "number": "1"
            },
            {
                "number": "2"
            },
            {
                "number": "3"
            },
            {
                "number": "4"
            },
            {
                "number": "5"
            },
            {
                "number": "6"
            },
            {
                "number": "8"
            },
            {
                "number": "10"
            }
        ],
        "orderedInputs": false,
        "volumeMaxLevel": 25,
        "volumeCanMuteAndUnmute": false,
        "levelStepSize": 3,
        "commandOnlyVolume": true,
        "supportActivityState": false,
        "supportPlaybackState": false
    },
    "deviceInfo": {
        "manufacturer": "sample",
        "model": "xx",
        "hwVersion": "1.0",
        "swVersion": "1.0"
    }
}

これを Flask で実行する。
続いて、Actions on Google から SLACK へ ③へ

コメント

タイトルとURLをコピーしました