IoTTalk 物聯網應用操作入門手冊     -- by tsaiwn@cs.nctu.edu.tw 交大資工 蔡文能                   ...   
IoTtalk 使用者詳細使用手冊:   ( IoT = Internet of Things 物聯網--物物相連的互連網 )
      http://liny.cs.nctu.edu.tw/#IoTtalk   (林一平教授網頁)

      點入後在 Document 下方, 有中文版和英文版(English version);     or     點這看更多手冊
* 簡介:
IoTtalk 系統交通大學林一平博士帶領研發團隊開發的智慧物聯網應用開發平台, 提供業者一個整合、開放、低成本、高效率, 且能串聯不同規格標準的物聯網應用(例如智慧家庭、智慧校園、智慧農場)平台林一平教授曾任科技部次長,現任交大副校長林一平教授興趣多元,喜好藝術繪畫寫作遨遊於科技與人文間自得其樂,參看林一平教授的臉書(fB),以及林一平教授的Digitimes專欄文章。(點這看林一平教授寫的『大橋驟雨』以及關於歌川廣重的『大橋安宅驟雨』;還有,看看林教授該書中提到晚年住在亞爾Arles的梵谷模仿大橋驟雨的『雨中橋』油畫)
    目前這 IoTTalk 系統平台已經成功用於智慧校園智慧農業, 例如用於種植薑黃(5分鐘影片) (參看 今週刊報導(2019.01.23)農譯科技公司 AgritalkTech.com/ 以及分家出去的 AI_農業 Agritalk.com.tw/) (arduino.cc 分家出 arduino.org 訴訟後又和解+合併)
啊?IoTTalk 系統平台還能做甚麼喔?那就看大家的創意了 :-) (藝術家和賈伯斯都說: 創意, 偷就有了!)
    使用 IoTtalk 系統的好處是你可以利用 GUI 快速建立物聯網應用專案(在首頁點 Project 進入 GUI 畫面),針對任一個應用專案,可以加入一個或多個輸入和輸出的設備模型(Device Model),用滑鼠點按即可連接輸入設備和輸出設備(單點功能連接或多點功能連接),當物聯網設備連接至 IoTtalk 系統時,針對各種感測器,IoTtalk 會自動產生或使用應用軟體來處理,因此每一個輸入設備可以相當方便地連接至輸出設備,必要時還可用 Python 在連結點寫簡單前處理或後處理函數;如果是多點連接, 甚至可在連接點撰寫較複雜的處理函數。

* 如果想連接"真"的設備, 建議也 先看看 ArduTalk 操作手冊(在Github) 以便多了解一些概念。 裡面包括:
      (a)《安裝手冊》是告訴你如何利用Arduino IDE 把程式碼燒錄到 NodeMCU V2/V3 內,
     可點這跳到後面看更多關於燒錄到NodeMCU(及應用)的參考資料; 也可以點這跳到後面看關於Arduino Yun如何燒錄與使用的參考資料;
      (b)《操作手冊》則是教你如何在 IoTtalk 的專案使用NodeMCU設備搭配感測器等
      至於IoTtalk可以如何應用, 那取決於你的想像力和創意(賈伯斯說創意偷就有了)!
* 如果你還不清楚啥是 NodeMCU, 可以點這裡先往下跳到後面看看NodeMCU/ESP8266相關資料後, 再跳回這繼續看。

  ** 點這到後面(三)看關於Joint函數   點這到(四)如何用Python寫Dummy Device + (五_進階Dummy Device) + (六)    
  ** 點這到後面看(七)新增可用設備模型(管理Device Model);   點這到(八)如何用 IoTtalk 連接真實設備...
            跳到(九) 搭配 Raspberry Pi 3 B+;     (十) 關於 Rabboni 小玩具 以及Rabboni 搭配 IoTtalk

注意NodeMCU V2 開發板比較小方便使用麵包板, 但是經實測發現對 D0 做 PWM 輸出會導致WiFi網路斷線!
    所以, 如果用 NodeMCU V2 開發板, 要燒錄不同的程式碼, 請點這看關於我改過的 t7 版本

* 如果你對這 IoTTalk 物聯網應用平台到底怎麼做出來的有興趣, 可以點這到 iottalk.vip/0 看看開發者手冊
    ** 如果你不太懂 Python 和 Flask 但想快速懂一些, 可以點這開新窗看看我寫的如何快速用 Python + Flask 弄出一個網站(大一計概講義)。
在, 好玩的IoT物聯網應用 ..
要.. 開始囉 . . .
可以用哪個 IoTtalk Server 來體驗物聯網(IoT)的實驗操作呢?
  * 交大 IoT 物聯網實驗網站 https://demo.iottalk.tw (140.113.199.200 在交大電算中心)

★★★ 如果你在資策會上課:
     請點這 http://125.227.255.81 連到 IoT 物聯網實驗網站 (這機器 在資策會)
    或 http://192.168.20.101/ (資策會內部網路; 注意上面 Public IP 可能被防火牆擋住)

 萬一不能用, 用以下給 Guest 測試的:點這 https://demo.iottalk.tw 連到交大 IoT 互聯網實驗網站 (這機器 140.113.199.200 在交大電算中心)
  * 或 另一部機器 test.iottalk.tw (注意如果用到 NodeMCU 則要注意使用的 IoTtalk Server IP)  

(一)用電腦 或 手機控制開關燈, 虛擬燈泡(Bulb)可以在自己或別人電腦上, 甚至也可以在手機上


準備建立一個 IoTtalk 物聯網應用專案(Project)
(1)點交大 http://demo.iottalk.tw 連到物聯網互動練習網站,
      ( 或點 交大 http://test.iottalk.tw 連到另一個練習網站 )
      資策會的可以 點 http://125.227.255.81 連到物聯網互動練習網站,
      ( 或資策會內網: http://192.168.20.101/ )
      連入 IoTtalk 伺服器網站後會出現如下網頁, 在網頁內, 點那個 Project
      此時會彈出新網頁(...:7788/connection),
      此時會彈出新網頁,

      此時會彈出新網頁, (說三次免得有些人沒看到:-)
請在新窗點 Select a project, 然後可選 add project 建立新專案,或選以前你建立過的專案名稱。



(2)在彈出的小窗輸入專案名稱(Project Name), 和 對應這專案的密碼 (以後開啟這專案要用)
   建議專案名稱用你學號後三碼開頭比較能認出是你做的專案,
   密碼要打自己容易記住不會忘掉,但別人又不容易猜到的 :-)

  * 也可以不打密碼免得忘掉, 但這樣別人也可點入把你專案砍掉, 不過那也沒關係, 反正不是很重要 :-)

(3)這時專案是空的, 左上角會出現你專案名稱
   要開始加入這專案的設備(Model), 滑鼠移動到 Model 上, 捲動滾輪選取設備
   選錯了還可以砍掉(Delete), 所以不用怕選錯 :-)
   以下我們先加入一個燈泡 (Bulb):


(4)為選到的設備勾選零件(就是選擇要哪些功能 Feature)
   這燈泡有兩個零件(功能,Feature)可以選: Color-O (顏色) 和  Luminance (亮度, Lumen=流明)
   至少要選一樣後 Save 才會出現設備的圖示; 如果設備只有單一功能則會自動出現在視窗內;
   之後隨時可以點圖示左上角的齒輪重新設定零件, 所以也是不用怕選錯 :-)
   以下我們先只選 Luminance (亮度) 用來控制燈泡的亮度:



(5)接下來, 再生出一個設備(Model) "Remote_Control" (遙控器)
   剛才那 Bulb 燈炮是 "輸出" 設備 (就是會被控制的),
   再來我們加入一個"輸入"(Input)設備, 就是讓使用者可以操作 "輸入" 一些資料(例如按開關, 旋轉轉輪, 甚至打字等);現在來加入遙控器:
   遙控器功能很多, 可以只選轉輪(Knob)一個即可, 或你要順便選一個開關(Switch)也不錯 :-)
   選定之後, 點按 Save 就會在視窗內左邊出現該設備(Remote Control)
 
 現在應該有發現: 左邊會放"輸入"設備, 右邊會放 "輸出"設備 !
   在上圖中, 燈泡設備圖示的右上方格子內出現26.Bulb表示已經關聯到 26號燈泡,
   這 26 號燈泡可能是你之前打開的, 也可能是別人打開的燈泡,
   你隨時可以點該處重新關聯到別的燈泡 !

(6)把遙控器的零件和燈泡的零件連接起來
   第一個連接點會自動叫做 Join 1, 在連接點上可以寫簡單 Python 程式碼做處理
   不過, 通常不必寫就可以使用 :-)
   連接好之後記得要按右上角的 Save
 
    在上圖中, 有沒注意到: 有編號 1, 2, 3, 5, 奇怪怎沒有 4 ? 
    因為 4 是要選擇把 Bulb 關聯到一個可用的 Bulb 啦。

(7)現在物聯網專案已經完成, 剩下的是要把代表設備的"設備圖示"關聯到真正的設備;
   (a)請到同一部Server(例如demo.iottalk.tw)物聯網首頁點 Bulb 開啟一個網頁燈泡, 注意上方的編號;
      就是到剛才一開始開啟的網頁點 Bulb, 當然現在另外開新網頁只要連到同一部伺服器(Server)也是 OK 啦 !
      如果你一開始還沒建立專案就先開啟一個 Bulb 備用也可以, 順序不重要, 重要的是該 Bulb 的編號 !
   (b)用手機的 Chrome 或任意瀏覽器連到同一部伺服器(例如 demo.iottalk.tw)然後點那個 Remote_Control(Mobile)
      也是注意此遙控器的編號 
      ** 沒手機也可以在電腦上點開那 Remote_Control(Mobile) 也是注意其編號
   (c)把燈泡窗拉開到永遠看得見, 若用電腦點開 Remote_Control(Mobile), 也拉開方便控制
   (d)接著可以回到你剛開的專案(Project)視窗, 準備把設備關聯到代表設備的"設備圖示"
      就是告訴電腦: 遙控器是在誰手上的遙控器, 燈炮又是在哪邊的燈炮(Bulb)


(8)更改設備屬性(功能)以及改變設備的關聯對象
     ** 隨時可以點齒輪更改該設備的零件
     ** 也可以隨時重新做關聯
   (a)你可以隨時點設備左上角的齒輪改變設備的屬性(功能), 也可以隨時把專案內設備關聯到不同的"設備"
     注意: 改變屬性功能之後, 有可能需要重新連連看連線(如果你砍了某功能則其連線也會自動被砍掉, 廢話 :-) 
   (b)針對每個設備, 點它齒輪右邊的方格, 然後在右半邊視窗點選你要連接的設備(例如燈泡26.Bulb)
     注意關聯之後, 在該方格內會用藍色字體顯示其關聯到的設備編號。
   (c)為了確定有弄懂, 可以請兩位同學幫你測試, 要他們用手機或電腦連到同一部 Server,
      然後請他們也點選那個 Remote_Control(Mobile)  (注意, 要有 Mobile 那項喔 !)
      當然也要請他們把編號告訴你, 讓你到你的專案視窗中點 Remote_Control 圖示齒輪右方的格子,
      先改"關聯"到第一位同學, 請他開關燈, 再次改"關聯"到另一位同學, 也請他開關燈,
      確定你有弄懂可以在你的物聯網專案(Project)快速切換設備物件的真正關聯對象 !
   (d)你也可以讓一位同學的手機用那 Remote_Control(Mobile) 控制另一位同學手機上的 Bulb 喔! 
   (e)注意 ! 要連到同一部 IoTtalk 的 server 才有辦法互相控制喔 !
      老是有同學連到不同 Server 才來問說怎都沒效果 :-( !!! 

                  >
(9)測試、模擬輸入、監看進出連結點(Join)的資料
   (a)現在, 可以用手機上的 Remote_Control(Mobile)控制電腦上的燈泡(Bulb),
   (b)也可改把燈泡關聯到另一位同學手機上的燈泡, 變成用手機遙控器控制另一位同學手機上的燈泡 :-)
***(c)模擬輸入: 即使沒關聯到輸入設備, 仍可用模擬方式觀看燈泡開關(ㄚ當然輸出設備一定要關聯啦) !
           即使沒關聯到輸入設備, 仍可用模擬方式觀看燈泡開關(ㄚ當然輸出設備一定要關聯啦) !
           即使沒關聯到輸入設備, 仍可用模擬方式觀看燈泡開關(ㄚ當然輸出設備一定要關聯啦),
           請參看以下圖片右上角, 在圖片中的 Simulation 是點亮的 (ON綠燈) !
   (d)監看資料: 還有, 用滑鼠右鍵點 Join 點, 可以監看進出該節點的資料(在右半邊視窗)
 出問題 !? 出現黃色驚嘆號 !  或 Flush 右邊綠燈變紅燈 怎麼辦?!怎麼辦 ?!
 出問題 !? 出現黃色驚嘆號 !  或 Flush 右邊綠燈變紅燈 怎麼辦?!怎麼辦 ?!
 出問題 !? 出現黃色驚嘆號 !  或 Flush 右邊綠燈變紅燈 怎麼辦?!怎麼辦 ?!
   (e)刷新 Flush: 萬一出問題出現黃色驚嘆號, 可以點驚嘆號大略看看是啥錯誤,
      不過通常點一下 Flush 讓它紅燈又回到綠燈阿就可解決問題 !
      參看下圖:  (注意圖片中左上角的 Flush 以及右上角的 Simulation 之說明 ! )

> ※ 劍橋字典 dictionary.cambridge.org 劍橋字典
(二)用你手機控制丟球, 球建議選 Ball-Throw2
      建立一個新專案(Project), 或用原專案修改也可以, 一個專案可以有無數個輸入設備和無數個輸出設備 !
      * 這次輸入設備改選 Smartphone (智慧型手機),
       Smartphone 智慧型手機的功能很多, 這次只要選加速器(Accelerator)一項功能即可;
      你也可以故意把智慧型手機的加速器連到燈泡控制看會怎樣 !? (hint: 到時候甩動手機會讓燈炮會忽明忽暗)
      不過這次主要是要連到 Ball-throw2 這個丟球小遊戲(球打到木板上紅色那處會發聲音說 Good Job)
      當然你要回首頁 點 Ball-throw2 開啟一個丟球畫面來用(在往下的 VPython List: 大約第 10 個),
      下圖中已經關聯到 60.Ball-Throw2 (加入Ball-Throw2 時如只有一個會自動關聯)
      也是要找一位同學用手機連入同樣網站, 這次點 Smartphone 注意編號, 例如下圖:
      已經把 Smartphone 關聯到 61.Smartphone
  ** 補充說明:
      在 IoTtalk 系統首頁 VPython List 之下的視覺化網頁應用(Visual Web Application)
      都是用 VPython 視覺化的語言(其實是程式庫)寫的應用 !
      在 VPython 的首頁就說:
      VPython 是 3D Programming for Ordinary Mortals (凡人用的 3D 程式設計)

      * 想體驗 VPython programming,
          請點這連到 https://EduTalk4.NCTU.edu.tw/ (免費註冊 Sign up)

      * 想看更多 VPython programming 範例,
          請點這連到 VPython 官方的 Examples

      VPythonPython中一個稱為 Visual 的模組所擴充而來。其原始架構是由Carnegie Mellon University的大學生 David Scherer 在2000年開發出來,核心為Python 這個易學的程式語言,以其建構的三維繪圖模組來描述虛擬的物理世界,讓使用者可以輕易的利用程式來做三 維空間的物理繪圖,具備有動態的時間演進和不同的視角觀察,讓學生可以更直覺的利用程式來學習物理,尤其是需要視覺化和動態觀察的物理現象。

      VPython 目前有多個版本被廣泛使用,除了原本的單機版的 VPython 之外,另有在網頁上可執行的GlowScript,與新世代的vpython-jupyter計畫(就是提供 API 讓 VPython 可以在> 網頁執行,在 IoTtalk 系統裡面的 VPython List 各應用 以及在 EduTalk4.NCTU.edu.tw 都是在瀏覽器執行 VPython 程式碼)。

 
   
如果發現手機不動也會自動丟球,
先看看是否你點亮了模擬(Simulation), 如沒有, 那可能手機加速度的取值設定被改錯了,
正常狀況預設是採用"變動量"(variant)抓取三軸加速度, 看下圖:
  
萬一不小心被改為 "sample" 取樣當時看到的值, 則可能導致手機不動, 但球卻自己亂丟 !    
注意.. 注意..
這時手機很耗電 ! 還有.. 
注意千萬不要把你手機丟出去, 丟出去摔壞了別怪我沒先講喔 :-) 

**思考: 如何用"手機"控制開關前面(一)的 Bulb 燈泡?
     例如: 手機正面朝上開燈, 正面朝下時關燈, 或反過來 !
     Hint: 
           (1) 加速度感測器的 Z 軸值在手機正面朝上約 9.8; 正面朝下約 -9.8
           (2) 顯然這時須把加速度值從 Variant 改為 Sample (可以只改 Z 軸), 就是 Smart Phone (IDF) 的 x3 屬性。
           (3) 需要在 Join 連結點寫個簡單小 Python 程式

(三)也可以玩三個人分別用手機控制同一個燈(Bulb)的顏色 一個控制紅色 一個控制綠色 一個控制藍色
請參考以下各圖的連接方式, (a)注意專案中, 選用三次的 Remote_Control, 各自都只勾選一個 Knob 就 Save, (b)專案中也選用一個 Bulb, 只勾選亮度 (Luminance) (c)再注意專案中三個 Remote_Control 遙控器都接到 Join 1 就是其中一個連接燈泡後, 其他兩個遙控器要連到 Join 接點 (d)在電腦上也是要開啟一個 Bulb 燈泡拉成永遠看得到, 並把該編號燈泡 關聯到 專案內的 Bulb 代表圖示 (e)然後請三位同學各自用手機連到 demo.iottalk.tw 點裡面的 Remote_Control (Mobile) (f)請三位分別報出手機上遙控器的編號以便關聯到專案中三個遙控器代表圖示; 再來, 點專案中的連接點(Join 1)要寫一個合成的程式碼(以下我稱 haha), 以及三個拆開給紅綠藍使用的 rr, gg, bb 三個函數; haha( ) 函數的內容是 return [ args[0], args[1], args[2] ] # 把三個參數組合成一個串列 rr( ) 函數的內容是 return args[0][0]*255 gg( ) 函數的內容是 return args[0][1]*255 bb( ) 函數的內容是 return args[0][2]*255 然後三位同學就可以用手機上遙控器的 Knob 轉輪控制網頁上的燈泡囉 ! *** 注意各函數的頭部是自動產生, 都是 def run(*args):
    Top  幾個英文字讀音 *** 提醒: joint function 一定要 Save, 套用, 再 Save *** 上圖中的 haha( ) 把三個參數組合成一個串列
*** 下圖中的 gg( ) 從串列中取出第2個; 注意 [1] 是第 2 個不是第一個 ** rr( ), gg( ), bb( ) 是想分別取出 紅(Red) 綠(Green) 藍(Blue)的成份

*參看下圖, 點 Join 1 連結點, 注意右邊各個函數套用設定是否正確 ! 最後記得要按右上角那個 "Save" 喔 !如果發現上方 Flush 右邊是亮紅燈, 表示出問題了, 要點一下 Flush 讓它變綠燈 !

再把前面說明重複貼這方便查看 : 
請參考上面各圖的連接方式, 
(a)注意專案中, 選用三次的 Remote_Control, 各自都只勾選一個 Knob 就 Save,
(b)專案中也選用一個 Bulb, 這次只勾選顏色 (Color-O) 
(c)再注意專案中三個 Remote_Control 遙控器都接到 Join 1
   就是其中一個連接燈泡後, 其他兩個遙控器要連到 Join 接點
(d)在電腦上也是要開啟一個 Bulb 燈泡拉成永遠看得到,
   並把該編號燈泡 關聯到 專案內的 Bulb 代表圖示
(e)然後請三位同學各自用手機連到 demo.iottalk.tw 點裡面的 Remote_Control
(f)請三位分別報出手機上遙控器的編號以便關聯到專案中三個遙控器代表圖示;
   再來, 點專案中的連接點(Join 1)要寫一個合成的程式碼(以下我稱 haha),
   以及三個拆開給紅綠藍使用的 rr, gg, bb 三個函數; 
   haha( ) 函數的內容是  return [ args[0], args[1], args[2] ]
   rr( )  函數的內容是  return args[0][0]*255
   gg( )  函數的內容是  return args[0][1]*255
   bb( )  函數的內容是  return args[0][2]*255
然後三位同學就可以用手機上遙控器的 Knob 轉輪控制網頁上的燈泡囉 !
*** 注意各函數的頭部是自動產生, 都是 def run(*args): 

** 既然可以在連結點寫簡單的 Python 程式, 我們當然可以加入一些"人工智慧"(AI; Artificial Intelligence) ! 例如, 可以在偵測到溫度高過 25度就開啟電扇, 或是高過 28度就開啟冷氣機:-) 再如, 當發現二氧化碳 或 一氧化碳濃度過高, 就自動開啟窗簾以及窗戶, 甚至開啟排風機; 等空氣品質變好再依序關閉! 那這"人工智慧(AI)"要寫在哪呢? 通常, 如果很複雜就把"AI 人工智慧"寫在伺服器內, 甚至可能把資料送去雲端幫忙計算處理再送回來使用! 若不是很複雜可以寫在 DAI (例如用 Arduino Yun) 或寫在 Joint Function; 若很簡單甚至可寫在 IDA (IoT Device 內的韌體)! (參考IoTTalk 系統開發者手冊) * 推薦閱讀: ** 當人工智慧遇上物聯網 迎接AIoT智慧時代(今週刊2018.02.09) ** 2019未來科技展 再造台灣「隱形冠軍」(交大轉載MoneyDJ) | 2019未來科技展 ** AIoT浪潮席捲全球 Edge AI晶片設計思維大不同(DigiTimes 2019.10.31)

  TOP   幾個英文字讀音    
