DEVELOPER GUIDE

OneANK AI Farm API Reference

សៀវភៅមគ្គុទ្ទេសក៍ដ៏ក្បោះក្បាយនេះ ត្រូវបានរៀបចំឡើងដើម្បីណែនាំអ្នកអភិវឌ្ឍន៍ (Developers) និងវិស្វករគ្រឿងរឹង (IoT Engineers) ឱ្យយល់ច្បាស់ពីរបៀបធ្វើសមាហរណកម្ម (Integration) និងបញ្ជូនទិន្នន័យមកកាន់ "ម៉ាស៊ីនមេកណ្តាល" នៃកសិដ្ឋានដោយសុវត្ថិភាព។

ទិដ្ឋភាពទូទៅ និងការផ្ទៀងផ្ទាត់

ប្រព័ន្ធ OneANK ត្រូវបានបែងចែកជាពីរគោលដៅធំៗគឺ Hardware API (សម្រាប់គ្រឿងបរិក្ខារ IoT ដូចជា ESP8266, Sensors) និង AI Server API (សម្រាប់ដំណើរការបញ្ញាសិប្បនិម្មិត Python)។ រាល់ប្រតិបត្តិការទាំងអស់ត្រូវបានការពារយ៉ាងតឹងរ៉ឹងដោយសោរវេទមន្ត API Key។

សោរវេទមន្ត (API Key Authentication)

រាល់ការហៅចូល (Requests) ទៅកាន់ API របស់ម៉ាស៊ីនមេ ត្រូវតែភ្ជាប់មកជាមួយនូវ Header ឈ្មោះ x-api-key។ ប្រសិនបើគ្មាន Header នេះទេ ម៉ាស៊ីនមេនឹងបដិសេធសំណើដោយឆ្លើយតបនូវកូដ 401 Unauthorized

Header Example: x-api-key: OneANK_Secret_Device_Key_2026

អាសយដ្ឋានគោល (Base URLs)

Hardware API (PHP Endpoint)

សម្រាប់ចុះឈ្មោះ និងបញ្ជាឧបករណ៍ IoT

http://[YOUR_SERVER_IP]/hardware_api.php

AI Engine API (Python Server)

សម្រាប់វិភាគទិន្នន័យ Machine Learning

http://[YOUR_SERVER_IP]:5050/

Hardware / IoT Endpoints

POST ?action=register_device
ចុះឈ្មោះឧបករណ៍ (Device Heartbeat)

ប្រើប្រាស់នៅពេលដែលឧបករណ៍ចាប់ផ្តើមដោតភ្លើងដំណើរការ (Boot up) ដើម្បីរាយការណ៍ប្រាប់ម៉ាស៊ីនមេថាខ្លួននៅរស់ និងកត់ត្រាពេលវេលា last_seen

Request Body (JSON)

{
  "device_id": "NODE_001_ZONE_A",
  "device_type": "ESP8266_NODE"
}

Response (200 OK)

{
  "status": "success",
  "message": "Device pinged successfully"
}
GET ?action=get_command&device_id={ID}
សុំបញ្ជាពីម៉ាស៊ីនមេ (Polling)

តម្រូវឱ្យឧបករណ៍ IoT ហៅ (Poll) មកកាន់ Endpoint នេះជារៀងរាល់ ៣ ទៅ ៥ វិនាទី។ ប្រសិនបើឧបករណ៍អវត្តមានលើសពី ១៥ វិនាទី ម៉ាស៊ីនមេនឹងចាត់ទុកថា OFFLINE ហើយបាញ់សារ Alert ចូល Telegram ភ្លាម។

Query Parameters

device_id Required (String). លេខសម្គាល់ឧបករណ៍។

Response (200 OK)

{
  "status": "success",
  "data": {
    "pump_state": "ON",
    "auto_mode": 1
  }
}
POST ?action=update_flow
រាយការណ៍ទិន្នន័យលំហូរទឹក

ប្រើប្រាស់សម្រាប់ឱ្យ Sensor (ឧទាហរណ៍ YF-S201) បញ្ជូនទិន្នន័យជាក់ស្តែងពីបរិមាណទឹកដែលបានបូមចេញ ត្រលប់មកកត់ត្រាក្នុង MySQL វិញ។

Request Body (JSON)

{
  "device_id": "NODE_001_ZONE_A",
  "flow_rate": 15.5,
  "total_volume": 120.5,
  "is_running": 1
}

Response (200 OK)

