2023年10月27日 星期五

Node-Red dashboard

 Node-Red dashboard

安裝dashboard

開啟設定,選擇控制面板, 點選安裝tab,輸入 dashboard關鍵詞,
找到 node-red-dashboard 的庫。點選安裝。

使用template

template的節點

節點的頭部有一個 類似html標籤的符合</>。表示這個節點可以寫自定義的html,也可以寫一些javascipt。

將節點拖放到編輯區域,雙擊節點進行編輯屬性。

在編輯之前我先給大家詳細介紹一下這個節點能做什麼。
改節點就像一個angular的元件一樣,你可以定義樣式style,也可以寫js,當然也可以寫html。 另外重要的一點是,改元件已經自動將payload注入其中了。你可以直接使用,此外它還提供了一個send方法,將頁面的變數傳送到flow中。
這就是為什麼 template節點擁有入口 和 出口。因為它接受入參,輸出結果。

需要注意的一點是,元件的內容必須要以angular的格式來寫。
如果你還不太熟悉angular。也沒關係。找到官方檔案看一遍就可以寫了。

顯示flow中的資料

template的作用大致就是上面說的那些,下面我們來真實地操作一些案例。

需求:現有一個溫度計,每2秒傳送一次檔案。要求在頁面上顯示出這個值。

針對這個需求我們使用三個節點來完成。
inject+function+template

  • inject節點來定時迴圈注入,
  • function節點用於生產亂數。
  • template 節點用於顯示payload中的資料。

template中的設定很簡單。
只有一句話
<div ng-bind-html="msg.payload"></div>

寫好後看一下效果

在看一個稍微複雜一點的例子

<div layout="row" layout-align="space-between">
  <p>The number is</p>
  <font color="{{((msg.payload || 0) % 2 === 0) ? 'green' : 'red'}}">
    {{(msg.payload || 0) % 2 === 0 ? 'even' : 'odd'}}
  </font>
</div>

使用 msg.payload 來控制字型顏色,並表明是偶數還是奇數

這裡寫的案例都是一些直接顯示msg中資料的例子。

看一個使用scope來監聽msg的例子

<div id="{{'my_'+$id}}" style="{{'color:'+theme.base_color}}">Some text</div>
<script>
(function(scope) {
  scope.$watch('msg', function(msg) {
    if (msg) {
      // Do something when msg arrives
      $("#my_"+scope.$id).html(msg.payload);
    }
  });
})(scope);
</script>

使用scope.$watch來監聽msg的改變, 改變後觸發回撥函數 將msg.payload填寫到頁面上。

到這裡講的就是使用template顯示msg中的資料的所有例子。

提交資料到flow中

有這樣一個需求,我們需要在頁面做一個表單,這個表單有點特殊。有自己的排版,樣式,和邏輯,用自帶的form節點無法實現。

於是我們就需要使用template來客製化一個表單。

比如我們要查詢一個裝置的用電量和記憶體使用情況。

這個複雜的例子晚點講,我們先來看一下,如何使用template將變數傳入到flow中

看下面這個例子

<script>
var value = "hello world";
// or overwrite value in your callback function ...
this.scope.action = function() { return value; }
</script>
<md-button ng-click="send({payload:action()})">
    Click me to send a hello world
</md-button>

頁面有一個按鈕,點選後觸發send函數。這個函數是沒有被定義的,其實這是該節點的內建函數。 該函數接受一個物件。 會將該物件傳送到flow中。

讓我們來測試一下。
節點的完整設定資料如下

[
    {
        "id": "db8e4c3f.dbfbc",
        "type": "tab",
        "label": "流程 1",
        "disabled": false,
        "info": ""
    },
    {
        "id": "368ada2b.e3eaa6",
        "type": "ui_template",
        "z": "db8e4c3f.dbfbc",
        "group": "b87ab62e.53b358",
        "name": "",
        "order": 1,
        "width": 0,
        "height": 0,
        "format": "<script>\nvar value = \"hello world\";\n// or overwrite value in your callback function ...\nthis.scope.action = function() { return value; }\n</script>\n<md-button ng-click=\"send({payload:action()})\">\n    Click me to send a hello world\n</md-button>",
        "storeOutMessages": true,
        "fwdInMessages": true,
        "resendOnRefresh": true,
        "templateScope": "local",
        "x": 680,
        "y": 620,
        "wires": [
            [
                "c268ee84.e5d9e"
            ]
        ]
    },
    {
        "id": "4423dbcc.dbfcd4",
        "type": "inject",
        "z": "db8e4c3f.dbfbc",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "2",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "num",
        "x": 230,
        "y": 620,
        "wires": [
            [
                "a9b78dc0.d4e02"
            ]
        ]
    },
    {
        "id": "a9b78dc0.d4e02",
        "type": "function",
        "z": "db8e4c3f.dbfbc",
        "name": "",
        "func": "msg.payload = Math.floor(Math.random()*100)\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 460,
        "y": 620,
        "wires": [
            [
                "368ada2b.e3eaa6"
            ]
        ]
    },
    {
        "id": "c268ee84.e5d9e",
        "type": "debug",
        "z": "db8e4c3f.dbfbc",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 920,
        "y": 620,
        "wires": []
    },
    {
        "id": "b87ab62e.53b358",
        "type": "ui_group",
        "name": "Default1",
        "tab": "245d6810.4fdae8",
        "order": 1,
        "disp": true,
        "width": 20,
        "collapse": false
    },
    {
        "id": "245d6810.4fdae8",
        "type": "ui_tab",
        "name": "Tab 2",
        "icon": "dashboard",
        "order": 2,
        "disabled": false,
        "hidden": false
    }
]

