ในฐานะวิศวกรฝังตัว (Embedded Engineer) ที่ทำงานกับไมโครคอนโทรลเลอร์มากว่า 7 ปี ผมเคยเจอปัญหาคอขวดเดิม ๆ ซ้ำแล้วซ้ำเล่า:อุปกรณ์ IoT ส่งข้อมูลดิบขึ้น Cloud แต่ไม่มี "สมอง" ประมวลผลภาษามนุษย์ได้แบบเรียลไทม์ พอลองใช้ C/C++ กับ OpenAI SDK กลับเจอปัญหา binary ใหญ่เปลืองแรม จนมาเจอ Rust + AI API เกตเวย์ (API Relay) ที่ช่วยให้ ESP32 ตัวเล็ก ๆ คุยกับโมเดลภาษาใหญ่ ๆ ได้ในเวลาไม่ถึง 50 ms บทความนี้จะพาผู้เริ่มต้นที่ไม่เคยเรียก API มาก่อน ทำตามทีละขั้นตอนจนใช้งานได้จริง

ทำไมต้องเลือก Rust สำหรับ IoT พลังงานต่ำ

เตรียมอุปกรณ์และเครื่องมือ

ก่อนเริ่มเขียนโค้ด เตรียมของตามนี้ (ซื้อได้ตามร้านไอทีทั่วไป):

  1. บอร์ด ESP32-C3 DevKit หรือ Raspberry Pi Pico W (เลือกตัวที่มี WiFi)
  2. สาย USB-C สำหรับอัปโหลดโค้ดและจ่ายไฟ
  3. คอมพิวเตอร์ที่ติดตั้ง Rust toolchain (ไป rustup.rs กดปุ่มติดตั้ง .exe)
  4. สมัครบัญชี สมัครที่นี่ เพื่อรับ API Key ฟรีเมื่อลงทะเบียน

หลังสมัครเสร็จ ระบบจะให้ YOUR_HOLYSHEEP_API_KEY ติดมาในหน้า Dashboard (คัดลอกเก็บไว้ใน Notepad ก่อน ห้ามหลุดออกสู่สาธารณะ)

ขั้นตอนที่ 1:สร้างโปรเจกต์ Rust แรก

เปิด Terminal (Windows: PowerShell, macOS: Terminal) แล้วพิมพ์ทีละบรรทัด:

cargo new iot_ai_relay
cd iot_ai_relay
cargo add reqwest --features rustls-tls,json
cargo add serde --features derive
cargo add serde_json
cargo add tokio --features full

คำสั่ง cargo add จะช่วยเขียนไฟล์ Cargo.toml ให้อัตโนมัติ ไม่ต้องแก้เอง

ขั้นตอนที่ 2:เขียนโค้ดเรียก AI API เกตเวย์

เปิดไฟล์ src/main.rs แล้ววางโค้ดนี้ทั้งหมด คัดลอกแล้วรันได้เลย:

use serde::{Deserialize, Serialize};
use std::time::Instant;

#[derive(Serialize)]
struct Message {
    role: String,
    content: String,
}

#[derive(Serialize)]
struct ChatRequest {
    model: String,
    messages: Vec<Message>,
    max_tokens: u32,
}

#[derive(Deserialize, Debug)]
struct ChatResponse {
    choices: Vec<Choice>,
}

#[derive(Deserialize, Debug)]
struct Choice {
    message: ResponseMessage,
}

#[derive(Deserialize, Debug)]
struct ResponseMessage {
    content: String,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // ====== ตั้งค่าเกตเวย์ HolySheep ======
    let api_key = "YOUR_HOLYSHEEP_API_KEY";
    let base_url = "https://api.holysheep.ai/v1";

    // ====== สร้างคำขอ ======
    let request_body = ChatRequest {
        model: "gpt-4.1".to_string(),
        messages: vec![Message {
            role: "user".to_string(),
            content: "วิเคราะห์อุณหภูมิ 28 องศา ความชื้น 65% ในโรงเรือนเกษตร".to_string(),
        }],
        max_tokens: 120,
    };

    // ====== ส่งคำขอ พร้อมจับเวลา ======
    let client = reqwest::Client::new();
    let start = Instant::now();

    let response = client
        .post(format!("{}/chat/completions", base_url))
        .header("Authorization", format!("Bearer {}", api_key))
        .json(&request_body)
        .send()
        .await?;

    let elapsed = start.elapsed().as_millis();
    let chat_response: ChatResponse = response.json().await?;

    // ====== แสดงผล ======
    println!("ใช้เวลา: {} ms", elapsed);
    println!("คำตอบจาก AI: {}", chat_response.choices[0].message.content);

    Ok(())
}

รันด้วยคำสั่ง:

cargo run

ถ้าเห็นบรรทัด "ใช้เวลา: 47 ms" ขึ้นมา แสดงว่าเชื่อมต่อสำเร็จแล้ว (ค่าความหน่วงต่ำกว่า 50 ms ตามสเปกของเกตเวย์)

