Webduino使用LINE自訂積木(四):LINE Bot

上一篇

我想要使用LINE聊天的方式與Webduino開發板互動

網路上有不少LINE Bot教學文章,但不一定適合做成Webduino程式積木,思索後決定採用Google Apps Script與Firebase Realtime Database做為LINE與Webduino積木間的介接
辦法絕對不只一種,但目前筆者只會這種,就先分享了

架構圖

架構圖1號位置:
Webduino程式積木會產生類似下面的程式碼,將參數資料傳遞給2號的Google Apps Script程序
line_bot({token:'金鑰',userId:'使用者ID',message:'顯示在LINE的訊息'});

function line_bot(data) {
   $.post('https://script.google.com/macros/s/.../exec',    /*將data傳給GoogleAppsScript*/
      data,
      function(e){
console.log(e);
      }
   );
}

架構圖2號位置:
Google Apps Script完整程式碼如下
此程序部署為網路應用程式,提供Webduino程式積木使用
function doPost(e) {
  var param = e.parameter;

 //處理Webduino積木傳送過來的參數
  var obj = {
    'to': param.userId,
    'messages': []
  };
  if(param.message)
    obj['messages'].push({'type':'text','text':param.message});
  if(param.packageId && param.stickerId)
    obj['messages'].push({'type':'sticker','packageId':param.packageId,'stickerId':param.stickerId});
  if(param.i_previewImageUrl && param.i_originalContentUrl)
    obj['messages'].push({'type':'image','previewImageUrl':param.i_previewImageUrl,'originalContentUrl':param.i_originalContentUrl});
  if(param.v_previewImageUrl && param.v_originalContentUrl)
    obj['messages'].push({'type':'video','previewImageUrl':param.v_previewImageUrl,'originalContentUrl':param.v_originalContentUrl});
  if(param.a_duration && param.a_originalContentUrl && param.a_duration > 0)
    obj['messages'].push({'type':'audio','duration':param.a_duration,'originalContentUrl':param.a_originalContentUrl});

  //將處理過的參數透過LINE API顯示在LINE聊天
  UrlFetchApp.fetch('https://api.line.me/v2/bot/message/push', {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + param.token,
    },
    'method': 'post',
    'payload': JSON.stringify(obj)
  });
}

架構圖3號位置:
當使用者在LINE Bot輸入聊天訊息時,我們想要讀取這個訊息到Webduino中使用,
除了透過Google Apps Script程序傳遞訊息之外,還要請Firebase Realtime Database幫忙

Firebase Realtime Database是一個即時的JSON格式資料庫,當資料改變時,會立即同步到所有正在連結資料庫的用戶端,很適合做為聊天室使用,我們也利用這個特性,讓Webduino即時獲取LINE Bot傳遞過來的訊息

現在開始設定Firebase
使用Google帳號登入Firebase網站 https://firebase.google.com/
點擊網頁右上角的【前往控制台】

點擊【新增專案】

輸入自訂的【專案名稱】,然後點擊【建立專案】

點選左側【Project Overview】旁邊的齒輪Settings符號,選擇【專案設定】

點選【服務帳戶】裡面的【資料庫密鑰】

可以看到資料庫ID與密鑰,記下這兩項資訊,後面會用到

在左側選單點選【Database】,右邊內容捲動到下方,看到【您也可以選用「Realtime Database」】,在這裡點擊【建立資料庫】


接著出現安全性規格,請選擇【以測試模式啟動】,然後點擊【啟用】
稍後我們會將寫入的部分改成false,以防止未經授權寫入

現在可以看到空的資料庫,


接著點選【規則】,將寫入的部分由true改成false,再點擊【發佈】

回到【資料】,移到資料庫ID的文字旁,點選【+】先隨意新增一筆JSON紀錄,之後可以再刪除
如果資料庫是空的,下次進入Database要重新設定一次建立步驟以及變更寫入規則


Firebase Realtime Database設定完成,
接下來新增Google Apps Script程序,這個程序會接收LINE的訊息,並將訊息寫入Firebase資料庫

使用Google帳號登入Google Apps Script網站 https://script.google.com/
點選左上角的新增指令碼

點選【資源 >程式庫】

如果您還沒儲存過指令碼,會要求先設定專案的名稱

接著在【新增程式庫】的空格中填入以下字串
1hguuh4Zx72XVC1Zldm_vTtcUUKUA6iBUOoGnJUWLfqDWx5WlOJHqYkrt
然後點擊【新增】,加入FirebaseApp Library

點選版本的下拉選單,選擇最新的版本,然後點擊【儲存】

現在看到【程式碼.gs】的區域

以下面的程式碼取代
資料庫ID與密鑰請輸入前面設定Firebase時取得的資料
function doPost(e) {
  //reading data from LINE
  var msg = JSON.parse(e.postData.contents);
  var userId = msg.events[0].source.userId;
  var userMessage = msg.events[0].message.text;
  
  //writing data to firebase
  var base = FirebaseApp.getDatabaseByUrl("https://你的資料庫ID.firebaseio.com/","你的密鑰");
  base.updateData(userId, {userid:userId,message:userMessage});
  base.updateData(userId, {userid:userId,message:''});
}

儲存後,點選【發佈 > 部署為網路應用程式...】

專案版本設定【新增】
將應用程式執行為【我】
具有應用程式存取權的使用者設定為【任何人,甚至是匿名使用者】

首次部署,需要使用google帳戶進行授權

記下網路應用程式的網址

現在將應用程式的網址輸入LINE Messaging API Channel的【Webhook URL】位置,讓LINE Bot使用自己的應用程式傳送訊息 (請參閱上一篇)

架構圖4號位置:
使用自己建立的Firebase資料庫,請點擊左上角齒輪圖示,加入Firebase ID積木,並輸入前面建立Firebase Realtime Database時記下的資料庫ID(專案ID)

Webduino程式積木會產生類似下面的程式碼,與Firebase資料庫建立連接,當Firebase資料有異動時,會同步傳送給Webduino程式

var flag = true;
var linebot = {token:'LINEtoken',userId:'LINEuserID',onVal:''};

var firebase = new Firebase('https://你的資料庫ID.firebaseio.com/');
firebase.on('value',function(s){  //啟動程式及資料異動都會讀取資料庫
  var msg = false;
  if(flag){  //忽略啟動程式時讀到的舊資料
    flag = false;
    return;
  }
  else {
    s.forEach(function(e){ //取得LINE訊息:e.val().message
      if(e.val().userid===linebot.userId && e.val().message!==''){
        linebot.onVal = e.val().message;
        msg=true;}
    });
    if(!msg) return;
  }
  
  //---取得LINE訊息後,要執行的控制---
  document.getElementById('demo-area-01-show').innerHTML = linebot.onVal;
  // ...
  //----------------------------------
});

最後有一項說明,查閱Firebase官方文件Library已更新5.x,但在製作這個自訂積木時,為了使用Webduino Blockly內建的2.x舊版firebase.min.js,程式語法可能與官網查到的不同

Webduino Script

這個網誌中的熱門文章

Webduino使用LINE自訂積木(三):LINE Bot

Webduino使用LINE自訂積木(二):LINE Notify

製作 Micro:bit 循跡自走車(二):程式