開啟dashboard的頁面 看到只有一個按鈕

點選它

可以看到已經有值被注入到msg中了


2023年10月19日 星期四

MQTTX使用方法 (Broker : broker.mqtt-dashboard.com 1883 )

 MQTTX使用方法

下載 https://mqttx.app/downloads?os=windows


範例


Broker : broker.mqtt-dashboard.com  1883 

MQTTX

發行

  alex9ufo/esp32/led : on or off

 

訂閱

  alex9ufo/esp32/temp : 數值

 

MQTT Explorer

發行

alex9ufo/esp32/temp : 數值

 

訂閱

alex9ufo/esp32/led : on or off

 

 

MQTTX 設定

Name

LED/TEMP

自行命名

Client ID

mqttx_0654c264

系統給定的

Host

Mqtt:// broker.mqtt-dashboard.com

 

Port

1883

 

 



 

訂閱主題



發行主題:


發行與訂閱測試結果





2023年10月18日 星期三

Node-Red安裝 與 dashboard 安裝與使用範例

 Node-Red安裝 與 dashboard 安裝與使用範例


https://mega.nz/file/48sjmCAZ#tn2q3PUPPILFfVFuL0xsCH3RJdjfaXu2sA2gMUwz1Kw


https://mega.nz/file/Y1sFFZIB#Lh-q1p0U7S2VjTh47wSgYzPbdd1Hg-nmoo83SST-Xe4


https://mega.nz/file/Y1sFFZIB#Lh-q1p0U7S2VjTh47wSgYzPbdd1Hg-nmoo83SST-Xe4


Node-Red Dashboard 儀表板

 Node-Red Dashboard 儀表板





[{"id":"adf369ddecee6006","type":"inject","z":"5a79923e22a00434","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"1","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":140,"y":120,"wires":[["9da4406d95bbf298"]]},{"id":"9da4406d95bbf298","type":"function","z":"5a79923e22a00434","name":"產生亂數 function  ","func":"msg.payload=Math.random()\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":350,"y":120,"wires":[["609dbddbd8ad845d","b1e0a272d310792f"]]},{"id":"609dbddbd8ad845d","type":"ui_chart","z":"5a79923e22a00434","name":"","group":"f4a49ee6.74194","order":46,"width":0,"height":0,"label":"chart","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"","ymax":"","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"useUTC":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"outputs":1,"useDifferentColor":false,"className":"","x":590,"y":120,"wires":[[]]},{"id":"b1e0a272d310792f","type":"ui_gauge","z":"5a79923e22a00434","name":"","group":"f4a49ee6.74194","order":18,"width":0,"height":0,"gtype":"gage","title":"gauge","label":"units","format":"{{value}}","min":0,"max":"1","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","className":"","x":590,"y":160,"wires":[]},{"id":"f4a49ee6.74194","type":"ui_group","name":"Default","tab":"96c86955.4db458","order":1,"disp":true,"width":"6"},{"id":"96c86955.4db458","type":"ui_tab","name":"Home","icon":"dashboard"}]


參考來源
http://blog.3dgowl.com/node-red-dashboard%E5%84%80%E8%A1%A8%E6%9D%BF/


2023年10月17日 星期二

第一次 作業 需修改地方


第一次          作業 需修改地方

 

第一次 作業參考 格式

https://alex9ufoexploer.blogspot.com/2023/09/blog-post.html

作業1 位置

https://alex9ufoexploer.blogspot.com/2023/08/1-2-2023-08-esp32-rfid-mqtt-explorer.html

 

畫面 結果都是自己的實習結果

1)  Arduino

無線wifi 帳號 密碼 + MQTT 訂閱 發行  Topic



 



 

2)  Node-Red



 

broker.mqtt-dashboard.com  1883

alex9ufo/esp32/led  修改成自己的名字



 

 

alex9ufo/esp32/RFID



 

MyMQTT + MQTT Box + MQTT Explorer

訂閱 發行主題 都需要 跟著 修改

// MQTT Broker

const char *mqtt_broker = "broker.mqtt-dashboard.com";

const char *topic1 = "alex9ufo/esp32/led";

const char *topic2 = "alex9ufo/esp32/RFID";

 

const char *mqtt_username = "alex9ufo";

const char *mqtt_password = "public";

const int mqtt_port = 1883;

  

2023年10月9日 星期一

Node-Red 今明36小時天氣預報

 Node-Red 今明36小時天氣預報

https://opendata.cwa.gov.tw/dataset/all/F-C0032-001


 註冊 登入

取得 API授權碼
資料主題 :  搜尋 今明36小時天氣預報 -->API

中央氣象署開放資料平臺之資料擷取API


執行 -->拷貝 網址
  

如下 (被修改過了錯誤)

https://opendata.cwa.gov.tw/api/v1/rest/datastore/F-C0032-001?Authorization=CWB-40C25FFF-1224-4250-B9D9-3735AAE17DBF








 

function  (location  data)
============================
var a= msg.payload.cwaopendata.dataset.location;
msg.payload=a;
return msg;

set global temp
===================

global.set("tempera",msg.payload); //global. Set
return msg;

show raw data
===================
var rawdata = global.get("tempera"); //global.get
msg.payload=rawdata;
return msg;


List locationname
===================
var rawdata = global.get("tempera");
var cityarray=[];

