<!-- .slide: data-background="https://i.imgur.com/gJLfldF.jpg" data-background-color="#111111" data-background-opacity="0.2" --> ###### tags: `iot-greenhouse` `lab` 返回[物聯網自動化溫室監控系統](/s/PJIS24sFR76axKI0xOrnjQ) ## <span style="color:#F9BF45;">進階排程自動控制</span> ###### [點我開啟簡報模式](/@BEExANT-ta/r1omARwot#) ###### <kbd>ESC</kbd> 鍵進入總覽模式 ###### <kbd>&#8592;</kbd> <kbd>&#8593;</kbd> <kbd>&#8595;</kbd> <kbd>&#8594;</kbd> 切換頁面 --- ## 目標 **在 [控制幫浦與電磁閥](/J5myhWWZRviz1FPdEeWYpA) 中已了解如何設定開始與結束時間進行控制,再來要設計多種排程模式自動控制電磁閥啟動,能夠實際應用在現實案例中。** --- ## 設計原理 - 將區域變數的啟動時間改為全域變數,在到達設定的時間後時,重新設定啟動時間,就可以設計出 ==每隔一定時間啟動排程== 的控制模式。 - 從時間取出星期的值,便能判斷要在一週中的星期幾進行控制,可以設計出 ==每週指定的星期進行分區灑水== 的控制模式。 - 加入指定站別時間設定,能夠在設定時間中啟動對應站別及時間,可以設計出 ==每週指定的星期,根據不同作物的站別進行不同時間的噴灑== 的控制模式,以達到精準給水的效果。 ---- :::info :globe_with_meridians: 參考資源 - [JavaScript Date getDay()](https://www.w3schools.com/jsref/jsref_getday.asp) ::: --- ## 範例程式碼 新增程式檔並命名 ==進階排程自動控制==,將以下程式碼複製貼上程式編輯區執行。 ### 每隔10分鐘啟動一次排程,排程中每站輪流噴灑5秒 ```javascript= window.count = 0; window.finish = false; window.start = new Date("01/01/2022 12:00:00"); let date = new Date(Date.now()); let time = 600 * 1000; let step = 5 * 1000; if(date.getTime() >= start.getTime() && !finish) { console.log("已達啟動時間,開始各站灑水。"); valveOn.set(5); delay(step); valveOff.set(5); delay(1000); valveOn.set(6); delay(step); valveOff.set(6); delay(1000); valveOn.set(7); delay(step); valveOff.set(7); delay(1000); valveOn.set(8); delay(step); valveOff.set(8); delay(1000); finish = true; count = count + 1; } if(finish) { finish = false; date = new Date(Date.now()); start = new Date(date.getTime() + time); console.log("第 "+count+" 次排程結束,下次啟動時間為:\n" + start); } ``` ### 每週一、三、五、日的中午12點啟動一次排程,排程中每站輪流噴灑5秒 ```javascript= window.count = 0; window.finish = false; let date = new Date(Date.now()); let start_week = [1,3,5,0]; let start_hour = 12; let start_minute = 0; let step = 5 * 1000; if(start_week.includes(date.getDay()) && start_hour == date.getHours() && start_minute == date.getMinutes() && !finish) { console.log("已達啟動時間,開始各站灑水。"); valveOn.set(5); delay(step); valveOff.set(5); delay(1000); valveOn.set(6); delay(step); valveOff.set(6); delay(1000); valveOn.set(7); delay(step); valveOff.set(7); delay(1000); valveOn.set(8); delay(step); valveOff.set(8); delay(1000); finish = true; count = count + 1; } if(finish) { finish = false; console.log("第 "+count+" 次排程結束,現在時間為:\n" + date); } ``` ### 每週二、四、六的上午(6)、中午(12)、晚上(18)各啟動一次排程,排程中依據設定的站別時間啟動(單位為秒) ```javascript= window.count = 0; window.finish = false; let date = new Date(Date.now()); let start_week = [2,4,6]; let schedules = [[12,0,5,5,5,5],[6,0,5,5,0,0],[18,0,0,5,0,5]]; if(start_week.includes(date.getDay()) && schedules.some((s)=>s[0] == date.getHours() && s[1] == date.getMinutes()) && !finish) { let sche = schedules.filter((s)=>s[0] == date.getHours() && s[1] == date.getMinutes()); console.log("已達啟動時間,開始執行排程:\n"+ sche); sche = sche[0]; if(sche[2] > 0 ) { valveOn.set(5); delay(sche[2] * 1000); valveOff.set(5); delay(1000); } if(sche[3] > 0 ) { valveOn.set(6); delay(sche[3] * 1000); valveOff.set(6); delay(1000); } if(sche[4] > 0 ) { valveOn.set(7); delay(sche[4] * 1000); valveOff.set(7); delay(1000); } if(sche[5] > 0 ) { valveOn.set(8); delay(sche[5] * 1000); valveOff.set(8); delay(1000); } finish = true; count = count + 1; } if(finish) { finish = false; console.log("第 "+count+" 次排程結束,現在時間為:\n" + date); } ``` --- ## 程式解說 逐行講解程式意義。 ---- ### 每隔10分鐘啟動一次排程,排程中每站輪流噴灑5秒 ```javascript= window.count = 0; window.finish = false; window.start = new Date("01/01/2022 12:00:00"); ``` - 定義全域變數count,作為記錄啟動的次數。 - 定義全域變數finish,作為儲存是否完成排程的變數。 - 定義全域變數start,設定啟動的時間。 ---- ```javascript= let date = new Date(Date.now()); let time = 600 * 1000; let step = 5 * 1000; ``` - 定義區域變數date,設定為現在時間。 - 定義區域變數time,設為10分鐘(600秒)。 - 定義區域變數step,設為5秒鐘。 ---- ```javascript= if(date.getTime() >= start.getTime() && !finish) { console.log("已達啟動時間,開始各站灑水。"); valveOn.set(5); delay(step); valveOff.set(5); delay(1000); valveOn.set(6); delay(step); valveOff.set(6); delay(1000); valveOn.set(7); delay(step); valveOff.set(7); delay(1000); valveOn.set(8); delay(step); valveOff.set(8); delay(1000); finish = true; count = count + 1; } ``` - 當現在時間==大於等於==啟動時間且==finish為false==時,輪流啟動電磁閥,每站==間隔時間==為設定的==step==,結束控制後將==finish設為true==表示此次==排程完成==,count 增加一次。 ---- ```javascript= if(finish) { finish = false; date = new Date(Date.now()); start = new Date(date.getTime() + time); console.log("第 "+count+" 次排程結束,下次啟動時間為:\n" + start); } ``` - 當finish為true時,將finish設為false,重新取的目前時間,將start啟動時間設為date時間加上設定的time,顯示排程啟動次數與下次啟動時間。 ---- ### 每週一、三、五、日的中午12點啟動一次排程,排程中每站輪流噴灑5秒 ```javascript= let start_week = [1,3,5,0]; let start_hour = 12; let start_minute = 0; ``` - 定義三種區域變數,分別代表==啟動的星期,小時與分鐘==。 ---- ```javascript= if(start_week.includes(date.getDay()) && start_hour == date.getHours() && start_minute == date.getMinutes() && !finish) { console.log("已達啟動時間,開始各站灑水。"); valveOn.set(5); delay(step); valveOff.set(5); delay(1000); valveOn.set(6); delay(step); valveOff.set(6); delay(1000); valveOn.set(7); delay(step); valveOff.set(7); delay(1000); valveOn.set(8); delay(step); valveOff.set(8); delay(1000); finish = true; count = count + 1; } ``` - 與第一種控制模式判斷方式不同,先判斷設定的==啟動星期有無包含現在時間的星期==,再判斷設定的==啟動小時與分鐘是否等於現在時間的小時與分鐘==。 ---- ### 每週二、四、六的上午(6)、中午(12)、晚上(18)各啟動一次排程,排程中依據設定的站別時間啟動(單位為秒) ```javascript= let start_week = [2,4,6]; let schedules = [[12,0,5,5,5,5],[6,0,5,5,0,0],[18,0,0,5,0,5]]; ``` - 定義schedules陣列,用來儲存不同的排程,每一個排程的格式為 ==[時,分,一站時間,二站時間,三站時間,四站時間]==。 ---- ```javascript= if(start_week.includes(date.getDay()) && schedules.some((s)=>s[0] == date.getHours() && s[1] == date.getMinutes()) && !finish) { let sche = schedules.filter((s)=>s[0] == date.getHours() && s[1] == date.getMinutes()); console.log("已達啟動時間,開始執行排程:\n"+ sche); sche = sche[0]; if(sche[2] > 0 ) { valveOn.set(5); delay(sche[2] * 1000); valveOff.set(5); delay(1000); } if(sche[3] > 0 ) { valveOn.set(6); delay(sche[3] * 1000); valveOff.set(6); delay(1000); } if(sche[4] > 0 ) { valveOn.set(7); delay(sche[4] * 1000); valveOff.set(7); delay(1000); } if(sche[5] > 0 ) { valveOn.set(8); delay(sche[5] * 1000); valveOff.set(8); delay(1000); } finish = true; count = count + 1; } ``` - 判斷方式與前一種相似,不同的是要==取出schedules中的各個陣列去判斷有無符合現在時間==。 - 當判斷為真時,利用==filter=這個方法取出目前使用的排程。 - ==sche = sche[0];== 由於上面filter回傳二維陣列,所以重新設定sche取得一維陣列。 - 對sche中每一站設定時間進行判斷,若大於0則執行設定的時間。 --- ## 參數修改 為方便實作,以下會將範例程式中可修改的參數標示出來,進行實作時只需修改對應參數,並觀察結果即可。 :::warning :zap: 詳細內建JS參數參考 - [內建Js參數及功能總覽](/s/1TmPhQPFRyKsDRf5d3xyzg) ::: ---- :::success **window.start = new Date("01/01/2022 12:00:00");** ::: - 在第一種控制模式中,可以設定啟動的時間,格式為 "mm/dd/yy hr:min:sec" (24小時制)。 ---- :::success **let time = ==x==; let step = ==y==;** ::: - x為每次排程的間隔時間,單位為毫秒。 - y為每站噴灑的間隔時間,單位為毫秒。 ---- :::success **let start_week = ==x==; let start_hour = ==y==; let start_minute = ==z==;** ::: - x為啟動排程的星期陣列,輸入 ==[1,3,5,0]== 表示==星期一、三、五、日==。 - y為啟動排程的小時。 - z為啟動排程的分鐘。 ---- :::success **let schedules = ==x==;** ::: - x為排程陣列,格式為 ==[[時,分,一站時間,二站時間,三站時間,四站時間],[時,分,一站時間,二站時間,三站時間,四站時間],[時,分,一站時間,二站時間,三站時間,四站時間]]== ,可以新增多個排程。 --- ## 範例影片 {%youtube lAZ4OPx6pa8 %} ---- {%youtube 3_EmkEiwbNg %} ---- {%youtube cU23GQbFqpQ %} <a class="btn btn-warning" style="width:100%;color:#333333;" href="/s/plbQC05nQROOJRu_QgnIfw" role="button"> Line訊息異常通報 **&#8680;** </a> <a class="btn btn-primary" style="width:100%;" href="/s/nSWrH8KxTpualN8Ws8kkwA" role="button"> **&#8678;** 裝置互聯設定與遠程控制 </a>
{"metaMigratedAt":"2023-06-16T17:02:06.941Z","metaMigratedFrom":"YAML","title":"進階排程自動控制","breaks":true,"slideOptions":"{\"transition\":\"slide\",\"transitionSpeed\":\"fast\",\"theme\":\"league\"}","contributors":"[{\"id\":\"a1db0c29-d848-4070-be84-9191a2398ca8\",\"add\":10785,\"del\":2843}]"}
    753 views
   owned this note