{
  "status": "success"
}

AI Engine Endpoints (Python)

POST /predict
វិភាគទិន្នន័យដំណាំ (Crop Analysis)

ទទួលយកទិន្នន័យ Sensor ពីកសិដ្ឋាន ដើម្បីវិភាគតាមរយៈ Machine Learning Model រួចបញ្ចេញជាលទ្ធផលវាយតម្លៃ និងអនុសាសន៍។

Request Body (JSON)

{
  "temperature": 32.5,
  "humidity": 60.0,
  "soil_moisture": 30.5
}

Response (200 OK)

{
  "status": "success",
  "data": {
    "crop_name": "Mixed Farm Zone A",
    "health_status": "Critical: Dry",
    "confidence_score": 95.5,
    "recommended_action": "Activate irrigation immediately."
  }
}

កូដឧទាហរណ៍ (Code Integration Examples)

1. C++ (ESP8266 HTTPClient)

ឧទាហរណ៍នៃការបញ្ជូនសំណើ POST ដើម្បីចុះឈ្មោះឧបករណ៍ពីបន្ទះ ESP8266។

esp8266_register.ino
                            
                                                                /*
                                * AI FARM - ESP8266 Auto Irrigation Node
                                * * រចនាដោយ: កល្យាណ សម្រាប់ បងពិសិដ្ឋ
                                * គ្រឿងបន្លាស់: ESP8266, 12V Relay (Solenoid), YF-S201 Water Flow Sensor
                                */

                                #include 
                                #include 
                                #include 
                                #include 

                                // ========== ការកំណត់ Wi-Fi & Server ==========
                                const char* ssid     = "WiFi_Name";
                                const char* password = "WiFi_Password";
                                // តំណភ្ជាប់ថ្មីសម្រាប់ Hardware API ដោយឡែក
                                const char* serverApiUrl = "http://YOUR_SERVER_IP/hardware_api.php"; 

                                // សោរវេទមន្តសម្រាប់ការពារសុវត្ថិភាព (ត្រូវតែដូចគ្នានឹងសោរនៅលើ PHP Server)
                                const char* API_KEY = "OneANK_Secret_Device_Key_2026"; 
                                const char* DEVICE_ID = "NODE_002_ZONE_B";

                                // ========== ការកំណត់ជើងភ្ជាប់ (Pins) ==========
                                const int RELAY_PIN = D1;       // ភ្ជាប់ទៅកាន់ជើងបញ្ជា 12V Relay
                                const int FLOW_SENSOR_PIN = D2; // ភ្ជាប់ទៅកាន់ខ្សែព៌ណលឿងរបស់ YF-S201

                                // ========== អថេរសម្រាប់គណនាលំហូរទឹក ==========
                                volatile int pulseCount = 0;
                                float flowRate = 0.0;
                                unsigned int flowMilliLitres = 0;
                                unsigned long totalMilliLitres = 0;
                                unsigned long oldTime = 0;

                                // ========== អថេរគ្រប់គ្រងប្រព័ន្ធ ==========
                                bool isValveOpen = false;
                                unsigned long lastServerPoll = 0;
                                const long pollInterval = 3000; // សួរសុខទុក្ខ Server រៀងរាល់ ៣ វិនាទី

                                // Interrupt Service Routine (ISR) សម្រាប់រាប់ការវិលរបស់កង្ហារទឹក YF-S201
                                void IRAM_ATTR pulseCounter() {
                                pulseCount++;
                                }

                                void setup() {
                                Serial.begin(115200);
                                
                                // រៀបចំជើងបញ្ជា Relay ឱ្យបិទជាស្រេចនៅពេលដោតភ្លើងដំបូង
                                pinMode(RELAY_PIN, OUTPUT);
                                digitalWrite(RELAY_PIN, HIGH); // Relay ភាគច្រើន Active LOW ដូច្នេះដាក់ HIGH ដើម្បីបិទ
                                
                                // រៀបចំភ្នែកវាស់ទឹក (Flow Sensor)
                                pinMode(FLOW_SENSOR_PIN, INPUT_PULLUP);
                                attachInterrupt(digitalPinToInterrupt(FLOW_SENSOR_PIN), pulseCounter, FALLING);

                                // ភ្ជាប់ Wi-Fi
                                Serial.println("\n[IoT] កំពុងភ្ជាប់ទៅកាន់ប្រព័ន្ធវ៉ាយហ្វាយ...");
                                WiFi.begin(ssid, password);
                                while (WiFi.status() != WL_CONNECTED) {
                                    delay(500);
                                    Serial.print(".");
                                }
                                Serial.println("\n[IoT] ភ្ជាប់ Wi-Fi ជោគជ័យ! IP: " + WiFi.localIP().toString());
                                
                                // ចុះឈ្មោះឧបករណ៍ជាមួយ Server ពេលបើកដំណើរការដំបូង
                                registerDeviceOnServer();
                                }

                                void loop() {
                                // ១. គណនាលំហូរទឹករៀងរាល់ ១ វិនាទី
                                if ((millis() - oldTime) > 1000) { 
                                    detachInterrupt(digitalPinToInterrupt(FLOW_SENSOR_PIN));
                                    
                                    // រូបមន្តសម្រាប់ YF-S201: FlowRate (L/min) = Pulse Frequency / 7.5
                                    flowRate = ((1000.0 / (millis() - oldTime)) * pulseCount) / 7.5;
                                    
                                    // បូកសរុបបរិមាណទឹកដែលបានហូរចេញ (គិតជាលីត្រ)
                                    flowMilliLitres = (flowRate / 60) * 1000;
                                    totalMilliLitres += flowMilliLitres;
                                    
                                    // បោះពុម្ភបង្ហាញលើ Serial Monitor
                                    if(isValveOpen) {
                                    Serial.print("លំហូរទឹក: ");
                                    Serial.print(flowRate);
                                    Serial.print(" L/min  |  សរុប: ");
                                    Serial.print(totalMilliLitres / 1000.0);
                                    Serial.println(" L");
                                    }

                                    pulseCount = 0;
                                    oldTime = millis();
                                    attachInterrupt(digitalPinToInterrupt(FLOW_SENSOR_PIN), pulseCounter, FALLING);
                                }

                                // ២. សួរសុខទុក្ខ (Polling) ទៅកាន់ Server ដើម្បីទទួលបញ្ជា
                                if (millis() - lastServerPoll > pollInterval) {
                                    lastServerPoll = millis();
                                    checkServerCommand();
                                }
                                }

                                // អនុគមន៍ចុះឈ្មោះឧបករណ៍ទៅកាន់ Server
                                void registerDeviceOnServer() {
                                if(WiFi.status() == WL_CONNECTED) {
                                    WiFiClient client;
                                    HTTPClient http;
                                    String url = String(serverApiUrl) + "?action=register_device";
                                    
                                    http.begin(client, url);
                                    http.addHeader("Content-Type", "application/json");
                                    http.addHeader("x-api-key", API_KEY); // បញ្ជូនសោរវេទមន្ត
                                    
                                    StaticJsonDocument<200> doc;
                                    doc["device_id"] = DEVICE_ID;
                                    doc["device_type"] = "ESP8266_IRRIGATION_NODE";
                                    doc["status"] = "ONLINE";
                                    String requestBody;
                                    serializeJson(doc, requestBody);
                                    
                                    int httpCode = http.POST(requestBody);
                                    String payload = http.getString();
                                    
                                    if (httpCode > 0) {
                                    if (httpCode == HTTP_CODE_OK || httpCode == 200) {
                                        Serial.println("[IoT] បានចុះឈ្មោះឧបករណ៍ទៅកាន់ Server ដោយជោគជ័យ។ (Server ឆ្លើយតប: " + payload + ")");
                                    } else {
                                        Serial.printf("[IoT] បរាជ័យក្នុងការចុះឈ្មោះ! HTTP Code: %d\n", httpCode);
                                        Serial.println("មូលហេតុ: " + payload);
                                    }
                                    } else {
                                    Serial.printf("[IoT] បរាជ័យក្នុងការភ្ជាប់ទៅកាន់ Server (Network Error): %s\n", http.errorToString(httpCode).c_str());
                                    }
                                    
                                    http.end();
                                }
                                }

                                // អនុគមន៍សម្រាប់ខ្សឹបសួរម៉ាស៊ីនមេ
                                void checkServerCommand() {
                                if(WiFi.status() == WL_CONNECTED) {
                                    WiFiClient client;
                                    HTTPClient http;
                                    
                                    String url = String(serverApiUrl) + "?action=get_command&device_id=" + String(DEVICE_ID);
                                    http.begin(client, url);
                                    http.addHeader("x-api-key", API_KEY); // បញ្ជូនសោរវេទមន្តការពារ
                                    
                                    int httpCode = http.GET();
                                    
                                    if (httpCode == HTTP_CODE_OK || httpCode == 200) {
                                    String payload = http.getString();
                                    
                                    StaticJsonDocument<256> doc;
                                    DeserializationError error = deserializeJson(doc, payload);
                                    
                                    if (!error) {
                                        String pumpState = doc["data"]["pump_state"].as();
                                        
                                        if(pumpState == "ON" && !isValveOpen) {
                                        openValve();
                                        } else if (pumpState == "OFF" && isValveOpen) {
                                        closeValve();
                                        }
                                        
                                        // ផ្ញើរបាយការណ៍លំហូរទឹកត្រលប់ទៅ Server វិញ
                                        updateFlowToServer();
                                    }
                                    }
                                    http.end();
                                }
                                }

                                void openValve() {
                                Serial.println("\n[Solenoid] ទទួលបញ្ជា! កំពុងបើកសន្ទះទឹក...");
                                digitalWrite(RELAY_PIN, LOW); // បញ្ជូនភ្លើង 12V ទៅកាន់ Solenoid (Active LOW)
                                isValveOpen = true;
                                }

                                void closeValve() {
                                Serial.println("\n[Solenoid] ទទួលបញ្ជា! កំពុងបិទសន្ទះទឹក...");
                                digitalWrite(RELAY_PIN, HIGH); // កាត់ផ្តាច់ភ្លើង
                                isValveOpen = false;
                                logIrrigationSession();
                                totalMilliLitres = 0; 
                                }

                                void updateFlowToServer() {
                                WiFiClient client;
                                HTTPClient http;
                                String url = String(serverApiUrl) + "?action=update_flow";
                                
                                http.begin(client, url);
                                http.addHeader("Content-Type", "application/json");
                                http.addHeader("x-api-key", API_KEY); // បញ្ជូនសោរវេទមន្ត
                                
                                StaticJsonDocument<200> doc;
                                doc["device_id"] = DEVICE_ID;
                                doc["flow_rate"] = flowRate;
                                doc["total_volume"] = totalMilliLitres / 1000.0;
                                doc["is_running"] = isValveOpen ? 1 : 0;
                                String requestBody;
                                serializeJson(doc, requestBody);
                                
                                int httpCode = http.POST(requestBody);
                                
                                if (httpCode <= 0 || (httpCode != HTTP_CODE_OK && httpCode != 200)) {
                                    Serial.printf("[IoT] បរាជ័យក្នុងការបញ្ជូនទិន្នន័យទឹក! HTTP Code: %d\n", httpCode);
                                }
                                
                                http.end();
                                }

                                void logIrrigationSession() {
                                Serial.println("[System] បានរក្សាទុកកំណត់ត្រាទឹកប្រចាំគ្រា។");
                                }
                            

