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
|
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:
上述的(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內搜尋 function 或 event_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 端執行的!
|
* 資料庫由
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
|
|
|
|
* 如何增加/修改 Device Model 物聯網設備類別 ?
(0)阿這是IoTtalk使用者該知道的喔, 在使用者手冊內有詳細解說 !
這與如何增加/修改/刪除 Device Features(設備功能屬性)在同一個操作介面,
都是從IoTtalk首頁點選 Device Feature Management進入頁面;
這時
左上角是Device Feature,
用滑鼠點一下就可切換 Device Feature 和 Device 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.vip
的 Atest (在 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特色課程
|
當你使用自動懶人安裝法 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:
| |
You are the
-th visitors.
|
* 點這看如何快速安裝 IoTtalk 系統
* 點這看如何選擇 VPS ?(建議用 Hostwinds.com 或流量小可以先用免費的 AWS EC2)
*
PuTTY officeal site to Download PuTTY
PieTTY project official site
Download Pietty0400b14.zip
|
|