iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 28
0
AI & Data

利用Google App Script 實作Telegram Bot系列 第 28

Day 28-Telegram Bot:天氣機器人後端

  • 分享至 

  • xImage
  •  

Day 28-Telegram Bot:天氣機器人後端

前言:

上一篇我們了解中央氣象局API取得的方法了。

再來我們來想想使用者會想要怎麼跟機器人溝通來取得天氣資料。

其實做法有好幾種。

可以分好幾層,先跟機器人說要查天氣,機器人問說要查甚麼時間,回覆時間,要查哪裡的天氣,回覆地點……。

又或者說可以用Inline keyboard來讓使用者選擇要查的時間地點等等。

說真的我覺得使用者應該會想要馬上查到想要的資料,不會想要慢慢一個一個訊息傳給機器人後才得到資訊。

所以我的設計是只要輸入/weather 地點,就可以顯示出那個地點的未來36hr天氣預報。

首先我一樣在sendtext方法寫了一個message的判斷式。

程式碼:

sendtext.gs

  if(estringa.message.text.match("/weather ")){
    var temp  = estringa.message.text.split("/weather ");
    var location = temp[1];
    var Weatherfile = get_weather(location,chatid);
    var mensaje = weather_forecast(Weatherfile,location,chatid); 
  return mensaje;
  }

第1行:判斷訊息是否符合/weather ,這邊要特別注意,/weather的後面是有一個空格的。
第2行:把/weather <城市>,整段訊息分兩部分拆開,temp[0]/weathertemp[1]是<城市>。
第3行:將城市名稱放入location
第4行:將get_weather的資料放入Weatherfile
第5行:將Weatherfile放入weather_forecast方法並執行。

關於文字的判斷,如何去避免使用者只輸入/weather後面沒輸入城市,或是輸入沒有的城市等等的狀況,我就不特別說明了,寫法有很多種大家可以自行發揮。

另外開一個指令碼專案,名稱設為weather.gs

weather.gs

裡面包含兩個方法:get_weatherweather_forecast

function get_weather(location,chatid){
  
  var response = UrlFetchApp.fetch("https://opendata.cwb.gov.tw/api/v1/rest/datastore/F-C0032-001?Authorization=你的授權碼" + "&" + "locationName=" + location );
  var weatherData = JSON.parse(response);
  //Logger.log(response);
  return weatherData;
  
}

第1行:把locationchatid放入get_weather方法,這邊要注意,()裡面放的參數要和sendtext方法裡面寫的一樣。
第3行:fetch至中央氣象局的API資料,location為前面使用者在輸入/weather <城市>,時所打的地點。
第4行:將response的資料轉為JSON格式儲存。
第5行:設一個Log用來測試是否有取得API資料。
第6行:這邊要記得是return weatherData而不是return response,因為如果沒有返回weatherData,那得到的資料就不會是JSON格式,在後面取得資料時就會出錯。

function weather_forecast(Weatherfile,location,chatid) {

var payload = {
        "method": "sendMessage",
        'chat_id': "chatid",
        'text': '測試傳送天氣預報'
      }
      payload.text = location+ " 36hr天氣預報\n" + "\n" +
      Weatherfile.records.location[0].weatherElement[0].time[0].startTime+ "~" + Weatherfile.records.location[0].weatherElement[0].time[0].endTime +"\n"+
      "天氣狀態:"+ Weatherfile.records.location[0].weatherElement[0].time[0].parameter.parameterName+ "\n" + 
      "降雨機率:"+ Weatherfile.records.location[0].weatherElement[1].time[0].parameter.parameterName+ "%" + "\n" +
      "最低溫度:"+ Weatherfile.records.location[0].weatherElement[2].time[0].parameter.parameterName+ "°C" + "\n" +
      "最高溫度:"+ Weatherfile.records.location[0].weatherElement[4].time[0].parameter.parameterName+ "°C" + "\n" +
      "天氣舒適度:"+ Weatherfile.records.location[0].weatherElement[3].time[0].parameter.parameterName+ "\n" + "\n" +
      Weatherfile.records.location[0].weatherElement[0].time[1].startTime+ "~" + Weatherfile.records.location[0].weatherElement[0].time[1].endTime +"\n"+
      "天氣狀態:"+ Weatherfile.records.location[0].weatherElement[0].time[1].parameter.parameterName+ "\n" +
      "降雨機率:"+ Weatherfile.records.location[0].weatherElement[1].time[1].parameter.parameterName+ "%" + "\n" +
      "最低溫度:"+ Weatherfile.records.location[0].weatherElement[2].time[1].parameter.parameterName+ "°C" + "\n" +
      "最高溫度:"+ Weatherfile.records.location[0].weatherElement[4].time[1].parameter.parameterName+ "°C" + "\n" +
      "天氣舒適度:"+ Weatherfile.records.location[0].weatherElement[3].time[1].parameter.parameterName+ "\n" + "\n" +
      Weatherfile.records.location[0].weatherElement[0].time[2].startTime+ "~" + Weatherfile.records.location[0].weatherElement[0].time[2].endTime +"\n"+
      "天氣狀態:"+ Weatherfile.records.location[0].weatherElement[0].time[2].parameter.parameterName+ "\n" +
      "降雨機率:"+ Weatherfile.records.location[0].weatherElement[1].time[2].parameter.parameterName+ "%" +"\n"+
      "最低溫度:"+ Weatherfile.records.location[0].weatherElement[2].time[2].parameter.parameterName+ "°C" + "\n" + 
      "最高溫度:"+ Weatherfile.records.location[0].weatherElement[4].time[2].parameter.parameterName+ "°C" + "\n" +
      "天氣舒適度:"+ Weatherfile.records.location[0].weatherElement[3].time[2].parameter.parameterName+ "\n" +"";
      //Logger.log(payload.text);    
      return payload;
}