> ※ 劍橋字典 dictionary.cambridge.org 劍橋字典/thyme
(四)練習從 github 抓 Python 虛擬裝置(Dummy devie)來用 (就用來控制燈泡開關好了)
    * 在PC/Windows不安裝 git 仍可選用"Download ZIP"方式下載 !
還沒有 git 但想安裝 git 的可以點這到 https://git-scm.com/downloads下載安裝
 
到 https://desktop.github.com/ 抓 Desktop github
  * 在PC/Windows不安裝 git 仍可選用"Download ZIP"方式下載 !
(1)用 Google 搜尋 dummy + iottalk + python
   應該會在前幾篇找到 GitHub - IoTtalk/Dummy_Device_IoTtalk_v1_py
     (Hint: 我搜尋結果是有時在第一篇, 或第二篇, 或 在第 三 篇)
(2)點進去, 稍微看一下說明, 它有說會用到網頁相關的 python module 'requests'
   就是說萬一有錯誤訊息可能你沒用 pip 安裝過 requests 模組啦 !
   到時候, 當然就是要照它說的安裝囉: (requests 是負責處理網頁溝通用的模組)
       pip  install  requests 
   別緊張, 不用現在 pip install requests 喔, 因為說不定你的 Python 已經有安裝過該模組了 :-)
(3)點 Clone or download 準備下載這 Dummy_Device專案壓縮檔
   如果你電腦有 git 則可複製顯示的網址以便做 "git clone 網址"  抓回來
   在 Windows 上也可以點 Download ZIP  抓回來解壓縮
   (註: PC 上也可以安裝 git 以便用來 git clone 網址)
    ** 注意這時複製到的網址尾巴應該是 .git
    ** 如果你是在 Download ZIP 上按滑鼠右鍵選複製網址則尾巴應是 .zip 可用 wget 抓回 .zip 檔案
(4)如果抓 ZIP 檔案請解壓縮(Linux 上可用 unzip 命令)
   如果用 git clone 則是抓回放在子目錄 Dummy_Device_IoTtalk_v1_py
   用 cd 命令進入該子目錄
   Hint: 在 CMD 命令視窗內要善用 TAB 按鍵, 就是說只要打開始幾個字母就可按 TAB, 不對就再按一次 TAB, ...

(5)修改 DAI.py 檔案, 其他 DAN.py 和 csmapi.py 都不要管, 只要放同一目錄即可;
   阿 DAI.py 也只要改第三列那個 IP, 改為你在用的 iottalk 伺服器, 
   例如 125.227.255.81 或 demo.iottalk.tw
   這時變成類似如下:(紅色部分就是你正在用的 IoTtalk 伺服器, 也可以用 IP address)
     ServerURL = 'http://125.227.255.81:9999' #with no secure connection
    或交大 demo 伺服器:
     ServerURL = 'http://demo.iottalk.tw:9999' #with no secure connection
(6)仿照前面(一)用遙控器開關燈的專案,
   只是把 Remote_Control (遙控器)改為選用 Dummy_Device (虛擬裝置),
   提醒 Dummy_Device  的 IDF (輸入功能), 就是感測器(Sensor)
   
(7)執行 DAI.py 以便產生虛擬裝置並註冊到 iottalk 伺服器
   開啟 CMD 命令窗 進入到該目錄, 像以下這樣執行:
      python DAI.py    #  如果在 Ubuntu Linux 則用 python3 DAI.py
   注意看印出信息顯示的裝置編號 (亂數產生的), 關聯時要用到!

(8)回到 iottalk 專案網頁, 把虛擬裝置關聯起來, 當然虛擬燈炮也要關聯起來喔 !

(9)仔細看看虛擬燈炮會怎樣?
說明:
   這個 DAI.py 其實包括 IDF, 本來該讀取 IoT 的感測器(Sensor), 以便丟去給伺服器,
   現在用亂數產生一個值模擬讀到的 Sensor value;
   另外, 也包括一個 ODF 叫做 'Dummy_Control', 那是從 Server 送來的串列(Python 的 List 就是 Array 啦)
   這 DAI.py 只是從 Server "拉回"這 ODF 的串列, 然後如果收到的不是 None, 則只印出第一個值: 
        print (value1[0]) 
   真正的裝置可能要拿這值來做控制某些設備或做其他事情 !
   目前我們沒用到這 ODF, 所以你專案內可以不勾選 ODF, 或勾選了不關聯到任何設備 !

確定都有聯接好且關聯到虛擬裝置和燈炮, 應該有看到變化吧 !? 燈好像忽開忽關忽明忽暗對不對 !? 那是因為 DAI.py 是幫 'Dummy_Sensor' 產生亂數送出去 ! 接著來改為從鍵盤讀入再送出 ..
  Top   幾個英文字讀音
> ※ 劍橋字典 dictionary.cambridge.org 劍橋字典/thyme 讀如 time
(五)修改 (四) 的 DAI.py 改為從鍵盤讀取要送出的值
    # 新版的 DAI.py (建議用 DAI2.py 做名稱) 如下: (不要 Mark 到左方的每列編號 !)
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# DAI2.py  -- new version of Dummy Device DAI.py, modified by tsaiwn@cs.nctu.edu.tw
# you can get from here:  https://goo.gl/6jtP41   ; Search dummy + iottalk  for other files
import time, DAN, requests, random 
import threading, sys

# ServerURL = 'http://Your_server_IP_or_DomainName:9999' #with no secure connection
# ServerURL = 'http://192.168.20.101:9999' #with no secure connection
#  注意你用的 IoTtalk 伺服器網址或 IP 
ServerURL = 'https://demo.iottalk.tw' #with SSL secure connection
# ServerURL = 'https://Your_DomainName' #with SSL connection  (IP can not be used with https)
Reg_addr = None #if None, Reg_addr = MAC address

mac_addr = 'C860008BD249'  # put here for easy to modify;;  the mac_addr in DAN.py is NOT used
# Copy DAI.py to DAI2.py and then modify the above mac_addr, then you can have two dummy devices
Reg_addr = mac_addr   # Otherwise, the mac addr generated in DAN.py will always be the same !

DAN.profile['dm_name']='Dummy_Device'   # you can change this but should also add the DM in server
DAN.profile['df_list']=['Dummy_Sensor', 'Dummy_Control']
#DAN.profile['d_name']= None # None for autoNaming
DAN.device_registration_with_retry(ServerURL, Reg_addr)

# global gotInput, theInput
gotInput=False
theInput="haha"
allDead=False

def doRead( ):
    global gotInput, theInput, allDead
    while True:
        if gotInput:
           time.sleep(0.1)
           continue  # go back to while
        try:
           theInput = input("Give me data: ")
        except Exception:    ##  KeyboardInterrupt:
           allDead = True
           print("\n\nDeregister " + DAN.profile['d_name'] + " !!!\n",  flush=True)
           DAN.deregister()
           sys.stdout = sys.__stdout__
           print(" Thread say Bye bye ---------------", flush=True)
           sys.exit( );   ## break  # raise   #  ?
        gotInput=True
        if theInput !='quit' and theInput != "exit":
           print("Will send " + theInput, end="   , ")

#creat a thread to do Input data from keyboard, by tsaiwn@cs.nctu.edu.tw
threadx = threading.Thread(target=doRead)
threadx.daemon = True
threadx.start()

while True:
    try:
    #Pull data from a device feature called "Dummy_Control"
        value1=DAN.pull('Dummy_Control')
        if value1 != None:
            print (value1[0])
    #Push data to a device feature called "Dummy_Sensor" 
        if gotInput:
           if theInput =='quit' or theInput=="exit":
              break;  #  sys.exit( );
           #value2=random.uniform(1, 10)
           try:
              value2=float( theInput )
           except:
              value2=0
           gotInput=False   # so that you can input again 
           if(allDead): break;
           DAN.push ('Dummy_Sensor', value2,  value2)

    except Exception as e:
        print(e)
        if str(e).find('mac_addr not found:') != -1:
            print('Reg_addr is not found. Try to re-register...')
            DAN.device_registration_with_retry(ServerURL, Reg_addr)
        else:
            print('Connection failed due to unknow reasons.')
            time.sleep(1)    
    try:
       time.sleep(0.2)
    except KeyboardInterrupt:
       break
time.sleep(0.5)
try: 
   DAN.deregister()
except Exception as e:
   print("===")
print("Bye ! --------------", flush=True)
sys.exit( );
這個新版的 DAI2.py 改為派一個 Thread (執行緒) 同時(平行)做事, 負責讀取使用者從鍵盤輸入;
請注意, 在等輸入的同時, 主程式仍不斷的 "Pull" ODF ('Dummy_Control')
並且在 "小弟" 有幫忙讀到一個值之時, 把該值 (value2) push 送去給 Server :
      DAN.push ('Dummy_Sensor', value2,  value2)  
在這是故意把 value2 寫兩次表示送出兩個值, 也可以送更多個 !  
補充關於用 Thread 平行做事:
 (a)Line 27-44 定義一個函數 doRead( )
    這函數利用一個全域變數 gotInput 讓 "主人" 知道是否有讀到輸入值(放在 theInput 內)
 (b)Line 47-49 設定並啟動 Thread 執行緒, 執行的是 doRead( )
 (c)Line 58-68 是主人發現 gotInput 亮燈表示有資料時, 取出資料, 
         並把 gotInput 弄為 False 以便讓小弟知道主人已經把資料 theInput 拿走
         請注意, 在 Line 59-60 還有檢查輸入值, 如果是 'quit' 或 'exit' 則結束程式 !

(六)修改專案, 改為放兩組 Dummy Device, 然後互相傳遞資料
   (1)複製並修改 (五)的 DAI2.py  為 DAI3.py,
      這 DAI3.py 只是改一下 第13列的 mac_addr, 把裡面 249 改為 你喜歡的其他三位數,
      因為如果 mac_addr 相同, 則會被 Server 看作同一個裝置 !
   (2)你必須開兩個命令視窗, 一個跑 DAI2.py, 另一個跑 DAI3.py
      執行時請注意看各自印出的裝置號碼, 關聯時要用到 !
   (3)也可以找同學合作, 一個跑 DAI2.py, 另一個跑 DAI3.py
      專案當然是由誰建立都可以, 只要把代表 DAI2.py 和代表 DAI3.py 的虛擬裝置關聯到即可,
      注意, 在專案中加入兩組 Dummy_Device 兩次都有勾選 IDF 與 ODF, 則共會有四個 Dummy_Device,
      兩個輸入用, 兩個輸出用 !
   (4)這時, DAI2.py 和 DAI3.py 都各自身兼兩個設備: 輸入(IDF) 和 輸出(ODF)
      所以關聯設備時, DAI2.py 和 DAI3.py 各會被用到兩次
      其實你也可以再複製為 DAI4.py 和 DAI5.py (當然要改 mac_addr), 開四個 CMD 窗各自執行,
      這樣負責輸入的就不必負責輸出 !
   (5)測試時,
      各自都打一個數值然後按 Enter 送出 ;可以打實數因為我用 :
          value2=float( theInput )
   (6)做習題的同學注意: 測試過程也要 CTRL_PrintScr 抓取畫面繳交 !
Top   幾個英文字讀音        
(七) 如何增加/修改 Device Model 物聯網設備類別 ?                 
    (0)阿這是IoTtalk使用者該知道的喔, 在使用者手冊內有詳細解說 !
          這與如何增加/修改/刪除 Device Features(設備功能屬性)在同一個操作介面,
        都是從IoTtalk首頁點選 Device Feature Management進入頁面;
        這時 左上角是Device Feature, 用滑鼠點一下就可切換 Device FeatureDevice Model 管理頁面!

    (1) 在iottalk 首頁點選 Device Feature Management
          這時可以增加或刪除 Device Feature 設備功能, 功能可用於各種設備(Model),
        如果某功能(Feature)已經被至少一種設備(Model)使用, 則無法刪除(會警告且不給刪除)。

        想增刪或修改設備(Model)則請讓我們跟新聞主播盛竹如繼續看下去..
    (2) 點左上角的 Device Feature 切換為 Device Model 畫面 (參考下圖)
     
    (3) 右邊視窗中點選 add new DM 以便新增 Device Model (設備)
    (4) 然後要選 想要哪些 IDF 以及/或者 哪些 ODF, 選擇類別 Category, 然後選你要的功能
    (5) 最後記得要點 Save 存檔, 它會問你 Device Model Name (設備名稱)
    (6)注意 Device Model name 若與已經有的重複會警告你要蓋掉 !
    (7)成功加入之後, 就可在 Project 中新增這個Device Model 設備類了
   
    Top   幾個英文字讀音
(八) 如果要用 IoTtalk 連接真實設備(例如真的燈泡)那要如何做 ?
      (關於 ArduTalk 與 NodeMCU 以及IoTtalk物聯網應用)
    A: 這時需要一個 ESP8266 或 NodeMCU 的微控器(Micro controller),
         裡面要有程式可以和 IoTTalk 系統溝通, 又可以控制真實燈泡等物聯網設備。
         ( 註: ESP8266 是指 WiFi 模組(當然含SoC), NodeMCU 通常指 ESP8266 開發板 )
         ( 還有, ESP8266 是樂鑫公司開發, NodeMCU 是安信可公司(為ESP8266第三方公司)基於ESP8266開發 )
         ( 目前 NodeMCU 除了 NodeMCU ESP8266之外,
              還有增加支援藍芽的 NodeMCU ESP32S(基於樂鑫的ESP32開發); 台灣物聯科技代理但很貴:-(也參考這ESP32手冊ESP32 支援 SPI 傳輸
)
    A2: 如果不使用 NodeMCU 開發板, 也可以使用 Arduino UNO + ESP8266 WiFi; 或是使用較貴的 Arduino Yun (大約台幣兩千元上下)!
          Arduino Yun 開發板內有兩個 CPU, 一個類似 Arduino UNO, 另一個 SoC 跑類似 Unix 可以執行 Python 程式碼,
          ==> 可以點這跳到稍微後面看關於Arduino Yun如何燒錄與使用的參考資料;

     於要放 NodeMCU ESP8266 裡面的程式,
      我們已經寫好一個ESP8266的通用範例(C++),
      你可以用 Arduino IDENodeMCU ESP8266 所需要的 C++ 程式碼燒錄進去,  
      那要怎樣"燒錄"進去呢?
     阿這在本網頁最前面說過喔, 就是要:
         到Github ArduTalk-for-NodeMCU網頁,
    進入網頁後點入 Documents 目錄,

    看裡面 ArduTalk安裝教學(通常只須要燒錄一次)
    以及 ArduTalk 操作教學
後面還有更多關於 NodeMCU 燒錄以及 IoT 應用的參考資料/連結
** 如果你不太知道 Arduino, 建議先看看我以前在育達寫的 Arduino 入門講義
      (也可看看我以前在老共Arduino社群寫的一些文章, 例如: 【小常識】從按鈕開關看上拉pull-up電阻下拉電阻是蝦密碗糕 )

** 額外推薦閱讀Arduino、Web到IoT(林信良 | 2015-05-15)

* 通常使用 Arduino IDE 開發程式碼會用 Serial.print( ) 來印訊息到序列埠(serial Port)以便用序列埠監視窗查看;
    很多人以為把多個 serial.print( ) 利用字串串接方式合併成一個 Serial.print( ) 比較省時間 !?
    其實錯了, 不但沒省時間, 而且也沒省空間(記憶體)!! 詳細可以點這看我以前寫的這篇點這看更多我寫的Arduino相關文章
    也可以點這看我以前在另一個也是很多人用的 Arduino 社群發表的文章(都用 tsaiwn 帳號:-)
** 國字小常識: "埠" (Port) 的讀音 ..
          序列埠(Serial Port)的"埠"念作 "步", Port("埠")意思是港口; 老共把Serial Port翻譯為"串口"好像比較貼切:-)
          所以 Serial Port Monitor (序列埠監視器)老共則翻譯為 "串口監視窗"。
** 非廣告 (沒付我廣告費)【飆_IoT創客】手機控制與IOT 輕鬆上手22+1堂課(Arduino系列) ;
              WebDuino】-- QNAP QIoT : 物聯網(IoT) -- WEBDUINO 輕鬆實現跨入物聯網的第一步
以下是用手機開瀏覽器連入 NodeMCU 準備設定網路的畫面:
* 當然手機要開啟 WiFi 並連接 NodeMCU 的 WiFi
* 這時 NodeMCU 在 AP Server mode, 按下 Submit 後會切換為 Client mode
* 以下用 192.168.0.7 是因為燒錄進去的程式故意用這網址!

  TOP   幾個英文字讀音
  Q: 那該買 ESP8266 模組 還是買 NodeMCU ESP8266 開發板
  A: 如果你自己會焊接電路板, 且要燒錄非常多片, 那可買 ESP8266 模組 比較便宜(但還要另外買 USB to TTL 轉接器才能燒錄!)
    否則當然應該買 NodeMCU ESP8266 開發板 (大約台幣 100元 ~ 120元), 後面會補充 !
    甚至大片的 V3 版 NodeMCU 開發板只賣 NT$90 元, 且它的小麵包板也只要每片 NT$8元
    (注意大片的放麵包板要兩塊麵包板併用! 或要另外買 V3 擴充底板大約台幣50元到85元)
    (有寫 LoLin 的就是 V3 版; V3 開發板早期使用 CH340 接口晶片, 但後來其實也有用 CP2102 晶片的比較小片就不必用擴充底板)
    如果你跟代理商買, 當然就會發現 NodeMCU 開發板不論 V2 或 V3 都很貴竟然一片要大約台幣三百元上下 !
    購買 NodeMCU 之前, 建議先看看這篇"第一次購買 NODEMCU 就上手"
  * 注意 NodeMCU V2 板比 V3 板多一顆 On Board LED(和 D0, 即 GPIO 16 連在一起)
  * 再注意, NodeMCU V2 開發板的 D0 如果做 analogWrite( ) 會影響 WiFi 連線,
      所以 NodeMCU 的程式碼必須稍微修改(看後面說的 t7 版本) !
* NodeMCU V2 開發板插在一塊麵包板上仍可用杜邦線連接物聯網裝置
* NodeMCU V3 開發板如果是用CH340接扣晶片的因較大片則需兩片麵包板併用
* 關於 ESP8266, 點這看 GitHub 上的 ESP8266 core for Arduino 以及 Documentation 文件
* 關於 ESP32, 點這看 GitHub 上的 ESP32 core for Arduino
* 請注意, ESP8266 的 Timer (有兩個) 使用上要非常小心!
* 關於 String 類別, 點這看 Arduino 的 WString.cpp 以及 點這看 ESP8266 用的 WString.cpp
簡介 ArduTalk (Arduino + iotTalk) 與 NodeMCU
   ArduTalk 是為了讓物聯網設備(IoT Device)可以很方便利用 IoTtalk 的專案連接,
   主要包括 ArduTalk-for-Arduino Yun 雲版本(Python), 和 ArduTalk-for-NodeMCU 版本既然是強調 Arduino, 怎會用 NodeMCU ESP8266 ESP12E 呢?     
   其實 NodeMCU ESP12E 不但和 Arduino 相容且多了 WiFi 模組, 可以用 Arduino IDE 開發軟體!
   ArduTalk 本來是考慮 Arduino-Yun 和 Arduino-Uno 兩個開發板 !
       其中 Arduino-Yun 雖然一片大約台幣 2000 ~ 2500元, 但因為它同時有一般Arduino 的 MCU ATmega32u4,
   又有可以支援 Linino/OpenWRT(一種 Linux)的 Atheros AR9331 MCU SoC, (第一版 Yun 已經降價到 NT$1218)
   可以灌 Python 且又有 Ethernet 和 WiFi 且可以用 C/C++ 寫程式碼到 ATmega32u4 的Flash記憶體,
   所以並不算貴; 但很普及的 Arduino-Uno/UNONano 還要另外買 WiFi 模組才方便使用, 加起來大約五百元ㄟ!
   而 NodeMCU 開發板就相當於 Arduino-Nano + WiFi 模組, 且只要台幣120元上下!!(淘寶網有70元以下的!)
   所以, NodeMCU 是不錯的選擇(Analog Input 和 GPIO 較少), 於是就有了 ArduTalk-for-NodeMCU囉 ! 
   ** 如果你是要用 Arduino Yun 來連接 IoTtalk, 則要看 ArduTalk-for-ArduinoYun(Github)
      可以點這看如何把 ArduinoYun Rev.2 連接到 IoTtalk 的操作手冊。
   ** 這邊有 NT$2280 的 Arduino Yun 開發板 Rev.2, 也有限時五月份特價 NT$1800元喔!(同一家)
**如果你不太知道 Arduino, 建議先看看我以前在育達寫的 Arduino 入門講義    (也可看看我以前在老共Arduino社群寫的一些文章, 例如: 【小常識】從按鈕開關看上拉pull-up電阻下拉電阻是蝦密碗糕)

