IoTtalk System Developers' Guid (開發者手冊) Ver. 0.96    
提醒這是 IoTtalk 開發者手冊; IoTtalk 新手入門應用則應該看 https://iottalk.vip/000/;
要先會用再談安裝與修改, 關於 IoTtalk 的使用也請先大概看看IoTtalk的使用手冊:
    http://liny.cs.nctu.edu.tw/#IoTtalk(林一平教授網頁) 
 點入後在 Document 下方, 有中文版和英文版;   點這看更多手冊
 * 建議也 先看看 ArduTalk 操作手冊  
 * 想知道如何增加/修改 Device Model物聯網設備類別        
 * 要測試使用IoTtalk 可以連這:   http://demo.iottalk.tw 
 * 關於 IoTtalk授權與自己架設IoTtalk Server (有問題也請點這看 Q & A 問與答)  
 * 關於 IoTtalk System 的相關術語(Terminology) 
 * 關於 IoTtalk Server 的啟動方式(目錄 setup/) 
 * 關於 IoTtalk Server 檔案目錄架構 
 * 關於 lib/ccm/static/gui.js 和 project GUI 網頁 
 * 關於 uwsgi, Nginx 和 https 相關  
 * 關於 lib/db.py 與 sqlite3 資料庫   
 * 關於 SQLALchemy (Python ORM Lib.) 點這參考這篇 SQLALchemy (Python ORM Lib.) 教學 
  * 關於 網頁如何和 Python flask 程式之間互傳資料 ? (Q 11)
  * 關於 如何寫 Service 啟動服務 (Q & A6) 以及看它的 Log ?
  * 點這跳到看如何增加 Cyber Device? Vpython Device List?(首頁如何生出 VP DA List)
      以及如何使用NodeMCU/Arduino Yun 控制 Device?

  * 如果你有登入臉書帳號就可以跳到後面留言
簡介 (Introduction)
IoTtalk 系統交通大學林一平博士帶領研發團隊開發的智慧物聯網應用開發平台, 提供業者一個整合、開放、低成本、高效率, 且能串聯不同規格標準的物聯網應用(例如智慧家庭、智慧校園、智慧農場)平台林一平教授曾任科技部次長,以及交大副校長現任交大資工系終身講座教授 林一平教授興趣多元,喜好藝術繪畫寫作遨遊於科技與人文間自得其樂 ,參看林一平教授的臉書(fB),以及林一平教授的Digitimes專欄文章。(點這看林一平教授寫的『大橋驟雨』以及關於歌川廣重的『大橋安宅驟雨』;還有,看看林教授該書中提到晚年住在亞爾Arles的梵谷模仿大橋驟雨的『雨中橋』油畫)。
目前這 IoTTalk 系統平台已經成功用於智慧校園以及智慧農業, 例如用於種植薑黃(5分鐘影片)! (參看 今週刊報導 以及 農譯科技 www.Agritalk.com.tw/ )
啊?IoTTalk 系統平台還能做甚麼喔?那就看大家的創意了 :-) (藝術家和賈伯斯都說: 創意, 偷就有了!)
*** 林ㄧ平教授講解 IoTtalk 物聯網商業化應用經驗(五個影片) 

     使用 IoTtalk 系統最大的好處是你可以利用 GUI 快速建立應用專案(在首頁點 Project 進入 GUI 畫面), 針對任一個應用專案, 可以加入一個或多個輸入和輸出的設備模型(Device Model), 用滑鼠點按即可連接輸入設備和輸出設備(單點功能連接或多點功能連接),當物聯網設備連接至 IoTtalk 系統時,針對各種感測器,IoTtalk 會自動產生或使用應用軟體來處理,因此每一個輸入設備可以相當方便地連接至輸出設備,必要時還可用 Python 在連結點寫簡單前處理或後處理函數;如果是多點連接, 甚至可在連接點撰寫較複雜的處理函數。

      建立 IoTtalk 應用專案之後, 可以隨時將專案中的設備模型關聯(Associate)到任一個該模型的真實IoT設備, 或關聯到事先寫好的虛擬設備(Cyber Device 或 VPython 設備)或自己用程式寫的虛擬IoT設備, 這樣就能快速實現你的創意體驗物聯網應用。

     針對任一應用專案(Project), 在 GUI 操作介面也可以隨時增減設備模型(DM),修改要使用的設備功能屬性(DF), 隨時切換連結方式與對象,更可以隨時改變各模型關聯到的真實或虛擬設備。

      還有, 從首頁點 Device Feature Management 可進入維護管理 Device Feature 和 Device Model 的管理畫面(進入管理畫面後可以點左上角切換DF管理/DM管理), 不但可以修改維護已有設備模型(Device Model)的設備功能屬性(Device Feature), 也可以建立新的設備功能屬性(Add new DF), 甚至也可以建立新的設備模型(Add new DM), 使得建立IoT物聯網應用更有彈性。

* 關於如何使用 IoTtalk 平台體驗物聯網應用, 請參看 IoTTalk 物聯網應用操作入門手冊
    如果你是系統管理者需要了解IoTtalk系統安裝以及IoTtalk程式內部架構, 
那手冊中最重要的應該是文件內以下這張圖(右邊的部分):
     
 * 關於IOTtalk系統安裝.. 請先大略看看  http://iottalk.vip/2
     雖然可用兩個指令快速完成IoTtalk系統部署(Deploy), 建議還是要先看看如何手動安裝部署。
   * 如果沒有可當Server的機器, 可以先試用Amazon免費的 VPS: AWS EC2(免費一年)
  IoTtalk Server 的啟動
* IoTtalk Server 是 Python Flask Web application [+ nodejs ] + 一些 Python 程式。
* 多支應用程式 (有網頁式也有非網頁式) 利用 GNU screen 做多工處理,
    其中 CSM 和 CCM 是兩支最主要的網頁式應用程式(Web Application)
    都是使用 Python Flask 框架(Flask Framework)寫的Web Application;
    目前 CSM 是聽(Listen)Port 9999, CCM 則聽 Port 7788;
    請注意, ESM 並不算 Web Application, 它不讓使用者從瀏覽器直接使用它,
    但它會透過 lib/csmapi.py 以 http 請求 調用 CSM 內的程序。
    ** 注意用到的相關設定在 lib/ec_config.py 這檔案內。

* 在 /etc/rc.local 內執行 setup/startup.sh 啟動 IoTtalk Server System
    sudo -u iotsvr /home/iotsvr/iottalk_server_1.0/setup/startup.sh
  ** 以上這是假設你用 iotsvr 這帳號來執行 IoTtalk Server
說明:
   # add_to_screen( ) 為寫在 /bin/sh 腳本 setup/startup.sh 內的函數
   # 以下摘自 setup/startup.sh 這腳本
#...
#以下是已經設定Current directory為 帳號 $iotuser 的根目錄:
# 也 就是 ~/iottalk_server_1.0/
#...

add_to_screen CSM "./bin/csm $python3"
# 或 add_to_screen CSM "sudo uwsgi ./lib/wsgi_csm.ini"        

sleep 3
add_to_screen SIM "./bin/ecsim $python3"

add_to_screen CCM "./bin/ccm $python3" 
# 或 add_to_screen CCM "sudo uwsgi ./lib/ccm/wsgi_ccm.ini" 

add_to_screen ESM "./bin/esm $python3"

