Pico 2 W × Thonny|第 5 次課程
JSON 與 IoT 資料格式
感測器產生資料,Pico 負責整理與傳送;要讓不同設備、程式和伺服器都能理解同一筆資訊,就需要清楚一致的資料格式。本篇介紹 JSON 的基本結構、Python 字典與 JSON 的轉換,以及 IoT 遙測欄位的設計方法。
作者:施朝斌一、為什麼 IoT 需要 JSON?
如果只傳送 28.3,71.2,350,接收端雖然看到三個數字,卻不知道它們各自代表溫度、濕度還是光照。JSON 在資料旁附上欄位名稱,讓資料較容易閱讀,也讓程式能依欄位取值。
{
"temperature": 28.3,
"humidity": 71.2,
"light": 350
}
以上數字沿用課程投影片作為格式示例,不代表實際場域量測結果。正式資料應由感測器讀取,並清楚標明單位與資料來源。
二、JSON 的基本結構
JSON 物件使用大括號 {},以「欄位名稱:值」的方式組織資料;陣列使用中括號 [],可以放置多筆項目。常見值的型態包括字串、數字、布林值、物件、陣列,以及 null。
{
"device": "PICO01",
"temperature": 28.3,
"humidity": 71.2,
"relay": true,
"location": {
"room": "A101"
},
"alerts": []
}
- 字串:文字需使用雙引號,例如
"PICO01"。 - 數字:例如
28.3;不要把數字不必要地存成文字。 - 布林值:使用小寫的
true或false。 - 物件:可再包含一組欄位,例如
location。 - 陣列:使用中括號,可表示多筆資料或多個項目。
- null:表示目前沒有可用值;它不同於字串
"null"或數字 0。
三、Python 字典與 JSON 互相轉換
在 Python 程式中,資料常先以字典整理。json.dumps()把 Python 資料轉成 JSON 文字;json.loads()則把 JSON 文字解析回 Python 資料。
import json
data = {
"temperature": 28.3,
"humidity": 71.2,
"relay": True
}
json_text = json.dumps(data)
print(json_text)
decoded_data = json.loads(json_text)
print(decoded_data["temperature"])
Python 的 True轉成 JSON 後會是小寫的 true;JSON 解析回 Python 後則會成為 True。同樣地,Python 的 None會轉成 JSON 的 null。
dumps把資料「序列化」成文字;loads把文字「解析」成資料。HTTP 傳輸時,送出或收到的通常是文字內容。四、設計 IoT 遙測資料欄位
一筆可交換的遙測資料,除了感測值,也應讓接收端知道資料來自哪個設備、何時產生,以及每個數字代表什麼。欄位名稱與格式最好固定,後續接入 HTTP API、MQTT 或 Dashboard 時才能共用。
{
"deviceId": "PICO01",
"timestamp": null,
"temperature": 28.3,
"humidity": 71.2,
"light": 350,
"battery": 4.05
}
這些感測值是投影片中的示範數字,不是實際量測結果。timestamp目前設為 null,表示範例沒有提供時間;只有在 Pico 已取得可靠時鐘並採用一致的時間格式後,才應填入時間戳記。每個欄位也應訂定單位,例如溫度使用 °C、電壓使用 V,避免不同設備各自解讀。
設計欄位時,還要決定設備識別方式、欄位拼法、數值型態、單位、取樣時間與缺值表示法。這些規則就是資料格式的一部分。
五、用 Python 建立自己的 JSON 遙測資料
以下以示範值展示資料結構。實作時請把數值換成程式實際讀到的感測器資料;若某欄位目前沒有讀值,使用 None轉成 JSON null,不要假裝已取得測量結果。
import json
telemetry = {
"deviceId": "PICO01",
"timestamp": None,
"temperature": 28.3,
"humidity": 71.2,
"relay": False
}
payload = json.dumps(telemetry)
print(payload)
接著可以把 payload放進 HTTP POST 的 Body,或在下一堂課將它作為 MQTT 訊息內容。只要欄位規則維持一致,接收端就能用相同方式解析。
六、錯誤資料也要處理
網路上的資料不一定完整、型態正確或仍然新鮮。接收端應先檢查必需欄位,再確認型態與時間資訊,並適當處理伺服器錯誤。
import json
response_text = '{"temperature": 28.3}'
try:
data = json.loads(response_text)
temperature = data.get("temperature")
humidity = data.get("humidity")
if temperature is None:
print("Temperature is missing")
elif not isinstance(temperature, (int, float)):
print("Temperature has the wrong type")
else:
print("Temperature:", temperature)
if humidity is None:
print("Humidity is missing")
else:
print("Humidity:", humidity)
except ValueError as error:
print("Invalid JSON:", error)
- 欄位不存在:使用
get()或明確檢查,避免直接索引而產生 KeyError。 - 型態錯誤:數字
28.3與文字"28.3"不是同一種資料。 - 資料過期:若有可靠時間戳記,可比較資料時間與目前時間;沒有時鐘時不要假裝能判定新舊。
- 伺服器錯誤:檢查 HTTP 狀態碼,必要時有限次重試並記錄結果。
七、REST API 路徑與資料責任
REST API 常用不同路徑區分資源或功能。例如 /api/telemetry可代表感測資料、/api/status可代表設備狀態、/api/control可代表控制要求、/api/config可代表設定資訊。路徑名稱只是設計示例,實際 API 應依服務規格使用。
把感測資料、設備狀態、控制命令與設定分開,有助於開發者理解每個端點的用途。欄位名稱與格式也要在設備端和伺服器端保持一致。
八、實作任務:定義自己的 Pico 資料格式
- 建立一個穩定的
deviceId。 - 選擇 2 至 3 個實際存在或課堂指定的感測欄位。
- 加入一個設備狀態欄位,例如繼電器開關狀態。
- 為每個欄位記錄型態、單位與缺值表示方式。
- 使用
json.dumps()轉成 JSON,並在 Shell 檢查輸出。 - 依課程提供的測試服務 POST,檢查狀態碼與回應內容。
本篇重點回顧
- JSON 以欄位名稱標示資料意義,方便不同設備和程式交換資訊。
- Python 字典可用
json.dumps()轉為 JSON 文字,用json.loads()解析回資料。 - IoT 遙測格式應固定欄位名稱、型態、單位、設備識別與時間規則。
- 要檢查欄位缺漏、型態不符、資料是否過期及 HTTP 錯誤。
- 範例數值只示範格式;實際結果應來自感測器或明確標示的測試資料。
下一篇將把一致的 JSON 遙測資料帶入 MQTT,讓 Pico 發布感測訊息,也能訂閱控制命令。
沒有留言:
張貼留言