這邊其實就只要搞懂我們API JSON格式的內容就很容易懂了。

在前面我們已經把get_weather方法的資料全部放進Weatherfile了,也就是說Weatherfile就是我們抓到JSON格式的資料。

我們檢視JSON的內容會看到裡面分了好幾層,而我們要抓的資料必須要一層一層抽出來。

最外層的部分是records物件。

再來是location陣列,location陣列第一個值location[0]是新北市

再來是weatherElement陣列,weatherElement[0]elementName:Wx天氣狀況,weatherElement[1]elementName:PoP降雨機率。

再來是time陣列,time陣列分成三個時段,time[0],time[1],time[2]

再來是parameter物件,裡面包含parameterNameparameterValue兩個值。

可以看到我在上面的敘述裡面特別強調物件還有陣列,這是因為如果是物件的話則不需要在後面加上[]來指定要取的值,如果是陣列的話則一定要加,我就在parameter的地方加上[]而一直出錯,直到後來才發現他不是陣列,抓資料時在數據的型態這部分一定要特別注意。

講到這邊大家應該有點概念了,假設我想要抓第一個時間段的值,我就把時間設為time[0],如果要抓某種天氣因子,就把weatherElement設為想要抓的天氣因子。

透過不同的排列組合就可以抓出想要的資料,像上方我寫的方法抓出來的資料就會長這樣。

https://ithelp.ithome.com.tw/upload/images/20201008/2013028323oFnt0cNo.png

那最後在GAS測試完記得部屬,到機器人這邊輸入訊息測試結果,實作完的成果就會是這樣。

https://ithelp.ithome.com.tw/upload/images/20201008/20130283KrcgDB0bsi.png

後記:

這個天氣機器人的功能其實也跟以圖搜圖一樣,是最初就想要做到的。

在做這個天氣機器人時其實也遇到了許多問題,基本上分三個問題吧。

我在做這個之前,根本就沒有抓過API,只對這種資料擷取的方式有點概念,所以在寫如何抓API資料的時候,其實有點靠運氣。

在看資料時發現中央氣象局的API資料取得時就已經是JSON格式了,就想說照著前一篇以圖搜圖的方法試著寫寫看,也不確定這樣子的寫法是不是對的,試著試著居然就寫出來了。

這次遇到的問題還有在return的地方回傳錯誤的值,一時也沒有發現,就這樣整個半天都卡在這邊,大家要記得加上return傳回自己前面放的值,也要記得參數別放錯。

最後一個遇到的問題就是解析JSON資料時遇到的,這種資料要一層一層的抓出來,資料的型態一定要特別注意,可以先不要抓太大量的資料,先從小範圍的值來看,從最一開始的records慢慢往外一層一層寫,會比較好理解。

總之,只要大家懂得fetch API的方式,就可以抓想要的API資料,並且透過解析JSON格式的資料,就能抓出特定的資訊,如此不管是今明36小時的天氣預報,又或者是地震報告、紫外線指數等等資料,都可以透過這個方法來呈現。

老話一句,接下來就看各位的發揮了!

參考資料:

https://www.est.idv.tw/telegram-bot-function-36hr%E6%B0%A3%E8%B1%A1%E9%A0%90%E5%A0%B1/


上一篇
Day 27-Telegram Bot:天氣機器人API
下一篇
Day 29-Telegram Bot:定時自動發送訊息
系列文
利用Google App Script 實作Telegram Bot30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言