add_to_screen WEB "sudo $python3 ./da/web.py"
# 或由 Nginx 負責轉送 CSM / CCM
sleep 3

$python3 ./da/Remote_control/startup_panel.py
$python3 ./da/Message/startup_msg.py
#...  
* 以下是 sudo reboot 重開機啟動 IoTtalk Server 後,
  用 PieTTY/Putty 登入然後用 screen -r 接管 screen 並切到 ESM 查看 Log:
   
  該些 Log 是因為操作以下動作產生:
    (a)從首頁點 Bulb 產生 Bulb 虛擬燈泡 (沒有在 ESM 產生Log),
    (b)從首頁點 Project 後進入 GUI 點選建立專案(Project) a,
    (c)在專案 a 加入設備 Bulb, 這時因只有一個 Bulb 所以自動關聯起來,
    (d)在專案 a 加入設備 Remote_Control,
    (e)把 Remote_Control 的 K 連接到 Bulb 的 Luminance
    (f)把 Remote_Control 的 S 連接到 Bulb 的 Luminance
    (g)回到 iottalk 首頁開啟 Remote_Control 控制燈泡開關與亮度
** 提醒: 用 screen -r 接管 screen 看完之後, 記得敲 CTRL_A 然後敲 d 讓 screen 回到背後跑 !

   
Terminology 相關術語:
Server 端 (Network Domain)
EC(Execution and Communication system,縮寫EC;執行與通訊系統) = CSM + ESM
    CSM 和 ESM 合起來稱 執行與通訊系統 (Execution and Communication system,EC)
CSM Communication SubModule system lib/csm.py
   通訊子模組系統(CSM) 定義 HTTP based RESTful API (Application Programming Interface),
   提供給設備應用(Device Application,縮寫 DA;) 用來傳送或取得輸入/輸出設備資訊。
   當一個物聯網設備註冊/取消註冊 (registers/deregister) 到 EC 時,
   DA 會經由 HTTP API 要求 CSM 去改變資料庫中之設備狀態,
   當物聯網設備完成註冊至 DA 後,即可以經由 EC (CSM+ESM) 彼此相互通訊。
ESM Execution SubModule system lib/esm/esm_main.py (import by lib/esm/__main__.py)
    執行子模組系統 (Execution SubModule system,ESM) 負責執行網路應用,以連接相關輸入與輸出功能。
SIM SIMulation Input Device Feature (IDF) lib/ecsim/ecsim.py
    模擬輸入功能模組,啟動這功能可模擬輸入設備的"輸入", 以驗證輸出設備功能是否正常。
CCM Creation, Configuration and Management system lib/ccm/ccm.py
    建立、設定與管理系統 (Creation, Configuration and Management system,CCM)
    負責建立與管理物聯網設備,自動設定輸入與輸出功能之連結,儲存所有相關資訊於資料庫系統 (DB)。