* 再次提醒:在上面以及 Github ArduTalk 說的 NodeMCU 是 ESP8266 ESP12E
NodeMCU  == Node  MicroController Unit 
**嚴格說來, NodeMCU 是指開源的SoC韌體(大陸稱固件), 點這看 NodeMCU 官方網站
   但是, 現在提到 NodeMCU 通常指開發板, 包括 NodeMCU 8266 V2 和 8266 V3, 以及 NodeMCU ESP32(多藍芽)** ESP8266 和 ESP32 的原廠是 樂鑫 espressif.com
** NodeMCU 開發板的原廠是安信可 AI-Thinker 公司, 可以點這看 NodeMCU ESP8266 介紹
** NodeMCU 也是 Ai-Thinker(安信可)公司發起的開源專案(Project)(不是樂鑫喔!)
**關於 NodeMCU 的文件, 可以 點這看 https://nodemcu.readthedocs.io/
**一般提到 NodeMCU 開發板主要分兩大類: ESP8266 和 NodeMCU-32S ESP32 (有很多開發板)
  NodeMCU 開發板 使用的 CPU --
        NodeMCU ESP8266 是用 Tensilica L106 32-bit RISC 處理器
        NodeMCU-32S ESP32 是用 Tensilica Xtensa LX6
     (Tensilica 公司在 2013年被 Cadence益華電腦 併購)
  * NodeMCU ESP8266 ==. Arduino Nano + WiFi 模組; ESP8266 有十幾種版本,
     各版本 ESP8266 請看 https://en.wikipedia.org/wiki/ESP8266NodeMCU-32S ESP32 ==.  ESP8266 + 藍芽 4.2 版本更亂, ESP32 製造廠商眾多,
     各版本 ESP32 請看  https://en.wikipedia.org/wiki/ESP32
     所以, ESP32 是樂鑫公司的帶 WiFi 和 藍芽 4.2 之 SoC, 但 ESP32S 是安信可公司產品;
     安信可的 ESP32S (注意 32 後面有 S) 和 樂鑫公司的 ESP-WROOM-32 完全相容。
  * NodeMCU 的硬體及韌體 和 Arduino 一樣是開源, 若要說原廠則是上海的樂鑫(Espressif):
      https://www.espressif.com/
     但是真正讓 ESP8266(做成 NodeMCU 開發板)普及的則是深圳市的安信可(Ai-Thinker)公司:
      https://www.ai-thinker.com/
     所以, 一般都會說"安信可原廠" NodeMCU 開發板(因為 NodeMCU 開發板是安信可公司做的), 例如:
      安信可 NodeMCU 開發板 V.2 (基於樂鑫 ESP8266 WiFi模組)(淘寶網安信可Ai-Thinker)
   ** 另外, 比較新的 NodeMCU 開發板則是搭載 ESP-12F; 也是有 V2 版和 V3 版
      (安信可公司NodeMCU開發板一開始用 ESP-12(V1), 後來 V2 開始用 ESP-12E; 12F 是 12E 的加強版)
   *** 這是蝦皮上賣的 ESP-12F 模組, 每片 NT$78元 (安信可AI-Thinker原廠)
    @ 不過, 安信可原廠在淘寶網上 ESP-12F 模塊(模組)只賣人民幣 RMB$11 元(約台幣 50元)
    % 這是用 ESP-12F 做的白牌 NodeMCU V3 每個約台幣 55元(注意天線的樣子!)
   *** 目前還有更新的, 使用 ESP-12N 的 NodeMCU V3 開發板
* 關於 上海樂鑫 Espressif.com 可以點這看該公司在知乎的帳號發表的文章
* 關於深圳 安信可 AI-Thinker 公司(深圳)
    ** 如果你不太知道 Arduino, 建議先看看我以前在育達寫的 Arduino 入門講義(用 Arduino Uno; 蝦皮較便宜)
            - - - 還有, 也可以看看我以前在老共Arduino社群寫的一些文章; (還有我在geek極客工坊也有發表一些文章) 例如:
                  【神秘知識】為何 delay(1000); 前後只有 999ms (milli second)?
                  教程為何說定時做事的ISR或中断程序內原则上不可用Serial.print
                  教程Arduino IIC/I2C 實驗示例補充   ;   IIC / I2C (讀 I square C) 簡介(IIC == Inter-Integrated Circuit Bus)
** 關於Arduino Yun (這是Rev.2); 至於 Rev.1 是較舊的版本;以及Ardutalk-for-Arduino Yun (雲)
** Arduino ; Yun ; ; ArduinoYun ; Next Yun 含稅1218元 ; Yun2/Yun2 ; OpenWRT ; openWRT ; Linino ; BridgeLibrary ; 物聯網OS
    --- ArduinoYun PWM pin: 3, 5, 6, 9, 10, 11, and 13. Provide 8-bit PWM output with the analogWrite() function.
    --- ArduinoYun 有兩個 CPU, 一個是 Atheros AR9331 跑 Linino/Linux (又稱 Yun OS) 可能須更新 OS + Python ; 另一個, ATmega32U4, 跑 C/C++

0.Blink沒用到 Yun(含雲開發板詳細資料) ; 第一次使用Arduino Yun雲 ; More Detail (老共翻譯) ; REST/RESTful
** ArduTalk-for-Arduino Yun 雲版本(Python) ; Yun2.pdf手冊 ( custom.py/DAI.py ; AtMega.ino ; 參考 ) ; ArduTalk-for-NodeMCU ;
 
** Summary about Arduino-Yun and Auduino Yun Rev.2 ...
      (1)Arduino Yun (Arduino 雲) 有兩個 CPU:
     一個是 Atheros AR9331, 跑 Linino/OpenWRT(從Linux改的)作業系統(OS), 通常執行 Python 寫的程式;
     一個是 ATmegaXXXX 與其他如 Arduino Leonado 等相同(Arduino UNO 則類似)的 CPU, 執行 C/C++ 程式

      (2)ArduinoYun 開發板上的兩個 CPU 之間透過共用的記憶體溝通資料, 並且各自負責一些主要工作:
     oo 利用 Bridge 類別程式庫做 read from / write to 到共用的記憶體
       注意, 該共用記憶體區在 Arduino Yun 關機或 Reset AR9331 就會不見; 如只 Reset ATmega CPU 則不會不見!

     o AR9331 CPU, Linino/Linux 上當然可執行 Python 程式, 通常負責較複雜的工作, 以及對外網路通訊的工作;
      -- 既然 Linino 也是 Linux 系統, 編輯程式和傳送檔案當然和一般 Linux 系統相同
     o ATmegaXXXX 的程式碼通常負責從 Arduino Input pin 讀取資料以及把資料寫到 Arduino 的一些 Output pin
      -- 用 Arduino IDE 把程式碼燒錄進去 ATmegaXXXX 的方法與使用其他 Arduino 開發板 (如 UNO / Leonado) 完全相同
  TOP   幾個英文字讀音

  要體驗 ArduTalk, 還需要哪些材料呢?
    首先你需要買個 NodeMCU 開發板, 大約 NT$120, 有更貴的但也有更便宜的, 等下會列出我辛苦搜尋結果給大家參考:-)
    還有, 需要一個或兩個麵包板(ㄟ..不是可以吃的那個麵包喔, 真的沒聽過的自己 Google 一下啦:-)
    至於還需要哪些零組件呢?
    就請看剛剛說的 ArduTalk 操作手冊, 點入之後, 先點看 ArduTalk操作教學.pdf文件,
    在 P.5 有列出基本上該有的材料, 這樣就可以體驗該操作教學文件內設計的六個實驗範例 !
   以下把該操作教學文件內 P.5 列的材料複製過來:

  ⊚ ↑ 以上這些材料網購總價大約 NT$310元(台灣正規店面購買則約500元~700元):
          120 + 15*2 + 18 + 10 + 25 + 5 + 2 + 35 + 運費 60 (預估)

* 關於 NodeMCU 開發板 (這裡指 ESP8266/NodeMCU 開發板, 不是多了藍芽的 ESP32/NodeMCU 開發板)
    購買 NodeMCU 開發板 之前建議可以先看看這篇 "第一次購買 NODEMCU 就上手" 經驗文
    再次提醒, 目前 NodeMCU 開發板有 V2 和 V3 (比較胖), 通常 V3 比較便宜一些;
      雖然建議買 NodeMCU V2 開發板比較小, 方便使用麵包板, 但是經實測發現對 D0 做 PWM 輸出會讓WiFi網路斷線,
    所以, 如果用 NodeMCU V2 開發板, 要燒錄不同的程式碼, 請點這看關於我改過的 t7 版本

* 如果你買的光敏電阻不是模組而是很便宜的一個只有兩端接腳的小光敏電阻(PhotoResistor),
    那還需要串一個 1K 歐姆的電阻再接地(這端並聯到 A0), 可以參考下圖的連接方法:  
  (NodeMCU 沒有 像 Arduino 的 5V, 所以另一端連接到 3.3V 即可)
* 在 NodeMCU 開發板上有支 VIN 的 Pin, 有些文章說它就是 5V 輸出;
    其實這說法不太對!
    但是, 該 VIN 『可能』 可以拿來當 5V 輸出用 ! 怎麼說『可能』呢 ?
    因為其實它是設計來輸入電源給 NodeMCU 用的(所以叫做 VIN);
    其實它就是和 MicroUSB 直接連在一起!
    所以如果你用 MicroUSB 連接 NodeMCU 供電, 這時 VIN 可拿來做 5V 輸出,
    但是要注意不保證 5V, 因為那由你的 USB 決定, 通常落在 4.6V 到 4.9V 之間。
    當然也無法由 MCU 程式碼控制該電壓!
    另外, 請注意,
    V3 版本(就是在 MicroUSB插孔附近寫 LoLin 的)則即使連接 MicroUSB 供電,
    該 VIN 沒辦法做 5V 用, (所以剛剛我才說 『可能』 可以當 5V 輸出用 :-)
    因此時 VIN 幾乎無電壓, 因為被一個 1N5817 Diode 二極管 隔開了!
** 這 V3 版本把 USB 的電另外直接拉到 A0 pin 附近,
      在 A0 往下數兩支 Pin, 叫做 VU, 參考右圖,
      VU 意思是 Volt 與 USB 相同, 這 VU 可拿來當作 5V輸出 :-)
      (山寨版的 V3 開發板可能把 VU 印成 VV 喔, 我買到的就是印著 VV :-)
      (還有, 山寨版的 V3 開發板可能把 LoLin 印成 LOL1n 喔 :-)
 
Q: 我連接簡易光敏電阻控制網頁上 Bulb 燈泡, 發現遮住光敏電阻 Bulb 接近關燈, 放開光敏電阻則 Bulb 接近全亮 !?
      可是這樣不是我要的啊 !? 怎辦 ?
A: 在 Project 專案內, 點從光敏電阻(例如 A0) 連接到 Bulb 亮度的 Join 連接點,
      這時右半邊視窗出現資料進出使用的函數, 可以寫一個小Python函數來處理 !
      當然你要先知道你光敏電阻的變化值, 可以先用滑鼠右鍵點 Join 連接點觀察資料進出變化 !
      或是你另外先寫個小程式燒錄進 NodeMCU 用 Serial.print( ) 印出讀取 A0 的值仔細比較各種變化 !
Hint: 提醒點Join 連接點寫 Python 小函數, 記得要存檔, 然後記得重新選取要套用的函數 !
      主要是修改函數並存檔並不表示要自動套用該函數 !
      還有, 套用完畢後, 建議再次用滑鼠右鍵點 Join 連接點觀察資料進出變化 !

Q: 那程式碼到底要如何寫呢 ?
A: 假設觀察到的 A0 數值在 500 到 825 之間, 希望反過來控制明亮, 參考以下 Code: (當然可以有別的寫法)
          gg = int(args[0]) - 500;
          if(gg < 0): gg = 0;   # 防止負數 < 0
          gg = int ( gg * 1.0 / (825 - 500) * 1024 );   # map 到 0..1023
          if(gg > 1023): gg = 1023;   # 防止超出上限
          return gg
          # 如果希望控制在 0..255; 把上面 1024 改為 256, 把 1023 改為 255 即可

**如果你不太知道 Arduino, 建議先看看我以前在育達寫的 Arduino 入門講義
      (也可看看我以前在老共Arduino社群寫的一些文章, 例如: 【小常識】從按鈕開關看上拉pull-up電阻下拉電阻是蝦密碗糕 )

* 單色LED 燈的接腳有「長短腳」之分,長腳接「高電位」(或數字接腳),短腳接「低電位」(接地或電源負極)。

* 在ArduTalk操作教學文件裡面提到的 RGB LED 的規格可以參考:
      https://reurl.cc/Ga8NG
主要就是要注意, 這 LED 的紅光電壓大約 2V, 但 NodeMCU 接腳輸出是 3.3V,
所以要串接一個 220歐姆(大約即可)的電阻以免燒壞 LED; 萬一手邊沒電阻, 可以串接一顆單色LED代替,
就是說, Signal Pin(數字接腳) --> 單色 LED 長腳; 單色 LED 短腳 --> 三色 LED 的 R 腳;
阿不過, 反正一顆三色 LED 才台幣兩塊錢燒壞也不會心疼 :-)
最長那支腳要接地(因為共陰極, 若是共陽則要接 3.3V); 在這最長腳的一邊只一支的是 R 紅光;
另一邊有兩支的, 由這支最長腳往外依序為 G 綠光, B 藍光, 參考下圖。



果你買的是三色LED 模組(比較貴)那就不需要再接電阻(因模組版子上已經有連接電阻)!
例如 這個 RGB 模組(NT$20)(蝦皮allen_6833)
這個 三色 LED 模組(NT$40)(蝦皮allen_6833)
(注意這是"共陽極"的, 寫 V 那接腳要接 3.3V,
    RGB 三支腳的值(用 analogWrite )則 0 是最亮, 1023不亮, 剛好反過來 !
    (Arduino 的 PWM(Pulse Width Modulation) 是 0 ~ 255; 但 NodeMCU 的 PWM 是 0 ~ 1023)
    不過, 你可以在 IoTtalk 專案的連結點寫個小 Python 把 Knob 傳的值用 1023 減去其值!)


這個 三色 LED 模組(NT$16)(注意這個是"共陰極"的) 或 這個 NT$15元也是共陰極的
    也有只賣 NT$8元的三色 LED不知道會不會亮 :-)
* 如果你買的是像這七彩自閃 LED 因工作電壓是 3.2V 就不必再串接電阻了  
* 至於小麵包板, 蝦皮上價格從 NT$7 到 NT$35 都有人賣(都是同樣的 170孔的)
還要買哪些材料來玩呢 ?
    很多啊, 溫濕度感測器, 蜂鳴器(Buzzer), 可調變電阻等都是很容易測試 !

**如果你不太知道 Arduino, 建議先看看我以前在育達寫的 Arduino 入門講義
      (也可看看我以前在老共Arduino社群寫的一些文章, 例如: 【小常識】從按鈕開關看上拉pull-up電阻下拉電阻是蝦密碗糕 )
** 如果你買了 Buzzer 蜂鳴器, 則可以把 NodeMCU 燒錄我這個 t8Songs 版本
    點入網頁後, 再點入 ArduTalk,
    然後, 再點入 ESP12E_modified_tsaiwn 子目錄, 裡面有 t8Songs 版本 以及 t5 和 t7 版本的壓縮檔。
    ( t5 和 t7 版本說明請在這網頁敲 CTRL_F 搜尋 t5.t7 t5 和 t7 )
* 使用這 t8Songs 版本, 把蜂鳴器(Buzzer)的信號接腳(Pin)接在 NodeMCU 的 D2;
    當然, 在 IoTtalk 專案內, D2~ 沒用了, 同時 D0~ 和 D5 及 D8 也取消沒用了, 簡單說明如下:
      * D5 可接 Local 的 Button 按鈕, 按了可撥放音樂 (從 D2)
      * D6 有效, digital, 0 / 1
      * D7 有效, 在專案內仍如以前用, 但在 NodeMCU 已經改 analogWrite(D7, 1023*從Server抓下的 D7 值);
      * D8 在專案內沒用, 但 D1~ 的資料會同時寫到 NodeMCU 的 D1 接腳和 D8 接腳 !
** 可以參考這我以前寫的三色LED+蜂鳴器在 Arduino Uno 的練習講義
** 至於可調變電阻當然要把信號腳(中間那支)接到 NodeMCU 的 A0, 左接 GND 右接 3.3V
** 這是以前在育達寫的用按鈕搭配可調變電阻練習講義也看看這Arduino送資料去PC的練習講義
**如果沒有按鈕(Button), 可用一條杜邦線或電線連接要偵測的 pin 腳去碰觸 GND(接地)即可!
      但是, 記得要把該 pin 設定為 INPUT_PULLUP 以便利用內建的上拉電阻
**聽說 analogRead( ) 很慢? 這是相對其他動作很慢! 可參考我以前寫的 Arduino 文章
  如果想知道關於 PWM 輸出與 analogWrite( ), 也可以點這看我以前寫的 Arduino 的 PWM 輸出
    不過, NodeMCU ESP8266 的 PWM 預設是用純軟體靠 CPU 的 Interrupt 做的 !
    ( Arduino 是靠 Timer 定時器做, UNO 板有三個 Timer 各管控兩個 PWM pin 所以有六個 PWM pin~ )
    NodeMCU 每一支 GPIO pin 都可以做 PWM 輸出
    主要因為 Aduino 的 Clock 只有 16MHz, 而 NodeMCU 有 80MHz 甚至有 160MHz 版本 !
* 注意: 不過, 實測發現 NodeMCU V2 的 D0 如果做 PWM 輸出會讓 WiFi 斷線! (V3 沒問題)
   

  ** 如果你不太知道 Arduino, 建議先看看我以前在育達上課寫的Arduino基礎入門講義
          (也可以看看我以前在老共Arduino社群寫的一些文章, 例如: 【小常識】從按鈕開關看上拉pull-up電阻下拉電阻是蝦密碗糕 )
    * 關於DHT-11等溫濕度感測器可以參考我在老共的社群發表的文章, 可以讓你學到更深入的概念
        如要了解dht11簡單的使用, 可以點這看這篇我以前在育達科大為大一課程寫的溫濕度感測器實驗講義
        如果你想了解如何從電腦送資料去 Arduino, 這篇應該可幫助你理解(也是我以前在育達上課講義)
    * 可調變電阻的連接方式也可參考我以前關於Arduino結合Processing講義。 或 參考這篇 Cooper Maa 關於 Arduino 實驗的教學文章

    * 基本上建議先把前述ArduTalk操作教學文件內設計的六個實驗範例做過之後, 再來考慮還要買哪些零件來玩 :-)
  TOP     幾個英文字讀音  
★※* 沒概念或沒靈感?
    賈伯斯說過: 創意, 偷就有了!(其實是畢卡索說的)
    ※※ 賈伯斯在1995遺失的訪談中(注意 1:07:05 處)說借用(偷取)別人的點子並不可恥
    號稱智商200的翟神也很認同(他說自己經常"偷學"別人的點子!)(這其實是摘自翟神寫的書) (創意並不是想出來的,而是偷來的)
    所以,你可以用 Google 搜尋 arduino教學實作來看看別人有哪些點子;
    你也可以在 youtube 打入 Arduino 專題 (或只打 arduino) 搜尋別人做過的來尋求靈感 !!
      ( 當然你也可以搜尋 Arduino project 找老外弄的:-)
    啥!?
    可不可以搜尋 NodeMCU 專題NodeMCU Project ?

    當然可以啊, 因為 NodeMCU (通常指 ESP12E 開發板) 和 Arduino (通常指 Arduino Uno 開發板)是相容的,
    而且硬體設計和軟體也都是開源(Open Source), 意思就是大家都可以合法 Copy/製作(只有註冊商標要錢)!

    使用 ESP8266 的 ESP12E 開發板有個好處, 就是它已經內建了 WiFi, 不需要另買 WiFi 模組 !
    可以把它當作簡單版的 Arduino 加上 WiFi 模組來用,
    你只要把你手機開無線網路熱點(無線基地台)分享給該 ESP12E 就可以實現聯網功能 !
* tc543 看台中高工的創意製作競賽-雲端智慧水耕植物工廠   107得獎   107年的   108年..   更多更多   請Gogle大神找更多類似
模仿 →改良 →創新。   模仿,是創新的第一步!   賈伯斯做了很多沒用的事,但豐富的經歷成了他的創意來源。
  《聖經》中說:「太陽底下無新事。」(見 傳道書 1:9)      
  《佛經》也說:「如果經驗不足,就應當盡量地模仿。」(參見金剛經)
      這個世界上,不存在真正的原創,創意的過程就像搭積木,知識就是積木塊,你的積木越豐富,搭出來的東西就越有趣。 (參考這篇的)
紐約時報暢銷書排行榜中有本書,叫《像藝術家一樣偷竊(點子都是偷來的)》(這是該書中文翻譯版),書中說,所有誠實的藝術家被問到創意是怎麼來的時候,都這麼說: 「我是偷來的」。
      藝術領域如此,科學領域更是如此,成功的科學家都是興趣廣泛,善於在看似不可能的知識點之間建立聯繫。