for (let i=0; i<rawdata.length;i++)
{
    cityarray[i]=rawdata[i].locationName;
}

msg.payload=cityarray;

global.set("loname",cityarray);

return msg;

city name to number
===================
global.set("locationnumber",0);
try {
    cityname=msg.payload.cityname;
   
   if(cityname.indexOf('台北市')!=-1 ||cityname.indexOf('臺北市')!=-1 )
    {
        //context.global.locationnumber=0;
        global.set("locationnumber",0);
   
    }
    else if(cityname.indexOf('新北市')!=-1)
    {
        //context.global.locationnumber=1;
        global.set("locationnumber",1);
    }
    else if(cityname.indexOf('桃園市')!=-1) //
    {
        //context.global.locationnumber=2;
        global.set("locationnumber",2);
    }
    else if(cityname.indexOf('臺中市')!=-1 || cityname.indexOf('台中市')!=-1) 
    {
        //context.global.locationnumber= 3;
        global.set("locationnumber",3);
    }
    else if(cityname.indexOf('臺南市')!=-1 || cityname.indexOf('台南市')!=-1) 
    {
        //context.global.locationnumber= 4;
        global.set("locationnumber",4);
   
    }
    else if(cityname.indexOf('高雄市')!=-1 ) 
    {
        //context.global.locationnumber= 5 ;
        global.set("locationnumber",5);
   
    }
    else if(cityname.indexOf('基隆市')!=-1 ) 
    {
        //context.global.locationnumber= 6 ;
        flow.set("locationnumber",6);
    }
    else if(cityname.indexOf('新竹縣')!=-1 ) 
    {
        //context.global.locationnumber= 7 ;
        global.set("locationnumber",7);
    }
    else if(cityname.indexOf('新竹市')!=-1 ) 
    {
        //context.global.locationnumber= 8 ;
        global.set("locationnumber",8);
    }
    else if(cityname.indexOf('苗栗縣')!=-1 ) 
    {
        //context.global.locationnumber= 9 ;
        global.set("locationnumber",9);
    }
    else if(cityname.indexOf('彰化縣')!=-1 ) 
    {
        global.set("locationnumber",10);
    }
    else if(cityname.indexOf('南投縣')!=-1 ) 
    {
        global.set("locationnumber",11);
    }
    else if(cityname.indexOf('雲林縣')!=-1 ) 
    {
        global.set("locationnumber",12);
    }
    else if(cityname.indexOf('嘉義縣')!=-1 ) 
    {
        global.set("locationnumber",13);
    }
    else if(cityname.indexOf('嘉義市')!=-1 ) 
    {
        global.set("locationnumber",14);
    }
    else if(cityname.indexOf('屏東縣')!=-1 ) 
    {
        global.set("locationnumber",15);
    }
    else if(cityname.indexOf('宜蘭縣')!=-1 ) 
    {
        global.set("locationnumber",16);
    }
    else if(cityname.indexOf('花蓮縣')!=-1 ) 
    {
        global.set("locationnumber",17);
    }
    else if(cityname.indexOf('臺東縣')!=-1 || cityname.indexOf('台東市')!=-1)
    {
        global.set("locationnumber",18);
    }
    else if(cityname.indexOf('澎湖縣')!=-1 ) 
    {
        global.set("locationnumber",19);
    }
    else if(cityname.indexOf('金門縣')!=-1 ) 
    {
        global.set("locationnumber",20);
    }
    else if(cityname.indexOf('連江縣')!=-1 ) 
    {
        //context.global.locationnumber= 21 ;
        global.set("locationnumber",21);
    }
    else  
    {
        // context.global.locationnumber= 0 ;
        global.set("locationnumber",0);
    }
   
   
    }

catch(err) {
    cityname="台北市";
    //context.global.locationnumber=0;
    global.set("locationnumber",0);
}

msg.payload= global.get("locationnumber");
return msg;

取得 max min 溫度
===================
var loc=msg.payload;
var rawdata = global.get("tempera");

var locationName=rawdata[loc].locationName;
var period0max=rawdata[loc].weatherElement[1].time[0].parameter.parameterName;
var period0min=rawdata[loc].weatherElement[2].time[0].parameter.parameterName;
var period0start=rawdata[loc].weatherElement[1].time[0].startTime;
var period0end=rawdata[loc].weatherElement[1].time[0].endTime;

var starthourtemp= period0start.split("T");
var starthour=starthourtemp[1].split(":")[0];
var endhourtemp= period0end.split("T");
var endhour=endhourtemp[1].split(":")[0];

msg.payload={"locationName":locationName,"time":starthour+"-"+endhour, "max":period0max,
"min":period0min};
return msg;

set options
===========================
var cityname = global.get("loname");

var cityarray=[];

for (let i=0; i<cityname.length;i++)
{
    cityarray[i]=cityname[i];

}
msg.options=cityarray;
return msg;