2. Python (Requests Library)

ឧទាហរណ៍នៃការតភ្ជាប់រវាង Python Script ខាងក្រៅ ឬ Raspberry Pi មកកាន់ប្រព័ន្ធ។

client_test.py
                            import requests
                                import json

                                API_URL = "http://YOUR_SERVER_IP/hardware_api.php?action=register_device"
                                API_KEY = "OneANK_Secret_Device_Key_2026"

                                headers = {
                                    "Content-Type": "application/json",
                                    "x-api-key": API_KEY
                                }

                                payload = {
                                    "device_id": "SENSOR_TEMP_002",
                                    "device_type": "SOIL_MOISTURE_SENSOR"
                                }

                                try:
                                    response = requests.post(API_URL, headers=headers, data=json.dumps(payload))
                                    response.raise_for_status() # Check for HTTP errors
                                    
                                    result = response.json()
                                    print("Success:", result)
                                except requests.exceptions.RequestException as e:
                                    print("Failed to connect:", e)
                            
                        

Over-The-Air (OTA) Updates

GET /ota_manager.php

Endpoint នេះអនុញ្ញាតឱ្យ ESP8266 ឆែករកកំណែកូដថ្មីដោយស្វ័យប្រវត្តិ។ បើមានកំណែថ្មី ម៉ាស៊ីនមេនឹងបាញ់ឯកសារ Binary (.bin) ឱ្យឧបករណ៍ដំឡើងដោយខ្លួនឯង។

Required Headers (Sent by ESP8266)

x-esp8266-version: [Current Version]
x-esp8266-sta-mac: [Device MAC Address]

Success

Operation completed.