2020年9月30日 星期三

Node-Red + MQTT 範例

Node-Red + MQTT 範例

1) 安裝 Node-red 

    http://alex9ufoexploer.blogspot.com/2018/03/node-red_7.html

2) 程式 

     127.0.0.1:1880 匯入程式

    



 Node-Red節點若是虛線代表該節點元件沒有安裝

   


 [{"id":"7377d363.84128c","type":"tab","label":"MQTT_LED","disabled":false,"info":""},{"id":"9a9808d2.b904e8","type":"mqtt in","z":"7377d363.84128c","name":"","topic":"alex9ufo/led/led_event","qos":"1","datatype":"auto","broker":"841df58d.ee5e98","x":140,"y":80,"wires":[["ff64ce35.d54d6","cc43c13c.49236","bd66ced7.e745b","7b270a19.2bfba4","30e4d5f1.5dabca"]]},{"id":"ff64ce35.d54d6","type":"ui_text","z":"7377d363.84128c","group":"6c9116b.b62d4e8","order":0,"width":0,"height":0,"name":"","label":"MQTT Suscribe Data","format":"{{msg.payload}}","layout":"col-center","x":400,"y":80,"wires":[]},{"id":"e10b330a.0e832","type":"ui_button","z":"7377d363.84128c","name":"","group":"6c9116b.b62d4e8","order":0,"width":0,"height":0,"passthru":false,"label":"On led","tooltip":"","color":"white","bgcolor":"","icon":"fa-circle","payload":"LED 開","payloadType":"str","topic":"","x":110,"y":280,"wires":[["a4db0e32.936f8"]]},{"id":"5ccc4685.ea9d18","type":"ui_button","z":"7377d363.84128c","name":"","group":"6c9116b.b62d4e8","order":0,"width":0,"height":0,"passthru":false,"label":"Off led","tooltip":"","color":"black","bgcolor":"","icon":"fa-circle-o","payload":"LED 關","payloadType":"str","topic":"","x":110,"y":340,"wires":[["a4db0e32.936f8"]]},{"id":"a4db0e32.936f8","type":"mqtt out","z":"7377d363.84128c","name":"","topic":"alex9ufo/led/led_event","qos":"1","retain":"false","broker":"841df58d.ee5e98","x":360,"y":280,"wires":[]},{"id":"cc43c13c.49236","type":"function","z":"7377d363.84128c","name":"Format timestamp","func":"var date = new Date();\nvar h = date.getHours();\nvar m = date.getMinutes();\nvar s = date.getSeconds();\nif(h<10){\n    h = '0'+h;\n}\nif(m<10){\n    m = '0' + m;\n}\nif(s<10){\n    s = '0' + s;\n}\nmsg.payload = msg.payload + ' --> Time:(' + h + ':' + m + ':' + s + ')' ;\n\nreturn msg;","outputs":1,"noerr":0,"x":190,"y":220,"wires":[["d3901e4c.e507d"]]},{"id":"d3901e4c.e507d","type":"function","z":"7377d363.84128c","name":"Set Line API ","func":"msg.headers = {'content-type':'application/x-www-form-urlencoded','Authorization':'Bearer A4wwPNh2WqB7dlfeQyyIAwtggn1kfZSI5LkkCdia1gB'};\nmsg.payload = {\"message\":msg.payload};\nreturn msg;\n\n//oR7KdXvK1eobRr2sRRgsl4PMq23DjDlhfUs96SyUBZu","outputs":1,"noerr":0,"x":370,"y":220,"wires":[["2d2f8066.cb721"]]},{"id":"2d2f8066.cb721","type":"http request","z":"7377d363.84128c","name":"","method":"POST","ret":"txt","paytoqs":false,"url":"https://notify-api.line.me/api/notify","tls":"","persist":false,"proxy":"","authType":"","x":540,"y":220,"wires":[["6085953d.1462ec"]]},{"id":"6085953d.1462ec","type":"debug","z":"7377d363.84128c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":690,"y":220,"wires":[]},{"id":"bd66ced7.e745b","type":"debug","z":"7377d363.84128c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":390,"y":20,"wires":[]},{"id":"7b270a19.2bfba4","type":"line-notify","z":"7377d363.84128c","name":"NODE-RED MQTT LED","message":"Hello! \nLED Changed","contentType":"sticker","imageUrl":"","stickerPackageId":"1","stickerId":"2","x":410,"y":140,"wires":[]},{"id":"30e4d5f1.5dabca","type":"ui_audio","z":"7377d363.84128c","name":"","group":"6c9116b.b62d4e8","voice":"zh-TW","always":true,"x":340,"y":180,"wires":[]},{"id":"841df58d.ee5e98","type":"mqtt-broker","z":"","name":"","broker":"broker.mqtt-dashboard.com","port":"1883","clientid":"","usetls":false,"compatmode":false,"keepalive":"15","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closePayload":"","willTopic":"","willQos":"0","willPayload":""},{"id":"6c9116b.b62d4e8","type":"ui_group","z":"","name":"Storing IOT Data ","tab":"eeb8e179.a47a4","order":1,"disp":true,"width":"6","collapse":false},{"id":"eeb8e179.a47a4","type":"ui_tab","z":"","name":"MySQL","icon":"dashboard","disabled":false,"hidden":false}]

  node-red-contrib-line-notify  安裝