想要有創意,就必須多積累知識,多看、多想、多記下別人的奇思妙想,擴展和連接才是創意的最重要來源。
猶太教與基督教的區別;   *基督教、猶太教、伊斯蘭教間的關係?; *在 Youtube 看9分鐘解說; 伊斯蘭教的崛起(Youtube)
佛教與印度教的關係以及差別(星雲); *為何印度人大都不信佛教??(Youtube); *佛教在中亞和印度是如何消亡的???(文章)
淨空法師說:每個人都不是孤獨的(Youtube); *證嚴法師說故事(Youtube); *印順法與證嚴(Youtube)
把知識連起來就是創意(文章); *老外看蘭陵王(Youtube); *老外看台灣(Youtube); *老外看中國(Youtube)
後面還有更多關於創意的論述       黃霑 滄海一聲笑   寒山寺為何在三更半夜敲鐘?   如何增強記憶力?   歷史很好玩(唐太宗+武則天+唐高宗)?
  gg543 .. How to Burn NodeMCU code -- board manager -- http://arduino.esp8266.com/stable/package_esp8266com_index.json
* 再談關於 NodeMCU 開發板  
    購買NodeMCU之前建議可以先看看這篇 "第一次購買 NODEMCU 就上手" 經驗文;
    也可以點這看看 NodeMCU 及其DEVKIT 開發板介紹
所以提醒大家, NodeMCU ESP8266 開發板建議購買 內建 CP210x 晶片的 ESP12E 開發板 !
如果帶有 CH340 晶片的(通常是 V3)雖然通常比較便宜,
但因為體積較大, 必須使用兩塊小麵包板併起來用, 或另買 V3 底座才有辦法連接材料!

    (當然你也可以說那我用杜邦線帶母頭的直接插到 MCU 接腳也可啦 !)

* 再次提醒, 雖然建議買 NodeMCU V2 開發板比較小, 方便使用麵包板, 但是經實測發現V2板對 D0 做 PWM 輸出會讓網路斷線,
    所以, 如果用 NodeMCU V2 開發板, 要燒錄不同的程式碼, 請點這看關於我改過的 t7 版本
  * 再談 關於燒錄程式碼到 NodeMCU 開發板 以及 ... 543...
ArduTalk for NodeMCU @ github(林一平教授研發團隊)
安裝 NodeMCU 相關驅動程式+ArduinoIDE 教學 .pdf (弘道國中 潘建弘老師)
      (潘建弘老師這篇寫得很仔細, 不過裡面 CP210x 驅動程式的連結是錯的 !)
  * 阿玉maker研究區: 關於安裝 NodeMCU 驅動程式
  ** 在 Arduino IDE 點偏好設定(Preference),
      -- 然後在偏好設定頁面的下方『額外的開發板管理員網址』格子內輸入:

          http://arduino.esp8266.com/stable/package_esp8266com_index.json
  *注意, 除了 NodeMCU 驅動程式, 還需要 CH34xCP210x 燒錄用驅動程式(NodeMCU開發板上有印字):
    ** CH34X (USB to TTL) 燒錄用驅動程式 .zip(通常是 V3, 但後來有些 V3 用 CP210x 變窄板)
    ** CP210X (USB to TTL) 燒錄用驅動程式 .zip(瘦小窄的開發板, 通常是 V2)
NodeMCU 搭配 L298N馬達驅動模組 .pdf (弘道國中 潘建弘老師)   王老師談 L298N ..解惑篇
NodeMCU 搭配 LED + DHT11模組 or LM35 .pdf (弘道國中 潘建弘老師)   關於 LM35 + Uno
  **關於 DHT-11, 可以參考我在老共的社群發表的讀取DHT11溫濕度文章, 可以讓你學到更深入的概念。
更多 IoT 裝置 -- 物聯網程式設計社 (弘道國中 潘建弘老師)
* 再說一次, 創意真的偷就有了:-) 賈伯斯在1995遺失的訪談中(1:07:05)說偷取別人的點子並不可恥

* 蝦皮上找到一個很便宜的 NodeMCU V2 開發板, 一個只要 NT$96元  
      點這連到蝦皮 bopultd 賣場   (隨時可能有更便宜的, 自己蒐尋一下, 不過如果庫存只有一個的建議不要買喔:-)

  (蝦皮, 雖然有些店家寫來自海外, 但五天到七天就可寄到也還好, 超商取貨付款運費 NT$60元 和國內店家相同)  
* 單買這項最多可買十個(因為重量與體積還是海外運輸關係, 我試過無法一次買11個)則平均每個運費台幣 6 元 :-)
* 這家也有賣小麵包板 (比較貴, 一片要 19元, 但和 NodeMCU 一起買只要一份運費:-)
      建議買400孔(台幣30元)或 830孔(台幣42元)的比較好用 !
    https://shopee.tw/search?keyword=%E9%BA%B5%E5%8C%85%E6%9D%BF&order=asc&page=0&shop=41998737&sortBy=price
** 有一片只要 NT$8 元或7元的小麵包板: (與剛 19元的完全相同, 問題是不同家買要另外運費 !)
    https://shopee.tw/search?keyword=%E9%BA%B5%E5%8C%85%E6%9D%BF&order=asc&page=0&sortBy=price
***當然還需要有 Micro USB 數據線才能把程式碼燒錄進去 NodeMCU 這家賣 27元(很貴)(往下捲有allen_6833賣18元)
      (用 Android 手機的 USB 線即可, 當然要可以傳資料的! 有些只能充電用!)
    https://shopee.tw/Micro-USB-Cable-wire-1m-for-NodeMcu-i.41998737.2070403488    

***這家蝦皮桃園(allen_6833)的 USB 數據線(1公尺) 只要 NT$18元且品質很好 (我買過:-)
      https://reurl.cc/eVg97
***這家蝦皮桃園的也有賣 NodeMCU, V2 小片(帶 CP2102接口京片)的 NT$120元;
          NodeMCU V3 大片的 NT$100元(帶CH340 USB to TTL 轉接晶片的):
      https://shopee.tw/search?keyword=nodemcu&shop=4877344
      如果你買了 V3 大片的NodeMCU, 使用時需要兩塊麵包板併起來用, 或者也可另買 V3 擴充底板

***這家蝦皮桃園的有賣很多材料, 不過它的 NodeMCU 小片要價 NT$120 元稍微貴一點點,
    但是, 幾乎你想要的實驗材料這家通通有 :-) 且店家在桃園蘆竹通常一兩天就可收到貨 !
    https://shopee.tw/search?keyword=arduino&order=asc&page=0&shop=4877344&sortBy=price
***例如, 麵包, 阿不是, 我是說 麵包板:   點這看該店 allen_6833 賣 麵包板
***例如, 光敏電阻 (Light Sensor):   點這看該店 allen_6833 賣 光敏電阻
***例如, 繼電器 (Relay):   點這看該店 allen_6833 賣 繼電器
***例如, 杜邦線:   點這看該店 allen_6833 賣 各種杜邦線
***例如, 各種 LED:   點這看該店 allen_6833 賣 各種 LED 零件

*** 如果你買的都是 "模組", 那其實就不需用到 額外的電阻 了 ! !
          點這看該店 allen_6833 賣 RGB LED 模組

阿我好像應該跟這店家( allen_6833 蝦皮 ) 要廣告費才對 .. 呵呵 :-)

* 柯P說過用腳頭烏想也知道(除非你腳頭烏壞掉)蝦皮上的價格隨時可能變動, 請自己隨時到蝦皮搜尋;
  如果要更便宜的 NodeMCU, 那要到淘寶網找 (不過買少量連運費可能不伐算 !)
  (a)最便宜的在淘寶網 "全球易創客", 每個約 NT$65, (人民幣12.75); 库存1885321件
       https://reurl.cc/gnOqQ        (** 提醒:  帶 CP2102 的是窄板)
     (原價 人民幣 12.75, 買第一個特價 8.00元, 注意第2個起每個是人民幣 12.75元)
     *該家另有賣 USB 傳輸線可一起買, 每條約台幣 10元
     *該家要另加運費人民幣至少6元寄送到海岸集運中心, 你再上網付海運費/空運費約每公斤人民幣23元
     *就是說到淘寶網買東西要付兩次錢, 一次付給店家的, 另一次付給物流到台灣的"集運"公司
  (b)淘寶網"8266模組的家", 也是每個約 NT$65, (人民幣13.3);; 库存22121878件)
       https://reurl.cc/dqE3M       (** 提醒:  帶 CP2102 的是窄板)
      (原價 人民幣 13.3, 買第一個特價 9.38, 第2個開始每個 13.3元)
     *該家要另加運費人民幣30元(選官方集運是人民幣8元)寄送到海岸集運中心, 你再上網付海運費/空運費約每公斤人民幣23元
以下是我試著從 淘寶網 "全球易創客" 這店家購買要結帳的畫面:
  (通常很多店家提供如果不到一公斤可以勾選連全部運費一次結算)


* 以下這個則是帶 CH340x 燒錄晶片 的 NodeMCU V3 版本, 比較胖(寬), 須用兩塊麵包板:
    NodeMCU V3 (帶 CH340x 燒錄晶片) ; 每個台幣不到 50元(人民幣 11.2元; 第一個單價 8.22元)
      ( * 該家要另加運費人民幣30元(選官方集運是人民幣8元)寄送到海岸集運中心, 你再上網付海運費/空運費約每公斤人民幣23元 )

* NodeMCU 開發板 須要燒錄一個會和 IoTtalk Server 溝通的程式碼 !
* 再說一次,
    一般提到 NodeMCU 是指 ESP8266 ESP12E 開發板, 因這最普遍;
    ESP8266 是樂鑫公司開發的 WiFi SoC; NodeMCU 則是安信可(AI-Thinker)公司基於ESP8266 ESP12E 的開發板;
    (安信可公司是 ESP8266 的第三方開發商, 其 ESP8266 產品有 ESP-01, ESP-02, ... ESP12, ESP12E, ESP12F, ...)
    其實 ESP8266 現在有很多廠商做很多版本型號, 可以點這看看 ESP8266點這看 ESP32 (多了藍芽4.2)

   面已經說過, 你可以用 Arduino IDE 把 NodeMCU 所需要的 C++ 程式碼燒錄進去,
詳細的步驟在 ArduTalk安裝教學(NodeMCU).pdf
該檔案在 用 google 搜尋 Github + ardutalk + nodemcu 的 Repository ,
就是在 https://github.com/IoTtalk/ArduTalk-for-NodeMCU 裡面,
點入後, 程式碼在 ArduTalk_ESP12e_1 目錄內,
    至於剛剛說的安裝教學文件則請點入 Documents 目錄,
點那有"安裝"的.pdf檔案 ArduTalk安裝教學(NodeMCU).pdf教你如何用 Arduino IDE 把 NodeMCU 的程式碼燒錄進去 MCU;
簡單說就是要有 Arduino IDE (到 Arduino.cc 抓壓縮檔來解壓縮即可使用)
然後要安裝 NodeMCU 驅動程式 和燒錄晶片的驅動程式(CH340x 或 CP210x), 之後才能把程式碼燒錄進去 !
    燒錄好 NodeMCU (ESP8266 ESP12E) 之後, 如何使用來連接電子零件原則上類似 Arduino 操作, 這樣說是因為網路上有非常多的 Arduino 教學或專題心得等, 自己問 Google 大神和 搜尋 Youtube 就可找到一堆; 不過我們是要和 IoTtalk Server 結合, 所以,
請接著看 Ardutalk操作教學.pdf, 裡面提供了使用前面說的一些材料(在操作手冊內P.5)六個可操作練習範例, 至少先練習其中的兩個 !
* 關於用 Arduino IDE 把程式碼燒錄到 NodeMCU 開發板, 網路上也有很多教學文章可以參考 !
    其實前面我已經列出一些, 可以點這跳到前面看看 ! ! (按 PageUp 大約五下, 黃色底的網頁)
以下先略述該 NodeMCU 程式碼 (ArduTalk_ESP12e_1.ino) 的行為:
(0)開機, 設定 GPIO 0 為 INPUT_PULLUP (for 長按 Flash 按鈕清除 EEPROM 網路資料)
 設定以下七個 GPIO 為輸出接腳:
    pinMode(16, OUTPUT);// D0~    
    pinMode(5, OUTPUT); // D1~    
    pinMode(4, OUTPUT); // D2~
    pinMode(14, OUTPUT);// D5
    pinMode(12, OUTPUT);// D6    
    pinMode(13, OUTPUT);// D7        
    pinMode(15, OUTPUT);// D8        
  * 另外 A0 接腳是做 analogRead( ) 用的不必設定
    analogRead 是類比輸入, 大陸翻譯為模擬輸入, 可以讀到的值 0 ~ 1023
(1) 讀取 EEPROM 內網路相關設定 (SSID, PASS, IoTtalkServer IP)
     如讀取到資料則做 CALL (2) connect_to_wifi(wifissid, wifipass);
     否則做 CALL (3) wifi_setting();
    Goto (4)
(2) function connect_to_wifi(wifissid, wifipass);  // LINE 185
    試著連線, 只試 10 秒, 如果 timeout 無法成功就 CALL (3)
    如果連線成功就設定為 STA mode, 就是 wifimode = 0
    return;  // 成功 或 10秒 Timeout
(3) function wifi_setting();  // LINE 165
    進入 AP Server mode (wifimode = 1)
    等待 User 用手機連入 192.168.0.1
    連入後會做 handleRoot(0);
    在該函數內會先掃描所有的 WiFi SSID,
    吐出網頁讓使用者選擇 SSID 並且輸入其密碼
     還要輸入正確的 IoTtalk Server IP
    輸入完成之後, 點按 Submit, 這時會跳去網頁 /setup 
     也就是執行  saveInfoAndConnectToWiFi( )  // LINE 137
     它會把 SSID 和 PASSwortd 以及 IoTtalk Server IP 存入 EEPROM
     接著會 CALL (2) connect_to_wifi(_SSID_, _PASS_); 
     return;

(4) while( 在 AP server mode) {  // 就是說  wifimode != 0 
       delay(10);  一直等等等.. 等 User 用手機 瀏覽器設定網路並且連線(會設 wifimode=0;)
    }

(5) 已經連線成功 wifimode == 0
    向 IoTtalk Server 做 iottalk_register( )
    while(註冊失敗) { delay(3000); 繼續 try 註冊; }
    // 注意, 如果註冊不成功, 將陷入這 while Loop
(6) 已經向 IoTtalk Server 註冊成功, 做一些 I/O 準備的設定, 結束 setup( ) { }
(7) 這裡開始是在 loop( ) { ... } 函數內 
  用 cycleTimestamp 來檢查時間以便每 0.2 秒才做一次 Push/Pull 
  // 注意只 Push 一個資料(從 A0 讀取的 0 ~ 1023 的值), 但會 Pull 七個資料下來
  // Pull 下來的資料有可能代表 "沒資料", 這時不會 Write 到 GPIO pin
  // D0~, D1~, D2~  這三個對應到 PWM(Pulse Width Modulation) 的 pin (其值是 0 ~ 1023);
  // (Arduino 的 PWM 是 0 ~ 255; 但 NodeMCU 的 PWM 是 0 ~ 1023)
 /// On ESP12E, PWM may be used on GPIO pins 0 to 16 using analogWrite(pin, value). 
 /// analogWrite 翻譯為類比輸出, 大陸翻譯為模擬輸出
 /// https://iotbyhvm.ooo/gpio-pins-esp8266/
  // PWM range may be changed by calling analogWriteRange(new_range).
  // PWM frequency is 1kHz by default. Call analogWriteFreq(new_frequency) to change the frequency.
  // Pin interrupts are supported through attachInterrupt, detachInterrupt functions. 
  // Interrupts may be attached to any GPIO pin, except GPIO16. 
  // The ESP8266 has 17 GPIO pins (0-16), however, you can only use 11 of them, 
  //  .. because 6 pins (GPIO 6 - 11) are used to connect the Flash Memory chip.
  //  .. And, usually TX (GPIO 1) and RX (GPIO 3) are used to do communication job
  // GPIO16 has a built-in pull-down resistor. (NOT Pull-Up)
  // GPIO15 is always pulled low, so you can’t use the internal pull-up resistor.
  // GPIO2 (on board LED) can NOT be LOW at boot, so you can NOT connect a switch to it.
  loop( ) {
    a. 如果發現 Flash Button 被按下就跳去準備清除 EEPROM
       必須有長按住 Flash Button 超過 3 秒才會做否則會返回此處
       如果有做清除動作則重開機 ESP.reset( );  // 官方建議用 ESP.restart( );
    b. if( cycleTimestaml 已經過了 0.2秒){
        b1. 用 analogRead( ) 讀取 A0 然後 把 A0 push 去 IoTtalk Server
            // A0 為類比輸入(大陸稱模擬輸入), 讀取的值為 0 ~ 1023 
        b2. 處理三個 PWM 的資料
           依序從 IoTtalk Server PULL 資料並且用 analogWrite( ) 寫到對應接腳
             Pull D0~   寫到 GPIO 16
             Pull D1~   寫到 GPIO 05
             Pull D2~   寫到 GPIO 04
        b3. 處理四個 digital 的資料
           依序從 IoTtalk Server PULL 資料並且用 digitalWrite( ) 寫到對應接腳
             Pull D5   寫到 GPIO 14
             Pull D6   寫到 GPIO 12
             Pull D7   寫到 GPIO 13
             Pull D8   寫到 GPIO 15
        b4. 重設 cycleTimestamp = millis( );
       } // 每 0.2秒做 Push/Pull  
    c. 確保每 2 秒左右可以閃一次 LED
  } // loop(
   
Q: 我看網路上說 GPIO 16 不能做 PWM 輸出, 真的嗎 ?
A: 你看的資料太舊啦 ! 自己試驗從 D0 (GPIO 16) 用 analogWrite( ) 控制 LED 不就知道了 !
      點這裡面有 PWM 範例剛好就是使用 GPIO 16
      阿不過, 如果是 NodeMCU V2 則對 GPIO 16 做 PWM 確實會影響 WiFi 網路(V3 則沒影響!)
      為此, 我改了一個 t7 版本, 請往下往下捲 或 點這往下跳 先看完 t5 說明再繼續看關於 t7 版本的說明

Q: 要如何把 NodeMCU 程式碼燒錄進去 NodeMCU ESP8266/ESP-12E 開發板?
A: 前面有說過資料在 Github 上的 ArduTalk-for-NodeMCU 內啊 !
就是說要在你的 Arduino IDE 安裝(a)NodeMCU ESP8266 的驅動程式以及(b)USB to TTL 的 CP210x 或 CH34x 的驅動程式, 然後開發板選 NodeMCU1.0, 並確定選到正確的 COM Port, 然後開啟程式碼專案, 就可以把程式碼編譯並"上傳"進去 NodeMCU 開發板; 詳細步驟在前面說過了, 就是要看在 ArduTalk for NodeMCU 內的ArduTalk安裝教學(NodeMCU).pdf
* 關於 NodeMCU1.0驅動程式, 也可以點這看 Github 上的 ESP8266/Arduino/ 裡面的說明
* 關於 CP210x 驅動程式(USB to TTL), 也可以點這到官方網站抓
* 關於 CH340 驅動程式(USB to TTL), 也可以點這進去抓 CH341SER.EXE



小片(with CP210x的) NodeMCU 其時也有擴充底板(注意天線圖樣不同!)
* 有人每片賣 NT$89 (露天拍賣店家); 也有人很誇張賣每張 NT$180 (注意真的只有底板喔!)

* 大片(V3, with CH34x) NodeMCU 用的擴充底板相對就比較便宜,
    有人每片只賣 NT$49 (我確定這片是 for V3 with CH34x 的, 雖然它沒寫 !); 甚至每片 NT$44元(海外寄通常也只要五天)
    其他可以點這看看蝦皮一些賣家各自賣不同價格 !
** 注意看底板上印的天線的樣子就可以分辨是 for V3 (LoLin) 還是 for V2 (都是用 ESP-12E 或 ESP-12F)
** 注意 NodeMCU V2 板比 V3 板多一顆 On Board LED(和 D0, 即 GPIO 16 連在一起)

ESP-12F 是 ESP-12E 加強版, WiFi 距離更遠 !
ESP-12E 在 Arduino IDE 內 pin 腳 定義:
      https://github.com/esp8266/Arduino/blob/master/variants/wifinfo/pins_arduino.h
* 注意 D3 與 Flash 按鈕共用 GPIO 0; 而 D4 是 on board LED ( GPIO 2 )
關於 t5 版本的說明.. (t5 t7 類似, t7 主要給 NodeMCU V2 板 -- 因為 V2 板 D0 用 analogWrite( ) 會讓 WiFi 斷線! )   另外,
另外, 我有修改了另一個版本 t5, 用手機連上設定 AP 時比較好用(可指定當時不存在的 AP 之 SSID);
放在 https://goo.gl/6jtP41
點入該網頁之後, 點 ArduTalk 目錄兩下, 進入再點入 ESP12E_modified_tsaiwn 子目錄,
裡面有一個壓縮檔案 ArduTalk_ESP12e_1_t5.zip
抓回來用 Arduno IDE 打開專案之後, 裡面有詳細說明如何從 Arduino IDE 安裝驅動程式, 包括 ESP12E (NodeMCU 1.0) 的驅動程式, 以及燒錄所需的 CH340 或 CP210x 驅動程式;

