2026年8月3日 星期一

[水井村USR] EP05|ESP32 × Django REST API:將感測資料上傳雲端

智慧生活科技專業社群|IoT 入門系列|適合大一新生
前四篇已完成 I²C、四種水質感測器、ESP32 讀值,以及 Wi-Fi AP 與 NVS 設定。EP05 將把這些成果送上雲端:ESP32 透過 Wi-Fi 將水溫、pH、溶氧與鹽度組成 JSON,再以 HTTP POST 傳送到 Django REST API,最後顯示於智慧養殖 Dashboard。

請先將 EP05 主圖上傳 Blogger,再把 EP05_MAIN_IMAGE_URL 換成圖片網址。


圖:從 Atlas 水質感測器、ESP32、Django REST API 到 Dashboard 的完整資料流程。

一、這一篇要完成什麼?

任務 1|建立 JSON把感測值轉成 API 可接受的資料格式。
任務 2|HTTP POSTESP32 將 JSON 傳送到 Django。
任務 3|REST APIDjango 驗證並儲存資料。
任務 4|Dashboard顯示各養殖戶最新水質狀況。

二、完整系統架構

Atlas 感測器 → ESP32 → Wi-Fi → HTTP POST → Django REST API → 資料庫 → Dashboard

ESP32 不需要知道資料庫帳號密碼,也不需要直接操作資料表,只要把資料送到 API 即可。

核心觀念:ESP32 是資料提供者;Django REST API 是資料入口;資料庫負責保存;Dashboard 負責呈現。

三、實際使用的 API 與 Dashboard

本專案 API 端點:

Django REST API
https://shuijingusr.pythonanywhere.com/api/pond/sensor-reading/

智慧養殖 Dashboard:

開啟智慧養殖 Dashboard

四、什麼是 REST API?

REST API 是讓不同裝置或程式透過 HTTP 交換資料的方式。ESP32、手機 App、網站與 Python 程式,都可以使用相同 API。

HTTP 方法用途本篇是否使用
GET讀取資料Dashboard 查詢資料時使用
POST新增資料ESP32 上傳感測資料
PUT/PATCH修改資料本篇未使用
DELETE刪除資料本篇未使用

五、JSON 是什麼?

JSON 是 IoT 最常見的資料交換格式。每筆資料由 Key 與 Value 組成:

本專案 JSON 格式
{
  "token": "abc123",
  "farm_name": "湖虎戰隊",
  "pond_code": "1",
  "water_temperature": 30.01,
  "salinity": 0.44,
  "ph": 6.80,
  "dissolved_oxygen": 31.92,
  "water_source": "直流變頻水車運轉中",
  "recorded_at": "2026-08-03T21:30:00+08:00"
}
數值欄位應使用數字,不要加上引號。例如 "ph": 6.80,不要寫成 "ph": "6.80"。

六、ESP32 建立 JSON

程式碼 1:建立 Payload
String buildPayload() {
  String payload;

  payload += "{";
  payload += "\"token\":\"abc123\",";
  payload += "\"farm_name\":\"湖虎戰隊\",";
  payload += "\"pond_code\":\"1\",";
  payload += "\"water_temperature\":30.01,";
  payload += "\"salinity\":0.44,";
  payload += "\"ph\":6.80,";
  payload += "\"dissolved_oxygen\":31.92,";
  payload += "\"water_source\":\"直流變頻水車運轉中\"";
  payload += "}";

  return payload;
}

正式程式中,不應把感測值寫死,而是帶入 RTD、pH、DO 與 EC 讀值。

七、確認 Wi-Fi 已連線

程式碼 2:連線檢查
if (WiFi.status() != WL_CONNECTED) {
  Serial.println("Wi-Fi 尚未連線,本次不上傳");
  return;
}

若 Wi-Fi 尚未連線,程式應停止本次 POST,避免重複產生連線錯誤。

八、ESP32 使用 HTTPS POST

程式碼 3:HTTP POST 核心流程
#include <WiFi.h>
#include <HTTPClient.h>
#include <NetworkClientSecure.h>

const char* API_URL =
  "https://shuijingusr.pythonanywhere.com/"
  "api/pond/sensor-reading/";

void uploadData(String payload) {
  if (WiFi.status() != WL_CONNECTED) {
    return;
  }

  NetworkClientSecure client;

  // 測試階段使用
  client.setInsecure();

  HTTPClient http;

  http.begin(client, API_URL);

  http.addHeader(
    "Content-Type",
    "application/json"
  );

  http.addHeader(
    "Accept",
    "application/json"
  );

  int httpCode =
    http.POST(payload);

  String response =
    http.getString();

  Serial.print("HTTP Code:");
  Serial.println(httpCode);

  Serial.print("Response:");
  Serial.println(response);

  http.end();
}
測試時可使用 setInsecure(),正式部署時建議改用伺服器根憑證驗證 HTTPS。

九、Content-Type 為什麼重要?

Django 需要知道 Request Body 是 JSON,因此必須設定:

HTTP Header
Content-Type: application/json

若沒有這個 Header,後端可能無法正確解析資料。

十、Django REST API 的資料流程