0



安裝過程要等待不可以中途放棄

node-red-dashboard 安裝




127.0.0.1:1880/ui 使用者介面

  

 可以按 ON LED 或OFF LED 發行publish 訊息到MQTT 上

MQTT Broker :   http://broker.mqtt-dashboard.com/


3) 執行畫面

 MQTT_BOX 

MQTT Client Name : 自行命名 

Protocol : MQTTTCP 

Host : broker.mqtt-dashboard.com:1883/ws



Topic to publish : alex9ufo/led/led_event

LED 關 或是 LED 開  --> Publish

Topic to subscribe : alex9ufo/led/led_event

QoS : 0 或1 ,2  > Subscribe



Line Notify 要修改



請參考

https://alex9ufoexploer.blogspot.com/2020/10/create-line-messaging-api-channel.html


Set Line API 要修改


msg.headers = {'content-type':'application/x-www-form-urlencoded','Authorization':'Bearer A4wwaPNh2WqB7dlfeeQyyIAwtggn1kfZSI5LkkCdia1gB'};

msg.payload = {"message":msg.payload};

return msg;


紅字為自己的發行權杖

請參考


MQTT In 修改

MQTT Out  修改



主題Topic :  MQTT in 與 MQTT  out 二者TOPIC 要相同


Line Notify 有二個

1) https://notify-bot.line.me/zh_TW/ 


2) https://developers.line.biz/zh-hant/



Line Notify  需修改成自己的

 不然是我收到line 訊息

 1) 發行權杖  https://notify-bot.line.me/zh_TW/ 

https://alex9ufoexploer.blogspot.com/2019/11/node-red-line-notify-massage.html


2) 使用LINE Messaging API發送消息的節點

https://www.learncodewithmike.com/2020/06/python-line-bot.html

http://alex9ufoexploer.blogspot.com/2020/08/pushmessageline-messaging-api.html


MQTT 簡報

http://www.mediafire.com/file/fai82oxhnuqy7wm/%25E8%25AA%258D%25E8%25AD%2598MQTT.pdf/file

http://www.mediafire.com/file/g2slozzylsvapid/MQTT%25E5%258D%2594%25E5%25AE%259A.pptx/file

2020年9月5日 星期六

透過 ngrok 轉發讓 localhost 浮出檯面

 源自於 https://dotblogs.com.tw/wasichris/2018/10/01/000610

透過 ngrok 轉發,將 host 在 localhost 的服務/站台露出至 Internet 中,省去 line bot 開發時需頻繁地佈署 Webhook 才能驗證功能的困擾。

前言


最近筆者有稍微玩一下 line bot 開發,發現若要除錯或驗證功能都需要不斷地將程式推送到版控中,等待自動佈署到 line bot 綁定的 Webhook 後才會生效,這樣真的是非常麻煩;還好我們可以使用 ngrok 將 host 在 localhost 的服務/站台透過轉發露出至 Internet 中,這樣在本機一修改代碼就直接生效的感覺真是太美妙了;另外,有時候在開發期間,會想要將本機開發中網頁版本跟客戶確認效果,此時透過 ngrok 也可以輕鬆達陣。

 

 

申請 ngrok 帳號


請至 ngrok-signup 申請帳號,完成後可以獲得一組代表此帳號的 auth token 資料。

 

 

取得 ngrok 與連結帳號


依各作業系統下載 ngrok 解壓縮 (支援各平台 windows, mac os x, linux),切換目錄至該檔案位置後,輸入以下指令來連結至你剛剛申請的帳號 (自行調整 auth token 資訊),執行後產出 ngrok.yml 檔案即表示成功,這步驟只需執行一次。

$ ngrok authtoken 8T89n51s4RVbqjxMoqyw_JT8oooooooYccp9NCved

 

 