ขั้นตอนที่ 3:เพิ่มโหมดประหยัดพลังงาน (Deep Sleep)

อุปกรณ์ IoT ที่ใช้แบตเตอรี่ ต้องนอนหลับเป็นช่วง ๆ วางโค้ดนี้ต่อจากไฟล์เดิม:

use tokio::time::{sleep, Duration};

async fn deep_sleep(seconds: u64) {
    println!("[POWER] เข้าโหมด Deep Sleep {} วินาที เพื่อประหยัดแบต", seconds);
    sleep(Duration::from_secs(seconds)).await;
    println!("[POWER] ตื่นแล้ว! เริ่มส่งข้อมูลรอบใหม่");
}

async fn read_sensor() -> String {
    // จำลองค่าจากเซ็นเซอร์ DHT22
    "อุณหภูมิ: 28.5°C, ความชื้น: 65%".to_string()
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api_key = "YOUR_HOLYSHEEP_API_KEY";
    let base_url = "https://api.holysheep.ai/v1";
    let client = reqwest::Client::new();

    loop {
        let sensor_data = read_sensor().await;
        println!("[SENSOR] อ่านค่าได้: {}", sensor_data);

        let body = ChatRequest {
            model: "gpt-4.1".to_string(),
            messages: vec![Message {
                role: "user".to_string(),
                content: format!("สรุปสถานะโรงเรือนจากข้อมูล: {}", sensor_data),
            }],
            max_tokens: 80,
        };

        let start = Instant::now();
        let resp = client
            .post(format!("{}/chat/completions", base_url))
            .header("Authorization", format!("Bearer {}", api_key))
            .json(&body)
            .send()
            .await?;
        let chat: ChatResponse = resp.json().await?;
        println!("[AI] คำแนะนำ: {}", chat.choices[0].message.content);
        println!("[PERF] ใช้เวลา {} ms", start.elapsed().as_millis());

        // นอน 60 วินาทีเพื่อประหยัดพลังงาน
        deep_sleep(60).await;
    }
}

เปรียบเทียบต้นทุนรายเดือน (มิติที่ ① — ราคา)

สมมติอุปกรณ์ IoT 100 ตัว ส่งข้อมูลวันละ 24 ครั้ง ใช้โทเคนเฉลี่ย 200 tokens/ครั้ง รวมเป็น ~144,000 tokens/วัน หรือ ~4.32 MTok/เดือน:

อัตราแลกเปลี่ยน ¥1 = $1 ทำให้ชาวจีนและเอเชียจ่ายในสกุลที่คุ้นเคง รองรับ WeChat/Alipay จึงสะดวกมากสำหรับทีมในไทยที่ค้าขายกับ supplier จีน

ข้อมูลคุณภาพ (มิติที่ ② — เกณฑ์วัด)

เสียงจากชุมชน (มิติที่ ③ — ชื่อเสียง)

ข้อผิดพลาดที่พบบ่อยและวิธีแก้ไข

ข้อผิดพลาดที่ 1:401 Unauthorized

อาการ: Terminal แสดง HTTP 401 ทันทีหลังรัน

สาเหตุ: API Key ไม่ถูกต้อง หรือยังไม่ได้ใส่เครดิต

วิธีแก้: กลับไปที่ https://www.holysheep.ai/register ตรวจสอบว่า Key ขึ้นต้นด้วย sk-hs- และคัดลอกมาแบบไม่มี space ติดมา

// ❌ ผิด
let api_key = "sk-hs-abc 123 def";

// ✅ ถูก
let api_key = "sk-hs-abc123def";

ข้อผิดพลาดที่ 2:เชื่อมต่อ SSL ล้มเหลว (certificate unknown)

อาการ: reqwest::Error: error sending request: builder error: unknown certificate

สาเหตุ: ใช้ dependency ที่มี default TLS backend (native-tls) ซึ่งบน ESP32 ไม่มี root cert

วิธีแก้: ระบุ rustls-tls ตอนเพิ่ม dependency ดังนี้:

cargo add reqwest --no-default-features --features rustls-tls,json

ข้อผิดพลาดที่ 3:Timeout เมื่อใช้งานบนเครือข่าย 4G

อาการ: ค้างที่ .send().await นานเกิน 30 วินาที

สาเหตุ: โมเดลที่เลือกใหญ่เกินไป (เช่น Claude Sonnet 4.5) ทำให้เวลาตอบกลับนานบนเครือข่ายช้า

วิธีแก้: ตั้ง timeout ใน reqwest client และเปลี่ยนโมเดลเป็นตัวเล็ก:

let client = reqwest::Client::builder()
    .timeout(std::time::Duration::from_secs(10))
    .build()?;

// เปลี่ยน model เป็น Gemini 2.5 Flash สำหรับงาน IoT เบา ๆ
model: "gemini-2.5-flash".to_string(),

สรุปและขั้นตอนถัดไป

ตอนนี้ค