為了方便你查看程式碼, 在該處我也放了一個 .pdf 檔案, 就是 該 C++ 程式碼的全部 !
以下略述到底改了蝦密 (這些有寫在程式碼內):
////////// This is a modified version. current version number is  t5
///   Version t5, modified by tsaiwn@cs.nctu.edu.tw
///(0)When Power On and/or Reset
///   LED on for 2 seconds and then quickly falsh around one second
///(1)Read the network Info (SSID, PASS, IoTtalkServerIP) from EEPROM
///   If there is NO data, goto (3) to enter AP server mode
///   If it Got netword info, the on board LED will Quickly Flash twice.
///(2)Try to connect to the AP specifined in the network Info.
///   Enter STA (station) mode, will try to connect the AP for 25 seconds
///   During this time, It will flash the on board LED quickly 6 times every 3 seconds
///   After timeout (25 seconds), enter AP server mode with IP 192.168.0.1
/// ** try 25 秒如無法連上, 會切換到 AP server mode 等待連線 (如果EEPROM沒網路資料就不會 try 25秒)
///(3)Enter AP server mode, Server IP address is 192.168.0.1
///   LED will flash twice slowly every 5 seconds.
///  ** 此時 on board LED 燈會每隔約五秒連續慢閃燈2下, 表示在 AP mode 等待連入做設定
///   User can use a smart Phone to connect to the ESP WiFi AP which SSID begins with "MCU"
///   And then open a Browser to connect to 192.168.0.1 to do wifi setting/Configuration
///  *** AP 的 SSID 為 MCU- 開頭, 無需密碼; 用你手機開啟 WiFi 選該 MCU- 開頭的即可連上網路
///(4)ESP MCU will DO SCAN all available WiFi SSID and add them into the web Page
///   You can choose One of them; You may have to enter the Password for that AP.
///   Or you can even Enter a SSID name of an AP you prefered (This will be used if any)
///  ** 也可以自己手動指定 AP 與密碼 (這有填寫的話就會優先用這!!), 
///   Also enter its Password if required
///   Then click the Submit Button to save the network Information
///(5)ESP MCU will respond with a sucessful Page and then enter WiFi Station mode
///   It will Goto (2) to try to connect to the specified AP (for 25 seconds)
///(*)More about (4)
///  ****** 例如可填你手機分享的 AP, 或你實驗室自己的 AP, 甚或學校的 AP (這通常不能用! 理由如下);
///  ***      注意很多學校的 AP 連入之後還要用網頁做帳號密碼驗證, 這樣不能給 MCU 用!!
///  ***      所以, 不要填連上後還要網頁認證一次的 AP, 否則無法使用 ! (誰能從 MCU 內去開網頁認證?!)
///  ***      還有, 當然也可從網頁內修改要連的 IoTtalk Server IP (也可填 FQDN 網址)
///  ***** *** 不論是填入指定或選擇 AP, 好了之後點按 Submit 按鈕即可存起來並透過 AP 連出去 Internet
///(6)About RESET and How to clear the network Info in EEPROM ?
///   Press the RESET (RST) button will restart the MCU, 相當於拔電源重新插入 (廢話 :-)
///   Flash 按鈕 (USB 接頭旁邊有兩個小按鈕, 左邊 Reset, 右邊 Flash, 有寫字)
///// Long Press the Flash button (more than 5 seconds) will cause the network Info in EEPROM been erased !
///// ESP will restart( ) after clearing the EEPROM network Info.
/// ** 按住不放(LED燈會亮)超過五秒, 會把 EEPROM 內網路連線資料刪除, 重新開機,
///    (* Note that the data in EEPROM are  AP SSID, PassWord, IoTtalkServer IP ! *)
/// ---(** 如果後悔可在燈亮著還沒五秒之前放掉Flash 按鈕 ! **)---
///    這時自動重開後, 因為沒之前網路連線資料, 會立即進入 AP server 模式等你用手機連入做網路設定!
////// 自動重開 LED 應該會先亮 3 秒左右, 如果沒有亮則可能 Reboot 失敗, 請手動按 Reset 按鈕!!
////// (那是 ESP8266 ESP-12E 以及各版本的 Bug)
////// 關於 NodeMCU ESP8266 各版本請看 https://en.wikipedia.org/wiki/ESP8266 
////// NodeMCU 另外有 ESP32 (比 ESP8266 多了藍芽), 請看  https://en.wikipedia.org/wiki/ESP32
//////============== ========================================================================
///// Original Version by Jyneda (Dr. Yun-Wei Lin) :  Jyneda@Gmail.com
/// 用 Google 搜尋  iottalk + ardutalk + nodemcu 可找到以下網址
// See  https://github.com/IoTtalk/ArduTalk-for-NodeMCU
// Doc in  https://github.com/IoTtalk/ArduTalk-for-NodeMCU/tree/master/Documents
// === Installing Drivers with Boards Manager ===
//(0)Start Arduino and open Preferences window(偏好設定).
//     https://github.com/esp8266/Arduino
//(1)Enter the following URL into "Additional Board Manager URLs" field.
//     http://arduino.esp8266.com/stable/package_esp8266com_index.json 
//(2)Open Boards Manager from Tools
//   Tools 工具  >  Board  開發板 >  Board Manager  開發板管理員
//(3)在 開發板管理員 找到 或搜尋 ESP8266, 安裝最新版 (目前 2.5.0)
///// Documentation for the ESP8266: 
///   https://arduino-esp8266.readthedocs.io/en/2.5.0/
///===== Or use git clone to install the Library
// Clone git hub repository into hardware/esp8266com/esp8266 directory
/////  cd hardware;  mkdir esp8266com ; cd esp8266com
/////  git clone https://github.com/esp8266/Arduino.git esp8266
///// cd esp8266
///// git submodule update --init
//////////////////////////////////////////////////////////////////
//(4) USB to TTL Driver : CH34x or CP210x depends on your Development Board
/// You will also need CH34x Driver  OR  CP210x  Driver !
/// See https://github.com/IoTtalk/ArduTalk-for-NodeMCU/tree/master/Documents 
/// CH34x and Cp210x Drivers can be found there
///  CLick ArduTalk安裝教學(NodeMCU).pdf
///// https://sparks.gogo.co.nz/ch340.html
///// http://www.wch.cn/download/CH341SER_EXE.html
///Cp2102 Usb-to-Serial Driver Installation 
/////  https://exploreembedded.com/wiki/Cp2102_Usb-to-Serial_Driver_Installation
////////
//(5)Choose correct Board and COM port .. Before you starting to Burn the program ...
/// Board:  Tools 工具 > 開發板 Board  >  選  NodeMCU 1.0(ESP-12E Module)
/// COM:   Tools  工具 > Serial Port 序列埠  >  Choose CORRECT port 
////////////////////////////////////////////////////////////////////////// 

另外, 修改了原程式一個小 Bug:
原程式在 loop( ) 函數程式碼在接近最後的地方,
    if (millis()-LEDonCycle > 1) digitalWrite(2, 1);
這句會不斷的丟 HIGH(1)給 on board LED (GPIO 2), 現在修改為如下:
    (雖不重要, 但沒必要一直送 1 給 GPIO 2)
// 在 loop( ) 函數之前加入一個變數 int LEDisON = 0;
if(!LEDhadFlashed) {
  ... 讓 LED 亮 .. 改 LEDhadFlashed 狀態 
  LEDonCycle = millis( );   // 為了每 2 秒要點亮一次 LED
  LEDisON = 1;   // 新增的
}
if( LEDisON && (millis() - LEDonCycle > 5) ) {  // 增加 檢查 LEDisON     
  ... 關閉  LED (就是丟 1 給 GPIO 2)
  LEDisON = 0; // 新增
}
////////////////////////////////
* 原 ArduTalk 的 NodeMCU ESP-12E/F 程式碼在以下網址:
      https://github.com/IoTtalk/ArduTalk-for-NodeMCU
* 修改過的 NodeMCU ESP-12E/F 程式碼在: (包括 t5 版本和 t7 版本)
      https://GOO.GL/6jtP41
    (進入後在 ArduTalk 目錄內的 ESP12E_modified_tsaiwn 子目錄內)
* 關於在 Arduino IDE 用開發板管理員安裝 NodeMCU 驅動程式, 這篇裡面的圖片比較清楚
 
