2026年4月22日 星期三

Node Red MQTT

Node Red MQTT

https://hackmd.io/@joe94113/node-red_mqtt_esp32_and_open_api




























wokwi程式 修改mqtt_server = "broker.mqtt-dashboard.com"; // MQTT 服務器地址

#include <WiFi.h>  
#include <PubSubClient.h>
#include <DHTesp.h>

const int DHT_PIN = 15;  // DHT 感測器的連接 PIN
DHTesp dht;
const char* ssid = "Wokwi-GUEST"; // WiFi SSID
const char* password = ""; // WiFi 密碼
const char* mqtt_server = "broker.mqtt-dashboard.com"; // MQTT 服務器地址

WiFiClient espClient;
PubSubClient client(espClient);
unsigned long lastMsg = 0; // 記錄上一次消息發送的時間
float temp = 0; // 溫度變量
float hum = 0; // 濕度變量

// 設置 WiFi 連接
void setup_wifi() {
  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  // 等待 WiFi 連接
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  randomSeed(micros());

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

// MQTT 消息回調函數
void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
}

// 重連 MQTT 服務器
void reconnect() {
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    String clientId = "ESP32Client-";
    clientId += String(random(0xffff), HEX);
    if (client.connect(clientId.c_str())) {
      Serial.println("Connected");
      client.publish("/ThinkIOT/Publish", "Welcome");
      client.subscribe("/ThinkIOT/Subscribe");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}

// 初始化設置
void setup() {
  pinMode(2, OUTPUT);    
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
  dht.setup(DHT_PIN, DHTesp::DHT22); // 初始化 DHT22
}

// 主循環
void loop() {
  // 如果未連接 MQTT,則嘗試重新連接
  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  unsigned long now = millis();
  if (now - lastMsg > 2000) { // 每 2 秒發布一次數據
    lastMsg = now;
    TempAndHumidity  data = dht.getTempAndHumidity();

    String temp = String(data.temperature, 2);
    client.publish("/Thinkitive/temp", temp.c_str()); // 發布溫度數據
    String hum = String(data.humidity, 1);
    client.publish("/Thinkitive/hum", hum.c_str());   // 發布濕度數據

    Serial.print("Temperature: ");
    Serial.println(temp);
    Serial.print("Humidity: ");
    Serial.println(hum);
  }
}



看到這個提示別擔心,這通常是因為瀏覽器基於安全性考量暫時關閉了腳本功能。只要幾個簡單的步驟就能重新開啟。

以下是針對目前主流瀏覽器的開啟教學:


1. Google Chrome (電腦版)

  1. 點擊瀏覽器右上角的 「三個點」 圖示,選擇 「設定」

  2. 在左側選單點擊 「隱私權和安全性」

  3. 點擊 「網站設定」

  4. 向下滑動找到「內容」區塊,點擊 「JavaScript」

  5. 勾選 「網站可以使用 JavaScript」

  6. 回到原本的網頁並 重新整理 (F5)


2. Microsoft Edge

  1. 點擊右上角的 「三個點」 圖示,選擇 「設定」

  2. 在左側選單選擇 「Cookie 和網站權限」

  3. 在「所有權限」清單中找到並點擊 「JavaScript」

  4. 「允許 (建議)」 的開關切換為 開啟狀態

  5. 重新整理網頁。



Node-RED 中安裝 MQTT broker 的步驟,並可以開始使用 MQTT 進行消息傳輸

[{"id":"073cac6e5e434d41","type":"mqtt out","z":"de93e29c07cca82f","name":"","topic":"sensors/livingroom/temp","qos":"","retain":"","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"841df58d.ee5e98","x":310,"y":180,"wires":[]},{"id":"ceb8068819adc757","type":"inject","z":"de93e29c07cca82f","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":"","topic":"","payload":"22","payloadType":"num","x":110,"y":180,"wires":[["073cac6e5e434d41"]]},{"id":"5fc97feb1b566004","type":"mqtt in","z":"de93e29c07cca82f","name":"","topic":"sensors/livingroom/temp","qos":"2","datatype":"auto-detect","broker":"841df58d.ee5e98","nl":false,"rap":false,"inputs":0,"x":150,"y":260,"wires":[["6c6dc58f97ab8f86"]]},{"id":"6c6dc58f97ab8f86","type":"debug","z":"de93e29c07cca82f","name":"","active":true,"console":"false","complete":"false","x":350,"y":260,"wires":[]},{"id":"bcca028dd9cde448","type":"debug","z":"de93e29c07cca82f","name":"debug 19","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":340,"y":40,"wires":[]},{"id":"20f600cc71d280e5","type":"debug","z":"de93e29c07cca82f","name":"debug 20","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":340,"y":100,"wires":[]},{"id":"a4ee27d876e6c883","type":"aedes broker","z":"de93e29c07cca82f","name":"","mqtt_port":"1884","mqtt_ws_bind":"port","mqtt_ws_port":"","mqtt_ws_path":"","cert":"","key":"","ca":"","certname":"","keyname":"","caname":"","persistence_bind":"memory","dburl":"","persist_to_file":false,"usetls":false,"x":130,"y":80,"wires":[["bcca028dd9cde448"],["20f600cc71d280e5"]]},{"id":"841df58d.ee5e98","type":"mqtt-broker","name":"","broker":"broker.hivemq.com","port":"1883","clientid":"","autoConnect":true,"usetls":false,"compatmode":false,"protocolVersion":"4","keepalive":"15","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","birthMsg":{},"closeTopic":"","closePayload":"","closeMsg":{},"willTopic":"","willQos":"0","willPayload":"","willMsg":{},"userProps":"","sessionExpiry":""}]


Node-RED 中配置 MQTT 並訂閱 ESP32 發送資料

[{"id":"06616414d9f0a6f3","type":"aedes broker","z":"3b843e74e7ab6ef8","name":"","mqtt_port":"1884","mqtt_ws_bind":"port","mqtt_ws_port":"","mqtt_ws_path":"","cert":"","key":"","certname":"","keyname":"","dburl":"","usetls":false,"x":130,"y":80,"wires":[["866a2384f6992b64"],["b013bf4fca5a488e"]]},{"id":"866a2384f6992b64","type":"debug","z":"3b843e74e7ab6ef8","name":"debug 19","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":340,"y":40,"wires":[]},{"id":"b013bf4fca5a488e","type":"debug","z":"3b843e74e7ab6ef8","name":"debug 20","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":340,"y":100,"wires":[]},{"id":"ceb3112cd35e970e","type":"mqtt in","z":"3b843e74e7ab6ef8","name":"","topic":"/Thinkitive/temp","qos":"0","datatype":"auto-detect","broker":"b9efc827e98bf7f9","nl":false,"rap":true,"rh":0,"inputs":0,"x":120,"y":180,"wires":[["7c6bdec976aab81d"]]},{"id":"a51c937face296dc","type":"mqtt in","z":"3b843e74e7ab6ef8","name":"","topic":"/Thinkitive/hum","qos":"0","datatype":"auto-detect","broker":"b9efc827e98bf7f9","nl":false,"rap":true,"rh":0,"inputs":0,"x":120,"y":240,"wires":[["f06f1d6381b63b69"]]},{"id":"7c6bdec976aab81d","type":"ui_gauge","z":"3b843e74e7ab6ef8","name":"TRMP","group":"70d1d491db52e4fe","order":7,"width":6,"height":4,"gtype":"gage","title":"ESP32溫度","label":"","format":"{{value}}","min":0,"max":"150","colors":["#00b500","#e6e600","#ec2727"],"seg1":"","seg2":"","diff":false,"className":"","x":330,"y":180,"wires":[]},{"id":"f06f1d6381b63b69","type":"ui_gauge","z":"3b843e74e7ab6ef8","name":"","group":"70d1d491db52e4fe","order":12,"width":6,"height":4,"gtype":"gage","title":"ESP32濕度","label":"","format":"{{value}}","min":0,"max":"60","colors":["#15cb15","#e6e600","#ca3838"],"seg1":"","seg2":"","diff":false,"className":"","x":350,"y":240,"wires":[]},{"id":"b9efc827e98bf7f9","type":"mqtt-broker","name":"broker.mqtt-dashboard.com","broker":"broker.mqtt-dashboard.com","port":"1883","clientid":"","autoConnect":true,"usetls":false,"protocolVersion":"4","keepalive":"60","cleansession":true,"autoUnsubscribe":true,"birthTopic":"","birthQos":"0","birthRetain":"false","birthPayload":"","birthMsg":{},"closeTopic":"","closeQos":"0","closeRetain":"false","closePayload":"","closeMsg":{},"willTopic":"","willQos":"0","willRetain":"false","willPayload":"","willMsg":{},"userProps":"","sessionExpiry":""},{"id":"70d1d491db52e4fe","type":"ui_group","name":"esp32圖表","tab":"2156c1cf7f043d72","order":2,"disp":true,"width":"6","collapse":false,"className":""},{"id":"2156c1cf7f043d72","type":"ui_tab","name":"天氣圖表","icon":"dashboard","disabled":false,"hidden":false}]

Node-RED 中連接到一個公開的氣象資料 API,並抓取各地區的溫度等氣象資訊

[{"id":"84974e3b6b184603","type":"aedes broker","z":"ee949a679aeaac8d","name":"","mqtt_port":"1883","mqtt_ws_bind":"port","mqtt_ws_port":"","mqtt_ws_path":"","cert":"","key":"","ca":"","certname":"","keyname":"","caname":"","persistence_bind":"memory","dburl":"","persist_to_file":false,"usetls":false,"x":110,"y":60,"wires":[["d3d0db98037eb5a0"],["221c64cb507138ba"]]},{"id":"d3d0db98037eb5a0","type":"debug","z":"ee949a679aeaac8d","name":"debug 19","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":320,"y":40,"wires":[]},{"id":"221c64cb507138ba","type":"debug","z":"ee949a679aeaac8d","name":"debug 20","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":320,"y":80,"wires":[]},{"id":"7a50625e9de576f5","type":"mqtt out","z":"ee949a679aeaac8d","name":"","topic":"sensors/livingroom/temp","qos":"","retain":"","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"9aa0e63a7fe55694","x":590,"y":160,"wires":[]},{"id":"bf5d80bdee7081a3","type":"mqtt in","z":"ee949a679aeaac8d","name":"","topic":"sensors/livingroom/temp","qos":"2","datatype":"auto-detect","broker":"9aa0e63a7fe55694","nl":false,"rap":false,"inputs":0,"x":130,"y":220,"wires":[["b5a377175f3a3413","80fc5a39dcdee086","90567bb2394770f0","a54071ebf5b7899e","8210955ad042a18f"]]},{"id":"b5a377175f3a3413","type":"debug","z":"ee949a679aeaac8d","name":"mqTT_In","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":420,"y":220,"wires":[]},{"id":"ea0a92334afe9e73","type":"ui_dropdown","z":"ee949a679aeaac8d","name":"","label":"選擇地區","tooltip":"","place":"點擊選擇","group":"f1ec0c040bdd2739","order":37,"width":6,"height":1,"passthru":true,"multiple":false,"options":[{"label":"桃園","value":"桃園","type":"str"},{"label":"苗栗","value":"苗栗","type":"str"},{"label":"南投","value":"南投","type":"str"},{"label":"彰化","value":"埤頭","type":"str"},{"label":"台中","value":"中坑","type":"str"},{"label":"雲林","value":"斗六","type":"str"},{"label":"嘉義","value":"水上","type":"str"},{"label":"台南","value":"安南","type":"str"},{"label":"屏東","value":"九如","type":"str"},{"label":"台東","value":"延平","type":"str"},{"label":"花蓮","value":"豐濱","type":"str"},{"label":"宜蘭","value":"三星","type":"str"},{"label":"高雄","value":"三民","type":"str"},{"label":"台北","value":"平等","type":"str"}],"payload":"","topic":"topic","topicType":"msg","className":"","x":80,"y":160,"wires":[["1610a92a9b0c39de"]]},{"id":"1610a92a9b0c39de","type":"http request","z":"ee949a679aeaac8d","name":"","method":"GET","ret":"txt","paytoqs":"ignore","url":"https://opendata.cwa.gov.tw/api/v1/rest/datastore/O-A0001-001?Authorization=CWB-40C25FFF-1224-4250-B9D9-3735AAE17DBF&limit=10&format=JSON&StationName={{payload}}&WeatherElement=Weather,Now,WindSpeed,AirTemperature,RelativeHumidity,AirPressure&GeoInfo=CountyName","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":240,"y":160,"wires":[["aa1c124b347003ba"]]},{"id":"aa1c124b347003ba","type":"json","z":"ee949a679aeaac8d","name":"","property":"payload","action":"","pretty":false,"x":390,"y":160,"wires":[["7a50625e9de576f5"]]},{"id":"80fc5a39dcdee086","type":"ui_gauge","z":"ee949a679aeaac8d","name":"","group":"f1ec0c040bdd2739","order":39,"width":6,"height":4,"gtype":"gage","title":"氣溫","label":"度","format":"{{payload.records.Station[0].WeatherElement.AirTemperature}}","min":0,"max":"40","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","diff":false,"className":"","x":410,"y":260,"wires":[]},{"id":"90567bb2394770f0","type":"ui_gauge","z":"ee949a679aeaac8d","name":"","group":"f1ec0c040bdd2739","order":40,"width":6,"height":4,"gtype":"gage","title":"風速","label":"m/s","format":"{{payload.records.Station[0].WeatherElement.WindSpeed}}","min":0,"max":"10","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","diff":false,"className":"","x":410,"y":300,"wires":[]},{"id":"a54071ebf5b7899e","type":"ui_gauge","z":"ee949a679aeaac8d","name":"","group":"f1ec0c040bdd2739","order":41,"width":6,"height":4,"gtype":"gage","title":"相對濕度","label":"%","format":"{{payload.records.Station[0].WeatherElement.RelativeHumidity}}","min":"50","max":"100","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","diff":false,"className":"","x":420,"y":340,"wires":[]},{"id":"8210955ad042a18f","type":"ui_gauge","z":"ee949a679aeaac8d","name":"","group":"f1ec0c040bdd2739","order":42,"width":6,"height":4,"gtype":"gage","title":"空氣壓力","label":"atm","format":"{{payload.records.Station[0].WeatherElement.AirPressure}}","min":"900","max":"1100","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","diff":false,"className":"","x":420,"y":380,"wires":[]},{"id":"9aa0e63a7fe55694","type":"mqtt-broker","name":"","broker":"localhost","port":"1883","clientid":"","autoConnect":true,"usetls":false,"protocolVersion":"4","keepalive":"60","cleansession":true,"autoUnsubscribe":true,"birthTopic":"","birthQos":"0","birthPayload":"","birthMsg":{},"closeTopic":"","closePayload":"","closeMsg":{},"willTopic":"","willQos":"0","willPayload":"","willMsg":{},"userProps":"","sessionExpiry":""},{"id":"f1ec0c040bdd2739","type":"ui_group","name":"天氣","tab":"2156c1cf7f043d72","order":1,"disp":true,"width":12,"collapse":false,"className":""},{"id":"2156c1cf7f043d72","type":"ui_tab","name":"天氣圖表","icon":"dashboard","disabled":false,"hidden":false}]

兩個圖表一起顯示 Node-Red

[{"id":"229d489a86aaea93","type":"mqtt out","z":"8c31de38cd0a6981","name":"","topic":"sensors/livingroom/temp","qos":"","retain":"","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"78f412356543fd12","x":630,"y":220,"wires":[]},{"id":"adaec6df5a6580fb","type":"mqtt in","z":"8c31de38cd0a6981","name":"","topic":"sensors/livingroom/temp","qos":"2","datatype":"auto-detect","broker":"78f412356543fd12","nl":false,"rap":false,"inputs":0,"x":630,"y":260,"wires":[["ae695b84fba5fc23","9ed7c60684d641e1","518b5e5ea5836bdd","61ae7765a9f9edf5","0b113fc7b52cbfdb"]]},{"id":"ae695b84fba5fc23","type":"debug","z":"8c31de38cd0a6981","name":"mqTT_In","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":880,"y":200,"wires":[]},{"id":"e2e6628b7bde7a1b","type":"aedes broker","z":"8c31de38cd0a6981","name":"","mqtt_port":1883,"mqtt_ws_bind":"port","mqtt_ws_port":"","mqtt_ws_path":"","cert":"","key":"","certname":"","keyname":"","dburl":"","usetls":false,"x":150,"y":60,"wires":[["f0ae9594e8fe0786"],["0243ee57c33cba12"]]},{"id":"f0ae9594e8fe0786","type":"debug","z":"8c31de38cd0a6981","name":"debug 19","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":360,"y":40,"wires":[]},{"id":"0243ee57c33cba12","type":"debug","z":"8c31de38cd0a6981","name":"debug 20","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":360,"y":80,"wires":[]},{"id":"f50edc83dba4da17","type":"ui_dropdown","z":"8c31de38cd0a6981","name":"","label":"選擇地區","tooltip":"","place":"點擊選擇","group":"f1ec0c040bdd2739","order":2,"width":6,"height":1,"passthru":true,"multiple":false,"options":[{"label":"桃園","value":"桃園","type":"str"},{"label":"苗栗","value":"苗栗","type":"str"},{"label":"南投","value":"南投","type":"str"},{"label":"彰化","value":"埤頭","type":"str"},{"label":"台中","value":"中坑","type":"str"},{"label":"雲林","value":"斗六","type":"str"},{"label":"嘉義","value":"水上","type":"str"},{"label":"台南","value":"安南","type":"str"},{"label":"屏東","value":"九如","type":"str"},{"label":"台東","value":"延平","type":"str"},{"label":"花蓮","value":"豐濱","type":"str"},{"label":"宜蘭","value":"三星","type":"str"},{"label":"高雄","value":"三民","type":"str"},{"label":"台北","value":"平等","type":"str"}],"payload":"","topic":"topic","topicType":"msg","className":"","x":120,"y":220,"wires":[["14e3088564d30c0c","cb6bc9284f648b45"]]},{"id":"e51d55930ce8853e","type":"json","z":"8c31de38cd0a6981","name":"","property":"payload","action":"","pretty":false,"x":430,"y":220,"wires":[["229d489a86aaea93"]]},{"id":"9ed7c60684d641e1","type":"ui_gauge","z":"8c31de38cd0a6981","name":"","group":"f1ec0c040bdd2739","order":6,"width":5,"height":3,"gtype":"gage","title":"氣溫","label":"度","format":"{{payload.records.Station[0].WeatherElement.AirTemperature}}","min":0,"max":"40","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","diff":false,"className":"","x":870,"y":240,"wires":[]},{"id":"518b5e5ea5836bdd","type":"ui_gauge","z":"8c31de38cd0a6981","name":"","group":"f1ec0c040bdd2739","order":4,"width":5,"height":3,"gtype":"gage","title":"風速","label":"m/s","format":"{{payload.records.Station[0].WeatherElement.WindSpeed}}","min":0,"max":"10","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","diff":false,"className":"","x":870,"y":280,"wires":[]},{"id":"61ae7765a9f9edf5","type":"ui_gauge","z":"8c31de38cd0a6981","name":"","group":"f1ec0c040bdd2739","order":10,"width":5,"height":3,"gtype":"gage","title":"相對濕度","label":"%","format":"{{payload.records.Station[0].WeatherElement.RelativeHumidity}}","min":"50","max":"100","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","diff":false,"className":"","x":880,"y":320,"wires":[]},{"id":"0b113fc7b52cbfdb","type":"ui_gauge","z":"8c31de38cd0a6981","name":"","group":"f1ec0c040bdd2739","order":12,"width":5,"height":3,"gtype":"gage","title":"空氣壓力","label":"atm","format":"{{payload.records.Station[0].WeatherElement.AirPressure}}","min":"900","max":"1100","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","diff":false,"className":"","x":880,"y":360,"wires":[]},{"id":"14e3088564d30c0c","type":"debug","z":"8c31de38cd0a6981","name":"debug 22","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":280,"y":140,"wires":[]},{"id":"d17279b29e0e15aa","type":"http in","z":"8c31de38cd0a6981","name":"","url":"/weather-app","method":"get","upload":false,"swaggerDoc":"","x":150,"y":320,"wires":[["19625023b6920da9"]]},{"id":"19625023b6920da9","type":"template","z":"8c31de38cd0a6981","name":"JS版本氣象html","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Weather Display</title>\n    <style>\n        body {\n            font-family: 'Arial', sans-serif;\n            margin: 0;\n            padding: 0;\n            background-color: #f4f4f4;\n            color: #333;\n        }\n\n        .weather-container {\n            margin-top: 20px;\n            background-color: white;\n            padding: 20px;\n            border-radius: 8px;\n            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n            width: 300px; /* 固定寬度 */\n        }\n\n        #stationSelect {\n            padding: 8px;\n            border-radius: 4px;\n            border: 1px solid #ddd;\n            margin-top: 20px;\n        }\n\n        h1, p {\n            margin: 10px 0;\n        }\n\n        #city {\n            font-size: 1.5em;\n            color: #0275d8;\n        }\n\n        #weather {\n            font-size: 1.2em;\n            color: #5cb85c;\n        }\n\n        #temperature {\n            font-size: 1.4em;\n            color: #f0ad4e;\n        }\n\n        /* 響應式布局 */\n        @media (max-width: 600px) {\n            .weather-container {\n                width: 90%;\n                margin: 20px auto;\n            }\n        }\n\n    </style>\n</head>\n<body>\n    <div>\n        <label for=\"stationSelect\">Choose a station:</label>\n        <select id=\"stationSelect\">\n            <option value=\"桃園\">桃園</option>\n            <option value=\"苗栗\">苗栗</option>\n            <option value=\"南投\">南投</option>\n            <option value=\"埤頭\">彰化</option>\n            <option value=\"中坑\">台中</option>\n            <option value=\"安南\">台南</option>\n            <!-- 更多選項 -->\n        </select>\n    </div>\n    <div class=\"weather-container\">\n        <h1 id=\"city\"></h1>\n        <p id=\"weather\"></p>\n        <p id=\"temperature\"></p>\n    </div>\n    <script>\n        document.getElementById('stationSelect').addEventListener('change', (event) => {\n            fetchWeatherData(event.target.value);\n        });\n\n        function fetchWeatherData(stationName) {\n            const apiUrl = `https://opendata.cwa.gov.tw/api/v1/rest/datastore/O-A0001-001?Authorization=your-token&limit=10&format=JSON&StationName=${stationName}&WeatherElement=Weather,Now,WindSpeed,AirTemperature,RelativeHumidity,AirPressure&GeoInfo=CountyName`;\n\n            fetch(apiUrl)\n                .then(response => {\n                    if (!response.ok) {\n                        throw new Error('Network response was not ok');\n                    }\n                    return response.json();\n                })\n                .then(data => {\n                    console.log(data)\n                    updateWeatherDisplay(data);\n                })\n                .catch(error => {\n                    console.error('There has been a problem with your fetch operation:', error);\n                });\n        }\n\n        function updateWeatherDisplay(data) {\n            const temperature = data.records.Station[0]['WeatherElement']['AirTemperature'];\n            document.getElementById('temperature').textContent = temperature;\n            const weather = data.records.Station[0]['WeatherElement']['Weather'];\n            document.getElementById('weather').textContent = weather;\n            const city = data.records.Station[0]['GeoInfo']['CountyName'];\n            document.getElementById('city').textContent = city;\n        }\n\n        // 初始化,載入頁面時自動加載預設站點的天氣數據\n        fetchWeatherData(document.getElementById('stationSelect').value);\n\n    </script>\n</body>\n</html>","output":"str","x":340,"y":320,"wires":[["1e0d037f5b8791d1"]]},{"id":"1e0d037f5b8791d1","type":"http response","z":"8c31de38cd0a6981","name":"","statusCode":"","headers":{},"x":510,"y":320,"wires":[]},{"id":"b9319af08c19eec4","type":"mqtt in","z":"8c31de38cd0a6981","name":"","topic":"/Thinkitive/temp","qos":"0","datatype":"auto-detect","broker":"b9efc827e98bf7f9","nl":false,"rap":true,"rh":0,"inputs":0,"x":140,"y":400,"wires":[["da1f699dede14640"]]},{"id":"9aca9e818558523e","type":"mqtt in","z":"8c31de38cd0a6981","name":"","topic":"/Thinkitive/hum","qos":"0","datatype":"auto-detect","broker":"b9efc827e98bf7f9","nl":false,"rap":true,"rh":0,"inputs":0,"x":140,"y":460,"wires":[["fff84846812b56a8"]]},{"id":"da1f699dede14640","type":"ui_gauge","z":"8c31de38cd0a6981","name":"TRMP","group":"70d1d491db52e4fe","order":1,"width":0,"height":0,"gtype":"gage","title":"ESP32溫度","label":"","format":"{{value}}","min":0,"max":"150","colors":["#00b500","#e6e600","#ec2727"],"seg1":"","seg2":"","diff":false,"className":"","x":350,"y":400,"wires":[]},{"id":"fff84846812b56a8","type":"ui_gauge","z":"8c31de38cd0a6981","name":"","group":"70d1d491db52e4fe","order":2,"width":0,"height":0,"gtype":"gage","title":"ESP32濕度","label":"","format":"{{value}}","min":0,"max":"60","colors":["#15cb15","#e6e600","#ca3838"],"seg1":"","seg2":"","diff":false,"className":"","x":370,"y":460,"wires":[]},{"id":"cb6bc9284f648b45","type":"http request","z":"8c31de38cd0a6981","name":"","method":"GET","ret":"txt","paytoqs":"ignore","url":"https://opendata.cwa.gov.tw/api/v1/rest/datastore/O-A0001-001?Authorization=CWB-40C25FFF-1224-4250-B9D9-3735AAE17DBF&limit=10&format=JSON&StationName={{payload}}&WeatherElement=Weather,Now,WindSpeed,AirTemperature,RelativeHumidity,AirPressure&GeoInfo=CountyName","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":280,"y":220,"wires":[["e51d55930ce8853e"]]},{"id":"78f412356543fd12","type":"mqtt-broker","name":"","broker":"localhost","port":"1883","clientid":"","autoConnect":true,"usetls":false,"protocolVersion":"4","keepalive":"60","cleansession":true,"autoUnsubscribe":true,"birthTopic":"","birthQos":"0","birthPayload":"","birthMsg":{},"closeTopic":"","closePayload":"","closeMsg":{},"willTopic":"","willQos":"0","willPayload":"","willMsg":{},"userProps":"","sessionExpiry":""},{"id":"f1ec0c040bdd2739","type":"ui_group","name":"天氣","tab":"2156c1cf7f043d72","order":1,"disp":true,"width":12,"collapse":false,"className":""},{"id":"b9efc827e98bf7f9","type":"mqtt-broker","name":"broker.mqtt-dashboard.com","broker":"broker.mqtt-dashboard.com","port":"1883","clientid":"","autoConnect":true,"usetls":false,"protocolVersion":"4","keepalive":"60","cleansession":true,"autoUnsubscribe":true,"birthTopic":"","birthQos":"0","birthRetain":"false","birthPayload":"","birthMsg":{},"closeTopic":"","closeQos":"0","closeRetain":"false","closePayload":"","closeMsg":{},"willTopic":"","willQos":"0","willRetain":"false","willPayload":"","willMsg":{},"userProps":"","sessionExpiry":""},{"id":"70d1d491db52e4fe","type":"ui_group","name":"esp32圖表","tab":"2156c1cf7f043d72","order":2,"disp":true,"width":"6","collapse":false,"className":""},{"id":"2156c1cf7f043d72","type":"ui_tab","name":"天氣圖表","icon":"dashboard","disabled":false,"hidden":false}]

沒有留言:

張貼留言

ESP32 and Node-RED with MQTT (Publish and Subscribe)

  ESP32 and Node-RED with MQTT (Publish and Subscribe) 參考來源  https://randomnerdtutorials.com/esp8266-and-node-red-with-mqtt/ mqtt_server = ...