GUI (Graphical User Interface)是 CCM模組( lib/ccm/ccm.py套用 lib/ccm/templates/index.html產生出 (render) 來的網頁(點首頁Project)
  主要用到 lib/ccm/static/gui.js 這 Javascript 腳本


WEB the Web portal (port 80) da/web.py
    ** 注意如果啟動 Nginx 轉送 CSM, 則不要執行 da/web.py
Client 端 (Device Domain)
  DA  -- Device Application(設備應用程式;縮寫DA),
     通常是在行動裝置如手機內(開啟網頁或APP),
     DA用 HTTP based RESTful API 與 CSM 溝通(IoTtalk系統提供 csmapi),
     關於 CSM 的處理程序, 可以在 lib/ 目錄內用以下命令大略看:
        grep app.route csm.py
        grep app.route csm.py -3n    # 會列出該列的前後 3 lines 且有列編號
  DAI  -- Device Application to Iot device
  DAN  -- Device Application to the Network(to IoTtalk Server)
  IDA  -- Iot Device Application, 物聯網裝置的控制器,
         通常用 NodeMCU/ESP8266/ESP32等連接物聯網裝置,
         IDA 以無線網路和 DA 的 DAI 溝通, DAI轉由 DAN 與 CSM 溝通。
    ** 要連接實體裝置,建議看 ArduTalk-for-NodeMCU (對啦, 網站上當時目錄寫錯成 NCU)
    ** Web-based 的 Client端用到 jQuery Library, 不熟的建議看看 jQuery Tutorial.
IotTalk Directory structure
  (點圖片可放大)
     
Memo for important files in IoTtalk:
 
重要參數在設定檔 lib/ec_config.py
lib/db.py   lib/ccm/static/gui.js
lib/ccm/templates/index.html

lib/esm/esm_main.py
lib/esm/esm_project.py
lib/esm/data_path.py
lib/esm/create_data_paths.py
lib/esm/exec_data_path.py
 
lib/csm.py
lib/csmapi.py
lib/ccm/ccm.py
** 這裡各目錄是在 iottalk server 專案目錄下 iottalk_server_1.0/
(1)   啟動檔setup/startup.sh
(2)   Port 80 --da/web.py  (如果啟動 https 這支可能不用)
(3)   重要檔案  lib/ec_config.py  ;  lib/csmapi.py  ;  lib/db.py
(4)   CSM:   port 9999;   lib/csm.py    (看 bin/csm)
(5)   CCM:   port 7788;   lib/ccm/ccm.py    (看 bin/ccm)
(6)   ESM:   lib/esm/__main__.py  調用 esm_main.py    (看 bin/esm)
       * ESM 沒有另外跑http, 它透過 csmapi 使用 CSM

(7)   SIM (模擬輸入裝置)  lib/ecsim/ecsim.py (看 bin/ecsim)
       * ecSIM(SIM) 也沒有另外跑http, 它透過 csmapi 用 CSM做push

(8)   DB   lib/db.py 提供 ORM API  (Object Relational Mapping API)
(9)   GUI (上圖右上角編號 i)是 CCM (port 7788) 吐出來的網頁(點首頁Project)
      lib/ccm/templates/index.html + lib/ccm/static/gui.js + ...
(10)   === END of the MEMO ===
  上述的(9) GUI lib/ccm/ccm.py 執行中產生(render)的網頁,
ccm.py 中是由以下 Python 程式碼用render_template產生GUI網頁:
    (** 提醒, Pythone 的 預設 template 目錄是該支 web 程式執行時目錄下的 /templates (注意尾巴有 s)子目錄)
 project_list = session.query(db.Project.p_name, db.Project.p_id).all()

    if len(project_list) != 0:
        project_list.insert(0, ('add project', 0))
        return render_template('index.html',
                        join_number = range(0,30),
                        model_list = model_list,
                        project_list = project_list,
                        p_id = -2,
                        p_name = "Select a project")
    else:
        return render_template('index.html',
                        join_number = range(0,30),
                        model_list = model_list,
                        project_list = project_list,
                        p_id = -1,
                        p_name = "Add new project")
主要用到 lib/ccm/templates/index.html + lib/ccm/static/gui.js + ...
GUI提供使用者建立/修改 IoT應用專案的 GUI操作畫面, 如下圖所示:  
* 使用者經由client端的 GUI 操作指示 server 端的CCM 做事,
    包括建立/修改 Device Model/Device Feature, DF function,
    以及物聯網應用Project的增刪設備設定與綁定(關聯)等各項操作;
    ** 這裡說的"指示 CCM 做事,"
      (a)在瀏覽器 HTTP Client 端主要是
          lib/ccm/static/gui.js 調用 lib/ccm/static/ajax.js 內各函數發出HTTP請求給CCM;

      *** 提醒 這些 .js 檔案都是隨 HTML 網頁被使用者 Browser 抓到 client 端執行的!
      (b)在 Server 端的 CCM 就是 lib/ccm/ccm.py
          你可以在 lib/ccm/ 目錄內用以下命令大略看看有哪些處理程序:
              grep app.route ccm.py

      或用額外關鍵字過濾, 例如 :
              grep app.route ccm.py | grep device

Top

*在 lib/ccm/static/gui.js 中總共提供了30個事件處理函數(event_handler function),
    分別處理使用者操作觸發的各種事件, 可在 gui.js內搜尋 functionevent_handler
    這些事件可以分為五類:
        Device Model 處理可用的設備 、 Device feature 處理設備功能相關 、
        Device Object 處理Project專案用的設備 、 Function 處理專案內的 Python 小函數 、
        Connection 處理專案內連接輸入設備與輸出設備

*操作GUI網頁過程中, 網頁的變化是透過調用 lib/ccm/static/make.js 裡面的各 make* 函數
;
*此外, 操作過程中會 需要與 IoTtalk Server 端互動, 包括取得/更新資料庫內容,
    這會調用 lib/ccm/static/ajax.js 內各 ajax_ 開頭的函數;
    主要是用 HTTP request 丟給 Server 端的 lib/ccm/ccm.py 檔案內對應的函數處理
*還有, 上圖中可看到檢視網頁內有用到 js/main.js 就是 lib/ccm/static/js/main.js
    那個是一個 Custom jQuery function

* 如果你不熟悉 jQuery, 可先看看維基百科 還有 這 jQuery 簡易教學   2   3   4   5   6   10  
      或是 看這 jQuery教學影片(兩小時)
*** 再次提醒, 上面說的該些 .js 檔案都是隨 HTML 網頁被使用者 Browser 抓到 client 端執行的!
 
     
* 關於 IoTtalk Server 的資料庫模組 lib/db.py 則是使用 sqlite3
    提供 ORM API (Object Relational Mapping API)
      sudo apt-get install sqlite3 libsqlite3-dev -y
     
* IoTtalk 目前只有 MapTalk (da/Map/) 會用到 MySQL (PyMySQL)
* 各模組都透過 lib/db.py 存取資料庫 sqlite/ec_db.db
    你還需要看看這設定檔 lib/ec_config.py
* 在 db.py 程式中則使用 sqlalchemy 套件(注意不是 flask_sqlalchemy)
      pip3 install sqlalchemy
  你找不到以上這句, 因為它藏在IoTtalk專案目錄內的 requirements.txt

      sudo -H su $iotuser -c 'sudo -H pip3 install -r requirements.txt'

* 不熟悉 sqlalchemy 的可以先看看 Wikepedia 關於 sqlalchemy 說明
*    再看看 SQLAlchemy-Python Tutorial 基礎教學
*    (1)SQLAlchemy介紹
*    (2)SQLAlchemy的使用
*    (3)SQLAlchemy總結+
*    關於 sqlite/pysqlite.py

*    Difference between sqlalchemy vs. flask_sqlalchemy
* 資料庫由 lib/db.py 建立/維護在 sqlite/ec_db.db 這資料庫檔案,
   有 17 個 tables, 可以用以下命令檢視 lib/db.py 看看:
      grep tablename db.py
 iotsvr@iottalk.vip:~/iottalk_server_1.0/lib$ grep tablename db.py
    __tablename__ = 'User'
    __tablename__ = 'DeviceFeature'
    __tablename__ = 'DeviceModel'
    __tablename__ = 'DM_DF'
    __tablename__ = 'Unit'
    __tablename__ = 'DF_Parameter'
    __tablename__ = 'Device'
    __tablename__ = 'Function'
    __tablename__ = 'FunctionVersion'
    __tablename__ = 'FunctionSDF'
    __tablename__ = 'Project'
    __tablename__ = 'NetworkApplication'
    __tablename__ = 'DeviceObject'
    __tablename__ = 'DFObject'
    __tablename__ = 'DF_Module'
    __tablename__ = 'MultipleJoin_Module'
    __tablename__ = 'SimulatedIDF'
iotsvr@iottalk.vip:~/iottalk_server_1.0/lib$
下表顯示其中 14個 資料表 被 ESM / CSM / CCM 存取方式:
   
各 table 資料表 大略如下兩圖, 可以點圖片開新窗顯示大圖片比較清楚 :-)
   

   
    * 必要時, 可以執行 setup/reset_db.sh 清除資料庫, 這腳本其實是執行 :
        bin/initdb.py sqlite:ec_db.db -q
 

對了, 沒用過 screen 這工具的.. 
請先看看 https://en.wikipedia.org/wiki/GNU_Screen

以及大略看一下 screen 用法, 自己Google 或點以下連結:
      http://man.linuxde.net/screen
 因為IoTtalk 跑多個 http, 現在是用到 screen 做多工處理 (參考 setup/startup.sh)
  關於 uwsgi, Nginx 和 https 相關等...
    IoTtalk Server 的 CSM 和 CCM 都是用 Python Flask 框架(Framework)實作的 Web Server,
雖然開發Flask Web程式時用 Python 直譯器, 寫好了通常就改用支援 WSGI 的執行環境。
(你在用 Python 手動執行 Flask Web時會看到訊息說Flask產品建議用支援 WSGI 的執行環境!)

    在IoTtalk啟動檔 setup/startup.sh 內已經寫好可以選用 uwsgi 取代 Python 開發環境,
如果你使用我們提供的自動安裝腳本如 iotubu, 在執行中會詢問你使否要用 uwsgi+Nginx ?
如果你回答 yes 則在 setup/startup.sh 會改用uwsgi執行CSM和CCM模組(並自動安裝 Nginx)。

    uwsgi 是支援WSGI的 HTTP Server,它是第一個實作WSGI協定的Python 執行環境(Runtime environment),
另外常聽到的還有 Bjoern, CherryPy, Gunicorn, Meinheld, mod_wsgi 等, 這裡有人做了評比
 
WSGI 全稱是 Web Server Gateway Interface,中文翻譯做 Web 伺服器閘道介面,
它是 Python 語言定義出來的 Web 伺服器和 Web 應用程式之間的簡單而通用的介面,
是基於現存的 CGI (Common Gateway Interface)標準設計,通常網頁是被從Web Server抓回
我們電腦的瀏覽器執行,但 CGI 程式是在 Server 端直接執行,CGI可以是任何語言寫的程式,
通常CGI程式會存取資料庫然後吐出新網頁, 如果還不清楚 CGI 和 FORM 的就Google一下吧。

註1: 如果你用我們提供的快速安裝法部署 Deploy IoTtalk Server,
       則 iotubu 等腳本會在你選擇用 uwsgi+nginx 時, 自動幫你安裝 Nginx 並自動設定,

       這時 CSM 和 CCM 會用 uwsgi 執行, 且它們的 http 會經由 Nginx 轉送, Performance would be much better !
