แจ้งเตือนระดับน้ำไป LINE Notify ด้วย Google Apps Script

ด้วยสถานการณ์น้ำในปัจจุบันที่ฝนตกหนักและมีการปล่อยน้ำจากเขื่อนเจ้าพระยามากขึ้น เราสามารถติดตามสถานการณ์ระดับนจากสถานีใกล้ๆ บ้าน ได้จากเว็บไซต์ คลังข้อมูลน้ำแห่งชาติ แต่ผมคงไม่มีเวลามานั่งตรวจสอบทั้งวัน เลยทดลองทำ Mini Project ในการแจ้งเตือนข้อมูลระดับน้ำจากสถานีวัดที่ต้องการไปยัง LINE Notify ครับ มีวิธีการยังไงมาลองดูกันเลย 🚀


1. ตรวจสอบข้อมูลระดับน้ำในเว็บไซต์ คลังข้อมูลน้ำแห่งชาติ

ให้ลองเปิดกราฟระดับน้ำจากสถานีที่ต้องการ และเลือกวันที่ที่ต้องการดูข้อมูล แล้วให้ Inspect และดูไปที่ Network

จะพบเจอกับ Link Url ของ API ที่ใช้เรียกข้อมูลระดับน้ำมาแสดงในกราฟแบบนี้

http://api2.thaiwater.net:9200/api/v1/thaiwater30/public/waterlevel_graph?station_type=tele_waterlevel&station_id=23&start_date=2021-09-27&end_date=2021-09-27%2001:00

จะเห็นได้ว่ามี Parameter อยู่ 3 ตัวก็คือ station_id, start_date และ end_date หากลองเปิด Link Url นี้จะได้ Response กลับมาเป็นข้อมูลแบบนี้

ซึ่งเราก็จะได้ข้อมูล วัน-เวลา และระดับน้ำ ในช่วงเวลาที่ต้องการมาในรูปแบบ JSON แล้วครับ เมื่อได้แบบนี้ก็มาลุยต่อกันเลย


2. สร้างไฟล์งานใน Google Sheet และเขียน Apps Script ในการเรียกข้อมูล และบันทึกลงใน Sheet ที่ต้อง พร้อมกับแจ้งเตือนไปยัง LINE Notify ในรอบเวลาที่กำหนด

2.1 สร้างไฟล์ Google Sheet อย่างรวดเร็วด้วยการพิมพ์ sheet.new ลงในช่อง Url ของ Web Browser ได้เลย แล้วทำการกำหนดชื่อไฟล์, คอลัมน์ และชื่อ Sheet ที่ต้องการบันทึกข้อมูลประมาณนี้

2.2 เปิดไฟล์ Apps Script โดยไปที่เมนู Tools -> Script Editor ตั้งชื่อ Project และลบ Code ตั้งต้นออกให้หมด แล้วแทนที่ด้วยตัวอย่าง Code นี้

function main() {
  // station : คลองอ้อมนนท์ บางใหญ่ (ถนนบางกรวย-ไทรน้อย) (station id : 23)
  const stationID = "<Your station water ID>";

  // spreadsheet id
  const ssID = "<Your Google Sheet ID>";

  // line notify token
  const notifyToken = "<Your LINE Notify Access Token>";

  // get date and time
  const { date, time } = getTodayDateTime();

  // get water level
  const { datetime, waterlevel } = getWaterLevel(stationID, date, time);

  Logger.log(`${datetime} : ${waterlevel}`);

  // set data to sheet
  setDataSheet(ssID, datetime, waterlevel);
  
  // get chart
  const chart = getChart(ssID, datetime);

  // create message for line notify
  let message = "\n\n⚠️ แจ้งเตือนระดับน้ำ 🌊" + "\n\nสถานี : คลองอ้อมนนท์บางใหญ่(ถนนบางกรวย-ไทรน้อย)" + "\n\nวันที่/เวลา : " + datetime + "\n\nระดับน้ำ : " + waterlevel + " (ระดับตลิ่ง 1.85)";

  const lastWaterLevel = getLastWaterLevel(ssID);

  // Logger.log(lastWaterLevel)

  if (lastWaterLevel > 0) {
    message += "\n\nเปลี่ยนแปลง : เพิ่มขึ้น " + lastWaterLevel.toFixed(2);
  } else if (lastWaterLevel < 0) {
    message += "\n\nเปลี่ยนแปลง : ลดลง " + Math.abs(lastWaterLevel).toFixed(2);
  } else {
    message += "\n\nเปลี่ยนแปลง : คงที่";
  }
  
  // message and chart image for send to line notify
  const messages = {
    message: message,
    imageFile: chart
  }

  // send to LINE Notify
  sendLineNotify(messages, notifyToken);
}

function getTodayDateTime() {
  const timeZoneOffset = (new Date()).getTimezoneOffset() * 60000;

  const todayTimeZoneOffset = (new Date(Date.now() - timeZoneOffset)).toISOString().slice(0, -1);

  const date = todayTimeZoneOffset.split("T")[0];

  const time = todayTimeZoneOffset.split("T")[1];

  return { date, time };
}

function getWaterLevel(id, date, time) {
  // url : https://api-v3.thaiwater.net/api/v1/thaiwater30/public/waterlevel_graph?station_type=tele_waterlevel&station_id=23&start_date=2021-09-27&end_date=2021-09-27%2001:00
  // url : http://api2.thaiwater.net:9200/api/v1/thaiwater30/public/waterlevel_graph?station_type=tele_waterlevel&station_id=23&start_date=2021-09-27&end_date=2021-09-27%2001:00
  const waterLevelUrl = `http://api2.thaiwater.net:9200/api/v1/thaiwater30/public/waterlevel_graph?station_type=tele_waterlevel&station_id=${id}&start_date=${date}&end_date=${date}%20${time}`;

  const response = UrlFetchApp.fetch(waterLevelUrl);

  if (response.getResponseCode() === 200) {
    const responseJSON = JSON.parse(response.getContentText());

    const datas = responseJSON.data.graph_data.sort((a, b) => {
      return new Date(b.datetime) - new Date(a.datetime);
    });

    let datetime;
    let waterlevel;

    for (let data of datas) {
      if (data.value) {
        datetime = data.datetime;
        waterlevel = data.value;
        break;
      }
    }

    return { datetime, waterlevel };
  }
}