Request JSON → View → Serializer → Model → Database
Model定義資料庫欄位。
Serializer驗證 JSON 與轉換資料。
View處理 POST Request。
URL設定 API 路徑。

十一、Django Model 概念

models.py 範例
from django.db import models

class SensorReading(models.Model):
    token = models.CharField(max_length=100)
    farm_name = models.CharField(max_length=100)
    pond_code = models.CharField(max_length=30)

    water_temperature = models.FloatField(
        null=True,
        blank=True
    )

    salinity = models.FloatField(
        null=True,
        blank=True
    )

    ph = models.FloatField(
        null=True,
        blank=True
    )

    dissolved_oxygen = models.FloatField(
        null=True,
        blank=True
    )

    water_source = models.CharField(
        max_length=200,
        blank=True
    )

    recorded_at = models.DateTimeField()

十二、Serializer 的工作

serializers.py 範例
from rest_framework import serializers
from .models import SensorReading

class SensorReadingSerializer(
    serializers.ModelSerializer
):
    class Meta:
        model = SensorReading
        fields = "__all__"

Serializer 會檢查:

  • 欄位是否存在。
  • 數值格式是否正確。
  • 時間格式是否可解析。
  • 必填資料是否缺少。

十三、API View 概念

views.py 範例
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status

@api_view(["POST"])
def sensor_reading(request):
    serializer = SensorReadingSerializer(
        data=request.data
    )

    if serializer.is_valid():
        serializer.save()

        return Response(
            serializer.data,
            status=status.HTTP_201_CREATED
        )

    return Response(
        serializer.errors,
        status=status.HTTP_400_BAD_REQUEST
    )

十四、URL 設定

urls.py 範例
from django.urls import path
from . import views

urlpatterns = [
    path(
        "api/pond/sensor-reading/",
        views.sensor_reading,
        name="sensor-reading"
    ),
]

十五、HTTP 狀態碼如何判斷?

狀態碼意義處理方式
200請求成功後端已接受或回傳資料
201新增成功感測資料已寫入資料庫
400資料格式錯誤檢查 JSON、欄位與資料型態
401/403驗證失敗檢查 token 或權限
500後端錯誤檢查 Django Log、Model、Serializer
負值ESP32 連線錯誤檢查 Wi-Fi、DNS、HTTPS 與網址

十六、使用 Postman 先測試 API

在 ESP32 上傳前,可先用 Postman 測試:

  1. Method 選擇 POST。
  2. 輸入 API 網址。
  3. Body 選擇 raw。
  4. 格式選擇 JSON。
  5. 貼入 Payload。
  6. 按 Send。
若 Postman 可成功,但 ESP32 不行,問題通常在 Wi-Fi、HTTPS、Header 或 ESP32 JSON 字串。

十七、實際上傳結果

序列監控範例
========== Django API 上傳 ==========
[API] URL:
https://shuijingusr.pythonanywhere.com/
api/pond/sensor-reading/

[API] HTTP 狀態碼:201
[API] 上傳成功
====================================

十八、Dashboard 即時顯示

資料寫入資料庫後,Dashboard 可以顯示:

  • 養殖戶與魚塭。
  • 水溫。
  • 鹽度。
  • pH。
  • 溶氧。
  • 最新資料時間。
水井村 USR 智慧養殖 Dashboard
請將 Dashboard 截圖上傳 Blogger,再替換 EP05_DASHBOARD_IMAGE_URL。
圖:ESP32 上傳後,Dashboard 顯示多家養殖戶的最新水質狀態。

十九、常見問題與排除

問題可能原因建議
POST 回傳 -1Wi-Fi、DNS、HTTPS 失敗先確認 ESP32 能否取得 IP
400 Bad RequestJSON 或欄位格式不符查看 Django 回應內容
403 ForbiddenToken 或權限錯誤檢查 token
500 Internal Server ErrorDjango 程式錯誤查看 PythonAnywhere Error Log
Dashboard 沒更新查詢不是最新資料檢查排序與最新一筆查詢
時間不正確NTP 未同步或時區錯誤使用 ISO 8601+08:00

二十、本篇重點

  1. ESP32 使用 JSON 封裝感測資料。
  2. 透過 HTTP POST 傳送到 Django REST API。
  3. Content-Type 必須設定為 application/json。
  4. Serializer 負責驗證資料。
  5. 201 表示資料新增成功。
  6. Dashboard 從資料庫取得最新監測值。

結語

完成 EP05 後,智慧養殖系統已經建立從感測器到雲端的完整資料鏈。ESP32 透過 I²C 取得水質資料,使用 Wi-Fi 與 HTTPS 將 JSON 傳送到 Django REST API,再由資料庫與 Dashboard 完成保存與呈現。這也是 IoT 系統中最重要的核心能力:把真實世界的感測資料,轉化為可查詢、可分析、可視化的數位資訊。

AI 協作聲明:本文由作者主導系統設計、ESP32 程式開發、Django REST API 建置、資料格式規劃、API 測試與 Dashboard 整合,並使用生成式 AI 協助文字整理、程式碼說明、版面設計與教學資訊圖生成;所有 API 欄位、測試流程與系統架構均依本專案實際開發成果整理,並由作者審核修訂。

沒有留言:

張貼留言