註2: 在 setup/startup.sh 用 uwsgi 執行 CSM 和 CCM 要用到以下兩個檔案:
         lib/wsgi_csm.ini --- 裡面會指定執行 lib/csm.py
         lib/ccm/wsgi_ccm.ini --- 裡面會指定執行 lib/ccm/ccm.py
       add_to_screen CSM "sudo uwsgi ./lib/wsgi_csm.ini"    
       add_to_screen CCM "sudo uwsgi ./lib/ccm/wsgi_ccm.ini"
       此外, 該兩個檔案內 uid = iottalk 這的 iottalk 必須改為 你執行 IoTtalk 的帳號 !
       不過這件事在我們的自動安裝腳本如 iotubu 執行時會自動幫你修改 :-)
註3: 上述該兩個給 uwsgi 命令用的 .ini 檔案內容..
* 以下是檔案 lib/wsgi_csm.ini 內容
[uwsgi]
;socket = 127.0.0.1:8001
socket=/tmp/uwsgi_csm.sock
chmod-socket = 664

;change to your account name, for example, iotsvr
uid = iottalk

#enable the following line if NOT using nginx to listen 9999(for ESM)
#http-socket = 127.0.0.1:9999
# 就是說只要在 nginx 內沒有 listen 9999 就須要開啟上列  127.0.0.1:9999
# 例如你在 nginx 把 listen 80; 用 uwsgi_pass unix:/tmp/uwsgi_csm.sock;
# .. 將 http  80  直接轉接到這 socket=/tmp/uwsgi_csm.sock

gid = www-data
env = PYTHONPATH=%v:%v/lib:%v/da:$PYTHONPATH
wsgi-file = %v/lib/csm.py
callable = app

; must be 1, don't change it.
processes = 1

threads = 2
buffer-size=32768
master = True
vacuum = true
die-on-term = true
* 以下是檔案 lib/ccm/wsgi_ccm.ini 內容
[uwsgi]
socket=/tmp/uwsgi_ccm.sock
chmod-socket = 664

;socket = 127.0.0.1:8002
#http-socket = 127.0.0.1:7788

;change to your account name, for example, iotsvr
uid = iottalk

gid = www-data
env = PYTHONPATH=%v:%v/lib:%v/da:$PYTHONPATH     
wsgi-file = %v/lib/ccm/ccm.py
callable = app

processes = 3
threads = 2
buffer-size=32768
master = True
vacuum = true
die-on-term = true
註4: 如果你手動安裝IoTtalk Server, 記得還要安裝 Nginx 和設定對應上述跑 uwsgi 的 CSM 和 CCM 模組,
      以下是在 /etc/nginx/sites-enabled/ 內的一個範例:
      (提醒通常設定檔放 /etc/nginx/sites--available/ 然後用 sudo ln -s ... 做 Enable)
      ( 例如: sudo ln -snv /etc/sites-available/wsgi_nginx.conf /etc/nginx/sites-enabled/ )
server {
        listen 9999;
        access_log off;
        location / {
                include      uwsgi_params;
                uwsgi_pass unix:/tmp/uwsgi_csm.sock;
        }
}

server {
        listen 7788;
        access_log off;
        location / {
                include      uwsgi_params;
                uwsgi_pass unix:/tmp/uwsgi_ccm.sock;
        }
}

server {
        listen 80 default_server;
        #server_name your_domainName;
        #access_log  /var/log/nginx/access.log  main;
        #access_log off;
        #error_log off;

        location / {
                proxy_pass              http://localhost:9999;
                proxy_set_header        Host $host;
        }

        location /static/ {
                proxy_pass              http://localhost:9999/static/;
                proxy_set_header        Host $host;
        }
}

      For more info, see: How To Install Nginx on Ubuntu
      和這 How To Serve Flask Applications with uWSGI and Nginx on Ubuntu 18.04

註5: 基本上跑 uwsgi 可以不搭配 Nginx, 但這時在 uwsgi 的 .ini 檔案內必須開放 http port,
       目前我們提供的 wsgi_csm.ini 和 wsgi_ccm.ini 這兩個的寫法沒有開放 http port,
       所以需要用到 Nginx 來當 Reverse Proxy 轉接 HTTP 請求(Request);

       主要考量 Nginx 是公認效能最好的 Web 伺服器, 比直接開放 uwsgi 的 http 效能好!
       注意這時使用 Nginx 並沒有開啟 https, 只是用來轉接到 uwsgi 的 web 應用程式。
       補充: 現在在 Q & A 的 Q7 補充說明如何不使用 Nginx 但有使用 uwsgi 執行 CSM, CCM, 和 WEB

註6: 如果要改跑 https, 機器要有 FQDN 領域名稱綁定你的IP,且要安裝合法憑證(CA),
       可以使用 Let's Encrypt 免費憑證, 且須要調整 Nginx 設定檔的 Rules

       Hint: 在 /etc/nginx/sites-available/ 目錄內
       可以參考這關於 Ubuntu 上用 Let's Encrypt + Nginx 的說明
基本上就是做以下幾個命令:
#First, add the repository for certbot:
sudo add-apt-repository ppa:certbot/certbot
sudo apt install python-certbot-nginx
# 把 FQDN 加入 nginx 設定檔案, for example:
# server_name iottalk.vip www.iottalk.vip;
# 以下測試給 nginx 的設定檔(Config file)是否正確 ?
sudo nginx -t
# 若沒語法錯誤信息, 那就重新載入(reload) Nginx 
sudo systemctl reload nginx
#
sudo certbot --nginx -d iottalk.vip -d www.iottalk.vip
###
sudo certbot renew --dry-run

TOP
  * 如何增加/修改 Device Model 物聯網設備類別 ?                 
    (0)阿這是IoTtalk使用者該知道的喔, 在使用者手冊內有詳細解說 !
        這與如何增加/修改/刪除 Device Features(設備功能屬性)在同一個操作介面,
        都是從IoTtalk首頁點選 Device Feature Management進入頁面;
        這時 左上角是Device Feature, 用滑鼠點一下就可切換 Device FeatureDevice Model 管理頁面!

    (1) 在iottalk 首頁點選 Device Feature Management
    (2) 點左上角的 Device Feature 切換為 Device Model 畫面
     
    (3) 右邊視窗中點選 add new DM
    (4) 然後選 IDF 或  ODF, 選擇類別 Category 然後選你要的功能
    (5) 最後記得要點 Save 存檔, 它會問你 Device Model Name
    (6)注意 Device Model name 若與已經有的重複會警告你要蓋掉 !
    (7)成功加入之後, 就可在 Project 中新增這個Device Model 設備類了
Top
    
* 如何增加 Cyber Device ?
  * 所有在 da/ 目錄下的子目錄, 只要裡面有 index.html 就會被當作一個 Cyber Device,      
      你可以故意在 da/ 目錄 mkdir 造一個子目錄例如 BBB 並在裡面 touch index.html 生出空index.html檔
      然後瀏覽器 IoTtalk 首頁 按 F5 重刷新你的網頁, 就會發現多了 BBB 的 Cyber Device
      其實Iottalk首頁是由 lib/csm.py 內 在 @app.route('/') 下的程式碼 檢視 da/ 下各子目錄後,
      把結果配合 lib/templates/web_da_index.html 這樣板做 render 生出的網頁;

          (但是它會排除 'vp', 'MusicBox' 這兩個子目錄, 摘錄其程式碼:)
 '''
    This route is for showing web da
'''
@app.route('/')
def show_web_da_list():
    js_da_list = sorted(
        f
        for f in os.listdir(ec_config.WEB_DA_DIR_PATH)
        if isdir(join(ec_config.WEB_DA_DIR_PATH, f))
            and f not in ('vp', 'MusicBox')
            and 'index.html' in os.listdir(join(ec_config.WEB_DA_DIR_PATH, f))
    )
    vp_da_list = sorted(
        f.replace('.py', '')
        for f in os.listdir(join(os.path.dirname(__file__), '../da/vp/py'))
        if f.endswith('.py')
    )
    return render_template('web_da_index.html', vp_da_list=vp_da_list, js_da_list=js_da_list)   