** 前面說過, NodeMCU V2 版本如果對 D0 做 analogWrite( ) 會導致 WiFi 網路斷線
      為此, 我改了一個 t7 版本 for ESP8266/NodeMCU 開發板 V2
      (開發資料下載也可參考官方網站: http://www.nodemcu.com )
* 再次提醒, 購買NodeMCU開發板之前, 建議可以先看看這篇 "第一次購買 NODEMCU 就上手" 經驗文
* 關於 NodeMCU 的文件 : https://nodemcu.readthedocs.io/
* 關於 ESP8266 的官方技術文件 :   (樂鑫官方網站)
      https://www.espressif.com/sites/default/files/documentation/esp8266-technical_reference_en.pdf

* 關於ADC(Analog to Digital Converter), 可以點這看用 analogRead(A0)讀取 ESP8266 的 ADC 引腳
* 關於 analogWrite( ) 與 PWM 的原理, 可以點這看以前我寫的關於 Arduino PWM 的文章
      不過 NodeMCU 的 PWM 是用軟體做出來的, 不像 Arduino 的 PWM 是利用計時器用硬體實作出來的 !
* 關於使用 millis( ) 請點這看 millis( ) 注意事項, 也可以點這看我以前寫的關於 Arduino 的 millis( )與 timer 的秘密
    也可以點這看 Arduino 的 millis( ) 原始碼 以及 ESP8266 用的 millis( ) 原始碼
* 關於Arduino 的定時做些事, 竟然有人把我寫的一些文章整理成一篇較長的文章。 不過似乎漏掉了我另一篇用 Timer 的文章
* 請注意, ESP8266 的 Timer (有兩個) 使用上要非常小心!
還有還有, 如果不太懂Interrupt中斷, 請看我以前寫的這篇『關於中断(Interrupt)的一些五四三..』
* 關於 String 的用法, 建議要看看這篇文章, 以及我寫的這篇關於 String.reserve( ) 函數(有被收入精華篇)
    如果你要研究 String 類別, 可以點這看 String class 的 C++ 原始碼
* 順便說一下, 把很多個 print 和 println 利用 String 併成一個 println( ) 並沒有省時間(也是我寫的:-)
* 關於連接 YeeLink 雲端使用經驗with ESP8266, 這也是用ESP8266接入yeelink
* 關於在ESP8266使用MicroPython, 點這看基于MicoPython如何下载代码到ESP8266中
* 關於 使用 ESP32 開發板 結合 Arduino IDE, 要看Github ESP32 重要資料 也可看 Node32s 的相關資料
* 注意 NodeMCU V2 板比 V3 板多一顆 On Board LED(和 D0, 即 GPIO 16 連在一起)
* 很多文章討論說 NodeMCU ESP32 網路比 ESP8266慢, 尤其用 https 又特別慢 !


**前面說過, NodeMCU V2 版本如果對 D0 (GPIO 16)做 analogWrite( ) 會導致 WiFi 網路斷線,
      為此, 我改了一個 t7 版本, 這 t7 版本會把 IoTtalk 專案上看到的 D0~ Pull 下來, 但不會寫到 D0,
      會改用 analogWrite(D8, 抓下的值)寫到 NodeMCU V2 開發板上的 D8;(專案內NodeMCU的D8變沒用);
      所以, 在 NodeMCU V2開發板上接線時, 請把原先接在 D0 的改接到 D8接腳上。
      另外, 為了方便測試, D7 接腳改用 analogWrite(D7, int(抓下D7值 * 1023) );
      請點這抓我改的 t7 版本, 進入後點入 ArduTalk,
      然後, 再點入 ESP12E_modified_tsaiwn 子目錄, 裡面有 t5 和 t7 以及 t8Sounds 版本的壓縮檔。
      關於 NodeMCU 的 GPIO, 可以點這看 ESP8266 GPIO 相關資料; 和 GPIO0 與 ESP8266 的啟動模式
** 關於 t8Sounds 版本則是為了使用蜂鳴器Buzzer修改了 analogWrite( ) 以便執行 tone( )
** NodeMCU 很類似 Arduino, 可以點這看我以前寫的關於 Arduino 的文章。(包括使用 Timer)
** 簡單使用 ESP8266 Timer 可以點這看 ESP8266 Timer and Ticker Example (或 這中文版本)
** 更多關於 ESP8266 Timer 可以點這看比較專業的說明
There are two types of timers on the ESP8266. There is os_timer, which is a software based interval timer and the os_timer apparently only has capacity to have seven timers set at one time. The second type of timer is a hardware based timer, hw_timer, of which there is apparently only one.
** ESP8266 ESP-12E Specs.   ESP8266 ESP-12E 規格書   ESP8266 ESP-12S 規格書   Docs.
** ESP8266 ESP-12F Specs.   ESP8266 ESP-12F 規格書  ESP8266 Wifi 模組使用手冊   ESP-12F
** ESP8266 core for Arduino
** ESP32 core for Arduino (Arduino core for ESP32 WiFi chip)
*** NodeMCU V3 _CH340 淘寶網   NodeMCU V3 _CP2102 淘寶網  
** 為協助台灣產業邁入AIoT(人工智慧+物聯網)時代台灣RISC-V產業聯盟日前正式成立(2019/03/11)
** ARM 霸權江山不保?晶心領軍開源指令集 RISC-V 趁勢而起(2019/03/19) RISC-V 是啥?(Wiki)
** 林百里:廣達AI財 30年也賺不完(2019/04/27)中美貿易戰也扯 AI (2019/05/21)
** 新思科技推動AIoT設計發展 開啟台灣IC設計產業新商機(2019/05/14)
** 【中美貿易戰】中國緊急宣布積體電路及軟體業 2 年免稅!(2019/05/23) 中美貿易戰對台影響(2019/05/16)
** 【稀土】到底是蝦秘碗糕?(2019/05/15)   【稀土】美國有備胎?(2019/05/21)

    TOP   幾個英文字讀音
創意(Idea),真的偷就有了 (copy)
      俗話說:「天下文章一大抄看你會抄不會抄!」 ::平衡報導!     LSE專家
**前面已經提到賈伯斯也說借用別人點子並不可恥, 還說他的創意都是偷來的
想要"創新",就要大膽借用別人的想法,關鍵是要把別人的想法消化與吸收。
你要做的,就是如何幫多數的眾人解決很頭痛的問題(成功八大秘訣裡面的"服務"),至於創不創新,根本不重要。
      講到科技界的"偷點子",臉書fB的故事就是最好的例子:
馬克·祖伯格(Mark Zuckerberg)一開始就是想要解決哈佛校園沒有同學名錄 (faceBook)的問題,想讓學生可以互相認識彼此。可是社交網絡(Social Network)這個概念,在Facebook之前已經有一大堆,1995年就有 Classmates.com(2019年排名14417),然後2002年3月有Friendster(2015年6月14日結束)、跟著2003年8月又有 MySpace(2019年排名3614),在2004年到2009年間 MySpace 是全美最流行的交友網站。
      根據2006年2月新聞報導, 當時 Myspace 的網路流量是 Google 的兩倍
阿那個在2005年我也註冊了一個帳號,但是後來就忘了它的存在,直到2014年它改版Email通之我才想起阿我竟然有Myspace帳號!?
如果你有看電影《社群網戰》(The Social Network)( 電影獲得奧斯卡金像獎八項提名,最終獲得最佳改編劇本、最佳原創音樂及最佳影片剪輯。 ),你就知道其實是馬克·祖伯格在2003/10/28晚上弄了「正妹比一比」網站在數小時內癱瘓了學校網路後, 然後2004年1月受到後來曾去2008北京奧運參加划船比賽的孿生兄弟卡麥隆·溫克沃斯與泰勒·溫克沃斯之賞識與邀請, 想做個哈佛專用的社群網站。然而2004年當時 Myspace 已經是全美最大的社群交友網站, 所以嚴格來講,在2004年當時這根本是一個舊到不行的點子(idea)。 隨後馬克·祖伯格自己偷偷撰寫網站在2004年2月4日開放「Thefacebook.com」(後來改名facebook.com), 當然也因此被溫克沃斯兄弟控告剽竊創意, 這起訴訟最後在2008年以1,200萬股的賠償條件達成和解(在Facebook首次公開募股後約市值3億美元)。 溫克沃斯兄弟後來用這筆錢投資比特幣(BitCoin)據說賺到13億美金。(不過如果他們在2017年底沒賣即使比特幣在2019年前七個月狂飆200%那就只剩不到七億美金囉!)
俗話說:「十年河東,十年河西」。在2005年排名第一的社群網站 Myspace 絕對沒想到它現在快倒了(2019年排名3614),而臉書卻成為排名第一的社群網站!
其實在2005年2月 Myspace 曾想併購剛起步的臉書,但是認為馬克·祖伯格要價七千五百萬美金價格太高(不到一億美金)而作罷!(後來當然很後悔,因為2019年臉書流量排名全球第三名(最近掉到第七)而臉書市值大約六千億美金蘋果電腦Apple市值則超過一兆美金。 )
 
(九) 使用 Raspberry Pi 做為真實設備 取代(四)(五)的虛擬裝置
連到 IoT 互聯網實驗網站http://192.168.20.101 (資策會 內網)連到 IoT 互聯網實驗網站http://125.227.255.81 (資策會 public IP)認識 Raspberry Pi GPIO 腳位    (Board板子上的編號 vs. BCM 編號)
*第一次把玩樹莓派的新手 (到 Raspberry PI 官方網站 下載NOOBS作業系統並安裝到 Micro SD 卡)
*Maker入門手冊-Raspberry Pi3安裝及環境建置Raspberry Pi台灣樹莓派(教學)    (3B+ vs. 3B)

*LED blink using Raspberry Pi and Python  ( 其他 很多方法閃爍 LED  )
# ledBlink.py  -- #這個程式是 Raspberry Pi 的基本測試程式
#請先把實體編號 12 的 pin 腳連接到一個電阻再連接到 LED 的長腳,
# 然後 LED 的短腳連接到 GND
#執行程式後, 該 LED 將會不斷的閃爍 
import RPi.GPIO as GPIO    # Import Raspberry Pi GPIO library
from time import sleep     # Import the sleep function from the time module
ledPin = 12
GPIO.setwarnings(False)    # Ignore warning for now
GPIO.setmode(GPIO.BOARD)   # Use physical pin numbering
GPIO.setup(ledPin, GPIO.OUT, initial=GPIO.LOW)   # Set pin 12 to be an output pin
try:
   print('按下 Ctrl-C 可停止程式')
   while True: # Run forever
      GPIO.output(ledPin, GPIO.HIGH) # Turn on
      sleep(1)                  # Sleep for 1 second
      GPIO.output(ledPin, GPIO.LOW)  # Turn off
      sleep(1)                  # Sleep for 1 second
except KeyboardInterrupt:
    print('Bye bye 程式')
finally:
    GPIO.cleanup()   # 索有用到的 GPIO pin 恢復到 Input 狀態
在 RASPBERRY PI 3 MODEL B 建立 PYTHON 3.6 環境(測試 led.py) *RASPBERRY PI 3 MODEL B 與 DHT11 溫溼度感應器之應用(用 Python 3.6 + dht11.py) * 關於DHT-11等溫濕度感測器可以參看我在老共的社群發表的文章, 可以讓你學到更深入的概念     (也可以看看這我以前教育達科大大一同學的 DHT11 講義) (還有以前我在老共Arduino社群寫的一些文章) *關於讀取按鈕 DIY- 2 Ways to Add a Button to Your Raspberry Pi Project。 *也是按鈕R-Pi 讀取按鈕用 GPIO.add_event_detect( )。 *Raspberry-pi-3-model-b-與 瞬時按鈕(用 Python 3.6 + button_poll.py,button_event.py)
# button_poll.py
# 如何測試:  注意, 這範例故意把實體 Pin 12 用做按鈕, LED 改到實體 pin 16 喔!
#  (a) 實體 pin 12 插入杜邦公母線, 公的那端可以碰觸 GND 或網路線連接頭的金屬(也算 GND)
#  (b) 實體 pin 16 連接到一個電阻再連到 LED 的長腳, 並把短腳連到 GND
import time
import RPi.GPIO as GPIO   #引入 GPIO 套件

BUTTON_PIN = 18  #實體編號 12 的腳位,其 BCM 編號為 18。
LED_PIN = 23  #控制 LED 的腳位,實體編號 16 的腳位,其 BCM 編號為 23。

def my_callback(channel):
    print('按下按鈕') 
    GPIO.output(LED_PIN, GPIO.HIGH)
    time.sleep(0.1)
    GPIO.output(LED_PIN, GPIO.LOW) 

GPIO.setmode(GPIO.BCM)   ##使用 BCM 編號方式。  
GPIO.setup(BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
# pull_up_down=GPIO.PUD_UP用來開啟內建上拉電阻  
GPIO.setup(LED_PIN, GPIO.OUT)   #腳位設定為輸出模式。 

try:
    print('按下 Ctrl-C 可停止程式')
    while True:  # 以下檢察按鈕是否被按下
        if GPIO.input(BUTTON_PIN) == GPIO.LOW:
            my_callback(BUTTON_PIN)
        time.sleep(0.25)
except KeyboardInterrupt:
    print('關閉程式')
finally:
    GPIO.cleanup()  #確保程式結束後,用到的腳位皆回復到預設狀態。
############################################################################

# button_event.py
# 如何測試:  與上面那個 button_pool.py 相同連接方式
#  (a) 實體 pin 12 插入杜邦公母線, 公的那端可以碰觸 GND 或網路線連接頭的金屬(也算 GND)
#   (b) 實體 pin 16 連接到一個電阻再連到 LED 的長腳, 並把短腳連到 GND
import time
import RPi.GPIO as GPIO

BUTTON_PIN = 18
LED_PIN = 23

def my_callback(channel):
    print('按下按鈕')
    GPIO.output(LED_PIN, GPIO.HIGH)
    time.sleep(0.1)
    GPIO.output(LED_PIN, GPIO.LOW)

GPIO.setmode(GPIO.BCM)  
GPIO.setup(BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)   
GPIO.setup(LED_PIN, GPIO.OUT) 
### 註冊當輸入腳位由高電位變成低電位 (GPIO.FALLING) 時,執行 my_callback 函數。
GPIO.add_event_detect(BUTTON_PIN, GPIO.FALLING, callback=my_callback, bouncetime=250) 

try:
    print('按下 Ctrl-C 可停止程式')
    while True:
        time.sleep(0.258)
except KeyboardInterrupt:
    print('關閉程式')
finally:
    GPIO.cleanup() # 用到的腳位皆回復到 INPUT
# https://reurl.cc/oEkpD 

# btnPollLED.py  -- 利用瞬時按鈕 Toggle LED 燈 開/關
# 如何測試: 注意, 這範例故意把 按鈕和 Led 的 pin 腳 跟前面兩範例對調 !!
#   (a) 實體 pin 16 插入杜邦公母線, 公的那端可以碰觸 GND 或網路線連接頭的金屬(也算 GND)
#   (b) 實體 pin 12 連接到一個電阻再連到 LED 的長腳, 並把短腳連到 GND
# 你當然可以改用其他 pin 
import RPi.GPIO as GPIO   #引入 GPIO 套件
import time

btnPin = 23  #實體編號 16 的腳位,其 BCM 編號為 23。
ledPin = 18  #控制 LED 的腳位,實體編號 12 的腳位,其 BCM 編號為 18。

def my_callback(channel):
    print('按下按鈕') 
    tmp = not GPIO.input(ledPin)   #  On / Off
    GPIO.output(ledPin, tmp)

GPIO.setmode(GPIO.BCM)   ##使用 BCM 編號方式。  
GPIO.setup(btnPin, GPIO.IN, pull_up_down=GPIO.PUD_UP)   
     ### pull_up_down=GPIO.PUD_UP用來開啟內建上拉電阻  
GPIO.setup(ledPin, GPIO.OUT)   #腳位設定為輸出模式。 

try:
    print('按下 Ctrl-C 可停止程式')
    while True:  # 以下檢察按鈕是否被按下
        if GPIO.input(btnPin) == GPIO.LOW:
            time.sleep(0.168)  # simple Debounce
            my_callback(btnPin)
        time.sleep(0.25)
except KeyboardInterrupt:
    print('Bye Bye 程式')
finally:
    GPIO.cleanup() 

RaspBerry Pi Button.py 數位輸入 + 讀取按鈕 *關於 PC/Windows 上安裝使用 Python
想在自己電腦上安裝官方版本的 Python ?
可以 點這連到 Python 官方網站, 建議不要抓最新版(通常 Bug 多多) ! (雖然上圖顯示 3.7.2, 那是我測試安裝一下啦:-)
如果用 Windows 10, 或確定你的 Windows 是 64 位元作業系統 (用滑鼠右鍵點"電腦" 選 "內容"看看),
建議點這抓3.6.8 會連到 python.org/ftp/python/3.6.8/python-3.6.8-amd64.exe

根據官方網站聲明: 3.6.8 是 3.6 版的最後一次修正版 !
也可 點這抓 Anaconda   以及 使用 Jupyter Notebook   點這看 Jupyter Notebook 使用介紹
(這有 台大學生寫的簡易教學老共寫的Anaconda教學)
#* 如何利用 IoTtalk 系統控制 Raspberry Pi 連接的 LED 燈?
# 拿 Dummy_Device 的 Python 程式來修改 .. 注意以下 Code 紅色的部份
#
# DAI777.py  -- new version of Dummy Device DAI.py, modified by tsaiwn@cs.nctu.edu.tw
# you can get from here:  https://goo.gl/6jtP41   ; Search dummy + iottalk  for other files
import time, DAN, requests, random 
import threading, sys    #
import RPi.GPIO as GPIO  
ledPin = 12

GPIO.setmode(GPIO.BOARD)   # Use physical pin numbering
GPIO.setup(ledPin, GPIO.OUT, initial=GPIO.LOW)  # 初始關燈  

# ServerURL = 'http://Your_server_IP_or_DomainName:9999' #with no secure connection
ServerURL = 'http://192.168.20.101:9999' #with no secure connection

# ServerURL = 'https://demo.iottalk.tw' #with SSL secure connection
# ServerURL = 'https://Your_DomainName' #with SSL connection  (IP can not be used with https)
Reg_addr = None #if None, Reg_addr = MAC address

mac_addr = 'C86770773739'  # put here for easy to modify;;  the mac_addr in DAN.py is NOT used
# Copy DAI.py to DAI2.py and then modify the above mac_addr, then you can have two dummy devices
Reg_addr = mac_addr   # Otherwise, the mac addr generated in DAN.py will always be the same !

DAN.profile['dm_name']='Dummy_Device'   # you can change this but should also add the DM in server
DAN.profile['df_list']=['Dummy_Sensor', 'Dummy_Control']
#DAN.profile['d_name']= None # None for autoNaming
DAN.device_registration_with_retry(ServerURL, Reg_addr)

# global gotInput, theInput
gotInput=False
theInput="haha"
allDead=False

def doRead( ):
    global gotInput, theInput, allDead
    while True:
        if gotInput:
           time.sleep(0.1)
           continue  # go back to while
        try:
           theInput = input("Give me data: ")
        except Exception:
           allDead = True  # 通知老闆說我死了喔 :-)
           print("\n\nDeregister " + DAN.profile['d_name'] + " !!!\n",  flush=True)
           DAN.deregister()
           sys.stdout = sys.__stdout__
           print(" Thread say Bye bye ---------------", flush=True)
           sys.exit( );   ## break  # raise   #  ?
        gotInput=True
        if theInput !='quit' and theInput != "exit":
           print("Will send " + theInput, end="   , ")

#creat a thread to do Input data from keyboard, by tsaiwn@cs.nctu.edu.tw
threadx = threading.Thread(target=doRead)
threadx.daemon = True
threadx.start()

while True:
    try:
    #Pull data from a device feature called "Dummy_Control"
        value1=DAN.pull('Dummy_Control')
        if value1 != None:     #   注意這列不可以刪除喔 !
            ggg = value1[0]
            if  ggg ==  0: GPIO.output(ledPin, GPIO.LOW)
            else:  GPIO.output(ledPin, GPIO.HIGH)
    #
    #Push data to a device feature called "Dummy_Sensor" 
        if gotInput:   # 小弟(thread)已經幫忙讀到資料放在 theInput
           if theInput =='quit' or theInput=="exit":
              break;  # sys.exit( );
           #value2=random.uniform(1, 10)
           try:
              value2=float( theInput )
           except:
              value2=0
           gotInput=False   # so that you can input again ; 讓小弟知道我已經取走資料
           if(allDead): break;
           DAN.push ('Dummy_Sensor', value2,  value2)

    except Exception as e:
        print(e)
        if str(e).find('mac_addr not found:') != -1:
            print('Reg_addr is not found. Try to re-register...')
            DAN.device_registration_with_retry(ServerURL, Reg_addr)
        else:
            print('Connection failed due to unknow reasons.')
            time.sleep(1.258) 
    try:
       time.sleep(0.2)
    except KeyboardInterrupt:
       break
time.sleep(0.5)
try: 
   DAN.deregister()
except Exception as e:
   print("===")
print("Bye ! --------------", flush=True)
sys.exit( );   ####### End of DAI777.py 


#* 加入讀取 R-Pi 板子上的瞬時按鈕, (取代原先讀取鍵盤的部份), 把按鈕的值 push 去 IoTtalk 伺服器
# 注意, 以下的 pin 腳編號故意用板子上實際的編號 -- GPIO.setmode(GPIO.BOARD)
## 注意以下 Code 紅色的部份
#
#
# DAI888.py  -- new version of Dummy Device DAI.py, modified by tsaiwn@cs.nctu.edu.tw
#  
import time, DAN, requests, random 
import threading, sys    #
import RPi.GPIO as GPIO  ##
ledPin = 12  # 注意這程式用實體編號 -- mode 用 GPIO.BOARD
btnPin = 16  #實體編號 16 的腳位,其 BCM 編號為 23 
ledLocal = 12   # 如果你有兩個 LED, 把這 12 改為別的值 ; 這用來監看按鈕有沒成功按到 !?

GPIO.setmode(GPIO.BOARD)   # Use physical pin numbering
GPIO.setup(ledPin, GPIO.OUT, initial=GPIO.LOW)  # 初始關燈 
GPIO.setup(ledLocal, GPIO.OUT, initial=GPIO.LOW)  # Local 用的 LED
GPIO.setup(btnPin, GPIO.IN, pull_up_down=GPIO.PUD_UP)   
       ### 上面句子的, pull_up_down=GPIO.PUD_UP用來開啟內建上拉電阻  

# ServerURL = 'http://Your_server_IP_or_DomainName:9999' #with no secure connection
ServerURL = 'http://192.168.20.101:9999' #with no secure connection

# ServerURL = 'https://demo.iottalk.tw' #with SSL secure connection
# ServerURL = 'https://Your_DomainName' #with SSL connection  (IP can not be used with https)
Reg_addr = None #if None, Reg_addr = MAC address

mac_addr = 'C85770738749'  # put here for easy to modify;;  the mac_addr in DAN.py is NOT used
# Copy DAI.py to DAI2.py and then modify the above mac_addr, then you can have two dummy devices
Reg_addr = mac_addr   # Otherwise, the mac addr generated in DAN.py will always be the same !

DAN.profile['dm_name']='Dummy_Device'   # you can change this but should also add the DM in server
DAN.profile['df_list']=['Dummy_Sensor', 'Dummy_Control']
#DAN.profile['d_name']= None # None for autoNaming
DAN.device_registration_with_retry(ServerURL, Reg_addr)

# global gotInput, theInput
gotInput=False
allDead=False
theInput="haha"     # 現在 theInput 沒用了 !  
myState = 0   # 記住按鈕的狀態 

# 以下這個小弟 (thread 執行緒) 不再讀取鍵盤, 改為檢查按鈕
def doRead( ):
    global gotInput, theInput, allDead   # 
    global myState    ### 按鈕狀態
    while True:
        if gotInput:   # 老闆(主程式)還沒拿走
           time.sleep(0.1)
           continue  # go back to while 阿就一直等到老闆拿走啊 
        #theInput = input("Give me data: ")
        try:
           time.sleep(0.053)
           if GPIO.input(btnPin) == GPIO.LOW:    # 按了按鈕
              time.sleep(0.168)  # simple Debounce
              myState = 1 - myState     # Toggle 
              gotInput=True   # 通知老闆 (主程式 thread)
              time.sleep(0.25)   #故意不立即又檢查按鈕
        except Exception:
           allDead = True  # 通知老闆說我死了喔 :-)
           print("\n\nDeregister " + DAN.profile['d_name'] + " !!!\n",  flush=True)
           DAN.deregister()
           sys.stdout = sys.__stdout__
           print(" Thread say Bye bye ---------------", flush=True)
           sys.exit( );   ## break  # raise   #  ?
        ###### 

#creat a thread to do Input data from keyboard, by tsaiwn@cs.nctu.edu.tw
threadx = threading.Thread(target=doRead)
threadx.daemon = True
threadx.start()

while True:
    try:
    #Pull data from a device feature called "Dummy_Control"
        value1=DAN.pull('Dummy_Control')
        if value1 != None:     #  有拉到資料 ! 
            ggg = value1[0]   # 取出資料
            if  ggg ==  0: GPIO.output(ledPin, GPIO.LOW)   # 關燈
            else:  GPIO.output(ledPin, GPIO.HIGH)   ##  開燈
    ##
    #Push data to a device feature called "Dummy_Sensor" 
        if gotInput:    ### 小弟說已經有資料要送去 IoTtalk Server 
           #if theInput =='quit' or theInput=="exit":
           #   sys.exit( );
           #value2=random.uniform(1, 10)
           #value2=float( theInput )
           value2=float( myState )   # 丟實數以後比較有彈性 
           gotInput=False   # so that you can input again (通知負責讀取的小弟 thread)
           if(allDead): break;
           DAN.push ('Dummy_Sensor', value2,  value2)  #
           GPIO.output(ledLocal, myState)   # 故意用 Local 燈對照以便知道有沒按到按鈕 

    except KeyboardInterrupt:
        break;
    except Exception as e:
        print(e)
        if str(e).find('mac_addr not found:') != -1:
            print('Reg_addr is not found. Try to re-register...')
            DAN.device_registration_with_retry(ServerURL, Reg_addr)
        else:
            print('Connection failed due to unknow reasons.')
            time.sleep(1)    
    try:
       time.sleep(0.23)
    except KeyboardInterrupt:
       break
time.sleep(0.5)
try: 
   DAN.deregister()
except Exception as e:
   print("===")
GPIO.cleanup() 
print("Bye ! --------------", flush=True)
sys.exit( );   ########  End of DAI888.py 

用 R-Pi 的 Python 讀取 dip-switch
Using Switch with Raspberry Pi – Python (其實寫得不太好!)
*如果用類似 Dip-Switch, 如何當 發現按鈕有變化才 push 去 IoTtalk Server ?

#修改之前的小弟函數..
allDead = False
myState = GPIO.input(btnPin)
oldState = myState
gotInput=False   # 表示沒變化, 老闆不會送按鈕狀態出去
##第一次, 利用以下設 True 通知老闆 (主程式 thread) 假裝 說按鈕有變化 
gotInput=True   # 如果一開始不要送, 在這列最左邊加 # 註解這列即可
# 以下這個小弟 (thread 執行緒) 不再讀取鍵盤, 改為檢查按鈕
def doRead( ):
    global gotInput, theInput, allDead   # 
    global myState, oldState    ### 按鈕狀態
    while True:
        if gotInput:   # 老闆(主程式)還沒拿走
           time.sleep(0.15)
           continue  # go back to while 阿就一直等到老闆拿走啊 
        #theInput = input("Give me data: ")
        try:
           time.sleep(0.055)
           myState = GPIO.input(btnPin)     # 讀取按鈕
           if myState != oldState:    # 按鈕有改變
              time.sleep(0.168)  # simple Debounce
              oldState = myState  # 記住 以便之後比對
              gotInput=True   # 通知老闆 (主程式 thread) 說按鈕有變化, 請它送出 myState
              time.sleep(0.25)   #故意不立即又檢查按鈕
        except KeyboardInterrupt:
           break;
        except Exception:
           break;    
    ### thread terminate the while Loop .. do clearn up 
    allDead = True   # 通知老闆說我死了喔 :-)
    print("\n\nDeregister " + DAN.profile['d_name'] + " !!!\n",  flush=True)
    try:
       DAN.deregister()
    except Exception:
       pass
    sys.stdout = sys.__stdout__
    print(" Thread say Bye bye ---------------", flush=True)
    sys.exit( );   ## break  # raise   #  ?  
    ###### end of doRead( )  for  Dip-Switch ###### 
   

*RaspberryPi-3B+ Pi3B+&電源+16GB Pi3B+ for OpenCV套件 更多搭配選擇 (德源科技) USB網路卡(較貴) (可自己找一下其他有開發票的)
Raspberry Pi-4B @ 台灣樹梅派 ;; 開機久最好買個帶風扇的鋁合金外殼 ;; 各種版本 R-Pi ;; 與NVIDIA Jetson Nano比
Raspberry Pi-4B性能 ; Buster OS/更新 ;; Raspberry Pi-4B vs. Pi-3B+ ; Raspberry Pi-3B+ vs. Pi-3B
[R-Pi]完全不接螢幕鍵盤滑鼠,電腦一開始就用網路線遠端連線Pi(CaveEDU)
      -- 要注意的是 R-Pi 的 OS 預設關閉 SSH 連線, 但只要在 boot磁區根目錄下有檔名 SSH 的文字檔就會開啟!
      -- 就是說, 在燒錄 OS 到 MicroSD 後,在Boot的根目錄新建一個名為SSH的無副檔名空檔案( 不是資料夾! )即可。
[R-Pi]一次做好 Raspberry Pi 3B+ 系統安裝 ( 沒螢幕 沒鍵盤 沒滑鼠 )
[R-Pi4B]樹莓派 Raspberry Pi 4 Model B 開箱,搭建 Homeassistant 簡單又穩定(2019.08.28)
[R-Pi] Python + 樹莓派 GPIO ; [ C/C++ 開發 ] 樹莓派 GPIO 功能介紹 ;
貴的USB3.0網卡 ; 貴的USB2.0網卡 ;; 有NT$68的USB網卡這也便宜 (便宜通常要手動安裝驅動) (自己搜尋找一下其他有開發票的)
**USB網路卡NT$80USB網路卡 *USB網路卡 ***免驅動USB網路卡USB3.0 Giga網路卡 or NT$299  網路線
其實所謂免驅動程式有些是偷偷把驅動程式塞在USB內啦!   不過也有真的免驅動, 因已經內建在 Windows/作業系統 內啦!
      TOP   ※ 看看幾個英文字的讀音  Rabboni 的意思
> ※ 劍橋字典 dictionary.cambridge.org 劍橋字典/thyme 讀如 time
(十)Rabboni 小玩具   (使用 ICM-20689 (類似 MPU6050) 六軸感測器三軸重力加速度 + 三軸陀螺儀  )
  * 點這看今天講義 Rabboni_d5.pdf (關於 Dummy Device 請看前面(四)(五(六)各大項)
  * 點這看 Rabboni API 文件(含BLE/USB範例)    或   Rabboni API 文件 .pdf 檔案   ( .docx 檔案)

  * 點這抓新版 Rabboni API 文件(1.7).pdf   點這抓新版 Rabboni API 文件(1.7).docx  
  * 點這抓 LibRab007.zip   (解壓縮到 你的 Python 程庫所在 Lib\site-packages\ 即可)
          - 正常情況應該是用 pip install rabboni 安裝 Rabboni 的程式庫即可 !
  * 如果要送資料去IoTtalk Server, 點這 抓之前上課用的程式碼 Rabboni.zip(連接 IoTtalk 用)
  ** 如果讀出的數據都很小, 請改用舊的(0.7版)程式庫: (舊版重力加速度 1g 用 9.8 表示, 0.8版開始 1g 用 1.0 表示)
      pip install rabboni==0.7   (線上已經找不到就抓我前面說的 LibRab007.zip 去解壓縮)
  ** 如果你的電腦不認識 pip 命令, 可利用 Python 內建的 pip 模組 "生" 出 pip 命令:
      python -m pip install --upgrade pip
  (萬一有 Error, 改用以下:)
      python -m pip install --upgrade pip --user
  ** 如果要建立隔離的 Python 虛擬環境: (如果你沒有系統管理員的權限就必須這麼做!)
      python -m venv myvenv
      cd myvenv
      Scripts\activate
    ==  現在開始已經在隔離的Python 虛擬環境 myvenv (其實系統只是改了 PATH)
      --- 補充說明剛剛三列做的事:
          python -m venv myvenv 建立子目錄 myvenv 並且
                    從系統把 Python 需要的淡不能共用的都 copy 到該 myvenv 目錄內
          cd myvenv 阿就切換進入該 myvenv 子目錄啊 (其實可以不必 :--)
          Scripts\activate 執行這個腳本記住原先 PATH 並把 PATH 改為隔離環境內檔案優先做
          --- 如果不做第二件的 cd myvenv 可以直接打 myvenv\Scripts\activate 即可
  === 要離開該隔離環境 myvenv 只要打 deactivate 即可(其實系統也只是改回了 PATH)
*10-1 簡單範例讀取 Rabboni 六軸資料, 最多讀取100次
###  USB.py   (USB mode)
# -*- coding: UTF-8 -*-
## 原範例 USB.py  ; 注意, 必要時, 就是如果檔案存檔用的編碼是Big5, 把上列的 UTF-8 改為 Big5
from rabboni import *
rabbo = Rabboni(mode = "USB") #先宣告一個物件                         
rabbo.connect()#連結上rabboni,若沒插上會報錯
print ("Status:",rabbo.Status)
try:
    rabbo.read_data()
    while True:#一直打印資料 直到結束程式  
        rabbo.print_data()#print資料  ; 會 delay 一下
        print (rabbo.data_num)
        if rabbo.Cnt > 10:
            rabbo.rst_count() #重置 計步器 count , 會delay一下
        if rabbo.data_num >= 100:
            break
except KeyboardInterrupt:  # 敲 CTRL_C 結束程式
    print('Shut done!')
print ("所有的", rabbo.data_num, " 個 Accx: ")
print(rabbo.Accx_list)#印出到結束程式時的所有Accx值
try:
   rabbo.stop()#停止運作
except Exception: pass
print('====== Bye bye')

如果讀出的數據都很小, 請改用舊的程式庫:
      pip install rabboni==0.7
*10-2 稍維修改原先的簡單範例, 讀取 Rabboni 六軸資料, 並直接存取六軸的資料, 最多讀取 8 次
### testUSB000.py   (USB mode)
# coding=Big5   #UTF-8  #Big5   #看檔案儲存時選哪種編碼; 編碼 先寫先贏
# -*- coding: UTF-8 -*-     # 另一種寫法, 但必須寫在 #LINE 2 或 LINE 1
### testUSB000.py  -- by tsaiwn@cs.nctu.edu.tw
from rabboni import *
import sys, time, math
try:
   rabbo = Rabboni(mode = "USB")  #先宣告一個物件  
   rabbo.connect()  #連結上rabboni,若沒插上會報錯
except Exception as e:
   print(e);   print("可能你沒把 Rabboni 用 USB 連接好 !   ")                              
   sys.exit( )
print ("Rabboni Status: ",rabbo.Status)
print("5 seconds to start:  ", end="", flush=True);
for i in range(1, 6)  :   # 1, 2, 3, 4, 5
   print(6-i, ". ", end="", flush=True);
   time.sleep(1);
print( )
try:
    rabbo.read_data()
    while True:#一直打印資料 直到結束程式
        rabbo.print_data()  #print資料, 會delay一下; 可把這列註解掉再測試看看  !!!
        print("---")   
        print("Acc x, y, z: ", rabbo.Accx, rabbo.Accy, rabbo.Accz,  end="    ;  ")
        print(math.sqrt( rabbo.Accx * rabbo.Accx + rabbo.Accy * rabbo.Accy + rabbo.Accz*rabbo.Accz) )
        print("Gyr x, y, z: ", rabbo.Gyrx, rabbo.Gyry,rabbo.Gyrz,)
        print ("# ", rabbo.data_num, )  
        if rabbo.Cnt > 100: rabbo.rst_count() #重置 計步器 count , 會delay一下
        if rabbo.data_num >= 8: break
except KeyboardInterrupt: pass; #結束程式
finally:
   print("=== Bye ", end="")
try:
   rabbo.stop()#停止運作
except Exception: pass
#print(rabbo.Accx_list) #印出到結束程式時的所有Accx值
print('====== Bye bye, data# =', rabbo.data_num)
### end of the program  testUSB000.py

如果讀出的數據都很小, 請改用舊的程式庫:
      pip install rabboni==0.7
*10-3 修改原先的簡單範例, 加入檢查 Rabboni 姿態 (檢查移動的 checkMoving( ) 在此程式後面)
### testUSB002.py  (USB mode)
# coding=Big5   #UTF-8  #Big5   #看檔案儲存時選哪種編碼; 編碼 先寫先贏
# -*- coding: UTF-8 -*-     # 另一種寫法, 但必須寫在 #LINE 2 或 LINE 1
### testUSB002.py  -- by tsaiwn@cs.nctu.edu.tw
from rabboni import *
import sys, time, math
     ###  checkMoving(  ) 函數可以放這裡 
scale=1.0   # use 9.8 for rabboni 0.8 ;  use 1.0 if Library is rabboni 0.7 
oldAns=0
def pose( ):    # 這 function 依據重力加速度三軸資料判定 Rabboni 的姿態, 回傳 0 到 18
   global oldAns
   ans=oldAns
   if( abs(rabbo.Accx)< 1.98/scale and abs(rabbo.Accy) < 1.98/scale):
      if(rabbo.Accz > 5.568/scale): ans = 1   #正面朝上幾乎平放
      if(rabbo.Accz < -5.68/scale): ans = 2   #背面朝上幾乎平放
   elif( rabbo.Accz > 1.1968/scale ):
      if(rabbo.Accx > 0 and rabbo.Accy < 0): 
         ans = 3   # 正面左傾
         if( abs(rabbo.Accy + rabbo.Accz) < 1.38/scale ): ans=13  # 正面左傾約45度
      if(rabbo.Accx < 0 and rabbo.Accy > 0): 
         ans = 4   # 正面右傾
         if( abs(rabbo.Accy - rabbo.Accz) < 1.38/scale ): ans=14  # 正面右傾約45度
      if(rabbo.Accx > 0 and rabbo.Accy > 0): ans = 7   # 正面前端向上
      if(rabbo.Accx < 0 and rabbo.Accy < 0): ans = 8   # 正面前端向下
   elif( rabbo.Accz < -1.1968/scale ):
      if(rabbo.Accx < 0 and rabbo.Accy > 0):
         ans = 5   # 背面左傾
         if( abs(rabbo.Accy + rabbo.Accz) < 1.38/scale ): ans=15  # 背面左傾約45度
      if(rabbo.Accx > 0 and rabbo.Accy < 0): 
         ans = 6   # 背面右傾
         if( abs(rabbo.Accy - rabbo.Accz) < 1.38/scale ): ans=16  # 背面右傾約45度
      if(rabbo.Accx > 0 and rabbo.Accy > 0): ans = 9   # 背面前端向上
      if(rabbo.Accx < 0 and rabbo.Accy < 0): ans = 10  # 背面前端向下
   elif( abs(rabbo.Accz) <= 1.1968/scale ):    # 差不多 :-)
      if(rabbo.Accx < 0 and rabbo.Accy > 0): ans = 11  # 正面向右垂直
      if(rabbo.Accx > 0 and rabbo.Accy < 0): ans = 12  # 正面向左垂直
      if(rabbo.Accx > 0 and rabbo.Accy > 0): ans = 17  #  前端向上垂直
      if(rabbo.Accx < 0 and rabbo.Accy < 0): ans = 18  # 前端向下垂直
   oldAns=ans
   return ans

msg = ["姿態不知", "正面朝上幾乎平放", "背面朝上幾乎平放", 
       "正面向上左傾", "正面向上右傾", "背面向上左傾", "背面向上右傾", 
       "正面前端向上", "正面前端向下", "背面前端向上", "背面前端向下",
       "正面向右垂直", "正面向左垂直", "正面左傾約45度","正面右傾約45度",
       "背面左傾約45度","背面右傾約45度","前端向上垂直","前端向下垂直",]
faceAB = [0, 1, 2, 1, 1, 2, 2,  1, 1, 2, 2, 1, 1, 1, 1, 2, 2,0,0, ]  # 1 正面; 2背面
try:
   rabbo = Rabboni(mode = "USB")  #先宣告一個物件  
   rabbo.connect()  #連結上rabboni,若沒插上會報錯
except Exception as e:
   print(e);   print("可能你沒把 Rabboni 用 USB 連接好 !   ")                              
   sys.exit( )
print ("Rabboni Status: ",rabbo.Status)
print("3 seconds to start:  ", end="", flush=True);
for i in range(1, 3)  :   # 1, 2, 3, 4, 5
   print(3-i, ". ", end="", flush=True);
   time.sleep(1);
print( )  #   要開始囉 ..
dtn=0    ## data Number 看看程式讀取 Rabboni 有多快
dataNum=-1  # 記住舊的 rabbo.data_num  
try:
    rabbo.read_data()
    while True:#一直打印資料 直到結束程式
        #rabbo.print_data()#print資料 ; 會 delay   ### 若沒叫用 rabbo.print_data()  會太快 !
        print("---")
        #print("Hex: ", rabbo.Hex_data); 
        print("Acc x, y, z: ", rabbo.Accx, rabbo.Accy, rabbo.Accz,  end="    ;  ")
        print(math.sqrt( rabbo.Accx * rabbo.Accx + rabbo.Accy * rabbo.Accy + rabbo.Accz*rabbo.Accz) )
        print("Gyr x, y, z: ", rabbo.Gyrx, rabbo.Gyry,rabbo.Gyrz,)
        print ("# ", rabbo.data_num, )
        face = pose( )   ### 算出姿勢代碼
        print( msg[ face ] )     # 如要檢查動作, Enable 下列, 並把用到的函數放進來前面
        #checkMoving(faceAB[face])   # faceAB[face] 判斷正面向上(1) or 背面向上(2)    
        if rabbo.Cnt > 100: rabbo.rst_count() #重置count 會delay一下
        if rabbo.data_num >= 8: break 
        if( rabbo.data_num != dataNum):
           dataNum = rabbo.data_num
           dtn= dataNum * 1000   ###   看看電腦有多快 ?
        time.sleep(0.05)    #   time.sleep(0.001)   # time.sleep(0.05)  # 或註解掉這列
        dtn += 1
        print("dtn = ", dtn)  # 看看電腦有多快 ?   
except KeyboardInterrupt: pass; #結束程式
finally:
   rabbo.stop()#停止運作
   print("=== Bye bye ===")
print("###### ######");
### end of the program  testUSB002.py

### 判斷動作的 function  checkMoving( ) ; 放在上面程式碼適當地方!
def checkMoving(faceNow: int):
   if(rabbo.Gyrx < -500 and rabbo.Gyry < -500):
      print("向左旋轉")
   if(rabbo.Gyrx > 500 and rabbo.Gyry > 500):
      print("向右旋轉")
   if(faceNow == 1):    # 正面向上
      if(rabbo.Gyrx > 500 and rabbo.Gyry < -500):
         print("正面前端向上向我旋轉")
      if(rabbo.Gyrx < -500 and rabbo.Gyry > 500):
         print("正面前端向下凹旋轉")
   elif(faceNow == 2):   #背面向上
      if(rabbo.Gyrx > 500 and rabbo.Gyry < -500):
         print("背面前端向下凹旋轉")
      if(rabbo.Gyrx < -500 and rabbo.Gyry > 500):
         print("背面前端向上向我旋轉")

如果讀出的數據都很小, 請改用舊的程式庫:
      pip install rabboni==0.7
*10-4 這是 Blue Tooth 藍芽版本
### testBLE.py  (BLE mode)
# coding=Big5   #UTF-8  #Big5   #看檔案儲存時選哪種編碼; 編碼 先寫先贏
# -*- coding: UTF-8 -*-
from rabboni import *
import time, sys
try:
   rabbo = Rabboni(mode="BLE") #先宣告一個物件
   rabbo.scan() #掃描所有藍芽Device
except Exception as e:
   print(e)
   print("可能你沒把 Rabboni 藍芽開啟或 Rabboni 沒電了 !")
   print("也可能缺 BLED112 驅動程式, 或 Dongle 忘了插入!")
   print("參考 http://www.picaxe.com/BLED112-Bluetooth-USB-Dongle/")
   sys.exit( )
rabbo.print_device() # 列出所有藍芽Device
print("====== 以上是掃描到的 BLE MAC =====")
#rabbo.connect("D1:FA:F0:F2:12:29")#依照MAC連接
rabbo.connect("C6:98:9D:BE:62:92")  #依照MAC連接
rabbo.discover_characteristics()#掃描所有服務 可略過
rabbo.print_char()#列出所有服務 可略過
# print (rabbo.characteristics)
# print (rabbo.Status)
time.sleep(3)  # 等 3 秒讓你看 :-)
rabbo.read_data()#讀取資料 必跑

try:
    while True:#一直打印資料 直到結束程式
        rabbo.print_data()#print資料
        if rabbo.Cnt == 100:
            rabbo.rst_count()
except KeyboardInterrupt:#結束程式
    print('Shut done!')
    print (rabbo.Accx_list)#印出到結束程式時的所有Accx值
    rabbo.stop()#停止dongle
    rabbo.write_csv(data = rabbo.Accx_list,file_name ="AccX")#將Accx寫出csv檔
    rabbo.plot_pic(data = rabbo.Accx_list,file_name = "AccX",show = True)#將Accx畫出圖案並存檔
finally:
    rabbo.stop()
### end BLE mode example ###

如果讀出的數據都很小, 請改用舊的程式庫:
      pip install rabboni==0.7
*10-5 這是 USB 版本, 讀取 168次, 會統計六軸的最大與最小值, 最後會印出讓你參考
### testUSB.py   (USB mode)
# coding=Big5   #UTF-8  #Big5   #看檔案儲存時選哪種編碼; 編碼 先寫先贏
# -*- coding: UTF-8 -*-
from rabboni import *
import sys, time, math
CNT_LIMIT = 38   # 當 Cnt > 38 會叫 rabbo.rst_count() 把 Cnt 重置 為 0
DATA_LIMIT = 168   # 讀取幾次 Data 後停止 program ?

try:
   rabbo = Rabboni(mode = "USB")  #先宣告一個物件  
   rabbo.connect()  #連結上rabboni,若沒插上會報錯
except Exception as e:
   print(e)
   print("可能你沒把 Rabboni 用 USB 連接好 !   ")                              
   #print("也可能缺 BLED112 驅動程式, 或 Dongle 忘了插入!")
   #print("參考 http://www.picaxe.com/BLED112-Bluetooth-USB-Dongle/")
   sys.exit( )

print ("Status:",rabbo.Status)
gg = input("要不要把 Count 歸 0 ? ")
if gg == "yes" or gg == "y": rabbo.rst_count()
try:
    rabbo.read_data()
    while True:#一直打印資料 直到結束程式
        rabbo.print_data()#print資料
        print("---")
        print("Acc x, y, z: ", rabbo.Accx, rabbo.Accy, rabbo.Accz,  end="    ;  ")
        print(math.sqrt( rabbo.Accx * rabbo.Accx + rabbo.Accy * rabbo.Accy + rabbo.Accz*rabbo.Accz) )
        print("Gyr x, y, z: ", rabbo.Gyrx, rabbo.Gyry,rabbo.Gyrz,)
        print ("# ", rabbo.data_num, )
        if rabbo.Cnt > CNT_LIMIT:
            rabbo.rst_count() #重置count 會delay一下
        if rabbo.data_num >= DATA_LIMIT:
            break

except KeyboardInterrupt:#結束程式
    print('Shut done!')
    # print (rabbo.Accx_list)#印出到結束程式時的所有Accx值
except Exception: # something wrong
    print(e)
finally:
    rabbo.stop()#停止運作
    print("=== done ===")
    rabbo.write_csv(data = rabbo.Accx_list,file_name ="AccX")#將Accx寫出csv檔
    rabbo.plot_pic(data = rabbo.Accx_list,file_name = "AccX",show = True)#將Accx畫出圖案並存檔
print("====== ====== ======")
xaaB = [max(rabbo.Accx_list), max(rabbo.Accy_list), max(rabbo.Accz_list), ]
xaaS = [min(rabbo.Accx_list), min(rabbo.Accy_list), min(rabbo.Accz_list), ]
xggB = [max(rabbo.Gyrx_list), max(rabbo.Gyry_list), max(rabbo.Gyrz_list), ]
xggS = [min(rabbo.Gyrx_list), min(rabbo.Gyry_list), min(rabbo.Gyrz_list), ]
print("ACC Max:", xaaB)
print("ACC Min:", xaaS)
print("Gyr Max:", xggB)
print("Gyr Min:", xggS)
### end of the program
### end of the program testUSB.py



如果讀出的數據都很小, 請改用舊的程式庫:
      pip install rabboni==0.7
*10-6 這是 BLE 版本, example00.py 搭配 pylive.py
# pylive.py
import matplotlib.pyplot as plt
import numpy as np

# use ggplot style for more sophisticated visuals
plt.style.use('ggplot')

def live_plotter(x_vec,y1_data,line1,identifier='',pause_time=0.1):
    if line1==[]:
        # this is the call to matplotlib that allows dynamic plotting
        plt.ion()
        fig = plt.figure(figsize=(13,6))
        ax = fig.add_subplot(111)
        # create a variable for the line so we can later update it
        line1, = ax.plot(x_vec,y1_data,'-o',alpha=0.8)        
        #update plot label/title
        plt.ylabel('Y Label')
        plt.title('Title: {}'.format(identifier))
        plt.show()
    
    # after the figure, axis, and line are created, we only need to update the y-data
    line1.set_ydata(y1_data)
    # adjust limits if new data goes beyond bounds
    if np.min(y1_data) <= line1.axes.get_ylim()[0] or np.max(y1_data) >= line1.axes.get_ylim()[1]:
        plt.ylim([np.min(y1_data)-np.std(y1_data),np.max(y1_data)+np.std(y1_data)])
    # this pauses the data so the figure/axis can catch up - the amount of pause can be altered above
    plt.pause(pause_time)
    
    # return line so we can update it again in the next iteration
    return line1

# the function below is for updating both x and y values (great for updating dates on the x-axis)
def live_plotter_xy(x_vec,y1_data,line1,identifier='',pause_time=0.01):
    if line1==[]:
        plt.ion()
        fig = plt.figure(figsize=(13,6))
        ax = fig.add_subplot(111)
        line1, = ax.plot(x_vec,y1_data,'r-o',alpha=0.8)
        plt.ylabel('Y Label')
        plt.title('Title: {}'.format(identifier))
        plt.show()
        
    line1.set_data(x_vec,y1_data)
    plt.xlim(np.min(x_vec),np.max(x_vec))
    if np.min(y1_data) <= line1.axes.get_ylim()[0] or np.max(y1_data) >= line1.axes.get_ylim()[1]:
        plt.ylim([np.min(y1_data)-np.std(y1_data),np.max(y1_data)+np.std(y1_data)])

    plt.pause(pause_time)
    
    return line1
   
### example00.py   -- 需要用到 pylive.py ;且請先 pip install rabboni
# -*- coding: UTF-8 -*-
# coding=UTF-8    #  簡單寫法, 如檔案是 Big5 編碼用 coding=Big5
from rabboni import *
from pylive import live_plotter
import numpy as np
import sys, time

try:
   rabbo = Rabboni(mode="BLE") #先宣告一個物件
except Exception as e:
   print(e)
   print("可能你沒把 Rabboni 開啟或 Rabboni 沒電了 !")
   sys.exit( )
rabbo.scan() #掃描所有藍芽Device
rabbo.print_device() # 列出所有藍芽Device
rabbo.connect("DA:E3:4C:8E:F1:6F")#依照MAC連接
rabbo.discover_characteristics()#掃描所有服務 可略過
rabbo.print_char() #列出所有服務 可略過
# print (rabbo.characteristics)
# print (rabbo.Status)
rabbo.read_data() #讀取資料 必跑

size = 100
x_vec = np.linspace(0,1,size+1)[0:-1]
y_vec = np.zeros((100,), dtype=float)
line1 = []

try:
    while True:#一直打印資料 直到結束程式
        #rabbo.print_data() #print資料
        ra=rabbo.data_num
        print('length',ra)
        val = rabbo.Accz
        print('value=',val)
        
        print('y=',y_vec)
        y_vec[-1] = val
        line1 = live_plotter(x_vec,y_vec,line1,pause_time=0.0001)
        y_vec = np.append(y_vec[1:],0.0)
        if rabbo.Cnt == 100: 
           rabbo.rst_count()
        
except KeyboardInterrupt: #結束程式  :  敲 CTRL_C
    print('Shut done!')
    print (rabbo.Accx_list) #印出到結束程式時的所有Accx值
    rabbo.stop() #停止dongle
    rabbo.write_csv(data = rabbo.Accx_list,file_name ="AccX") #將Accx寫出csv檔
    rabbo.plot_pic(data = rabbo.Accx_list,file_name = "AccX",show = True) #將Accx畫出圖案並存檔
finally:
    rabbo.stop()
   
* 手機搭配 Rabboni -- 可用手機掃瞄以下 QR code:
   
* 手機: 點這安裝 搭配 Rabboni 的 APP (GooglePlay)

  TOP   幾個英文字讀音
關於 Joint 函數的寫法與應用請參考(三)三個人用手機控制同一個燈
  ** 結合 IoTtalk Server ( Rabboni 把資料送去 IoTtalk Server )
  * 點這 抓之前上課用的程式碼 Rabboni.zip(連接 IoTtalk 用)
          解壓縮後,
          使用子目錄 IoTtalk_v1_USB 內的 DAN.py 和 csmapi.py 來配合以下程式碼 (for Rabboni)

如果讀出的數據都很小, 請改用舊的程式庫:
      pip install rabboni==0.7
*10-7 這是 USB 版本, DAI_Rab5u.py -- 資料會送去 demo.iottalk.tw 的 Rabboni 裝置
    ** 可找一個IDF/ODF接近的 DM (Device Model)來用, 或 參考(七)另行建立一個新的 Device Model (DM) 設備類別
    ** 以下範例是使用我另外建立的一個叫做 Rabboni 的 Device Model, 除了六軸資料, 我另加一個 Float (float) 和一個 Total (字串)
    ** 請注意看以下紅色字體的 code; 為了與別人的 Rabboni 區別, 請修改 Rabboni_BLE_address

    執行以下程式碼, 測試: (a)把Rabboni正面放著 (b)把 Rabboni 背面向上放著 (c)用力搖 Rabboni
### DAI_Rab5u.py -- Rabboni with IoTtalk  (USB mode)
# coding=Big5   #UTF-8  #Big5   ## 另外一種寫法, 但必須寫在 #LINE 2 或 LINE 1
# -*- coding: UTF-8 -*-
### DAI_Rab5u.py    # need DAN.py  and csmapi.py
import time, requests
import DAN
from rabboni import *
import sys, time, math, random

scale=1.0   # use 9.8 for rabboni 0.8 ;  use 1.0 if Library is rabboni 0.7 
Rabboni_BLE_address = 'C6:98:9D:BE:62:92'  # 你 Rabboni 的 MAC address  (其實跟 MAC 無關 :-)
ServerURL = 'http://demo.iottalk.tw:9999'  # 請確定 IoTtalk Server 
try:
   rabbo = Rabboni(mode = "USB") #先宣告一個物件
   rabbo.connect() #連結上rabboni,若沒插上會報錯
except Exception as e:
   print(e);   print("可能你沒把 Rabboni 用 USB 連接好 !   ")                              
   sys.exit( )
print ("Status:", rabbo.Status)
rabbo.read_data()
Reg_addr = Rabboni_BLE_address

DAN.profile['dm_name']='Rabboni'     # 對應到 IoTtalk 系統的 Device Model (DM) name 
DAN.profile['df_list']=['Acceleration', 'Gyroscope', "Float", "Total"]   # Device Feature 可自由增加
DAN.profile['d_name']= Rabboni_BLE_address
DAN.device_registration_with_retry(ServerURL, Reg_addr)  #跟 IoTtalk Server 註冊  
oldAx=0
oldGx=0
yyBBB=88  # 用力搖動 Rabboni 的 Float 這越來越大, 第一次故意限制不要超過這
yyOLD=0   # myFloat 變小的下限  ( 在 Rabboni 的 'Float' )
ggOLD=[0, 0, 0]    # 記住上一次的 Gyr? 陀螺儀 的值  
def calcGG( ):
    global ggOLD, yyOLD, yyBBB
    ans = 0
    if( abs(rabbo.Gyrx - ggOLD[0]) > 200): ans += abs(rabbo.Gyrx - ggOLD[0])/20
    if( abs(rabbo.Gyry - ggOLD[1]) > 300): ans += abs(rabbo.Gyrx - ggOLD[0])/33 
    if( abs(rabbo.Gyrz - ggOLD[2]) > 500): ans += abs(rabbo.Gyrx - ggOLD[0])/55
    yy = math.sqrt( rabbo.Accx * rabbo.Accx + rabbo.Accy * rabbo.Accy + rabbo.Accz*rabbo.Accz)
    if(yy > 18/scale): yy = 18/scale
    ans = ans * yy / 6.1568 *scale 
    if(ans < yyOLD): ans = yyOLD
    if(ans > yyBBB): ans = yyBBB
    if(ans > 1200): ans = 1200      # 限制上限為 1200  
    yyOLD = ans - 33  # 下次最多減少 33
    yyBBB = ans + 88  # 下次最多增加 88   
    if(yyOLD < 0): yyOLD = 0   # 故意不要有負的 :-)  # 因剛剛 ans - 33 可能小於 0
    return ans

gg = input("現在要不要把 Count Reset 歸 0 ? ")
if gg == "yes" or gg == "y": rabbo.rst_count()
while True:
    try: 
        DAN.push('Acceleration', rabbo.Accx, rabbo.Accy, rabbo.Accz) #Push data to an input device feature "Acceleration"
        #print('Acc:', rabbo.Accx, rabbo.Accy, rabbo.Accz) 
        DAN.push('Gyroscope', rabbo.Gyrx, rabbo.Gyry, rabbo.Gyrz)
        #print('Gyr:', rabbo.Gyrx, rabbo.Gyry, rabbo.Gyrz)
        myFloat = round( calcGG( ), 2)  # myFloat = abs(rabbo.Accx) + abs(rabbo.Accy) + abs(rabbo.Accz) 
        DAN.push('Float', myFloat) 
        ggOLD = [rabbo.Gyrx, rabbo.Gyry, rabbo.Gyrz]
        tot = (rabbo.Cnt % 23 ) * 1.568   # 亂寫的 :-)
        if( (rabbo.Accy - oldAx) > 5.0/scale): tot += 3 * abs(rabbo.Accy) * scale   # 這是隨便算的 :-)
        elif( (rabbo.Accy - oldAx) < -3.0/scale): tot -= 1 * abs(rabbo.Accy) * scale
        if( abs(rabbo.Gyrx - oldGx) > 200):  tot +=  abs(rabbo.Gyrx)/5  # 也是隨便算 :-)
        oldAx = rabbo.Accy  # 故意 y
        oldGx = rabbo.Gyrx
        tot = int(tot)  
        scale = random.randrange(3, 6)  # 3, 4, 5   
        if( tot < rabbo.Cnt ): tot = int(rabbo.Cnt / scale) % 38  # tot 比計步器值小, 另外亂算 :-)
        if( myFloat < 100.1 and  rabbo.Accz < 0  ):  #幾乎不動 and 背面向上
           if( tot < 88 ): tot = 88   # 故意最少給 88  
        DAN.push('Total', str(tot) )  # 因為 Total 是字串 
        print("===", myFloat, ", ", tot, ", Cnt=", rabbo.Cnt)
    except KeyboardInterrupt:   # CTRL_C 結束程式
        break;
    except Exception as e:
        print(e)
        if str(e).find('mac_addr not found:') != -1:
            print('Reg_addr is not found. Try to re-register...')
            DAN.device_registration_with_retry(ServerURL, Reg_addr)
        else:
            print('Connection failed due to unknow reasons.')
            time.sleep(1)
    try:
       time.sleep(0.1)
    except KeyboardInterrupt:
       break;
try: 
   DAN.deregister()
except Exception as ee:
   print("!!! ", ee)
finally:
   rabbo.stop() # Rabboni 停止運作
### end of the program  DAI_Rab5u.py    ( USB mode ) 

關於 Joint 函數的寫法與應用請參考(三)三個人用手機控制同一個燈
  * 點這 抓之前上課用的程式碼 Rabboni.zip(連接 IoTtalk 用)
          解壓縮後, 使用子目錄 IoTtalk_v1_BLE 內的 DAN.py 和 csmapi.py 來配合以下程式碼 (for Rabboni)

如果讀出的數據都很小, 請改用舊的程式庫:
      pip install rabboni==0.7
*10-8 這是 BLE 版本, DAI_Rab5b.py -- 資料會送去 demo.iottalk.tw 的 Rabboni 裝置
### DAI_Rab5b.py -- Rabboni with IoTtalk  (BLE mode)
# coding=Big5   #UTF-8  #Big5   ## 另外一種寫法, 但必須寫在 #LINE 1   或 LINE 2 (這時 Line 1 不可以有中文)
# -*- coding: UTF-8 -*-
### DAI_Rab5b.py    # need DAN.py  and csmapi.py
import time, requests
import DAN
from rabboni import *
import sys, time, math, random

Rabboni_BLE_address = 'C6:98:9D:BE:62:92'  # 你 Rabboni 的 MAC address 
ServerURL = 'http://demo.iottalk.tw:9999'  #請確定 Server 
try:
   rabbo = Rabboni(mode = "BLE") #先宣告一個物件
   rabbo.scan() #掃描所有藍芽Device  ; 知道自己的 MAC 後可註解掉這和以下列
   rabbo.print_device() # 列出所有藍芽Device
   rabbo.connect(Rabboni_BLE_address) #依照MAC連接
except Exception as e:
   print(e);  
   print("可能你沒把 Rabboni 的藍芽打開 或 沒插藍芽接收器 或 根本沒有 Rabboni 裝置 !   ")                            
   sys.exit( )
print ("Status:", rabbo.Status)
rabbo.read_data()
Reg_addr = Rabboni_BLE_address

DAN.profile['dm_name']='Rabboni'
DAN.profile['df_list']=['Acceleration', 'Gyroscope', "Float", "Total"]
DAN.profile['d_name']= Rabboni_BLE_address
DAN.device_registration_with_retry(ServerURL, Reg_addr)  #跟 IoTtalk Server 註冊
oldAx=0
oldGx=0
yyBBB=88  # 越來越大第一次不要超過這
yyOLD=0   # 變小的下限
ggOLD=[0, 0, 0]
def calcGG( ):
    global ggOLD, yyOLD, yyBBB
    ans = 0
    if( abs(rabbo.Gyrx - ggOLD[0]) > 200): ans += abs(rabbo.Gyrx - ggOLD[0])/20
    if( abs(rabbo.Gyry - ggOLD[1]) > 300): ans += abs(rabbo.Gyrx - ggOLD[0])/33 
    if( abs(rabbo.Gyrz - ggOLD[2]) > 500): ans += abs(rabbo.Gyrx - ggOLD[0])/55
    yy = math.sqrt( rabbo.Accx * rabbo.Accx + rabbo.Accy * rabbo.Accy + rabbo.Accz*rabbo.Accz)
    if(yy > 18): yy = 18
    ans = ans * yy / 6.1568
    if(ans < yyOLD): ans = yyOLD
    if(ans > yyBBB): ans = yyBBB
    if(ans > 1200): ans = 1200      # 限制上限為 1200
    yyOLD = ans - 33  # 下次最多減少 33
    yyBBB = ans + 88  # 下次最多增加 88
    if(yyOLD < 0): yyOLD = 0
    return ans

gg = input("現在要不要把 Count Reset 歸 0 ? ")
if gg == "yes" or gg == "y": rabbo.rst_count()
while True:
    try: 
        DAN.push('Acceleration', rabbo.Accx, rabbo.Accy, rabbo.Accz) #Push data to an input device feature "Acceleration"  
        #print('Acc:', rabbo.Accx, rabbo.Accy, rabbo.Accz) 
        DAN.push('Gyroscope', rabbo.Gyrx, rabbo.Gyry, rabbo.Gyrz)  
        #print('Gyr:', rabbo.Gyrx, rabbo.Gyry, rabbo.Gyrz)
        myFloat = round( calcGG( ), 2)  # myFloat = abs(rabbo.Accx) + abs(rabbo.Accy) + abs(rabbo.Accz) 
        DAN.push('Float', myFloat)  
        ggOLD = [rabbo.Gyrx, rabbo.Gyry, rabbo.Gyrz]
        tot = (rabbo.Cnt % 23 ) * 1.568   # 亂寫的 :-)
        if( (rabbo.Accy - oldAx) > 5): tot += 3 * abs(rabbo.Accy)   # 這是隨便算的 :-)
        elif( (rabbo.Accy - oldAx) < -3): tot -= 1 * abs(rabbo.Accy)
        if( abs(rabbo.Gyrx - oldGx) > 200):  tot +=  abs(rabbo.Gyrx)/5  # 也是隨便算 :-)
        oldAx = rabbo.Accy  # 故意 y
        oldGx = rabbo.Gyrx
        tot = int(tot)  
        scale = random.randrange(3, 6)  # 3, 4, 5    
        if( tot < rabbo.Cnt ): tot = int(rabbo.Cnt / scale) % 38   ## tot 比計步器值小, 另外亂算 :-)
        if( myFloat < 100.1 and  rabbo.Accz < 0  ):  #幾乎不動 and 背面向上
           if( tot < 88 ): tot = 88   # 故意最少給 88  
        DAN.push('Total', str(tot) )  # 因為 Total 是字串  
        print("===", myFloat, ", ", tot, ", Cnt=", rabbo.Cnt)
    except KeyboardInterrupt:   # CTRL_C 結束程式
        break;
    except Exception as e:
        print(e)
        if str(e).find('mac_addr not found:') != -1:
            print('Reg_addr is not found. Try to re-register...')
            DAN.device_registration_with_retry(ServerURL, Reg_addr)
        else:
            print('Connection failed due to unknow reasons.')
            time.sleep(1)
    try:
       time.sleep(0.1)
    except KeyboardInterrupt:
       break;
try: 
   DAN.deregister()
except Exception as ee:
   print("!!! ", ee)
finally:
   rabbo.stop() # Rabboni 停止運作
### end of the program  DAI_Rab5b.py    (BLE mode)

#====== END of Rabboni 小玩具 ======
關於 Joint 函數的寫法與應用請參考(三)三個人用手機控制同一個燈


Rabboni 內部晶片 -- 採用 ICM-20689 (類似 MPU6050) 六軸感測器
萬有引力 -- g = 物件在地球表面上自由下落的加速度為每平方秒9.8米(Wiki)
    ** 注意, Rabboni 程式庫 0.8 開始, 重力加速度感測器三軸的值改用 1.0 代表 1g; 之前版本用 9.8 代表 1g
          pip install rabboni==0.8
          pip install rabboni==0.7
關於invensense新一代 ICM-20689 DMP Driver六軸感測器驅動程式與範例
六軸傳感器ICM-20689 運動傳感器 資料表     六軸傳感器ICM-20689 Documents
六軸傳感器icm20602的自檢和校準學習
Accelerometer & Gyro Tutorial -- using IMU devices (Inertial Measurement Unit)
如何使用加速度計與陀螺儀(IMU)  或   加速度計和陀螺儀的數學模型和基本演算法
加速度計(Accelerometer),也叫重力感應器(G-Sensor), 可測量 x, y, z 三軸的重力加速度值;
    陀螺儀(Gyroscope、GYRO-Sensor)也叫地感器或者角速度計。陀螺儀通過測量自身的旋轉狀態,判斷出設備
    當前運動狀態,是向前、向後、向上、向下、向左還是向右,是加速(角速度)還是減速(角速度),都可以實現。

認識加速度感測器(G-sensor)的感測值 (Micro:bit)
關於加速度計和陀螺儀傾角測量的物理分析(解說)
關於MPU6050六軸感測器   * 用MPU6050計算角度(C / C++ Arduino)
MPU6050介紹及姿態解算   加速度傳感器的值 與 角度值 轉換原理(解說)
陀螺儀數值 和 加速度計 的數值
多感測器資料融合演算法—9軸慣性感測器
MPU6050 陀螺儀/加速器換算方式
陀螺儀角度計算 (Android Studio開發) (using Java Language)
以陀螺儀 (HiTechnic Gyro)推算物體的旋轉角度的實作測試
感測器原理與無人機...
Raspberry Pi + Python + 六軸感測器 MPU-6050
利用Arduino+MPU6050慣性感測器控制Servo
加速度感測器的原理(.pdf) -- using IMU devices (Inertial Measurement Unit)
Arduino教程:MPU6050的數據獲取、分析與處理
Arduino:加速度計和陀螺儀融合得到精確角度
其他關於六軸感測器的資料
 
手機陀螺儀 (用 javascript)
 
 
創意真的偷就有了! --- 把知識連起來就是創意   點子都是偷來的:10個沒人告訴過你的創意撇步
5G尚未商用,6G就已踏上來時路! 下一代地面無線通信的頻段0.12THz (0.12 太赫茲)   台灣5G..2019年12月競標中...
    ( 5G通訊台灣採用的是3.5GHz頻段和28GHz頻段以及1800MHz頻段 ) (據說太赫茲波還可以治療癌症ㄟ)   台灣無線電視頻段

    ★★★ 太赫兹波(TeraHertz, THz)是頻率在0.1THz-10THz (1T = 1 Tera = 10的 12次方)範圍内的電磁波。   光速約每秒30萬公里   暗物質無法通過電磁波觀測   暗能量
    ★★★ 輻射不等於電磁波,但是電磁波會產生輻射   科學家2012年找到上帝粒子   回到未來:蟲洞是是時空的隧道   黑洞其實不是洞   白洞可能不存在   真有平行時空?   救世主
    ★★★ 關於頻率也可看看我以前寫的鬼話連篇談無線網路與電磁波頻率(舊版)。啥?有些很像是亂ㄅㄞ的喔?對啦.. 有些是我亂掰的啦..咬我啊:-)不過大部分都是有根據的喔!  

※※※ 不過, 一個 Tera 也才 10 的 12次方,不但『不可說』和『不可說不可說』都比一個 Tera 大很多,甚至一個 Googol 也遠比它大
⊚ ⊚ 關於小倍數 例如nano:何處惹塵埃? "瞬息"、 "須臾"、 "彈指", 這三個到底哪個最? 哪個最

健康很重要!要顧好身體, 不然沒機會實現你的創意 (醫生的診斷有三成是誤診,by老共醫師紀小龍) 黑心錢 感冒藥vs瘦肉精 黑心才能變名醫(備用)
  ※😷請注意感冒其實沒有藥   珍珠奶茶最好少喝或不要喝! 塑化劑滅國?   脂肪和膽固醇被誤會四十年其實兇手是糖!   糖是兇手! 不是脂肪!

* 號稱飢餓大師劉一鳴醫師強調發燒不該吃退燒藥( 其實是感染科名醫王任賢說的; 建議從頭看該影片!可以把播放速度設 1.25 倍節省時間:-)  
劉醫師說慢性病可以逆轉不用吃藥!   劉醫師又說吃素其實不健康!還說要經常斷食飢餓可治療百病?   說梅干扣肉的扣肉比梅干建康   劉醫師還說喝黑咖啡很好!?   甚至還說要多吃牛肉!?   不同說法!?
      (註:有人批評劉一鳴醫師騙錢大王..因為他診療費每小時四千元且還跟你推銷數萬元到數十萬的維他命!
            (其實他推銷數十萬元的營養品就是抗氧化劑維他命營養素, 去 iherb 買較便宜, 可以參考我寫的 iherb 購買心得教你省更多!)
          -- 不過罵他的主要是罵他斂財$ 對於劉一鳴的書與醫學知識則大多贊同! 請自行多看自己判斷.. 盡信醫生不如不要看醫生! 反正.. 加減看 MED/Youtube 不要錢
:-)
    ※ 其實..斷食..可以從略過一餐開始克里斯汀·德·迪夫博士在1974年獲得諾貝爾醫學獎, 因為他首度發現體內細胞自噬機制(Autophagy = self-eating);
          其追隨者大隅良典(Yoshinori Ohsumi)博士則因為發現一日飢餓(間歇斷食)的秘密得到2016年諾貝爾醫學獎為什麼研究飢餓也可獲獎?
    江坤俊醫師說想餓死癌細胞仍要吃維生素D(要曬太陽或吃D3) 一天一D3 江坤俊醫師說D3吃多了不會中毒! D其實是賀爾蒙+低醣優脂可抗癌! 餓死癌細胞! 癌細胞愛吃糖! 癌細胞怕這些菜!
      -- 所以劉乂鳴醫師一週吃七餐其實也是有理論基礎的ㄟ(2016諾貝爾醫學獎認證)!   越來越多正規醫師開始說維他命真的有用!

    ※ 但是請注意:根據許多醫師研究與統計,若常常早餐不吃已經被證明比較容易得膽結石胰臟癌
      所以,建議斷食期間早上(最好七點半之前)還是要喝些帶有油脂的東東並喝250cc~500cc的室溫開水
光年之外 Marshmello - Alone (孤獨) Alan Walker - Alone (孤單一人) Alan Walker - Faded (解說人間迷走Piano) 2 (滴妹訪問Alan Walker (艾倫·沃克) (Wiki)) 漂向北方
哈佛大學說:風力發電害氣候暖化 不輸火力發電(自由時報) 外媒說沒那麼嚴重 -- 平衡報導   芒種Lyrics 芒種MV 芒種Rap搞笑 MR 國曆6月6附近 立冬 二十四節氣   佛系 一曲
台北市捷運行政大樓之興建史(交大資工系蔡中川教授委託置放)   【玩老外】我不懂英文! Let It Go 放開手   我喜歡 你不懂 好孤單 西海情歌   涼涼   不一樣 追光者 打了烊   雲朵天長地久 天路
     
  TOP     要聞香的看過來:點這可以下載蔡英文1984的論文共416頁 (加入會員才可下載;2019/10/17開始在 LSE 不需登入就可下載多少人下載下載別人的論文;公聽會/政經/關不了/孫先生)
You are the -th visitors.       、,:;。「︓」『』?!  * ★ ※ ──  👉 ※ ★ ? 😇 I'll be back!』 《 Bite me! 》! 
* 想學 Python + Flask 請點這     Jinja2 Jinja2 Doc     *點這看我寫的超簡單 HTML 網頁教學(可搜尋 HTML + tsaiwn 找到)   *也有要錢的瀏覽器 (沈修平博士)
* 點這看如何選擇 VPS ?     (建議用 DigitalOcean 或 Hostwinds.com 流量小可以先用免費的 AWS EC2)     C++11 vs. 14   14 vs. 17     OppO R17 vs. R17Pro

* PuTTY officeal site to Download PuTTY
* PieTTY project official site   Download Pietty0400b14.zip

* 取妻當取李子柒? 影片中都不說話的網紅年賺多少館長也很她ㄟ!唱歌好聽的阿冷以及台灣任何網紅還要紅的李子柒李子柒何許人 i 網紅 阿冷演講 沙漠骆驼
   李子柒、辦公室小野谷阿莫...谷阿莫這群人、蔡阿嘎、 還有小玉、以及黃氏兄弟讓大家相信只要努力就可以賺到Youtube的錢。 排名點閱排名也是排名   第一名   黃氏兄弟
    👉 其實,博恩去年(2018.0928 Friday)有來本校(交大)演講一小時;當時演講費兩萬, 現在應該不只這個價錢了:-) 交大第一名網紅九妹談回交大演講 再回母校交大突擊 網紅排名2019.08 排名
    👉2020 韓粉英粉都瘋狂 七七 韓粉抓狂 英粉抓狂(三立完整版) 英粉喊讚 波特王撩妹,行銷高雄魚幫水 水幫魚   1450崩潰 英粉崩潰 藍軍崩潰 韓粉崩潰 ; 蔡會贏450萬票? 韓會贏150萬票?
* 成功人士一致認為,創意並不是想出來的,而是偷來的。 ( 關於內容農場(Content farm) 以及 為什麼? 那個KKNews.cc並非老共那據說很賺錢『今日頭條』 )  
* 關於林一平教授可以參看林教授個人網站林教授Digitimes專欄林教授的書『大橋驟雨』 (林一平fB臉書大戰宅神)。       創意真的偷就有了!   👉 沒有是非的時代誰造成的