Writing
RData ScienceAgricultureAPI

หาความชื้นดินผ่าน API ด้วย R

หาความชื้นดินผ่าน API ด้วย R

เช็คความชื้นดินผ่าน API ฟรีด้วย R (Smart Farming ฉบับมินิ)

สำหรับใครที่ทำโปรเจกต์ด้านการเกษตร หรือกำลังสนใจทำระบบรดน้ำอัตโนมัติ (Smart Farming) ข้อมูลที่สำคัญมากๆ อย่างหนึ่งก็คือ “ความชื้นในดิน” (Soil Moisture) ครับ

ถ้าเรายังไม่มีเซ็นเซอร์วัดความชื้นปักลงไปในดินจริงๆ เราสามารถใช้ตัวย่อด้วยการดึง ข้อมูลประมาณการความชื้นในดินจากดาวเทียมและโมเดลสภาพอากาศ มาใช้ก่อนได้ ซึ่งโมเดลที่เราจะใช้วันนี้คือข้อมูลระดับความลึก 3-9 เซนติเมตร จาก Open-Meteo API ครับ (ฟรีเหมือนเดิม!)


1. สร้างฟังก์ชันดึงค่าความชื้นในดินด้วย R

เรามาเริ่มด้วยการเขียนฟังก์ชันสั้นๆ ใน R ที่รับค่าละติจูด (Latitude) และลองจิจูด (Longitude) แล้ววิ่งไปดึงข้อมูลจาก API กลับมา:

# ติดตั้งแพ็กเกจ: install.packages(c("jsonlite", "dplyr", "purrr"))
library(jsonlite)
library(tidyverse)
library(purrr)

get_current_soil_moisture <- function(lat, lon) {
  
  # ระบุพิกัดและโมเดลความชื้น 3-9 cm
  url <- paste0("https://api.open-meteo.com/v1/forecast?latitude=", lat, 
                "&longitude=", lon, 
                "&hourly=soil_moisture_3_to_9cm&forecast_days=1")
  
  # ดึงข้อมูลจาก API
  res <- tryCatch(fromJSON(url), error = function(e) NULL)
  
  # หน่วงเวลาเล็กน้อยป้องกันการรัว Request จนโดนบล็อก (Polite Scraping)
  Sys.sleep(0.2)
  
  # เช็คว่า API ส่งข้อมูล soil_moisture_3_to_9cm กลับมาไหม ถ้าเกิดพังให้คืนค่า NA
  if (is.null(res) || is.null(res$hourly$soil_moisture_3_to_9cm)) {
    return(NA_real_) 
  }
  
  # หยิบค่าความชื้นชั่วโมงปัจจุบันใบแรกมาใช้
  val <- res$hourly$soil_moisture_3_to_9cm[1]
  
  if (is.null(val) || is.na(val)) {
    return(NA_real_)
  }
  
  # ส่งค่าความชื้นที่มีหน่วยเป็น m³/m³ กลับไป
  return(as.numeric(val))
}

ฟังก์ชันนี้จะส่งคืนเป็นตัวเลข (ความชื้นดินในหน่วยลูกบาศก์เมตรต่อน้ำ 1 ลูกบาศก์เมตร หรือ $m^3/m^3$) กลับมา ถ้าเกิดโหลดจาก API ไม่ได้ก็จะส่งกลับเป็น NA ครับ


2. ประยุกต์ใช้กับตำแหน่งหลายๆ ฟาร์มพร้อมกัน

ทีนี้ ถ้าเรามีข้อมูลแปลงผักหรือฟาร์มหลายกระจายอยู่ทั่วประเทศ เราจะมานั่งลูป for ก็อาจจะดูยืดยาดไป ลองใช้พลังของ purrr::map2_dbl() จาก tidyverse จัดการกันเลยครับ

# สมมติรายชื่อและพิกัดของฟาร์ม 3 แห่ง
my_farms <- data.frame(
  farm_name = c("ฟาร์มรังสิต (ปทุมธานี)", "ฟาร์มดอยอินทนนท์ (เชียงใหม่)", "ฟาร์มปากช่อง (โคราช)"),
  lat = c(14.02, 18.58, 14.70),
  lon = c(100.62, 98.48, 101.41)
)

# ใช้ mutate และ map2_dbl โยนละติจูด, ลองจิจูด แต่ละแถวเข้าไปในฟังก์ชัน
my_farms_updated <- my_farms |>
  mutate(
    current_moisture_m3_m3 = map2_dbl(lat, lon, get_current_soil_moisture)
  )

# ดูผลลัพธ์ว่าฟาร์มไหนความชื้นเป็นยังไงบ้าง
print(my_farms_updated)

ผลลัพธ์ที่ได้จะเป็นตารางแบบนี้:

                     farm_name   lat    lon current_moisture_m3_m3
1        ฟาร์มรังสิต (ปทุมธานี) 14.02 100.62                  0.342
2 ฟาร์มดอยอินทนนท์ (เชียงใหม่) 18.58  98.48                  0.415
3         ฟาร์มปากช่อง (โคราช) 14.70 101.41                  0.198

แค่นี้เราก็สามารถรู้ความชื้นดินเบื้องต้นของพื้นที่แปลงเกษตรของเรา แล้วเอาไปตั้งเงื่อนไขต่อได้ว่า ถ้าน้อยกว่า 0.2 ให้แจ้งเตือนเข้า LINE หรือให้ส่งสัญญาณเปิดปั๊มน้ำอัตโนมัติก็ทำได้แล้วครับ! สนุกกับการปลูกผักอัจฉริยะนะครับ 🌱