2015年5月9日 星期六

Raspberry Pi +WebIOPi 完成物聯網應用


使用Raspberry Pi +  WebIOPi  + Sensor 完成一個IOT物聯網應用.

WebIOPi 0.7 Released 
To use WebIOPi interface that uses javascript to control our GPIO from a web page that can be accessed anywhere in the world.






1) 基本安裝作文件:
  • 修改web登入帳號及密碼,執行webiopi-passwd再重新啓動服務
$ webiopi-passwd

設定檔/etc/webiopi/config
#一次啓動2個python script 
[SCRIPTS]
myscript = /home/pi/iot/python/script.py
myscript1=/home/pi/iot/examples/scripts/blink/script.py


[HTTP]
# HTTP Server configuration
enabled = true
port = 80

# File containing sha256(base64("user:password"))
# Use webiopi-passwd command to generate it
passwd-file = /etc/webiopi/passwd

# Change login prompt message
prompt = "WebIOPi"

# Use doc-root to change default HTML and resource files location
doc-root = /home/pi/iot/html

# Use welcome-file to change the default "Welcome" file
#welcome-file = index.html

啓動Webiopi
sudo webiopi -d -c /etc/webiopi/config 
------------Ittraining IoT Platform-----------------
it:WebIOPi command-line usage
webiopi [-h] [-c config] [-l log] [-s script] [-d] [port]

Options:
 -h, --help Display this help
 -c, --config file Load config from file
 -l, --log file Log to file
 -s, --script file Load script from file
 -d, --debug Enable DEBUG
Arguments:
 port Port to bind the HTTP Server
cat /usr/bin/webiopi
#!/bin/sh
python3 -m webiopi $*

-m mod : run library module as a script

主程式為 __main__.py

INSTALL=/usr/local/lib/python3.2/dist-packages/WebIOPi-0.7.0-py3.2-linux-armv6l.egg/webiopi


不要密碼的話, 直接刪除 rm /etc/webiopi/passwd
2) 同學必看
https://code.google.com/p/webiopi/wiki/Tutorial_Devices

3)youtube 影片
https://www.youtube.com/watch?v=6RaBz01pi4E

4) References:
http://ruten-proteus.blogspot.tw/2012/11/webiopi-gpio.html



The customization process has 3 steps :
  1. Write a simple Python script to initialize the GPIO and handle auto on/off
  2. Write a simple HTML/Javascript page
  3. Configure WebIOPi Server
    • You can build your HTML / Web UI from scratch, using the WebIOPi JS library or not.
    • You can extend the WebIOPi behavior by loading custom Python script using an Arduino like syntax with setup/loop functions

HTML (javascript)與python 的關係
home- pi
  - myproject
    - html --> .html
    - python --> Python script .py
     

1) html 為前端使用者界面 .html檔案,html 主要是利用 htdocs\webiopi.js的java script WEB I/O函式庫 
     <script type="text/javascript" src="/webiopi.js"></script>
2) python 放的是.py程式, 負責Web後端處理 , 用來get/set 系統狀態。python 亦有python I/O 函式庫可使用。python I/O 函式庫有底層GPIO, I2C, SPI 抽象Bus界面類別。函式庫亦有針對一些感測器, 溫度、溼度、壓力感測器模組,提供裝置驅動程式,以OO物件思維,提供類別相對應的Method。 (如何自己新增一個Device? 往下看!)
# python script code
@webiopi.macro
def setLightHours(on, off):
global HOUR_ON, HOUR_OFF
HOUR_ON = int(on)
HOUR_OFF = int(off)
return getLightHours()
3) 從HTML(javascript)呼叫後端python 程式方法 
javascript 利用 callMacro()的方式,來呼叫python 的函式
如:
webiopi().callMacro("setLightHours", hours, updateLightHours);