露出本機站台至 Internet 


若需要將本地端 9527 port 露出至 Internet 中,可使用以下指令。

$ ngrok http 9527

 

現在開始就可以透過以下兩個「隨機」網址轉發 Request 來訪問本機 9527 port 站台囉!

 

 

效果驗證


驗證一下,目前本機 9527 port 站台如下

 

透過 ngrok 產生的 URL 確實可以訪問到 host 在本機 9527 port 的站台頁面。

 

在做 line bot 測試時只接把 Webhook 設定導向該 URL,就可以輕鬆地在本機調整邏輯並驗證效果了。

 

 

使用限制


由於 ngrok 是可以免費使用,所以會有一些限制存在,例如產生的轉發 URL 是隨機的無法固定,只能執行單個 ngrok 轉發功能,並且每分鐘限制只能有 40 個 connections,不過如果只是拿來做測試應該是綽綽有餘;另外,它也提供了許多方案可以供開發者選購,請自行參考以下圖片中各方案提供的功能。

 

 

參考資訊


 Ngrok – 讓本機也可以開發 webhook 免部署環境的神器

在本地端使用 Nodejs & Ngrok 進行 Line Bot 開發測試

ngrok與Node-red 結合將localhost:1880 porting 到外網

 ngrok與Node-red 結合將localhost:1880 porting 到外網

免費版本 ngrok ip只能維持8小時










ngrok 教學

 ngrok 教學

源自於https://markteaching.com/ngrok-2/

ngrok是什麼?

ngrok 是一個反向代理,通過在公共的端點和本地運行的Web 服務器之間建立一個安全的通道。 ngrok 可捕獲和分析所有通道上的流量,便於後期分析和重放。反向代理在計算機網絡中是代理服務器的一種。

詳細資訊可以查看:ngrok

為何我會用ngrok?

測試或是debug真的超方便!

正常要讓一個網站佈署到網上時,提供給測試人員或是其他工作夥伴,需要找一個正在運行的web服務器,還需要部署程式碼上去,測試結束後,再將此網站刪除。

真的有夠麻煩的!但是有了ngrok就不一樣了!

你只要安裝了ngrok後,在本地端執行,他會給你一串網址,直接透過這個網址就能讓他人順利連接到你本地端架設好的網站。

ngrok 與 Webhook 完美搭配!

那當然的除了用在web以外,當然也是可以用在webhook。

Webhook是什麼呢?

在web開發過程中的webhook,是一種通過通常的callback,去增加或者改變web page或者web app行為的方法。這些callback可以由第三方用戶和開發者維持當前,修改,管理,而這些使用者與網站或者應用的原始開發沒有關聯。詳細資訊可以查看:「API vs Webhook」比較 介紹 筆記

ngrok install(安裝)步驟流程與使用

請點我安裝 ngrok (免費的)

請點擊 Get started for free

ngrok install

請登入帳號,可以用Google或是GitHub登入

ngrok install

下面的流程可以照個網頁顯示步驟

下載ngrok解壓縮 (mac一定要用指令解壓縮,否則會有問題)照著上面打因為我們已經開啟了Flask server port 預設是5000,因此我們輸入 ./ngrok http 5000

ps:第三步驟 Connect your account 記得要執行,需要與我們的帳號進行綁定。

mark ->> ~/Downloads $ ./ngrok http 5000
ngrok install

這時 (Forwarding) https://081dd978.ngrok.io 就會是我們的外網的網址,可以透過這個網址來訪問你的本地端的網站。

ngrok by @inconshreveable                                                             (Ctrl+C to quit)

Session Status                online
Account                       MarkwwLiu (Plan: Free)
Version                       2.3.35
Region                        United States (us)
Web Interface                 http://127.0.0.1:4040
Forwarding                    http://081dd978.ngrok.io -> http://localhost:5000
Forwarding                    https://081dd978.ngrok.io -> http://localhost:5000

Connections                   ttl     opn     rt1     rt5     p50     p90
                              0       0       0.00    0.00    0.00    0.00

ngrok主要是在開發階段使用喔!也就是在本地端測試用,使用上來說真的超方便!

2020年9月4日 星期五

Node-Red 利用 ngrok 取得臨時之外部網址

 Node-Red  利用 ngrok 取得臨時之外部網址

源自於 https://medium.com/@jonathan.chiou_30271/node-red-%E5%AD%B8%E7%BF%92%E7%AD%86%E8%A8%98-2020-01-21-01-cada06d9e9e1