以下則是 lib/templates/web_da_index.html 裡面對應的片斷:
 <div>
  <h4 style="margin-bottom:0;">Cyber Device List:</h4>
    <ul style="margin:0;">
      {% for da_name in js_da_list %}
      <li><a href="/da/{{da_name}}" target='_blank'>{{da_name}}</a></li>
      {% endfor %}
      <li><a href="#" target='_blank' onclick="window.open('http://'+location.hostname+':5566', '_blank');">MusicBox</a></li>
      <li><a href="#" target='_blank' onclick="window.open('http://'+location.hostname+':5566/mboxctl', '_blank');">MusicBoxController</a></li>
    </ul>
  <h4 style="margin-bottom:0;">VPython List:</h4>
    <ul style="margin:0;">
      {% for da_name in vp_da_list %}
      <li><a href="/da/vp/web_py_index.html#{{da_name}}" target='_blank'>{{da_name}}</a></li>
      {% endfor %}
    </ul>
  </div>


* 建議先看看林芸蔚博士提供的這 Dummy_Device_WebVersion
    然後再 看 da/Bulb 目錄內 index.html 和 da/Bulb/js/ 內各檔案 (github 上的比較舊)
  我把它放在 iottalk.vipAtest (在 Bulb 上方)
  你可以自己檢視在你安裝部署 IoTtalk Server內的 da/Bulb/ 內檔案 )

* 再看看林芸蔚博士提供的這 Dummy_Device (Python version)

* 如果你要用 NodeMCU/ESP8266 連接真正的物聯網設備,
    可看林芸蔚博士提供的   這 ArduTalk for NodeMCU
     (裡面有Ardutalk-NodeMCU-ESP8266安裝與操作教學)

* 還有如果要用 Arduino Yun 板 則要看 這 ArduTalk_for_ArduinoYun   (Python 程式)
   
* 如何增加 VPython Device ?
  * 所有在 da/vp/py/ 子目錄下的 *.py檔案, 都會被當作一個 Vpython Device,
      你可以故意在 da/vp/py/ 目錄下 touch ABC.py 生出一個空 ABC.py 檔(注意大小寫)
      然後瀏覽器 IoTtalk 首頁 按 F5 重刷新你的網頁, 就會發現多了 ABC 的 Vpython Device
      當然這點了也是不能用, 不過你可以這樣 cp Ball-throw2.py BAA.py
      然後瀏覽器 IoTtalk 首頁 按 F5 重刷新你的網頁, 在 Vpython List 下點 BAA 這 Device
      會發現與原先的 Ball-throw2 完全相同 !
    * 所以參考 da/vp/py/ 目錄下的 .py 檔案就可以寫出新的 Vpython Device 囉 !
          點這偷看這 da/vp/py/Free_Fall2.py    (很短, 才 38 列 :-)
          點這偷看這 da/vp/py/Ball-throw2.py
          (建立一個 Project 用 Smartphone 選加速度 IDF 連接這Ball-throw2就可用你的手機玩丟球的遊戲 !)

* 要了解VPython, 可以看 王一哲的VPython 教學文件
    還有, 可以 點這看曾靖夫的建中VPython & VPhysics特色課程

點這看如何讓 IoTtalk 首頁顯示機器和作業系統的相關資訊
VPS 建議用 Hostwinds.com 或流量小可以先用免費的 AWS EC2

點這看如何快速安裝 IoTtalk 系統 關於一些英文字 543 五四三 看IoTtalk的手冊(點入後在 Document 下方, 有中文版和英文版) 要測試使用IoTtalk 可以連這: http://demo.iottalk.tw 可以點這 偷看負責生出此網頁的 da/web.py 這是原先聽 port 80 網頁的 da/web.py

當你使用自動懶人安裝法 Quick way to Deploy IoTtalk Server,

* 如果你重複執行 如 iotubu 的 Script,
    則 /etc/rc.local 檔案會有多筆 sudo .. 執行 iottalk server
* If you run the script more than once,
    then in /etc/rc.local may have Multiple sudo commands for iottalk

In this case, please edit/modify the file /etc/rc.local by yourself.
請自行把 /etc/rc.local 內不需要的 sudo 命令 用井字號 # 註解掉 :

 


* 如果使用 vi / vim 時發現彩色的字都看不清楚:  
 * 這時可以打入命令 :synt off 把語法關聯到顏色功能關閉 :syntax off
   之後需要看彩色就打入 :synt on
 * 如果不太會用 vim / vi, 那就用號稱小孩也會用的 nano 編輯檔案啦 :-)
   提醒, nano 內隨時敲 CTRL_S 存檔, 要離開則敲 CTRL_X 即可 !

  TOP   TOP
      Q   &   A                              


Q1: 要如何安裝一個自己的 IoTtalk Server ?
  A: 你需要 IoTtalk 系統的原始碼和一部可以安裝 Linux 的伺服器 !
      (1)要先取得本校林一平教授研發團隊IoTtalk授權( 需要繳錢給交大研發處),
          可洽 03-5712121#52904 陳素蓉小姐詢問;
       (2)然後到 gitLab.com 申請一個帳號(要 git clone IoTtalk原始碼用),
           把帳號 E-mail 給林芸蔚博士( jyneda@gmail.com ) (密碼不用寄啦)
          以便讓林博士把你帳號加入 source code 授權;    
       (3)再來當然要有一台你有 root 權限的 Unix 主機,
           然後 點這看如何快速安裝 IoTtalk 系統 (兩句命令就自動安裝)
       (當然 執行時要回答帳號密碼以及是否要用 uwsgi 等, 請注意看螢幕訊息)
    (如果你沒有可用的 Unix 機器 -- 捲到最後有關於免費 AWS EC2 VPS 和便宜 VPS 的連結)


Q2: iottalk 系統的首頁在哪個目錄 ?
  A: 那是由 lib/csm.py 根據目錄 da/ 底下子目錄和 da/vp/py/ 內*.py檔案產生的,
    點這看如何增加 Cyber Device 處就有說明到這點


Q3: 我安裝的 IoTtalk 系統怎沒跑 https:// 呢?
  A: 如果只有 IP address 沒有綁定 Domain name 則無法用 https,
      因為 CA 憑證只針對 FQDN 發放, 不對 IP address 發放;
      如果你的Server已經有 FQDN 網域名稱, 想改用 https,
      可以 點這裡跳到前面看關於使用 Let's Encrypt 免費憑證搭配 Nginx


