Tài Liệu API
Hướng dẫn kết nối thiết bị phần cứng (ESP32 / IoT) với SmartSac Web Server để truyền nhận dữ liệu và điều khiển thời gian thực.
Giới Thiệu
SmartSac cung cấp hai nhóm API chính:
- Device API — dành riêng cho vi điều khiển (ESP32, Arduino). Dùng Station Token để xác thực.
- Web API — dành cho ứng dụng web/mobile đã đăng nhập. Dùng Session Cookie.
Base URL: https://hetcuu.com/smartsac
Xác Thực
Mỗi trạm sạc có một Station Token riêng (tạo từ trang Quản Lý Trạm). Gửi token theo một trong ba cách:
| Cách | Vị trí | Ví dụ |
|---|---|---|
| Bearer | Header Authorization | Authorization: Bearer SK_xxx |
| X-Header | Header tùy chỉnh | X-Station-Token: SK_xxx |
| Query | URL parameter | ?token=SK_xxx |
Không commit Station Token lên GitHub. Lưu trong Preferences hoặc EEPROM trên thiết bị.
Cấu Trúc Response
Mọi response đều là JSON với trường status:
{
"status": "success" | "error",
"message": "...", // mô tả lỗi (khi status=error)
"data": { ... } // dữ liệu trả về (khi status=success)
}
Gửi Telemetry
POST
/api/station/device/telemetry
Gửi dữ liệu cảm biến từ thiết bị lên server
Gọi định kỳ (khuyến nghị 3–5 giây) để cập nhật telemetry. Server lưu vào Redis với TTL 60s.
Headers
| Header | Giá trị |
|---|---|
| Content-Type | application/json |
| Authorization | Bearer <station_token> |
Body (JSON)
| Trường | Kiểu | Mô tả |
|---|---|---|
| p | float | Công suất (W) |
| v | float | Điện áp đầu vào (V) |
| i | float | Dòng điện (A) |
| ds | float | Nhiệt độ DS18B20 — bộ sạc (°C) |
| mlx | float | Nhiệt độ MLX90614 — vỏ bình (°C) |
| dht_t | float | Nhiệt độ môi trường DHT (°C) |
| dht_h | float | Độ ẩm môi trường (%) |
| state | string | Mã trạng thái sạc (xem bảng bên dưới) |
| state_text | string | Mô tả trạng thái tiếng Việt |
| charge_time_min | float | Thời gian đã sạc (phút) |
| relay_on | bool | Relay đang bật? |
| charging | bool | Đang sạc? |
| wifi_rssi | int | RSSI WiFi (dBm) |
| energy_session_kwh | float | Điện năng phiên hiện tại (kWh) |
| energy_total_kwh | float | Tổng điện năng tích lũy (kWh) |
Response thành công
HTTP 200
{ "status": "success", "message": "Đã nhận telemetry", "station": 42 }
Nhận Config & Lệnh Điều Khiển
GET
/api/station/device/config
Lấy cấu hình và lệnh điều khiển từ server
Gọi định kỳ (khuyến nghị 7–10 giây). Server trả về cấu hình mới nhất và lệnh điều khiển (nếu có).
Response (data object)
{
"status": "success",
"data": {
"station_name": "Trạm Sạc 01",
"config": {
"wait_time": 60, // phút chờ trước khi sạc
"measure_interval": 300, // giây xác nhận đầy
"threshold_w": 10.0, // ngưỡng đầy (W)
"limit_input_w": 1000, // công suất tối đa (W)
"max_temp_charger": 55, // nhiệt ngắt DS (°C)
"max_temp_battery": 55, // nhiệt ngắt MLX (°C)
"max_temp_env": 45, // nhiệt ngắt môi trường (°C)
"max_humidity": 85, // độ ẩm ngắt (%)
"max_time_h": 10, // giới hạn giờ sạc
"battery_type": "lead", // loại pin: lead | li-ion
"capacity_ah": 20, // dung lượng (Ah)
"output_a": 3.0 // dòng sạc (A)
},
"command": {
"action": "charge_now" // charge_now | charge_wait | charge_stop | ""
},
"telegram": {
"enabled": true,
"token": "123:ABC...",
"chat_id": "987654321"
}
}
}
Sau khi thực hiện lệnh action, thiết bị nên gửi telemetry ngay để server cập nhật trạng thái.
Ví dụ — ESP32 (Arduino / C++)
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
const char* SERVER = "https://hetcuu.com/smartsac";
const char* TOKEN = "SK_YOUR_TOKEN_HERE"; // lấy từ trang Quản Lý Trạm
// ── Gửi telemetry ──────────────────────────────────────────
bool postTelemetry(float p, float v, float i, float ds,
float mlx, float dht_t, float dht_h,
const char* state, bool charging) {
HTTPClient http;
http.begin(String(SERVER) + "/api/station/device/telemetry");
http.setTimeout(5000);
http.addHeader("Content-Type", "application/json");
http.addHeader("Authorization", String("Bearer ") + TOKEN);
StaticJsonDocument<512> doc;
doc["p"] = p; doc["v"] = v; doc["i"] = i;
doc["ds"] = ds; doc["mlx"] = mlx;
doc["dht_t"] = dht_t; doc["dht_h"] = dht_h;
doc["state"] = state;
doc["charging"] = charging;
String body; serializeJson(doc, body);
int code = http.POST(body);
http.end();
return code == 200;
}
// ── Lấy config & lệnh điều khiển ──────────────────────────
String fetchCommand() {
HTTPClient http;
http.begin(String(SERVER) + "/api/station/device/config");
http.setTimeout(5000);
http.addHeader("Authorization", String("Bearer ") + TOKEN);
int code = http.GET();
if (code != 200) { http.end(); return ""; }
String body = http.getString();
http.end();
StaticJsonDocument<2048> doc;
if (deserializeJson(doc, body)) return "";
return doc["data"]["command"]["action"] | "";
}
// ── Loop ───────────────────────────────────────────────────
unsigned long lastTelemetryMs = 0, lastConfigMs = 0;
void loop() {
unsigned long now = millis();
if (now - lastTelemetryMs >= 3000) {
postTelemetry(readPower(), readVoltage(), readCurrent(),
readTempDS(), readTempMLX(), readTempDHT(),
readHumDHT(), currentStateCode(), isCharging);
lastTelemetryMs = now;
}
if (now - lastConfigMs >= 7000) {
String cmd = fetchCommand();
if (cmd == "charge_now") startChargingNow();
else if (cmd == "charge_wait") setWaitMode();
else if (cmd == "charge_stop") stopAll();
lastConfigMs = now;
}
}
Ví dụ — Python
import requests, time
SERVER = "https://hetcuu.com/smartsac"
TOKEN = "SK_YOUR_TOKEN_HERE"
HEADERS = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"}
def post_telemetry(data: dict):
r = requests.post(f"{SERVER}/api/station/device/telemetry",
json=data, headers=HEADERS, timeout=5)
return r.json()
def get_command() -> str:
r = requests.get(f"{SERVER}/api/station/device/config",
headers=HEADERS, timeout=5)
return r.json().get("data", {}).get("command", {}).get("action", "")
# Ví dụ vòng lặp
while True:
post_telemetry({"p": 150, "v": 220, "i": 0.68,
"ds": 38.5, "mlx": 35.2,
"dht_t": 30, "dht_h": 65,
"state": "DANG_SAC", "charging": True})
cmd = get_command()
if cmd: print("Lệnh từ server:", cmd)
time.sleep(3)
Ví dụ — cURL
# Gửi telemetry
curl -X POST https://hetcuu.com/smartsac/api/station/device/telemetry \
-H "Authorization: Bearer SK_YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"p":120,"v":220,"i":0.55,"ds":36,"mlx":33,"dht_t":28,"dht_h":70,"state":"DANG_SAC","charging":true}'
# Lấy config và lệnh
curl https://hetcuu.com/smartsac/api/station/device/config \
-H "Authorization: Bearer SK_YOUR_TOKEN"
Mã Trạng Thái Sạc
| Mã (state) | Ý nghĩa | Relay |
|---|---|---|
| DANG_SAC | Đang sạc bình thường | ON |
| DANG_DO | Đang đo công suất (probe) | ON |
| SAC_CHO | Chờ sạc (auto, đếm ngược) | OFF |
| FULL | Ngắt: pin đầy | OFF |
| NGAT_NHIET | Ngắt: quá nhiệt | OFF |
| NGAT_DO_AM | Ngắt: độ ẩm quá cao | OFF |
| NGAT_QUA_GIO | Ngắt: quá thời gian giới hạn | OFF |
| NGAT_QUA_CONG_SUAT | Ngắt: công suất vượt ngưỡng | OFF |
| LOI_CAM_BIEN | Lỗi cảm biến (DS/MLX/PZEM) | OFF |
| MAT_KET_NOI | Thiết bị mất kết nối >60s | — |
HTTP Status Codes
| Code | Ý nghĩa |
|---|---|
| 200 | Thành công |
| 400 | Dữ liệu gửi lên thiếu hoặc sai định dạng |
| 401 | Thiếu token hoặc token không hợp lệ |
| 404 | Không tìm thấy trạm ứng với token này |
| 503 | Tính năng tạm tắt (ví dụ: AI đang bảo trì) |
| 500 | Lỗi server nội bộ |