"setLightHours": 為python 函式 (即macro)
hours: python 函式的代入參數值
updateLightHours: 為javascript Call Back函式, 當macro返回後,要呼叫那個函式來處理。通常此函式用來更新HTML UI的值。
// Following function will process data received from set/getLightHours macro.
var updateLightHours = function(macro, args, response) {
var hours = response.split(";");
// Following lines use jQuery functions
$("#inputOn").val(hours[0]);
$("#inputOff").val(hours[1]);
}



HTTP遠端呼叫 (WebIOPi REST API )

WebIOPi provides a REST API. Here’s the API reference: https://code.google.com/p/webiopi/wiki/RESTAPI
set  "in" or "out"
 curl -v -X POST  http://192.168.1.116/GPIO/22/value/1
set value "1" or "0"
有密碼時或非80 port時
curl -v -X POST -u pi:raspberry http://192.168.1.116:8000/GPIO/22/function/out

為URL 路徑設立新的別名
In /etc/webiopi/config
[ROUTES]
# Custom REST API route syntax :
# source = destination
# source : URL to route
# destination : Resulting URL
# Adding routes allows to simplify access with Human comprehensive URLs
 # In the next example with have the bedroom light connected to GPIO 25
# and a temperature sensor named temp2, defined in [DEVICES] section
# - GET /bedroom/light => GET /GPIO/25/value, returns the light state
# - POST /bedroom/light/0 => POST /GPIO/25/value/0, turn off the light
# - POST /bedroom/light/1 => POST /GPIO/25/value/1, turn on the light
# - GET /bedroom/temperature => GET /devices/temp2/temperature/c, returns the temperature in celsius
/bedroom/light = /GPIO/22/value
#/bedroom/temperature = /devices/temp2/temperature/c

 curl -v -X POST  http://192.168.1.116/GPIO/22/value/1
 curl -v -X POST  http://192.168.1.116/bedroom/light/1
curl -v -X POST  http://192.168.1.116/device/sensor/temperature/c
* Closing connection #0
1root@raspberrypi:/etc/webiopi# curl -v -X POST http://192.168.1.116/bedroom/light/0
* About to connect() to 192.168.1.116 port 80 (#0)
* Trying 192.168.1.116...
* connected
* Connected to 192.168.1.116 (192.168.1.116) port 80 (#0)
> POST /bedroom/light/0 HTTP/1.1
> User-Agent: curl/7.26.0
> Host: 192.168.1.116
> Accept: */*
>
* additional stuff not fine transfer.c:1037: 0 0
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Server: WebIOPi/0.7.0/Python3.2
< Date: Thu, 02 Oct 2014 07:23:14 GMT
< Cache-Control: no-cache
< Content-Type: text/plain
< Content-Length: 1
<
* Closing connection #0




如何加入REST API
1) python script在def函式定義先一行標示 @webiopi.macro 即可使該函數, 
成為HTTP遠端呼叫的對象

# destroy function is called at WebIOPi shutdown
def destroy():
 GPIO.digitalWrite(LIGHT, GPIO.LOW)
 
@webiopi.macro
def getLightHours():
 return "%d;%d" % (HOUR_ON, HOUR_OFF)

@webiopi.macro
def setLightHours(on, off):
 global HOUR_ON, HOUR_OFF
 HOUR_ON = int(on)
 HOUR_OFF = int(off)
 return getLightHours() 

2) HTTP 遠端呼叫使用方式: 

執行:
curl -v -X POST http://192.168.1.116/macros/getLightHours

輸出顯示:

* About to connect() to 192.168.1.116 port 80 (#0)
* Trying 192.168.1.116...
* connected
* Connected to 192.168.1.116 (192.168.1.116) port 80 (#0)
> POST /macros/getLightHours HTTP/1.1
> User-Agent: curl/7.26.0
> Host: 192.168.1.116
> Accept: */*
>
* additional stuff not fine transfer.c:1037: 0 0
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Server: WebIOPi/0.7.0/Python3.2
< Date: Tue, 07 Oct 2014 07:19:09 GMT
< Cache-Control: no-cache
< Content-Type: text/plain
< Content-Length: 5
<
* Closing connection #0
20;18


如何產生特定裝置的類別
未來只要修改 /etc/webiopi/config 就可以使用特定Sensor/Device,而非通用GPIO類別,而是產生特定裝置類別, 並且後續使用HTTP GET/POST來完成存取, 例如
# GPIO Expander(MCP302)裝置, 設定PIN 3值為HIGH
HTTP POST /devices/mcp/digital/3/value/1#溫度感測裝置, 取得溫度並且以攝氏溫度傳回

HTTP GET  /devices/tmp/temperature/c

程式架構:

1) 底層裝置HAL程式目錄結構, .py 為對應的device Interface python language

進入安裝路徑 /usr/local/lib/python3.2/dist-packages/WebIOPi-0.7.0-py3.2-linux-armv6l.egg/webiopi/devices
./webiopi/devices
├── analog   --> 類比裝置class
├── bus.py
├── digital/gpio.py --> 數位裝置class,gpio上層python,call _webiopi/GPIO.py
├── i2c.py
├── __init__.py --> Common INIT 函式
├── instance.py
├── manager.py
├── onewire.py
├── __pycache__
├── sensor --> 感測裝置class
├── serial.py
├── shield
└── spi.py
bus.py I/O 函式for spi.py, i2c.py,serial.py (low level I/O Python Library)
 
./digital
├── ds2408.py
├── gpio.py
├── __init__.py
├── mcp23XXX.py
├── pcf8574.py
2) 在Sensor 目錄下新增一個的Virtual Sensor 
2-1 新增Device class :在webiopi\devices\sensor
新增 itvirtual.py 檔案