利用 ngrok 取得臨時之外部網址 (有https喔)

什麼是ngrok,它是一個可以讓內網伺服器與外界溝通的一個服務。

一般來說在本機開發時,可以使用本機瀏覽器連到 http://localhost 或 http://127.0.0.1 的本地端伺服器預覽成果,或者在同網域之其他電腦,也可以透過內網之IP(例如192.168.1.55),連到你的本機伺服器預覽成果。

但是有些開發的場景就一定需要由外網可以連線到你的本地 伺服器,例如:

  1. Chatbot:聊天機器人通常需要設定一個 webhook url,讓服務端(如 Line、Facebook)可以將訊息發佈到你的伺服器端。
  2. 金流系統:在串接金流服務的時候,需要 ReturnUrl 回傳網址,在金流付款成功後將結果送到你的伺服器端。
  3. 其他各式各樣的 API callback

ngrok 這個服務可以幫我們解決這個問題。

Node Red如何使用 ngrok :

  1. 註冊一個 ngrok 帳號
  2. 在node-red安裝ngrok node
Image for post

3. 在ngrok網站取得authtoken

Image for post

4. 編輯 ngrok node,填入authtoken

Image for post

5. 啟動 ngrok,取得網址,免費版每次生成之網址只有8小時時效。

Image for post

2020年9月3日 星期四

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

 一般天氣預報-今明36小時天氣預報

http://opendata.cwb.gov.tw/govdownload?dataid=F-C0032-001&authorizationkey=rdec-key-123-45678-011121314

參考來源 

博客來-物聯網實作:Node-RED萬物聯網視覺化


資料集類型rawData
資料集描述臺灣各縣市今明36小時天氣預報預報-今明36小時天氣預報
主要欄位說明Wx(天氣現象)、MaxT(最高溫度)、MinT(最低溫度)、CI(舒適度)、PoP(降雨機率)
資料集提供機關中央氣象局
更新頻率每6小時
授權方式政府資料開放授權條款-第1版
授權說明網址http://data.gov.tw/license







