當我自豪的覺得應該已經沒問題了,NTP 時鐘看起來有模有樣,殊不知前去向 Bird 闡述我目前的所做的 “功能” 時,Bird 只回了我,你覺得這樣就夠了嗎?
頓時不知道該怎麼反應,Bird 立即又問了我,(原話如下) 你現在將 NTP server 寫死在裡面,如果 NTP server 壞掉了呢,抓不到時間這個時鐘不就沒用了? 你的顏色可不可以變?你用的是 256 * 256 * 256 種顏色的 colorduino LED matrix,你卻只讓他顯示三種顏色…,會不會太浪費?
功能這種東西不要我告訴你你該做什麼,你應該要自己想清楚,這些可以玩的東西太多了,如果你不會動腦想這些附加價值的東西,那就跟一般的所謂碼農沒兩樣。
不知道是我對時鐘沒有想像力,還是我現階段真的沒有辦法把這種問題思考的很明確,不管是哪種情況,這件事我想我會牢記在心,只為了不再犯此類似的錯誤,也為了不要成為沒有創造力的 progrmmer。
anyway 接下來就是分享上面 Bird 提到的兩個功能,先做完後再看看有沒有其他的可能性。
NTP server 的多重選擇
在上一篇 NTP 時鐘 – 程式碼彈性 & 產品思維 提到我在 ESP8266 的 web server 裡寫了一個 webpage 做為使用者的 interface,讓 user 可以利用此 interface 去和時鐘做互動。而多重的 NTP server 的功能,我也是利用 webpage 在上面加了三個 button 讓 user 在其中一個 NTP server 抓不到資料的時候,還有另外兩個 NTP server 可以選擇 (如果三個都掛掉的機率應該是不高…)
用程式碼來看,其實並沒有很難,只要在把 NTP server 的來源地址新增成三種來源,接著把 server 端的程式碼增加三個 button clicked 後送出的 HTTP GET 來的 request,只要這兩項搞定,這項功能也就解決了,以下是部份程式碼:
//there are three option | |
char *ntpServerName = "tick.stdtime.gov.tw"; | |
char *ntpServerName2 = "clock.stdtime.gov.tw"; | |
char *ntpServerName3 = "time.stdtime.gov.tw"; | |
void setup() | |
{ | |
//.skip this part | |
//. | |
//. | |
server.on("/NTP", []() | |
{ | |
ntpServer(ntpServerName); | |
hours = ((epoch % 86400L) / 3600) + 8; | |
minutes = (epoch % 3600) / 60; | |
seconds = epoch % 60; | |
show(); | |
server.send(1000, "text/html", page); | |
}); | |
server.on("/NTP2", []() | |
{ | |
ntpServer(ntpServerName2); | |
hours = ((epoch % 86400L) / 3600) + 8; | |
minutes = (epoch % 3600) / 60; | |
seconds = epoch % 60; | |
show(); | |
server.send(1000, "text/html", page); | |
}); | |
server.on("/NTP3", []() | |
{ | |
ntpServer(ntpServerName3); | |
hours = ((epoch % 86400L) / 3600) + 8; | |
minutes = (epoch % 3600) / 60; | |
seconds = epoch % 60; | |
show(); | |
server.send(1000, "text/html", page); | |
}); | |
} |
另外,程式碼中沒有提到的是 ntpServer 這個 function 我將裡面原先的 argument 換掉,不把送進去的東西寫死,而是可以吃不同來源的 NTP server 網址。
經過一番努力後確定這個 function 是可以 work 地非常好,接著下一個功能。
Color-picker 變換時鐘數字顏色
這的 part 是我在最近嘗試得比較久也比較多東西可以分享的部分。
想要變換時鐘顏色首先要先釐清的事情有幾個,我要在哪裡選擇且如何選擇我想要時鐘變換的顏色,還有現在的工作都是在 master 做好再丟 data 過去給 slave 端顯示,那就要先知道我要丟什麼東西過去給 slave,再來就是要知道 slave 端接收東西後要做什麼樣的事情才能做到正確顯示我給的顏色 data。
這件事其實沒有很容易,讓我來一一說明。
要讓 user 去選擇自己想要改的顏色的方式在經過我查了一些資料後決定用 color-picker 的方式讓 user 自己去選定想要時鐘顯示的顏色。
當然,這裡還是要站在巨人的肩膀上,一方面我目前 focus 的點不在網頁前端 (說真的我也沒有很喜歡) 重點在軟硬整合,另一方面真的有很多現成的 open source 可以使用,那我當然就直接把別人寫好的東西改成我要的形式即可。
不過過程中其實發生了很多意想不到的問題,畢竟我對前端也是略知一二而已,總之最後我將 color-picker 的東西成功整合進我的 webpage,讓使用者可以在網頁上調整顏色,我還順便把 webpage 背景色經由 user 調整顏色時,一起連動更改 (只是實現心裡小小的想法)。
接著第一個重頭戲來了,color-picker 在前端被 user 調整後要怎麼讓 web server 知道這件事情,並且讓 web server 去做出送出 data 給 slave 去改變顏色的動作。
先前在寫 ESP8266 server 端的程式時都是利用 HTTP GET 的形式,用 button clicked 的方法向 server 送出 request 並做出相對應的行為。而這次也不例外,也打算用相同的形式來做到我想達到的目標,但在實踐的過程中卻有些小不同。
當初讓 user 在 textbox 內設定值,當按下 button 時會將三個 textbox (分別為時分秒) 的值一起送到 web server 做 parse 的動作,不過現在 colorpicker 的清況是,我要抓出 bar 拉到 slider 某處後,那個 location RGB 分別的數字,也是利用 button clicked 的方法把值送出 request 給 web server 做相對應的行為。
這件事在我沒有很了解 jQuery 的情況下對我來說是難的,在詢問朋友還有自己找資料後才發現原來 form tag 裡面,的 submit button 一按下去的時候,會把有 name 的 tag 的資料一起送出去 (即向 web server 做 request 的動作),而 value 的部分在 js 裡面用 jQuery 就搞定了 (這也表示我一開始在做設定時間的功能的時候並不是非常了解其中運作的方式,當時純粹只是找到網路上的資料卻沒有很了解他真正的意義,不過幸好現在懂了)
所以現在的狀況是,我已經可以將 user 在 webpage 上調整到的顏色,利用 button clicked 的方式將 RGB 值送出 request 給 server 做動作。
接下來是第二個重頭戲的部分。可以送值到 server 是我想做的,但送進來的東西有 RGB 三個值,但很遺憾的是,如果先前的文章有 follow 到就會知道,我現在的每個顯示元素,不論是動畫,數字,還是 AppWorks 幾個大字,都是用二維陣列產生 0 或某個特定的數字 (1 是紅色,2 是黃色,3 是橘色),去決定在 colorduino 上面顯示的顏色。
那要如何解決這個問題,其實我當下真的沒有想出比較好的解法 (我一開始的想像甚至是,由於 user 是透過同個 AP 去連到 ESP8266 web server,我希望 user 可以在邊拉 color-picker 的 bar 時,數字的顏色就能跟著動,但以我現在手上現有的資源實際上不太可能),在和 Bird 討論此事後決定不要產生 16 個 million 多的顏色其實也無妨,一方面牽涉的軟體面太多不是此專案的重點 (就是我上面提到原先想要的形式,而且應該是用 python 做,小的不才目前還沒有涉略 python 的機會),另一方面人眼其實也沒有辦法辨識出這麼多種顏色。
所以不顯示 16 million 多的顏色,只顯示 256 種顏色是我的目標,而實作的方式會是將吃進來的值 (即 RGB 三個各別的值) 轉換成一個數字,比如說,R : 255, G : 215, B : 100,那我就 R 取前三個 bits,G 取中間 3 個 bits,B 取尾末 2 個 bits,用這樣的方式組成一個新的 byte 也就是一個全新的數字,即 244。
組成全新的數字後,就將這個值從 master 端傳給 slave 端,請 slave 端再做一次處理,使得能有效地顯示 RGB 的顏色。作法雷同只是會有問題,244 這個數字傳到 slave 後要再拆開一次,才會有 RGB 三個分別不同的值,而 R 因為是前 3 個 bits,因此是用 244 & 224 (即 11100000),取 R 的值,G 是中間 3 個 bits,因此是用 244 & 28 (即 00011100),B 最慘是尾沒 2 個 bits,因此是用 244 & 3 (即 00000011),這樣會產生的問題其實很明顯的可以知道 R 的顏色永遠比較強烈,而 B 的顏色就無法被辨識。
為了解決以上的問題,就又牽扯到演算法的部分,目前不想著重此部分,最後我只是將 G 吃進來的值 * 9 (即和 & 28 做完運作後的值再乘上 9),B 吃進來的值在 * 85,效果呈現的確好了非常非常多。
不過還是有問題存在,如果我當初在 color-picker 上調到的綠色好死不死就是 242 那我進 server 處理融合在拆開原先 242 是個頗大的數值,但在 slave 端卻會是 0,這是非常非常大的誤差,但說真的,用這種融合又拆解的方式,這基本上無解 (如果有人有解法麻煩告訴我,我會很感謝你)。
總之,現在時鐘可以讓 user 利用 webpage 設定顏色,雖然綠色的部分真的不太明顯,不過基本上很多顏色是可以清楚辨別的,算是一個小成功吧!
做完了這兩個 function 終於也過了 Bird 的認可,不過難的卻還在後頭 – Debug。
Bird 要我先將時鐘放在 AppWorks 的會議室兩個星期,倘若能夠正常運作沒出 trouble,就可以順利裝盒,當然,我從沒這麼幸運,我放了兩天就出問題……。待續……。