function setDataSheet(id, datetime, waterlevel) {
  const ss = SpreadsheetApp.openById(id);
  const sheet = ss.getSheetByName("data");

  const lastRow = sheet.getLastRow();

  // set datetime
  sheet.getRange(`A${lastRow + 1}`).setValue(`${datetime}`);

  // set water level
  sheet.getRange(`B${lastRow + 1}`).setValue(waterlevel);

  // set formula to column c
  sheet.getRange(`C${lastRow + 1}`).setFormula(`=B${lastRow + 1} - B${lastRow}`);
}

function getLastWaterLevel(id) {
  const ss = SpreadsheetApp.openById(id);
  const sheet = ss.getSheetByName("data");

  const lastRow = sheet.getLastRow();

  const lastWaterLevel = sheet.getRange(`C${lastRow}`).getValue();

  return lastWaterLevel;
}

function sendLineNotify(messages, accessToken) {
  const lineNotifyEndPoint = "https://notify-api.line.me/api/notify";

  const options = {
    "headers": { "Authorization": "Bearer " + accessToken },
    "method": 'post',
    "payload": messages,
  };

  try {
    UrlFetchApp.fetch(lineNotifyEndPoint, options);
  } catch (error) {
    Logger.log(error.name + ":" + error.message);
    return;
  }
}

function getChart(id, name) {
  const ss = SpreadsheetApp.openById(id);
  const sheet = ss.getSheetByName("data");
  const chart = sheet.getCharts()[0].getBlob().setName(name).getAs("image/png");

  return chart;
}

2.3 กำหนดค่าตัวแปร

  • ตัวแปร stationID คือค่า ID ของสถานีวัดระดับน้ำที่ต้องการข้อมูล หาได้จากตัวแปร station_id ใน Link Url ในข้อ 1
  • ตัวแปร ssID คือ Spread Sheet ID ที่เราสร้างขึ้นมา สามารถดูได้ในช่อง Url ซึ่งจะมีหน้าตาประมาณนี้ https://docs.google.com/spreadsheets/d/<Copy เอาจากตรงนี้>/edit#gid=0
  • ตัวแปร notifyToken คือ Access Token ของ LINE Notify ที่ต้องการแจ้งเตือน วิธีการสร้างอ่านได้ ที่นี่

2.4 สร้าง Line Chart จากข้อมูลระดับน้ำ และระดับตลิ่งขึ้นมาใน Google Sheet จะได้หน้าตาออกมาประมาณนี้ โดยเราจะส่ง Chart ไปพร้อมกับข้อความแจ้งเตือนด้วย

2.5 ทดสอบ Run ฟังก์ชัน main หากมีการแจ้งเตือนก็ Allow ให้หมดครับ หากไม่มี Error อะไรแจ้งขึ้นมา ก็มากำหนดให้ Apps Script ของเราทำงานแบบอัตโนมัติในช่วงเวลาที่ต้องการ เช่น ให้ Run ฟังก์ชันชื่อ main ทุกวันเวลาช่วง 12.00 PM – 13.00 PM (ตรงนี้กำหนดได้ตามต้องการเลย แต่ตามตัวอย่าง Code ก็ให้เลือกฟังก์ชันชื่อ main ครับ)

2.6 ผลลัพท์ของข้อความที่แจ้งเตือนมาที่ LINE Notify พร้อมกราฟแสดงระดับน้ำไว้ดูแนวโน้มเพิ่ม-ลด


ท้ายสุด จบแล้วครับกับการเขียนโปรแกรมด้วย Apps Script ให้บันทึกระดับน้ำจากสถานีวัดระดับน้ำที่ต้องการพร้อมส่งข้อความแจ้งเตือนไปที่ LINE Notify แบบอัตโนมัติ เท่านี้ก็จะได้ไม่ต้องมาคอยนั่งเช็คในเว็บไซต์ตลอดเวลา จะได้ทำงานอื่นๆ และเตรียมตัวยกของได้ทันหากมีแนวโน้มน้ำที่สูงขึ้นจนล้นระดับตลิ่ง ยุคนี้พึ่งใครไม่ได้นอกจากตัวเราเองครับ Happy Life…Happy Coding…😃

Source Code 🔗 https://github.com/ChaiyachetU/Water-Level-LINE-Notify


ประกันรถใกล้หมดแล้ว ไม่อยากจ่ายแพง อยากได้ราคาดีที่สุดคลิกเช็คเบี้ย ฟรี !!! ที่นี่ https://bit.ly/3sEMzHO

ฝากร้านหนังสือมือสองของผมด้วยครับ เป็นหนังสือที่ซื้อมาอ่านเอง เพื่อนๆ ที่สนใจสามารถติดตามและสั่งซื้อได้ที่ https://shop.line.me/@921ijoic

โปรโมชั่น คูปองส่วนลด และดีล ที่ดีที่สุดของร้านค้าออนไลน์กว่า 300 แบรนด์พร้อมรับเงินคืนจาก ShopBack https://bit.ly/3c4tlmV

Ruk-Com จดโดเมน-เช่าโฮสต์ ราคาประหยัด พร้อมให้บริการใน 1 นาที http://bit.ly/36q8A12