city name to number 2
==============================
global. Set("locationnumber",0);
try {
    cityname=msg.payload;
   
   if(cityname.indexOf('台北市')!=-1 ||cityname.indexOf('臺北市')!=-1 )
    {
        //context.global.locationnumber=0;
        global.set("locationnumber",0);
   
    }
    else if(cityname.indexOf('新北市')!=-1)
    {
        //context.global.locationnumber=1;
        global.set("locationnumber",1);
    }
    else if(cityname.indexOf('桃園市')!=-1) //
    {
        //context.global.locationnumber=2;
        global.set("locationnumber",2);
    }
    else if(cityname.indexOf('臺中市')!=-1 || cityname.indexOf('台中市')!=-1) 
    {
        //context.global.locationnumber= 3;
        global.set("locationnumber",3);
    }
    else if(cityname.indexOf('臺南市')!=-1 || cityname.indexOf('台南市')!=-1) 
    {
        //context.global.locationnumber= 4;
        global.set("locationnumber",4);
   
    }
    else if(cityname.indexOf('高雄市')!=-1 ) 
    {
        //context.global.locationnumber= 5 ;
        global.set("locationnumber",5);
   
    }
    else if(cityname.indexOf('基隆市')!=-1 ) 
    {
        //context.global.locationnumber= 6 ;
        flow.set("locationnumber",6);
    }
    else if(cityname.indexOf('新竹縣')!=-1 ) 
    {
        //context.global.locationnumber= 7 ;
        global.set("locationnumber",7);
    }
    else if(cityname.indexOf('新竹市')!=-1 ) 
    {
        //context.global.locationnumber= 8 ;
        global.set("locationnumber",8);
    }
    else if(cityname.indexOf('苗栗縣')!=-1 ) 
    {
        //context.global.locationnumber= 9 ;
        global.set("locationnumber",9);
    }
    else if(cityname.indexOf('彰化縣')!=-1 ) 
    {
        global.set("locationnumber",10);
    }
    else if(cityname.indexOf('南投縣')!=-1 ) 
    {
        global.set("locationnumber",11);
    }
    else if(cityname.indexOf('雲林縣')!=-1 ) 
    {
        global.set("locationnumber",12);
    }
    else if(cityname.indexOf('嘉義縣')!=-1 ) 
    {
        global.set("locationnumber",13);
    }
    else if(cityname.indexOf('嘉義市')!=-1 ) 
    {
        global.set("locationnumber",14);
    }
    else if(cityname.indexOf('屏東縣')!=-1 ) 
    {
        global.set("locationnumber",15);
    }
    else if(cityname.indexOf('宜蘭縣')!=-1 ) 
    {
        global.set("locationnumber",16);
    }
    else if(cityname.indexOf('花蓮縣')!=-1 ) 
    {
        global.set("locationnumber",17);
    }
    else if(cityname.indexOf('臺東縣')!=-1 || cityname.indexOf('台東市')!=-1)
    {
        global.set("locationnumber",18);
    }
    else if(cityname.indexOf('澎湖縣')!=-1 ) 
    {
        global.set("locationnumber",19);
    }
    else if(cityname.indexOf('金門縣')!=-1 ) 
    {
        global.set("locationnumber",20);
    }
    else if(cityname.indexOf('連江縣')!=-1 ) 
    {
        //context.global.locationnumber= 21 ;
        global.set("locationnumber",21);
    }
    else  
    {
        // context.global.locationnumber= 0 ;
        global.set("locationnumber",0);
    }
   
   
    }

catch(err) {
    cityname="台北市";
    //context.global.locationnumber=0;
    global.set("locationnumber",0);
}

msg.payload= global.get("locationnumber");
return msg;



report
===============================
var loc=msg.payload;
var rawdata = global.get("tempera");

var locationName=rawdata[loc].locationName;
var period0max=rawdata[loc].weatherElement[1].time[0].parameter.parameterName;
var period0min=rawdata[loc].weatherElement[2].time[0].parameter.parameterName;
var period0start=rawdata[loc].weatherElement[1].time[0].startTime;
var period0end=rawdata[loc].weatherElement[1].time[0].endTime;

var starthourtemp= period0start.split("T");
var starthour=starthourtemp[1].split(":")[0];
var endhourtemp= period0end.split("T");
var endhour=endhourtemp[1].split(":")[0];

//msg.payload={"locationName":locationName,"time":starthour+"-"+endhour, "max":period0max,
//"min":period0min};
//return msg;

msg.payload=locationName+'-->' + starthour+"點到"+endhour+"點 溫度最低:"+period0min+"度 , 最高"+period0max+"度";
return msg;





(被修改過了錯誤)