class TMPSi7020(I2C, Temperature):

 def __init__(self,slave=0x50,b=0):
 self.aa=b
 I2C.__init__(self, toint(slave))

 def __str__(self):
 return "TMP110(slave=0x%02X)" % self.slave

 def __getKelvin__(self):
 return 10

 def __getCelsius__(self):
 self.aa+=1
 return self.aa

 def __getFahrenheit__(self):
 return 30


2-2 新增裝置名稱 : 
修改 webiopi\devices\sensor\__init__.py

DRIVERS = {}
DRIVERS["bmp085"] = ["BMP085", "BMP180"]
DRIVERS["tmpXXX"] = ["TMP75", "TMP102", "TMP275"]
DRIVERS["tslXXXX"] = ["TSL2561", "TSL2561CS", "TSL2561T", "TSL4531"]
DRIVERS["itvirtual"] = ["TMPSi7020"]


2-3 編輯/etc/webiopi/config
# USB serial adapters
#usb0 = Serial device:ttyUSB0 baudrate:9600
#usb1 = Serial device:ttyACM0 baudrate:9600
Si7020 = TMPSi7020
#temp1 = TMP102 slave:0x49
#temp2 = DS18B20



2-4 建構前端網頁 device.html
<html>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 <meta name="viewport" content = "width = 420, user-scalable = no" />
 <title>WebIOPi | Devices Monitor</title>
 <script type="text/javascript" src="/webiopi.js"></script>
 <script type="text/javascript">
 webiopi().ready(function() {
 var content = $("#content");
 var device = webiopi().newDevice("Temperature","Si7020");
 device.element = $("<div>");
 content.append(device.element);
 device.refreshUI();

 });
 </script>
 <style type="text/css">
 button, .FunctionBasic {
 width: 50px;
 }
 </style>
</head>
<body>
<h1>Si7020 Temperature</h1>
<div id="content">
</div>
</body>
</html>

2-5 重新啓動 webiopi ,連入 http://192.168.1.116/device.html


 curl -v -X POST  http://192.168.1.116/bedroom/temperature


最底層的Driver驅動使用C
C code , 使用 open("/dev/mem")方式做上層User Space Driver 處理
GPIO.py python script will load GPIO library (.so)
./_webiopi 
├── GPIO.cpython-32mu.so (C Driver library)
├── GPIO.py (load C library)
├── __init__.py
└── __pycache__
 ├── GPIO.cpython-32.pyc
 └── __init__.cpython-32.pyc







沒有留言 :

張貼留言