sakura.io、駅すぱあとWebサービスを連携させたアプリケーション作成
以下の画像の「Webサービス連携」部分を説明します。
手順
- 駅情報を取得してみる
- 時刻表をslackに流してみる
駅情報を取得してみる
まず手始めに、node-redで駅すぱあとWebサービスにアクセスし、駅情報をデバッグウィンドウに表示してみましょう。
フローの読み込み
以下のjsonデータをコピーします。
[
{
"id": "19b0bb6c.855355",
"type": "comment",
"z": "587a8026.d6a8e",
"name": "駅取得",
"info": "",
"x": 90,
"y": 180,
"wires": []
},
{
"id": "6a66ce57.3cff9",
"type": "http request",
"z": "587a8026.d6a8e",
"name": "get station",
"method": "GET",
"ret": "obj",
"url": "",
"tls": "",
"x": 450,
"y": 220,
"wires": [
[
"a831f7a0.143f68"
]
]
},
{
"id": "fd0d2f59.0b0a5",
"type": "function",
"z": "587a8026.d6a8e",
"name": "set url",
"func": "var stationName = msg.payload\nvar url = encodeURI(context.global.ekispertWebServiceEndpoint + \"/v1/json/station?key=\" + context.global.ekispertWebServiceKey + \"&type=train&limit=1&name=\" + stationName)\nvar newMsg = {\n url: url\n}\nreturn newMsg",
"outputs": 1,
"noerr": 0,
"x": 310,
"y": 220,
"wires": [
[
"6a66ce57.3cff9"
]
]
},
{
"id": "53926285.dfebfc",
"type": "inject",
"z": "587a8026.d6a8e",
"name": "",
"topic": "stationName",
"payload": "なんば",
"payloadType": "str",
"repeat": "",
"crontab": "",
"once": false,
"x": 150,
"y": 220,
"wires": [
[
"fd0d2f59.0b0a5"
]
]
},
{
"id": "a831f7a0.143f68",
"type": "function",
"z": "587a8026.d6a8e",
"name": "set station",
"func": "context.global.stationName = msg.payload.ResultSet.Point.Station.Name\ncontext.global.stationCode = msg.payload.ResultSet.Point.Station.code\n\nreturn {\n payload: {\n stationName: context.global.stationName,\n stationCode: context.global.stationCode\n }\n}",
"outputs": 1,
"noerr": 0,
"x": 630,
"y": 220,
"wires": [
[
"d488d6ff.bfd1c8"
]
]
},
{
"id": "d488d6ff.bfd1c8",
"type": "debug",
"z": "587a8026.d6a8e",
"name": "",
"active": true,
"console": "false",
"complete": "payload",
"x": 810,
"y": 220,
"wires": []
},
{
"id": "8dd4c0c2.b8756",
"type": "inject",
"z": "587a8026.d6a8e",
"name": "Init",
"topic": "",
"payload": "",
"payloadType": "date",
"repeat": "",
"crontab": "",
"once": true,
"x": 110,
"y": 120,
"wires": [
[
"ab2b57e3.824908"
]
]
},
{
"id": "ab2b57e3.824908",
"type": "function",
"z": "587a8026.d6a8e",
"name": "set variables",
"func": "// 定数\ncontext.global.WebHookURL = \"!!! slackのwebhook urlを記入 !!!\"\ncontext.global.ekispertWebServiceKey = \"!!! 駅すぱあとwebサービスのアクセスキーを記入 !!!\"\ncontext.global.ekispertWebServiceEndpoint = \"http://api.ekispert.jp\"\n\n// 変数\ncontext.global.upperlimit = 0\ncontext.global.lightSensorOutput = 0\ncontext.global.stationCode = \"\"\ncontext.global.stationName = \"\"\ncontext.global.isLightOffNow = false\ncontext.global.isLightOffBefore = false\n",
"outputs": "0",
"noerr": 0,
"x": 270,
"y": 120,
"wires": []
},
{
"id": "def1fb54.561a68",
"type": "comment",
"z": "587a8026.d6a8e",
"name": "グローバル変数の定義",
"info": "",
"x": 140,
"y": 80,
"wires": []
}
]
メニュー > 読み込み > クリップボード をクリックし、先ほどコピーしたjsonデータを貼り付けて読み込み
を押します。
フローが読み込まれるので、適当な位置に置きます。
ノードの編集
グローバル変数をセットします。
set variables
ノードをダブルクリックし、ノードの編集を行います。context.global.ekispertWebServiceKey
の値を、当日お伝えするアクセスキーに置き換えます。
フローの実行
画面右上にあるデプロイ
をクリックして、フローを保存します。
timestampノードのをクリックして、デバッグウィンドウになんば
と表示されていたら成功です。
照度センサの値をトリガに駅の時刻表をslackに流してみる
slackのbot作成
駅の時刻表をつぶやいてくれるslack botを作成します。
https://slack.com/apps にアクセスします。
画面右上のSign in
をクリックし、handson20170623
を入力してcontinue
をクリックします。
メールアドレスとパスワードを入力してsign in
をクリックします。
以下の画面中央の検索窓にincoming webhook
と入力し、一番上に出てきたintegrationをクリックします。
Add Configration
をクリックします。
Post to Channel
に#random
チャンネルを選択してAdd Incoming Webhooks Integration
をクリックします。
以下の画面にありますWebhook URL
は後ほど利用するので、コピーしておくと良いです。
自分が設定したbotかどうかわかりやすくするために、Customize Name
やCustomize Icon
を変更してSave Settings
をクリックします。
slackの処理ノードを追加
メニュー > 処理ノードの追加削除 をクリックします。
処理ノードを追加
というタブをクリックし、検索窓にnode-red-contrib-slack
と入力して、一番上に表示された処理ノードをインストールします。
フローの読み込み
以下のjsonデータをコピーします。
[{"id":"bcd4302f.5a8ab","type":"websocket in","z":"fafa05fa.7df188","name":"Recieve data","server":"","client":"bcdfa2bd.f3d8d","x":110,"y":200,"wires":[["dc7908db.6694f8","add1cfe4.1c753"]]},{"id":"eb3ecbea.1024c8","type":"function","z":"fafa05fa.7df188","name":"Set light value","func":"context.global.lightSensorOutput = msg.payload.payload.channels[0].value;\ncontext.global.upperlimit = msg.payload.payload.channels[1].value;\ncontext.global.isLightOffBefore = context.global.isLightOffNow\nvar newMsg = {\n payload: context.global.lightSensorOutput + \" and \" + context.global.upperlimit\n}\n\nreturn newMsg","outputs":"1","noerr":0,"x":180,"y":320,"wires":[["8cccb387.f68da"]]},{"id":"dc7908db.6694f8","type":"json","z":"fafa05fa.7df188","name":"","x":270,"y":200,"wires":[["7e8ec163.9d985"]]},{"id":"7e8ec163.9d985","type":"switch","z":"fafa05fa.7df188","name":"Filter keepalives","property":"payload.type","propertyType":"msg","rules":[{"t":"neq","v":"keepalive","vt":"str"}],"checkall":"true","outputs":1,"x":440,"y":200,"wires":[["eb3ecbea.1024c8"]]},{"id":"add1cfe4.1c753","type":"debug","z":"fafa05fa.7df188","name":"","active":true,"console":"false","complete":"payload","x":270,"y":260,"wires":[]},{"id":"2ef8f9b.56f8606","type":"comment","z":"fafa05fa.7df188","name":"sakura.ioから照度センサの値を取得","info":"","x":250,"y":160,"wires":[]},{"id":"8cccb387.f68da","type":"switch","z":"fafa05fa.7df188","name":"","property":"lightSensorOutput","propertyType":"global","rules":[{"t":"gt","v":"upperlimit","vt":"global"},{"t":"lte","v":"upperlimit","vt":"global"}],"checkall":"true","outputs":2,"x":350,"y":320,"wires":[["5dfd702c.795ef"],["7525453c.80e1ac"]]},{"id":"5dfd702c.795ef","type":"function","z":"fafa05fa.7df188","name":"set boolean","func":"context.global.isLightOffNow = true;\n\nvar newMsg = {\n payload: \"now:\" + context.global.isLightOffNow + \",before:\" + context.global.isLightOffBefore\n}\n\nreturn newMsg;","outputs":1,"noerr":0,"x":510,"y":300,"wires":[["999500f9.ec1de"]]},{"id":"7525453c.80e1ac","type":"function","z":"fafa05fa.7df188","name":"set boolean","func":"context.global.isLightOffNow = false;\n\nvar newMsg = {\n payload: \"now:\" + context.global.isLightOffNow + \",before:\" + context.global.isLightOffBefore\n}\n\nreturn newMsg;","outputs":1,"noerr":0,"x":510,"y":340,"wires":[["999500f9.ec1de"]]},{"id":"999500f9.ec1de","type":"debug","z":"fafa05fa.7df188","name":"","active":true,"console":"false","complete":"payload","x":690,"y":320,"wires":[]},{"id":"e3b47492.258588","type":"inject","z":"fafa05fa.7df188","name":"","topic":"","payload":"","payloadType":"date","repeat":"2","crontab":"","once":false,"x":130,"y":420,"wires":[["a4fadca1.d23f"]]},{"id":"286334de.dc3cec","type":"http request","z":"fafa05fa.7df188","name":"get direction","method":"GET","ret":"obj","url":"","tls":"","x":730,"y":420,"wires":[["9b91ddbb.ee919"]]},{"id":"b7ad5715.cdacf8","type":"function","z":"fafa05fa.7df188","name":"set url","func":"var newMsg = {\n url: context.global.ekispertWebServiceEndpoint + \"/v1/json/station/timetable?key=\" + context.global.ekispertWebServiceKey + \"&stationCode=\" + context.global.stationCode\n}\nreturn newMsg;","outputs":1,"noerr":0,"x":570,"y":420,"wires":[["286334de.dc3cec"]]},{"id":"3984eecb.9b7a02","type":"http request","z":"fafa05fa.7df188","name":"get timetable","method":"GET","ret":"obj","url":"","tls":"","x":290,"y":480,"wires":[["9e64958a.3acf88"]]},{"id":"9b91ddbb.ee919","type":"function","z":"fafa05fa.7df188","name":"set url","func":"var newMsg = {\n url: \"http://api.ekispert.jp/v1/json/station/timetable?key=wC4SR9ETBhBcJ3Bv&stationCode=\" + context.global.stationCode + \"&code=1\",\n}\nreturn newMsg;","outputs":1,"noerr":0,"x":130,"y":480,"wires":[["3984eecb.9b7a02"]]},{"id":"9e64958a.3acf88","type":"function","z":"fafa05fa.7df188","name":"format message","func":"var hourTable = msg.payload.ResultSet.TimeTable.HourTable;\nvar times = [];\nvar displayTimes = [];\nvar stationName = msg.payload.ResultSet.TimeTable.Station.Name;\nvar lineName = msg.payload.ResultSet.TimeTable.Line.Name;\nvar direction = msg.payload.ResultSet.TimeTable.Line.Direction;\nvar minuteAfter = 20;\n\n// 現在時刻の取得\nvar now = new Date();\n\n// 現在時刻から○分後の時刻を取得\nvar timeAfter = new Date();\ntimeAfter.setMinutes(timeAfter.getMinutes() + minuteAfter);\n\n// 時刻表をtimes変数に格納\nfor(var i = 0; i < hourTable.length; i++ ) {\n for(var j = 0; j < hourTable[i].MinuteTable.length; j++) {\n times.push(new Date(now.getFullYear(), now.getMonth(), now.getDate(), hourTable[i].Hour, hourTable[i].MinuteTable[j].Minute));\n }\n}\n\n// 現在時刻から○分以内の時刻のみ抽出\nfor(var i = 0; i < times.length; i++) {\n if(now < times[i] && times[i] < timeAfter) {\n displayTimes.push(times[i]);\n }\n}\n\nvar slackMessage = `${lineName} ${stationName}の電車を調べたよ!\\n■${direction} 方面\\n${displayTimes.join(\"\\n\")}`;\n\nvar newMsg = {\n payload: slackMessage,\n channelURL: context.global.WebHookURL\n}\nreturn newMsg;","outputs":1,"noerr":0,"x":480,"y":480,"wires":[["a55f0d31.f2495"]]},{"id":"a55f0d31.f2495","type":"slack","z":"fafa05fa.7df188","name":"","channelURL":"","username":"","emojiIcon":"","channel":"","x":650,"y":480,"wires":[]},{"id":"99e69b35.9ac898","type":"comment","z":"fafa05fa.7df188","name":"時刻表取得","info":"","x":100,"y":380,"wires":[]},{"id":"a4fadca1.d23f","type":"switch","z":"fafa05fa.7df188","name":"","property":"isLightOffNow","propertyType":"global","rules":[{"t":"true"}],"checkall":"true","outputs":1,"x":290,"y":420,"wires":[["ce9ff196.b5822"]]},{"id":"ce9ff196.b5822","type":"switch","z":"fafa05fa.7df188","name":"","property":"isLightOffBefore","propertyType":"global","rules":[{"t":"false"}],"checkall":"true","outputs":1,"x":430,"y":420,"wires":[["b7ad5715.cdacf8"]]},{"id":"bcdfa2bd.f3d8d","type":"websocket-client","z":"","path":"wss://api.sakura.io/ws/v1/79f4a250-255e-4b8a-ae06-9c48b5721e0d","wholemsg":"false"}]
メニュー > 読み込み > クリップボード をクリックし、先ほどコピーしたjsonデータを貼り付けて読み込み
を押します。
フローが読み込まれるので、適当な位置に置きます。
ノードの編集
set variables
ノードをダブルクリックし、context.global.WebHookURL
の値を、先ほどslackで設定した Incoming Webhooks のWebhook URL
に置き換えます。
Recieve data
ノードをダブルクリックし、表示されたウィンドウ内のマークをクリックし、websocketURL[^1]を入力します。
フローの実行
画面右上にあるデプロイ
をクリックして、フローを保存します。
照度センサを手で覆ったタイミングでslackにメッセージがきたら成功です。