[{"id":"b980f83e7e252a26","type":"http request","z":"d7693fd56d8b2efc","name":"temp request","method":"GET","ret":"obj","paytoqs":"ignore","url":"https://opendata.cwb.gov.tw/fileapi/v1/opendataapi/F-C0032-001?Authorization=CWB-42C25FAF-1124-4279-BAD9-3735AAE27DDF&downloadType=WEB&format=JSON","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":230,"y":40,"wires":[["9de1016334d8623c","26ebff77b2828b4a"]]},{"id":"4bb96a171569d0f9","type":"inject","z":"d7693fd56d8b2efc","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"7200","crontab":"","once":true,"onceDelay":"1","topic":"","payload":"","payloadType":"date","x":90,"y":40,"wires":[["b980f83e7e252a26"]]},{"id":"9de1016334d8623c","type":"debug","z":"d7693fd56d8b2efc","name":"temp request result","active":true,"console":"false","complete":"payload","x":450,"y":20,"wires":[]},{"id":"3cd5cb269957a36a","type":"debug","z":"d7693fd56d8b2efc","name":"xml to json","active":true,"console":"false","complete":"payload","x":570,"y":60,"wires":[]},{"id":"bb13b23202d4439b","type":"function","z":"d7693fd56d8b2efc","name":"set global temp","func":"\nglobal.set(\"tempera\",msg.payload); //global.set\nreturn msg;\n\n//flow.set('YourVariable', value);    // to store a variable (YourVariable)\n//var x = flow.get('YourVariable'); //to retrieve a variable (YourVariable)","outputs":1,"noerr":0,"initialize":"","finalize":"","x":580,"y":100,"wires":[["bf512f83c4d093e0"]]},{"id":"7acc072c5b4a8d5b","type":"http in","z":"d7693fd56d8b2efc","name":"city?cityname=台中市","url":"/city","method":"get","upload":false,"swaggerDoc":"","x":120,"y":320,"wires":[["73054b4771d188f2","d03c603ca6be3d38"]]},{"id":"31fb20cd0f456310","type":"http response","z":"d7693fd56d8b2efc","name":"http out","x":720,"y":320,"wires":[]},{"id":"73054b4771d188f2","type":"function","z":"d7693fd56d8b2efc","name":"city name to number","func":"global.set(\"locationnumber\",0);\ntry {\n    cityname=msg.payload.cityname;\n   \n   if(cityname.indexOf('台北市')!=-1 ||cityname.indexOf('臺北市')!=-1 )\n    {\n        //context.global.locationnumber=0;\n        global.set(\"locationnumber\",0);\n   \n    }\n    else if(cityname.indexOf('新北市')!=-1)\n    {\n        //context.global.locationnumber=1;\n        global.set(\"locationnumber\",1);\n    }\n    else if(cityname.indexOf('桃園市')!=-1) //\n    {\n        //context.global.locationnumber=2;\n        global.set(\"locationnumber\",2);\n    }\n    else if(cityname.indexOf('臺中市')!=-1 || cityname.indexOf('台中市')!=-1) \n    {\n        //context.global.locationnumber= 3;\n        global.set(\"locationnumber\",3);\n    }\n    else if(cityname.indexOf('臺南市')!=-1 || cityname.indexOf('台南市')!=-1) \n    {\n        //context.global.locationnumber= 4;\n        global.set(\"locationnumber\",4);\n   \n    }\n    else if(cityname.indexOf('高雄市')!=-1 ) \n    {\n        //context.global.locationnumber= 5 ;\n        global.set(\"locationnumber\",5);\n   \n    }\n    else if(cityname.indexOf('基隆市')!=-1 ) \n    {\n        //context.global.locationnumber= 6 ;\n        flow.set(\"locationnumber\",6);\n    }\n    else if(cityname.indexOf('新竹縣')!=-1 ) \n    {\n        //context.global.locationnumber= 7 ;\n        global.set(\"locationnumber\",7);\n    }\n    else if(cityname.indexOf('新竹市')!=-1 ) \n    {\n        //context.global.locationnumber= 8 ;\n        global.set(\"locationnumber\",8);\n    }\n    else if(cityname.indexOf('苗栗縣')!=-1 ) \n    {\n        //context.global.locationnumber= 9 ;\n        global.set(\"locationnumber\",9);\n    }\n    else if(cityname.indexOf('彰化縣')!=-1 ) \n    {\n        global.set(\"locationnumber\",10);\n    }\n    else if(cityname.indexOf('南投縣')!=-1 ) \n    {\n        global.set(\"locationnumber\",11);\n    }\n    else if(cityname.indexOf('雲林縣')!=-1 ) \n    {\n        global.set(\"locationnumber\",12);\n    }\n    else if(cityname.indexOf('嘉義縣')!=-1 ) \n    {\n        global.set(\"locationnumber\",13);\n    }\n    else if(cityname.indexOf('嘉義市')!=-1 ) \n    {\n        global.set(\"locationnumber\",14);\n    }\n    else if(cityname.indexOf('屏東縣')!=-1 ) \n    {\n        global.set(\"locationnumber\",15);\n    }\n    else if(cityname.indexOf('宜蘭縣')!=-1 ) \n    {\n        global.set(\"locationnumber\",16);\n    }\n    else if(cityname.indexOf('花蓮縣')!=-1 ) \n    {\n        global.set(\"locationnumber\",17);\n    }\n    else if(cityname.indexOf('臺東縣')!=-1 || cityname.indexOf('台東市')!=-1)\n    {\n        global.set(\"locationnumber\",18);\n    }\n    else if(cityname.indexOf('澎湖縣')!=-1 ) \n    {\n        global.set(\"locationnumber\",19);\n    }\n    else if(cityname.indexOf('金門縣')!=-1 ) \n    {\n        global.set(\"locationnumber\",20);\n    }\n    else if(cityname.indexOf('連江縣')!=-1 ) \n    {\n        //context.global.locationnumber= 21 ;\n        global.set(\"locationnumber\",21);\n    }\n    else  \n    {\n        // context.global.locationnumber= 0 ;\n        global.set(\"locationnumber\",0);\n    }\n   \n   \n    }\n\ncatch(err) {\n    cityname=\"台北市\";\n    //context.global.locationnumber=0;\n    global.set(\"locationnumber\",0);\n}\n\nmsg.payload= global.get(\"locationnumber\");\nreturn msg;\n\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":340,"y":320,"wires":[["1491002b1d477b16","468d7901f9c1ed09"]]},{"id":"1491002b1d477b16","type":"debug","z":"d7693fd56d8b2efc","name":"city name to number result","active":true,"console":"false","complete":"payload","x":560,"y":280,"wires":[]},{"id":"c70236eb819e3239","type":"http in","z":"d7693fd56d8b2efc","name":"tempjson","url":"/tempjson","method":"get","upload":false,"swaggerDoc":"","x":80,"y":140,"wires":[["f9b8c0b903a70eca","53849aa8331f5ebd"]]},{"id":"51c1b494c061e296","type":"http response","z":"d7693fd56d8b2efc","name":"http out","x":420,"y":140,"wires":[]},{"id":"f9b8c0b903a70eca","type":"function","z":"d7693fd56d8b2efc","name":"show raw data","func":"\nvar rawdata = global.get(\"tempera\"); //global.get\nmsg.payload=rawdata;\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":240,"y":140,"wires":[["51c1b494c061e296","d49c24996ccca256"]]},{"id":"d49c24996ccca256","type":"debug","z":"d7693fd56d8b2efc","name":"temp data process","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":450,"y":160,"wires":[]},{"id":"f06206d380ceea1a","type":"function","z":"d7693fd56d8b2efc","name":"List locationname","func":"var rawdata = global.get(\"tempera\");\nvar cityarray=[];\n\nfor (let i=0; i<rawdata.length;i++)\n{\n    cityarray[i]=rawdata[i].locationName;\n}\n\nmsg.payload=cityarray;\n\nglobal.set(\"loname\",cityarray);\n\nreturn msg;\n\n\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":270,"y":240,"wires":[["9f42ecd51f3bfbec"]]},{"id":"9f42ecd51f3bfbec","type":"debug","z":"d7693fd56d8b2efc","name":"List all locationnames ","active":true,"tosidebar":true,"console":false,"complete":"payload","statusVal":"","statusType":"auto","x":480,"y":240,"wires":[]},{"id":"468d7901f9c1ed09","type":"function","z":"d7693fd56d8b2efc","name":"取得 max min 溫度","func":"var loc=msg.payload;\nvar rawdata = global.get(\"tempera\");\n\nvar locationName=rawdata[loc].locationName;\nvar period0max=rawdata[loc].weatherElement[1].time[0].parameter.parameterName;\nvar period0min=rawdata[loc].weatherElement[2].time[0].parameter.parameterName;\nvar period0start=rawdata[loc].weatherElement[1].time[0].startTime;\nvar period0end=rawdata[loc].weatherElement[1].time[0].endTime;\n\nvar starthourtemp= period0start.split(\"T\");\nvar starthour=starthourtemp[1].split(\":\")[0];\nvar endhourtemp= period0end.split(\"T\");\nvar endhour=endhourtemp[1].split(\":\")[0];\n\nmsg.payload={\"locationName\":locationName,\"time\":starthour+\"-\"+endhour, \"max\":period0max,\n\"min\":period0min};\nreturn msg;\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":550,"y":320,"wires":[["31fb20cd0f456310"]]},{"id":"425d95d9d66b86e5","type":"debug","z":"d7693fd56d8b2efc","name":"report result","active":true,"console":"false","complete":"payload","x":650,"y":460,"wires":[]},{"id":"7f602fb2fc83ea5d","type":"inject","z":"d7693fd56d8b2efc","name":"inject city options","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"7200","crontab":"","once":true,"onceDelay":"5","topic":"","payload":"","payloadType":"date","x":110,"y":400,"wires":[["0ce94b043103237f"]]},{"id":"0ce94b043103237f","type":"function","z":"d7693fd56d8b2efc","name":"set options","func":"var cityname = global.get(\"loname\");\n\nvar cityarray=[];\n\nfor (let i=0; i<cityname.length;i++)\n{\n    cityarray[i]=cityname[i];\n\n}\nmsg.options=cityarray;\nreturn msg;\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":290,"y":400,"wires":[["121c9ef10b189beb","7075347cd78180f5"]]},{"id":"f3ea573988ad08cd","type":"inject","z":"d7693fd56d8b2efc","name":"inject city","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":"3","topic":"","payload":"","payloadType":"date","x":100,"y":240,"wires":[["f06206d380ceea1a"]]},{"id":"d5b2479b4db9628e","type":"function","z":"d7693fd56d8b2efc","name":"city to number","func":"\nvar cityname;\ncontext.global.locationnumber=0;\ntry {\n   cityname=msg.payload;\n   \n   if(cityname.indexOf('台北')!=-1 ||cityname.indexOf('臺北')!=-1 )\n{\n    context.global.locationnumber=0;\n   \n}\nelse if(cityname.indexOf('新北')!=-1)\n{\n    context.global.locationnumber=1;\n   \n}\nelse if(cityname.indexOf('桃園')!=-1) //\n{\n    context.global.locationnumber=2;\n   \n}\nelse if(cityname.indexOf('臺中')!=-1 || cityname.indexOf('台中')!=-1) \n{\n    context.global.locationnumber= 3;\n   \n}\nelse if(cityname.indexOf('臺南')!=-1 || cityname.indexOf('台南')!=-1) \n{\n    context.global.locationnumber= 4;\n   \n}\nelse if(cityname.indexOf('高雄')!=-1 ) \n{\n    context.global.locationnumber= 5 ;\n   \n}\nelse if(cityname.indexOf('基隆')!=-1 ) \n{\n    context.global.locationnumber= 6 ;\n   \n}\nelse if(cityname.indexOf('新竹縣')!=-1 ) \n{\n    context.global.locationnumber= 7 ;\n   \n}\nelse if(cityname.indexOf('新竹')!=-1 ) \n{\n    context.global.locationnumber= 8 ;\n   \n}\nelse if(cityname.indexOf('連江')!=-1 ) \n{\n    context.global.locationnumber= 21 ;\n   \n}\nelse  \n{\n    context.global.locationnumber= 0 ;\n   \n}\n   \n   \n}\ncatch(err) {\n    cityname=\"台北\";\n    context.global.locationnumber=0;\n}\n\n\n msg.payload= context.global.locationnumber;\nreturn msg;\n","outputs":1,"noerr":0,"x":300,"y":600,"wires":[[]]},{"id":"a194220ee277441f","type":"debug","z":"d7693fd56d8b2efc","name":"selected city ","active":true,"tosidebar":true,"console":false,"complete":"payload","statusVal":"","statusType":"auto","x":650,"y":400,"wires":[]},{"id":"121c9ef10b189beb","type":"ui_dropdown","z":"d7693fd56d8b2efc","name":"","label":"city options","tooltip":"","place":"Select city","group":"11aebcbd.bc7383","order":0,"width":0,"height":0,"passthru":true,"multiple":false,"options":[{"label":"","value":"","type":"str"}],"payload":"","topic":"","topicType":"str","className":"","x":470,"y":400,"wires":[["a194220ee277441f","2f6ebe1b1bf47f35"]]},{"id":"ab1fad20da79e263","type":"ui_text","z":"d7693fd56d8b2efc","group":"11aebcbd.bc7383","order":0,"width":0,"height":0,"name":"","label":"","format":"{{msg.payload}}","layout":"row-center","className":"","x":630,"y":500,"wires":[]},{"id":"bf512f83c4d093e0","type":"debug","z":"d7693fd56d8b2efc","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":750,"y":100,"wires":[]},{"id":"7075347cd78180f5","type":"debug","z":"d7693fd56d8b2efc","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"options","targetType":"msg","statusVal":"","statusType":"auto","x":470,"y":360,"wires":[]},{"id":"26ebff77b2828b4a","type":"function","z":"d7693fd56d8b2efc","name":"function  (location  data)","func":"var a= msg.payload.cwaopendata.dataset.location;\nmsg.payload=a;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":360,"y":100,"wires":[["bb13b23202d4439b","3cd5cb269957a36a"]]},{"id":"53849aa8331f5ebd","type":"function","z":"d7693fd56d8b2efc","name":"show raw data","func":"\nvar rawdata = global.get(\"tempera\"); //global.get\nmsg.payload=rawdata[1].locationName;\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":240,"y":200,"wires":[["60ee24555bcce7b6"]]},{"id":"60ee24555bcce7b6","type":"debug","z":"d7693fd56d8b2efc","name":"debug 209","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":430,"y":200,"wires":[]},{"id":"d03c603ca6be3d38","type":"debug","z":"d7693fd56d8b2efc","name":"debug 210","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload.cityname","targetType":"msg","statusVal":"","statusType":"auto","x":290,"y":280,"wires":[]},{"id":"55631d8ecaa2eb98","type":"comment","z":"d7693fd56d8b2efc","name":"","info":"http://127.0.0.1:1880/city?cityname=連江縣\n\n{\"locationName\":\"連江縣\",\"time\":\"12-18\",\"max\":\"23\",\"min\":\"22\"}","x":70,"y":280,"wires":[]},{"id":"2f6ebe1b1bf47f35","type":"function","z":"d7693fd56d8b2efc","name":"city name to number","func":"global.set(\"locationnumber\",0);\ntry {\n    cityname=msg.payload;\n   \n   if(cityname.indexOf('台北市')!=-1 ||cityname.indexOf('臺北市')!=-1 )\n    {\n        //context.global.locationnumber=0;\n        global.set(\"locationnumber\",0);\n   \n    }\n    else if(cityname.indexOf('新北市')!=-1)\n    {\n        //context.global.locationnumber=1;\n        global.set(\"locationnumber\",1);\n    }\n    else if(cityname.indexOf('桃園市')!=-1) //\n    {\n        //context.global.locationnumber=2;\n        global.set(\"locationnumber\",2);\n    }\n    else if(cityname.indexOf('臺中市')!=-1 || cityname.indexOf('台中市')!=-1) \n    {\n        //context.global.locationnumber= 3;\n        global.set(\"locationnumber\",3);\n    }\n    else if(cityname.indexOf('臺南市')!=-1 || cityname.indexOf('台南市')!=-1) \n    {\n        //context.global.locationnumber= 4;\n        global.set(\"locationnumber\",4);\n   \n    }\n    else if(cityname.indexOf('高雄市')!=-1 ) \n    {\n        //context.global.locationnumber= 5 ;\n        global.set(\"locationnumber\",5);\n   \n    }\n    else if(cityname.indexOf('基隆市')!=-1 ) \n    {\n        //context.global.locationnumber= 6 ;\n        flow.set(\"locationnumber\",6);\n    }\n    else if(cityname.indexOf('新竹縣')!=-1 ) \n    {\n        //context.global.locationnumber= 7 ;\n        global.set(\"locationnumber\",7);\n    }\n    else if(cityname.indexOf('新竹市')!=-1 ) \n    {\n        //context.global.locationnumber= 8 ;\n        global.set(\"locationnumber\",8);\n    }\n    else if(cityname.indexOf('苗栗縣')!=-1 ) \n    {\n        //context.global.locationnumber= 9 ;\n        global.set(\"locationnumber\",9);\n    }\n    else if(cityname.indexOf('彰化縣')!=-1 ) \n    {\n        global.set(\"locationnumber\",10);\n    }\n    else if(cityname.indexOf('南投縣')!=-1 ) \n    {\n        global.set(\"locationnumber\",11);\n    }\n    else if(cityname.indexOf('雲林縣')!=-1 ) \n    {\n        global.set(\"locationnumber\",12);\n    }\n    else if(cityname.indexOf('嘉義縣')!=-1 ) \n    {\n        global.set(\"locationnumber\",13);\n    }\n    else if(cityname.indexOf('嘉義市')!=-1 ) \n    {\n        global.set(\"locationnumber\",14);\n    }\n    else if(cityname.indexOf('屏東縣')!=-1 ) \n    {\n        global.set(\"locationnumber\",15);\n    }\n    else if(cityname.indexOf('宜蘭縣')!=-1 ) \n    {\n        global.set(\"locationnumber\",16);\n    }\n    else if(cityname.indexOf('花蓮縣')!=-1 ) \n    {\n        global.set(\"locationnumber\",17);\n    }\n    else if(cityname.indexOf('臺東縣')!=-1 || cityname.indexOf('台東市')!=-1)\n    {\n        global.set(\"locationnumber\",18);\n    }\n    else if(cityname.indexOf('澎湖縣')!=-1 ) \n    {\n        global.set(\"locationnumber\",19);\n    }\n    else if(cityname.indexOf('金門縣')!=-1 ) \n    {\n        global.set(\"locationnumber\",20);\n    }\n    else if(cityname.indexOf('連江縣')!=-1 ) \n    {\n        //context.global.locationnumber= 21 ;\n        global.set(\"locationnumber\",21);\n    }\n    else  \n    {\n        // context.global.locationnumber= 0 ;\n        global.set(\"locationnumber\",0);\n    }\n   \n   \n    }\n\ncatch(err) {\n    cityname=\"台北市\";\n    //context.global.locationnumber=0;\n    global.set(\"locationnumber\",0);\n}\n\nmsg.payload= global.get(\"locationnumber\");\nreturn msg;\n\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":300,"y":480,"wires":[["5d47059b6015dcb7","6eecf6286be86c0f"]]},{"id":"5d47059b6015dcb7","type":"function","z":"d7693fd56d8b2efc","name":"report","func":"var loc=msg.payload;\nvar rawdata = global.get(\"tempera\");\n\nvar locationName=rawdata[loc].locationName;\nvar period0max=rawdata[loc].weatherElement[1].time[0].parameter.parameterName;\nvar period0min=rawdata[loc].weatherElement[2].time[0].parameter.parameterName;\nvar period0start=rawdata[loc].weatherElement[1].time[0].startTime;\nvar period0end=rawdata[loc].weatherElement[1].time[0].endTime;\n\nvar starthourtemp= period0start.split(\"T\");\nvar starthour=starthourtemp[1].split(\":\")[0];\nvar endhourtemp= period0end.split(\"T\");\nvar endhour=endhourtemp[1].split(\":\")[0];\n\n//msg.payload={\"locationName\":locationName,\"time\":starthour+\"-\"+endhour, \"max\":period0max,\n//\"min\":period0min};\n//return msg;\n\nmsg.payload=locationName+'-->' + starthour+\"點到\"+endhour+\"點 溫度最低:\"+period0min+\"度 , 最高\"+period0max+\"度\";\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":470,"y":480,"wires":[["425d95d9d66b86e5","ab1fad20da79e263"]]},{"id":"4749c3261fa9c119","type":"function","z":"d7693fd56d8b2efc","name":"report","func":"var loc=msg.payload;\n//var rawdata=context.global.temp;\nvar rawdata = flow.get(\"tempera\");\nvar locationName=rawdata.cwbopendata.dataset[0].location[loc].locationName[0];\nvar period0max=rawdata.cwbopendata.dataset[0].location[loc].weatherElement[1].time[0].parameter[0].parameterName[0];\nvar period0min=rawdata.cwbopendata.dataset[0].location[loc].weatherElement[2].time[0].parameter[0].parameterName[0];\nvar period0start=rawdata.cwbopendata.dataset[0].location[loc].weatherElement[1].time[0].startTime[0];\nvar period0end=rawdata.cwbopendata.dataset[0].location[loc].weatherElement[1].time[0].endTime[0];\n\nvar  starthourtemp= period0start.split(\"T\");\nvar starthour=starthourtemp[1].split(\":\")[0];\nvar  endhourtemp= period0end.split(\"T\");\nvar endhour=endhourtemp[1].split(\":\")[0];\n\nmsg.payload=locationName+starthour+\"到\"+endhour+\"點溫度最低\"+period0min+\"度最高\"+period0max+\"度\";\nreturn msg;\n","outputs":1,"noerr":0,"x":270,"y":560,"wires":[[]]},{"id":"6eecf6286be86c0f","type":"debug","z":"d7693fd56d8b2efc","name":"debug 211","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":490,"y":520,"wires":[]},{"id":"11aebcbd.bc7383","type":"ui_group","name":"City temperature","tab":"dc7935b7.cd8c68","order":1,"disp":true,"width":"12","collapse":false,"className":""},{"id":"dc7935b7.cd8c68","type":"ui_tab","name":"Home","icon":"dashboard"}]


2024_09 作業3 以Node-Red 為主

 2024_09 作業3  (以Node-Red 為主  Arduino 可能需要配合修改 ) Arduino 可能需要修改的部分 1)mqtt broker  2) 主題Topic (發行 接收) 3) WIFI ssid , password const char br...