Q4: 我 sudo reboot 重開機後無法開啟 IoTtalk Server 的網頁 !?
  A: 請登入系統用 screen -r 看看, 這時可以敲 CTRL_右箭頭 切換各個 screen 視窗,
      檢視CSM, CCM, ESM 各模組視窗看有何錯誤訊息?
      如果你修改了 da/web.py 則也要看看 WEB 那視窗有啥錯誤訊息 !?
       
      如果它說根本沒 screen 在跑, 可能你使用的帳號與執行 IoTtalk Server 的帳號不同!?
      這時請 cat /etc/rc.local 看裡面 sudo 執行 startup.sh 是用 sudo -u 哪個帳號 !
      如果不想重新登入, 可以用 sudo su 該帳號名稱 暫時切換 user 帳號
      注意, 看完後要記得 敲 CTRL_A 然後敲 d 讓 screen 回到背後跑
      如果你 screen -r 之後敲 CTRL_右箭頭 無法切換 screen 畫面,
      請抓正確的 .screenrc 到你的 Home Directory:
cd
wget iottalk.vip/screenrc  
cp -p screenrc .screenrc


Q5: 為何我用 screen -r 後看到的畫面與上面那題的畫面不太一樣 ??
  A: 如果你用我們提供的 iotubu 腳本自動安裝部署 IoTtalk,
      且有回答 y 要選用 uwsgi + nginx,
      則你看到的畫面應該類似如下:
 
        這是因為 WEB 的工作已經改由 nginx 執行,
      nginx 直接轉送 CSM (port 9999) 的 http 請求, 所以 da/web.py 不被執行了 !
      你可以檢視 setup/startup.sh 檔案看如何執行各模組
      阿就是說原先 da/web.py 的工作已經由 Nginx 取代,
      你可以檢視 /etc/nginx/sites-enabled/ 裡面生效中的設定檔案。

Q6: 可是上面這個畫面 怎沒有 CSM 模組呢 ? (上面已經解釋為何沒有 WEB 模組)
  A: 哈哈 .. 被發現了 :-)
      阿這是因為上面這機器上, 我把 CSM 模組改寫為 Service 了 :-)
      所以在 setup/startup.sh 內也沒有用 add_to_screen CSM ... 執行 CSM 模組。
      啥? 怎麼寫 Service 喔? Google 一下啊.. 好啦, 給..
      點這看這篇How To Serve Flask...uwsgi...應該就會了 :-)
      以下是我的 csmsock.service 檔案 (所以 Service name 是 csmsock )
      注意這檔案必須放在 /etc/systemd/system/ 目錄下
      名稱不可以與已經有的service name同名
[Unit]
Description=uWSGI server instance configured to serve csmsock by tsaiwn
After=network.target

# systemd service file for csmsock server, by tsaiwn@cs.nctu.edu.tw
# put this file in /etc/systemd/system/csmsock.service
#to enable the service csmsock
# sudo systemctl enable csmsock

#to check service
# sudo service csmsock status
# sudo systemctl  status  csmsock  (這與上列命令同效果)
#to start the service
#  sudo service csmsock start
# sudo systemctl  start  csmsock  (這與上列命令同效果)
#to stop the service
#  sudo service csmsock stop
#to disable service
# sudo systemctl disable csmsock

[Service]
User=iotsvr
Group=www-data
WorkingDirectory=/home/iotsvr/iottalk_server_1.0/lib
Environment="PATH=/usr/local/bin" 
ExecStart=/usr/local/bin/uwsgi --ini ./csmsock.ini 

# 在 /home/iotsvr/iottalk_server_1.0/lib 要有 csmsock.ini

[Install]
WantedBy=multi-user.target
有看到吧, 在以上Service檔案內 execStart=... 說要執行 uwsgi --ini ./csmsock.ini
      (注意 WorkingDirectory=/home/iotsvr/iottalk_server_1.0/lib 這工作目錄的設定)
      以下就是 lib/csmsock.ini 檔案內容 (裡面 # 開頭的註解也要看看)
[uwsgi]
# this file depends on /etc/systemd/system/csmsock.service
# if start from iotserver root/ 
# chdir=./lib
module = csmwsgi:app 

#http = localhost:9999 
http-socket = 127.0.0.1:9999 
#以上這句仍要留著否則 ESM 會有問題(會變成沒人在聽 9999)
#以上故意改用 127.0.0.1, 所以從其他電腦的瀏覽器無法使用 127.0.0.1:9999
#如希望 :9999 可以從任意電腦的瀏覽器用, 請改為 0.0.0.0:9999 即可 
# uwsgi 的 .ini 檔案可以有很多種寫法
#注意我在 Nginx 是聽 port 80 不是 9999
# 我在 Nginx 設定已經改用 socket 如下 
socket = csmsock.sock 
chmod-socket = 660
vacuum = true

# environment variables
env = PYTHONPATH=/home/iotsvr/iottalk_server_1.0:/home/iotsvr/iottalk_server_1.0/lib:/home/iotsvr/iottalk_server_1.0/da:$PYTHONPATH

master = true
#注意以下 processes 要放 1  不然有問題 !
processes = 1
threads = 3

die-on-term = true
注意上面這檔案內, 在 [uwsgi] 項目下有 module = csmwsgi:app
      意思要執行 csmwsgi.py 內的 app
      以下是 lib/csmwsgi.py 的內容, 只有三列, 阿就是執行原先的 csm.py 內的 app 啦
from csm import app
if __name__ == "__main__":
    app.run()

  還有還有, 在 lib/csmsock.ini 裡面的 socket = csmsock.sock 要用來與 Nginx 溝通,
      要正確設定 Nginx 把 port 80 轉送到這個跑 uwsgi 的 web 網頁(我們用 socket)
      以下就是 Nginx 在 /etc/nginx/sites-enabled/ 內有效設定檔與這 socket 有關的片段:
    location / {
        include uwsgi_params;
        uwsgi_pass unix:/home/iotsvr/iottalk_server_1.0/lib/csmsock.sock;
        uwsgi_param UWSGI_PYHOME /home/iotsvr/iottalk_server_1.0/lib/;
        uwsgi_param UWSGI_CHDIR  /home/iotsvr/iottalk_server_1.0/da/;
        # remember to do:   sudo systemctl enable csmsock
        # to check status:   sudo systemctl status csmsock
    }

* 為了方便, 可把 socket 檔案改放 /tmp 目錄之下, 例如:
    uwsgi_pass unix:/tmp/csmsock.sock;
    當然前面 .ini 檔案內 [uwsgi] 之下也要改成 socket = /tmp/csmsock.sock

* 最後, 要記得執行以下命令 enable 這 csmsock 服務:
          sudo systemctl enable csmsock
      這樣, sudo reboot 重開機之後就會自動執行這個 csmsock 服務

    ** 點這看看這 How to Install Flask with Python... 也很有幫助
    ** 再貼一下前面說的: 點這看這篇How To Serve Flask...uwsgi...應該就會了 :-)