[{"id":"75602f71.fa211","type":"http request","z":"37beda4f.c0b9b6","name":"temp request","method":"GET","ret":"txt","url":"http://opendata.cwb.gov.tw/govdownload?dataid=F-C0032-001&authorizationkey=rdec-key-123-45678-011121314","tls":"","x":290,"y":60,"wires":[["b730a4d3.4c40f8","a961f8af.aa1828"]]},{"id":"abd15c05.e4534","type":"inject","z":"37beda4f.c0b9b6","name":"","topic":"","payload":"","payloadType":"date","repeat":"7200","crontab":"","once":false,"x":110,"y":60,"wires":[["75602f71.fa211"]]},{"id":"b730a4d3.4c40f8","type":"debug","z":"37beda4f.c0b9b6","name":"temp request result","active":true,"console":"false","complete":"payload","x":489,"y":42,"wires":[]},{"id":"2312ea80.c326f6","type":"debug","z":"37beda4f.c0b9b6","name":"xml to json","active":true,"console":"false","complete":"payload","x":585,"y":76,"wires":[]},{"id":"dddad094.13cd7","type":"function","z":"37beda4f.c0b9b6","name":"set global temp","func":"\nflow.set(\"tempera\",msg.payload);\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,"x":600,"y":120,"wires":[["c2e73742.4ec328"]]},{"id":"a961f8af.aa1828","type":"xml","z":"37beda4f.c0b9b6","name":"","property":"payload","attr":"","chr":"","x":438,"y":100,"wires":[["dddad094.13cd7","2312ea80.c326f6"]]},{"id":"2ee796b5.8a225a","type":"http in","z":"37beda4f.c0b9b6","name":"city","url":"/city","method":"get","upload":false,"swaggerDoc":"","x":84,"y":347,"wires":[["f7faac86.6969e"]]},{"id":"9a2dd23b.bdd2","type":"http response","z":"37beda4f.c0b9b6","name":"http out","x":606,"y":347,"wires":[]},{"id":"f7faac86.6969e","type":"function","z":"37beda4f.c0b9b6","name":"city name to number","func":"\nvar rawdata = flow.get(\"tempera\");\n\n//context.global.locationnumber=0;\nflow.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    flow.set(\"locationnumber\",0);\n   \n}\nelse if(cityname.indexOf('新北')!=-1)\n{\n    //context.global.locationnumber=1;\n    flow.set(\"locationnumber\",1);\n}\nelse if(cityname.indexOf('桃園')!=-1) //\n{\n    //context.global.locationnumber=2;\n    flow.set(\"locationnumber\",2);\n}\nelse if(cityname.indexOf('臺中')!=-1 || cityname.indexOf('台中')!=-1) \n{\n    //context.global.locationnumber= 3;\n    flow.set(\"locationnumber\",3);\n}\nelse if(cityname.indexOf('臺南')!=-1 || cityname.indexOf('台南')!=-1) \n{\n    //context.global.locationnumber= 4;\n    flow.set(\"locationnumber\",4);\n   \n}\nelse if(cityname.indexOf('高雄')!=-1 ) \n{\n    //context.global.locationnumber= 5 ;\n    flow.set(\"locationnumber\",5);\n   \n}\nelse if(cityname.indexOf('基隆')!=-1 ) \n{\n    //context.global.locationnumber= 6 ;\n    flow.set(\"locationnumber\",6);\n}\nelse if(cityname.indexOf('新竹縣')!=-1 ) \n{\n    //context.global.locationnumber= 7 ;\n    flow.set(\"locationnumber\",7);\n}\nelse if(cityname.indexOf('新竹')!=-1 ) \n{\n    //context.global.locationnumber= 8 ;\n    flow.set(\"locationnumber\",8);\n}\nelse if(cityname.indexOf('新竹')!=-1 ) \n{\n    //context.global.locationnumber= 8 ;\n    flow.set(\"locationnumber\",8);\n}\nelse if(cityname.indexOf('苗栗')!=-1 ) \n{\n    //context.global.locationnumber= 9 ;\n    flow.set(\"locationnumber\",9);\n}\nelse if(cityname.indexOf('彰化')!=-1 ) \n{\n      flow.set(\"locationnumber\",10);\n}\nelse if(cityname.indexOf('南投')!=-1 ) \n{\n      flow.set(\"locationnumber\",11);\n}\nelse if(cityname.indexOf('雲林')!=-1 ) \n{\n      flow.set(\"locationnumber\",12);\n}\nelse if(cityname.indexOf('嘉義縣')!=-1 ) \n{\n      flow.set(\"locationnumber\",13);\n}\nelse if(cityname.indexOf('嘉義市')!=-1 ) \n{\n      flow.set(\"locationnumber\",14);\n}\nelse if(cityname.indexOf('屏東')!=-1 ) \n{\n      flow.set(\"locationnumber\",15);\n}\nelse if(cityname.indexOf('宜蘭')!=-1 ) \n{\n      flow.set(\"locationnumber\",16);\n}\nelse if(cityname.indexOf('宜蘭')!=-1 ) \n{\n      flow.set(\"locationnumber\",16);\n}\nelse if(cityname.indexOf('花蓮')!=-1 ) \n{\n      flow.set(\"locationnumber\",17);\n}\nelse if(cityname.indexOf('臺東')!=-1 || cityname.indexOf('台東')!=-1)\n{\n      flow.set(\"locationnumber\",18);\n}\nelse if(cityname.indexOf('澎湖')!=-1 ) \n{\n      flow.set(\"locationnumber\",19);\n}\nelse if(cityname.indexOf('金門')!=-1 ) \n{\n      flow.set(\"locationnumber\",20);\n}\nelse if(cityname.indexOf('連江')!=-1 ) \n{\n    //context.global.locationnumber= 21 ;\n    flow.set(\"locationnumber\",21);\n}\nelse  \n{\n   // context.global.locationnumber= 0 ;\n    flow.set(\"locationnumber\",0);\n}\n   \n   \n}\ncatch(err) {\n    cityname=\"台北\";\n    //context.global.locationnumber=0;\n    flow.set(\"locationnumber\",0);\n}\n\nmsg.payload= flow.get(\"locationnumber\");\nreturn msg;\n","outputs":1,"noerr":0,"x":264,"y":347,"wires":[["2c8b4a83.8b7a86","4bdb0698.ce5678"]]},{"id":"2c8b4a83.8b7a86","type":"debug","z":"37beda4f.c0b9b6","name":"city name to number result","active":true,"console":"false","complete":"payload","x":520,"y":296,"wires":[]},{"id":"1ee7ff8c.0e007","type":"http in","z":"37beda4f.c0b9b6","name":"tempjson","url":"/tempjson","method":"get","upload":false,"swaggerDoc":"","x":80,"y":160,"wires":[["7c1885a3.c076fc"]]},{"id":"b3616b02.682d08","type":"http response","z":"37beda4f.c0b9b6","name":"http out","x":460,"y":160,"wires":[]},{"id":"7c1885a3.c076fc","type":"function","z":"37beda4f.c0b9b6","name":"show raw data","func":"//flow.set('YourVariable', value);    // to store a variable (YourVariable)\n//var x = flow.get('YourVariable'); //to retrieve a variable (YourVariable)\n\n\n\n\n//var loc=msg.payload.loc;\n\nvar rawdata = flow.get(\"tempera\");\nmsg.payload = rawdata;\nreturn msg;\n\n//msg.playload=rawdata;\n//.cwbopendata.dataset[0].location;\n\n\n/*\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\":locationName,\"time\":starthour+\"-\"+endhour, \"max\":period0max,\n\"min\":period0min};\nreturn msg;\n*/\n\n/*if(time.getHours()<18)\n{\nmsg.payload={\"locationName\":locationName,\"todaymax\":period1max, \"todaymin\":period1min,\n             \"tonightmax\":period2max, \"tonightmin\":period2min,\"tomorrowmax\":period3max, \"tomorrowmin\":period3min};\n}\nelse\nmsg.payload={\"locationName\":locationName,\"tonightmax\":period1max, \"tonightmin\":period1min,\n             \"todaymax\":period2max, \"tonightmin\":period2min,\"tomorrowmax\":period3max, \"tomorrowmin\":period3min};\n}\n\n*/\n\n\n\n\n//msg.payload=rawdata.cwbopendata.dataset[0].location[loc].weatherElement[1].time[1];\n\n\n\n\n","outputs":1,"noerr":0,"x":260,"y":160,"wires":[["b3616b02.682d08","376599f1.00bc46"]]},{"id":"376599f1.00bc46","type":"debug","z":"37beda4f.c0b9b6","name":"temp data process","active":true,"console":"false","complete":"payload","x":470,"y":200,"wires":[]},{"id":"b7cea5f9.af6988","type":"function","z":"37beda4f.c0b9b6","name":"List locationname","func":"//var rawdata=context.global.temp;\nvar rawdata = flow.get(\"tempera\");\n//flow.set(\"loname\",rawdata.cwbopendata.dataset[0].location.locationName);\nvar location=rawdata.cwbopendata.dataset[0].location;\nvar citynumber=location.length;\nvar cityarray=[];\nvar i;\nfor (i=0; i<citynumber;i++)\n{\ncityarray[i]=location[i].locationName[0];\n}\n\n msg.payload=cityarray;\nflow.set(\"loname\",cityarray);\nreturn msg;\n\n/*\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\":locationName,\"time\":starthour+\"-\"+endhour, \"max\":period0max,\n\"min\":period0min};\nreturn msg;\n*/\n\n/*if(time.getHours()<18)\n{\nmsg.payload={\"locationName\":locationName,\"todaymax\":period1max, \"todaymin\":period1min,\n             \"tonightmax\":period2max, \"tonightmin\":period2min,\"tomorrowmax\":period3max, \"tomorrowmin\":period3min};\n}\nelse\nmsg.payload={\"locationName\":locationName,\"tonightmax\":period1max, \"tonightmin\":period1min,\n             \"todaymax\":period2max, \"tonightmin\":period2min,\"tomorrowmax\":period3max, \"tomorrowmin\":period3min};\n}\n\n*/\n\n\n\n\n//msg.payload=rawdata.cwbopendata.dataset[0].location[loc].weatherElement[1].time[1];\n\n\n\n\n","outputs":1,"noerr":0,"x":308,"y":255,"wires":[["b018b861.b76f68"]]},{"id":"b018b861.b76f68","type":"debug","z":"37beda4f.c0b9b6","name":"List all locationnames ","active":true,"console":"false","complete":"payload","x":527,"y":255,"wires":[]},{"id":"4bdb0698.ce5678","type":"function","z":"37beda4f.c0b9b6","name":"max min","func":"var loc=msg.payload;\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\":locationName,\"time\":starthour+\"-\"+endhour, \"max\":period0max,\n\"min\":period0min};\nreturn msg;\n\n/*if(time.getHours()<18)\n{\nmsg.payload={\"locationName\":locationName,\"todaymax\":period1max, \"todaymin\":period1min,\n             \"tonightmax\":period2max, \"tonightmin\":period2min,\"tomorrowmax\":period3max, \"tomorrowmin\":period3min};\n}\nelse\nmsg.payload={\"locationName\":locationName,\"tonightmax\":period1max, \"tonightmin\":period1min,\n             \"todaymax\":period2max, \"tonightmin\":period2min,\"tomorrowmax\":period3max, \"tomorrowmin\":period3min};\n}\n\n*/\n\n\n\n\n//msg.payload=rawdata.cwbopendata.dataset[0].location[loc].weatherElement[1].time[1];\n\n\n\n\n","outputs":1,"noerr":0,"x":462,"y":347,"wires":[["9a2dd23b.bdd2"]]},{"id":"319bfd95.7ee132","type":"debug","z":"37beda4f.c0b9b6","name":"report result","active":true,"console":"false","complete":"payload","x":670,"y":460,"wires":[]},{"id":"8a4cd7e0.8dd6a8","type":"inject","z":"37beda4f.c0b9b6","name":"inject city options","topic":"","payload":"","payloadType":"date","repeat":"7200","crontab":"","once":false,"x":130,"y":420,"wires":[["436ad80.bf7ed28"]]},{"id":"436ad80.bf7ed28","type":"function","z":"37beda4f.c0b9b6","name":"set options","func":"var rawdata = flow.get(\"tempera\");\nvar location=rawdata.cwbopendata.dataset[0].location;\nvar citynumber=location.length;\nvar i;\n\nvar cityarray=[];\nfor (i=0; i<citynumber;i++)\n{\ncityarray[i]=location[i].locationName[0];\n\n\n}\nmsg.options=cityarray;\nreturn msg;\n\n/*\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\":locationName,\"time\":starthour+\"-\"+endhour, \"max\":period0max,\n\"min\":period0min};\nreturn msg;\n*/\n\n/*if(time.getHours()<18)\n{\nmsg.payload={\"locationName\":locationName,\"todaymax\":period1max, \"todaymin\":period1min,\n             \"tonightmax\":period2max, \"tonightmin\":period2min,\"tomorrowmax\":period3max, \"tomorrowmin\":period3min};\n}\nelse\nmsg.payload={\"locationName\":locationName,\"tonightmax\":period1max, \"tonightmin\":period1min,\n             \"todaymax\":period2max, \"tonightmin\":period2min,\"tomorrowmax\":period3max, \"tomorrowmin\":period3min};\n}\n\n*/\n\n\n\n\n//msg.payload=rawdata.cwbopendata.dataset[0].location[loc].weatherElement[1].time[1];\n\n\n\n\n","outputs":1,"noerr":0,"x":310,"y":420,"wires":[["d70cb19e.ce9ba","974bb21a.bf192"]]},{"id":"70058bfd.8f6724","type":"inject","z":"37beda4f.c0b9b6","name":"inject city","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":108,"y":255,"wires":[["b7cea5f9.af6988"]]},{"id":"106060c9.96982f","type":"function","z":"37beda4f.c0b9b6","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":320,"y":560,"wires":[[]]},{"id":"b0a95da1.e863e","type":"function","z":"37beda4f.c0b9b6","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":510,"y":500,"wires":[["319bfd95.7ee132","ed8f6bef.e99c48"]]},{"id":"a8f73410.d3bb28","type":"debug","z":"37beda4f.c0b9b6","name":"selected city ","active":true,"tosidebar":true,"console":false,"complete":"payload","x":670,"y":420,"wires":[]},{"id":"d70cb19e.ce9ba","type":"ui_dropdown","z":"37beda4f.c0b9b6","name":"","label":"city options","tooltip":"","place":"Select city","group":"11aebcbd.bc7383","order":0,"width":0,"height":0,"passthru":true,"multiple":true,"options":[{"label":"","value":"","type":"str"}],"payload":"","topic":"","x":490,"y":420,"wires":[["a8f73410.d3bb28","8d19ea05.fe1fd8"]]},{"id":"ed8f6bef.e99c48","type":"ui_text","z":"37beda4f.c0b9b6","group":"11aebcbd.bc7383","order":0,"width":0,"height":0,"name":"","label":"","format":"{{msg.payload}}","layout":"row-spread","x":650,"y":520,"wires":[]},{"id":"c2e73742.4ec328","type":"debug","z":"37beda4f.c0b9b6","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":770,"y":120,"wires":[]},{"id":"974bb21a.bf192","type":"debug","z":"37beda4f.c0b9b6","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"options","targetType":"msg","x":490,"y":380,"wires":[]},{"id":"8d19ea05.fe1fd8","type":"function","z":"37beda4f.c0b9b6","name":"city name to number","func":"\nvar rawdata = flow.get(\"tempera\");\n\n//context.global.locationnumber=0;\nflow.set(\"locationnumber\",0);\ntry {\n   cityname=msg.payload;\n   \n   if(cityname.indexOf('台北市市')!=-1 ||cityname.indexOf('臺北市')!=-1 )\n{\n    //context.global.locationnumber=0;\n    flow.set(\"locationnumber\",0);\n   \n}\nelse if(cityname.indexOf('新北市')!=-1)\n{\n    //context.global.locationnumber=1;\n    flow.set(\"locationnumber\",1);\n}\nelse if(cityname.indexOf('桃園市')!=-1) //\n{\n    //context.global.locationnumber=2;\n    flow.set(\"locationnumber\",2);\n}\nelse if(cityname.indexOf('臺中市')!=-1 || cityname.indexOf('台中市')!=-1) \n{\n    //context.global.locationnumber= 3;\n    flow.set(\"locationnumber\",3);\n}\nelse if(cityname.indexOf('臺南市')!=-1 || cityname.indexOf('台南市')!=-1) \n{\n    //context.global.locationnumber= 4;\n    flow.set(\"locationnumber\",4);\n   \n}\nelse if(cityname.indexOf('高雄市')!=-1 ) \n{\n    //context.global.locationnumber= 5 ;\n    flow.set(\"locationnumber\",5);\n   \n}\nelse if(cityname.indexOf('基隆市')!=-1 ) \n{\n    //context.global.locationnumber= 6 ;\n    flow.set(\"locationnumber\",6);\n}\nelse if(cityname.indexOf('新竹縣')!=-1 ) \n{\n    //context.global.locationnumber= 7 ;\n    flow.set(\"locationnumber\",7);\n}\nelse if(cityname.indexOf('新竹市')!=-1 ) \n{\n    //context.global.locationnumber= 8 ;\n    flow.set(\"locationnumber\",8);\n}\nelse if(cityname.indexOf('苗栗縣')!=-1 ) \n{\n    //context.global.locationnumber= 9 ;\n    flow.set(\"locationnumber\",9);\n}\nelse if(cityname.indexOf('彰化縣')!=-1 ) \n{\n      flow.set(\"locationnumber\",10);\n}\nelse if(cityname.indexOf('南投縣')!=-1 ) \n{\n      flow.set(\"locationnumber\",11);\n}\nelse if(cityname.indexOf('雲林縣')!=-1 ) \n{\n      flow.set(\"locationnumber\",12);\n}\nelse if(cityname.indexOf('嘉義縣')!=-1 ) \n{\n      flow.set(\"locationnumber\",13);\n}\nelse if(cityname.indexOf('嘉義市')!=-1 ) \n{\n      flow.set(\"locationnumber\",14);\n}\nelse if(cityname.indexOf('屏東縣')!=-1 ) \n{\n      flow.set(\"locationnumber\",15);\n}\nelse if(cityname.indexOf('宜蘭縣')!=-1 ) \n{\n      flow.set(\"locationnumber\",16);\n}\nelse if(cityname.indexOf('花蓮縣')!=-1 ) \n{\n      flow.set(\"locationnumber\",17);\n}\nelse if(cityname.indexOf('臺東縣')!=-1 || cityname.indexOf('台東縣')!=-1)\n{\n      flow.set(\"locationnumber\",18);\n}\nelse if(cityname.indexOf('澎湖縣')!=-1 ) \n{\n      flow.set(\"locationnumber\",19);\n}\nelse if(cityname.indexOf('金門縣')!=-1 ) \n{\n      flow.set(\"locationnumber\",20);\n}\nelse if(cityname.indexOf('連江')!=-1 ) \n{\n    //context.global.locationnumber= 21 ;\n    flow.set(\"locationnumber\",21);\n}\nelse  \n{\n   // context.global.locationnumber= 0 ;\n    flow.set(\"locationnumber\",0);\n}\n   \n   \n}\ncatch(err) {\n    cityname=\"台北市\";\n    //context.global.locationnumber=0;\n    flow.set(\"locationnumber\",0);\n}\n\nmsg.payload= flow.get(\"locationnumber\");\nreturn msg;\n","outputs":1,"noerr":0,"x":320,"y":500,"wires":[["b0a95da1.e863e","20951ce2.e2f074"]]},{"id":"20951ce2.e2f074","type":"debug","z":"37beda4f.c0b9b6","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":530,"y":560,"wires":[]},{"id":"11aebcbd.bc7383","type":"ui_group","z":"","name":"City temperature","tab":"dc7935b7.cd8c68","order":1,"disp":true,"width":"6"},{"id":"dc7935b7.cd8c68","type":"ui_tab","z":"","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...