Q6b: 寫成 Service 那要如何看到它的 Log 呢 ? (此例就是 CSM 的 Log)
  A: 用 journalctl -u serviceName 即可看到, 例如以這 csmsock.service 為例:
      journalctl -u csmsock -f       # -f 表示只看最近的且持續看著(敲 CTRL_C 結束)
      journalctl -u csmsock -r       # -r 表示由新到舊反向時間排序顯示
  * Log 每列一事件所以很長, 只有在用 -f 持續監看時會依照螢幕寬度自動斷行
      否則在 journalctl 看 Log 時看不到右邊, 可敲往右箭頭(或往左箭頭)移動畫面,
      也可敲 Escape 然後敲右括號 ) 或左括號 ( 看看, (會移動半個螢幕畫面)
      跑到螢幕內容的太右邊則敲 Escape 然後敲左大括號 { 回到最左邊;
      敲 空白鍵 往下一頁, 敲 b 往回一頁面,
      必要時敲 h 看 help, 在 help 內敲 q 離開 help 畫面。

  * journal 意思是 日誌, 後面加 ctl 就是 journalctl 命令
  * system 意思是系統, 後面加 ctl 就是 systemctl 命令
      用 systemctl status csmsock 可看到 csmsock.service 的 status
      用 sudo systemctl status nginx 可看到 nginx 這 service 的 status
      用 sudo journalctl -u nginx -r 可看到 nginx 這 service 的 Log 日誌
     
 
Q7: 不跑 Nginx 可以用 uwsgi 來執行 IoTtalk 嗎?
  A: 當然可以, 前面就說過 uwsgi 和 Nginx 並沒有絕對的關係啊 :-)
      不過這時你的 lib/wsgi_csm.ini 和 lib/ccm/wsgi_ccm.ini 要把 http port 開放出來:
        在 lib/wsgi_csm.ini 內要加入這句: (開啟 port 9999)
          http-socket = 0.0.0.0:9999
        在 lib/ccm/wsgi_ccm.ini 內要加入這句: (開啟 port 7788)
          http-socket = 0.0.0.0:7788
      如果你已經安裝了 Nginx, 記得要 Disable 它(不用移除):
          sudo systemctl disable nginx
然後重開機就可以了
      不過這時因為沒有人在聽 Port 80, 你在網址列要自己多打 :9999 例如
            http://demo.iottalk.tw:9999
                                           
      如果你希望不必打 :9999 就可以用, 那要有人幫忙聽 port 80 並轉送 port 9999;
      你可以修改 setup/startup.sh 裡面讓那句 啟動 web.py 再次執行以便聽取 port 80
          add_to_screen WEB "sudo $python3 ./da/web.py"
      當然,
      也可以在 startup.sh 內改 用 uwsgi 來執行這 web.py 如下:
          add_to_screen WEB "sudo uwsgi ./da/wsgi_web.ini"

      就是參考把 CSM 和 CCM 改用 uwsgi 執行的方式啦, 包括:
        (a)寫一個 wsgi.ini 檔案用 sudo uwsgi 執行, 例如 wsgi_web.ini
          在 wsgi_web.ini 用以下兩句啟動 web.py
    wsgi-file = %v/da/web.py  
    callable = app
        (b)還有, 在 wsgi_web.ini 檔案內要開放聽取 port 80 如下
            http-socket = 0.0.0.0:80
        (c)注意 因為 port 80 須要 root 權限(Port 0 到 1023 都須要 root 權限),
            所以這 web.py 相關的 wsgi_web.ini 檔案內 uid = iottalk 必須刪除或改為:
            uid = root
            另外, 記得執行 uwsgi 命令必須用 sudo uwsgi ...
        (d)最後, 記得要稍微修改 web.py (當時寫 web.py 的人故意留一手 :-)
            有兩種修改方式:
          (1) 刪除 web.py 內最後那句 app.run( ...
          (2) 把最後那句 app.run( ... 改為以下兩句:
if __name__ == "__main__":
      app.run('0.0.0.0', port=int("80"),debug=True, threaded=True)
        建議選用第二種, 這樣必要時仍可以手動 sudo python3 web.py 執行 :-)
  ? 為啥要這樣呢 ?
        哈哈 .. da/web.py 是寫來害人浪費時間的 ! (考驗你對 Python 的理解 :-)
  * 就是要 注意如果 web.py 要給 uwsgi 用則裡面不可以有會直接執行 app 的命令 !
      要用 if __name__ == "__main__": 保護在其下方 !
      這句 if 的意思是必須是直接執行該檔案才會做其下方的句子,
      如果是被 import 則這時 if __name__ == "__main__": 這條件檢查不會成立 !

    點這看改好可給 uwsgi 執行的 新版 web.py
      提醒在 setup/startup.sh 內關於 WEB 窗要改類似這樣:
          add_to_screen WEB "sudo uwsgi ./da/wsgi_web.ini"
## 以下就是 wsgi_web.ini 範例:

[uwsgi]
#socket for nginx
socket=/tmp/uwsgi_web.sock
chmod-socket = 664
#comment out next line if you use Nginx
http-socket = 0.0.0.0:80
#WEB 的工作目錄是 da/
chdir = %v/da

; WEB
; this is the file da/wsgi_web.ini
; see setup/startup.sh
; usually uid is your id, but port 80 need root
uid = root

gid = www-data
env = PYTHONPATH=%v:%v/lib:%v/da:$PYTHONPATH
wsgi-file = %v/da/web.py
callable = app

processes = 3

threads = 4
buffer-size=32768
master = True
vacuum = true
die-on-term = true

Q8: 我用 vim 編輯檔案時很奇怪且字的彩色又看不清楚怎辦 ?
  A: vim 和 vi 都會讀取 .vimrc 的設定, 如果只是討厭彩色字體不清楚, 只要打入
      :synt off
    取消 vi/vim 根據文字的語法顯示顏色;
    如果是討厭在插入文句時自動縮排甚至自動在左邊補 # 這種雞婆動作, 那就改 ~/.vimrc 設定;
    如果你搞不清楚, 阿就做以下三列命令:
cd
wget iottalk.vip/vimrc   
cp -p vimrc .vimrc

Q9: 為何我電腦突然無法看 MAP 內的攝影機畫面, 原先看得到ㄟ o ,
      Google 的 Chrome 瀏覽器升級後就變看不到了!?
  A: 阿這是因為Google 偷改了新版 Chrome 的影音 AutoPlay policy,
      如果影片沒有聲音, 仍會 Auto Play,
      如果有聲音就不自動 Play, 免得上班被老闆知道在偷看影片:-)
      (想像旁邊很多人阿你點入網頁突然出現好大聲音 :-)
      解決方法有兩種:
        (1)看不到畫面時, 用滑鼠右鍵點選秀出 UI, 然後點小三角 Play 即可!
        (2)永久解決方案 .. 改 Chrome 的 AutoPlay policy, 在網址列打入:
              chrome://flags
          進入頁面後, 敲 CTRL_F 打入 autoplay 搜尋 Autoplay policy

          找到後, 在其右邊點選 No user gesture is required
          然後 點右下角 RELAUNCH NOW 或 關掉所有的Chrome視窗重新開啟Chrome即可 !


Q10: 關於 Map 與 Kurento Media Server (KMS) 的一些問題
  A: Map 是用一個網頁整合 Google Map 以及:
      (a)IoTtalk Application +
      (b)WebRTC/SRTP 連接 Kurento Media Server + (c)RTSP/RTP with IP Camera
    安裝部署 IoTtalk Server 之後還要另外有 Media Server 和 IP Camera;
      然後, 還要有 Live view with IoTtalk, 參考這目錄內檔案:

      da/Map/static/map-cam/
    通常你須要修改的是以下這個檔案:
      da/Map/static/map-cam/js/script.js

    * Kurento Media Server 很吃 CPU 和 Memory, 通常建議要安裝在另外的機器
    * 參考 https://github.com/Kurento/kurento-media-server
    * Kurento Media Server 目前(2018/12/09)還不支援 Ubuntu 18.xx 版本(只支援到 16.x)
      See Can I install Kurento on Ubuntu 18.04 ?
      根據該篇說法, 如果你要在 Ubuntu 18.x 上跑 Kurento, 只能用包好的 Docker 版本,
      至於 啥是 Docker 請點這看說明  或 點這看 10 個Q&A快速認識Docker
          sudo snap install docker
          sudo apt install docker.io
          sudo docker pull kurento/kurento-media-server

      For more information, See kurento in https://hub.docker.com/r/kurento/                
    * Kurento 的 Docker 版本無法使用Coturn (STUN/TURN)Server,
      參考: Kurento Media Server(KMS)& WebRTC初體驗與陷阱


Q11: 網頁如何和 Python flask 程式之間互傳資料 ?
  A: 我寫了一個簡單的網頁 echotest.html   ( 用到 Javascript 和 JQuery )
    可以把 JSON 資料用 POST 方式傳入 Python 程式 da/web.py 的 /echoans,
    在 /echoans 處理之後, 會套用 echoans.html 把結果回傳給 echotest.html,
    然後在 echotest.html 內用 document.write( 結果 ) 產生新網頁:
     點這測試 iottalk.vip/echotest
    ( 網頁內有連結可以讓你檢視各相關檔案, 看完應該就會了 :-)
    為了方便檢視, 以下是在 da/web.py 內關於 /echotest 和 /echoans 的程式碼:
@app.route('/echotest')
@app.route('/testecho')
def echotest():
    return render_template('echotest.html', name='Tsaiwn')

@app.route('/echoans', methods = ['POST', 'GET'])
def processEcho():
    if request.method == 'GET':           # 如果從網址打 /echoans 就會是 GET
        return redirect('/echotest')      # .. 那就轉址到 /echotest
        #return redirect('http://{}/echotest'.format(request.host))
    # read json "data" that "POST" to me, then pass "data" into  echoans.html, along with OS Information
    data = request.get_json(force=True)
    #print("Got ",data)
    osinfo = subprocess.check_output("cat /etc/*release", shell=True).decode("utf-8")
    nginxinfo =  subprocess.check_output("cat /etc/nginx/sites-enabled/*", shell=True).decode("utf-8")
    return render_template('echoans.html', data=data, name='蔡文能', osinfo=osinfo, nginx=nginxinfo)
      點這看 echotest.html             點這看 echoans.html
Q11b: 可否從 Python flask 程式內直接把資料回傳, 不要套用 HTML 樣版檔案?
  A: 當然可以, 我另外改寫一個 /echotest22 示範用 JQuery 處理回傳資料,
    也順便示範把 JSON 資料塞到一個 Table 排整齊 (cars 的資料)
    請點這測試 http://iottalk.vip/echotest22
    點這看 echotest22.html (會被在 web.py 內的 /echotest22 這 endpoint 拿來 render)
    以下則是在 da/web.py 內關於 /echotest22 和 /echoans22 的程式碼:
@app.route('/echotest22.txt')
def echotest22_txt():
    return send_file('templates/echotest22.html', attachment_filename='echotest22.txt')
@app.route('/echotest22')
def echotest22():
    return render_template('echotest22.html', name='Tsaiwn')

@app.route('/echoans22', methods = ['POST'])
def processEcho22():
    data = request.get_json(force=True)
    result = ''
    for item in data:
        # loop over every row
        make = str(item['make'])
        if(make == 'Porsche'):
            result += make + ' -- 好車 That is a good manufacturer\n<br>'
        elif (make == 'Benz') :
            result += make + ' -- <font color=red>哇哇 That is a car for  有錢人</font>\n<br>'
        else:
            result += make + ' -- 普普 That is only an average manufacturer\n<br>'
    #print("result=\n", result)
    return result
    #return Response(result, mimetype='application/text', status=200)
    #return jsonify(result)
    #return Response(result, mimetype='application/text')
    #return Response(result, mimetype='text/html', status=200)
            點這看 echotest22.html
      ** 因為 /echoans22 在 web.py 內直接回傳結果, 所以沒有 echoans22.html 喔 !

   
Q11c: 可否像一般FORM/CGI 那樣用 Form 的 action 丟給 Python flask 處理?
  A: 阿這也類似啊, 我改寫成 /testform (這直接由 da/web.py
      的 @app.route('/testform') 那段生出網頁)
    請點這測試 http://iottalk.vip/testform
      (會把 FORM 資料丟給 da/web.py 內的 /ansform 處理)
    也可以 點這看用來套用 FORM 資料的 ansform.html
    ** 注意, FORM 的 action 建議不要用 GET 或 PUT,應該用 POST 喔 ! (Why ?)
    以下則是在 da/web.py 內用來回應 /testform 的 /ansform 的程式碼:
########################################
@app.route('/echoform', methods = ['POST', 'GET'])
@app.route('/ansform', methods = ['POST', 'GET'])
def echoformtest( ):
   if request.method == 'GET':
      return redirect('/testform')
   data = request.form
   osinfo = "Unknown, maybe is Windows"
   nginxinfo = "empty nginx"
   try:
      osinfo = subprocess.check_output("cat /etc/*release", shell=True).decode("utf-8")
      nginxinfo =  subprocess.check_output("cat /etc/nginx/sites-enabled/*", shell=True).decode("utf-8")
   except:
     print("echoform error")
   return render_template("ansform.html",result = data, name='蔡文能 tsaiwn',nginx=nginxinfo, osinfo=osinfo)
    也可以 點這看用來套用 FORM 資料的 ansform.html
    ** 注意並沒有 testform.html, 因為 /testform 是在 da/web.py 內處理 /testform 直接生出網頁 !
          請點這測試 http://iottalk.vip/testform   進入網頁後, 可用滑鼠右鍵點選檢視網頁原始碼

Q11d: 可以用 GET 方法傳嗎 ?
  A: 當然可以, 不過網頁 FORM 的 action 建議不要用 GET 或 PUT,
      因為那樣會使得 URL 和參數都出現在網址列 !
      所以傳密碼千萬不要用 GET/PUT 喔!
    我另外寫一個 /testj 可以把網址列 /testj/字串一/字串二 GET 傳入產生的網頁,
    然後你可以選擇點一個連結 "GET" 到 Server, 由 Server 回傳成 JSON 資料 蓋掉網頁!

    或, 點我做的按鈕, 會用 jQuery $.get() 把資料傳到 Server, 由 Server 回傳成 JSON 資料,
      再用 JQuery 把 JSON 資料塞入一個事先準備的 div 區域中 !

    點這測試 "http://iottalk.vip/testj/ha haha/He he Heee


Q:
  A:


Q:
  A:


 
    To  be continued    

           



*** 林ㄧ平教授講解 IoTtalk 物聯網商業化應用經驗(五個影片) 

 
=== === === 要有 登入臉書才能留言 === === ===
You are the -th visitors.            
* 點這看如何快速安裝 IoTtalk 系統
* 點這看如何選擇 VPS ?(建議用 Hostwinds.com 或流量小可以先用免費的 AWS EC2)

* PuTTY officeal site to Download PuTTY   PieTTY project official site   Download Pietty0400b14.zip
 
  整理 by 蔡文能 tsaiwn@cs.nctu.edu.tw     交大資工系     tsaiwn.weebly.com     LINE ID: tsaiwn     FB: fb.me/tsaiwn     幾個英文字讀音   TOP
  TOP   Find your FB ID: https://findmyfbid.com/ if you want to Find your Facebook ID for your fb:admins