0.前言php
去年(2013年)2月第一次接觸yeelink平臺,當時該平臺已經運行了一些時間也吸引了很多極客。試想本身也將投身IoT(物聯網)行業,就花了些時間研究了它。陸陸續續使用和研究了一年,大體圍繞兩個問題展開——1.yeelink平臺如何使用,2.如何構造一個功能簡單些的yeelink平臺。
【
PHP學習筆記——索引博文】
本文將討論如何構造一個簡單restful架構平臺(該平臺有點像yeelink,不過功能比yeelink少的多),並結合樹莓派實現LED的遠程控制(網絡控制)。構建一個RESTFul平臺涉及到不少知識,經過如下連接提供一些學習資料。
【1】
Slim——簡單的 PHP5 框架可用來建立 RESTful 的 Web 應用
【2】MySQL——關係型數據庫管理系統
【5】
cURL——利用URL語法在命令行方式下工做的開源文件傳輸工具
若是親愛的讀者想快速入門也能夠看看個人博客文章。
【2014年3月補充】
【1】若是您想得到本篇博文的源代碼,
請點擊這裏【
CSDN代碼倉庫】。
數據庫操做使用RedBean。
【2】整理完本篇博文以後,修改了部分API函數並在GitHub創建了代碼倉庫(數據庫操做並無使用RedBean),若是本博文對您有用請點擊這裏【
GitHub Clone】。
【3】若是想更深刻一些例如部署到雲平臺中,請訪問個人京東雲擎——【
應用】
,相關代碼倉庫請猛擊這裏【
京東代碼倉庫】
1.REST風格API
在HTTP協議中定義了多種動做或者方法,這些方法具備不一樣的含義。
【GET 獲取】【POST 建立】【PUT 更新】【DELTE 刪除】
爲了更好的理解以上的方法,下面結合LED遠程控制舉個例子。假設在數據庫中已經保存了家庭中的LED設備信息,這些設備信息包括LED編號,LED設備描述和當前狀態(打開或關閉)等,例如位於客廳的LED處於打開狀態。
可經過GET方法得到某個LED設備的信息或者所有LED的信息。這些LED燈具備一個惟一的編號,例如客廳的LED燈編號爲1,那麼 /leds/1就是編號爲1的LED設備的惟一URI(可理解爲網址)。經過這樣相似的方法使每一個LED設備具備網址,可經過該網址訪問LED。經過GET方法可得到LED設備的全部信息,這些信息可經過JSON格式描述,例如:
[{"id":1,"description":"raspberry pi IO1","status":"off"},{"id":2,"description":"raspberry pi IO2","status":"on"}]
可經過POST方法建立一個新LED,新增長的LED具體信息可以使用JSON格式描述,例如:
{"description":"add a new led","status":"off"}
可經過PUT方法更新LED信息,而具體內容用JSON格式描述,例如:
{「status」:"on"}
對於LED網絡控制,REST API設計以下:
GET /leds 返回全部的LED信息
POST /leds 增長一個LED設備
GET /leds/id 返回編號爲id的LED設備信息
PUT /leds/id 更新編號爲id的LED設備信息
2.數據庫準備
2.1 修改mysql密碼
(2.1或2.2操做也可以使用phpMyAdmin)
2.1 新建LED設備表
使用mysql控制檯,進入mysql數據庫(輸入use mysql,mysql爲數據庫的名稱——安裝wampserver後的一個默認數據庫)。創建一個LED設備表,該表具備編號ID、描述description、狀態status 字段,主鍵爲id且自動增加(插入該數據表時 id寫寫入0或者不寫,id編號會自動增加)。
- CREATE TABLE IF NOT EXISTS `leds` (
- id int(11) NOT NULL AUTO_INCREMENT,
- description text NOT NULL,
- status text NOT NULL,
- PRIMARY KEY (id)
- ) DEFAULT CHARSET=utf8;
【小提示】
【1】選擇數據庫 use <databs_name>;
【2】查看錶的結構 desc <table_name>;
【3】刪除表 drop table <table_name>;
【4】id的數據類型爲int(11),千萬別覺得int的長度爲11位,int(11)只是一種int的表達方式。
2.2 插入設備內容
可在MySQL控制檯輸入如下內容,插入兩條數據:
- INSERT INTO leds (id, description , status) VALUES (1, 'raspberry pi pcf8574-IO1','on');
- INSERT INTO leds (id, description , status) VALUES (2, 'raspberry pi pcf8574-IO2','off');
3.GET方法得到全部LED信息
使用GET方法或的全部LED狀態——GET /leds。
返回LED狀態,使用JSON數據包描述。
【代碼片斷】
- <?php
-
- require 'rb.php';
- require 'Slim/Slim.php';
-
- \Slim\Slim::registerAutoloader();
-
- R::setup('mysql:host=localhost;dbname=mysql','root','<your password>');
- R::freeze(true);
-
- $app = new \Slim\Slim();
-
- $app->get('/leds', function () use ($app) {
-
- $led_array = R::getAll('select * from leds');
- $app->response()->header('Content-Type', 'application/json');
-
- echo json_encode( $led_array , JSON_NUMERIC_CHECK);
- });
-
- $app->run();
- ?>
【代碼解釋】
【1】 require 'rb.php'; 載入redbean,請把rb.php放在www根目錄。
【2】R::setup('mysql:host=localhost;dbname=mysql','root','<your password>');R::freeze(true);載入數據庫,填入數據庫的名稱和密碼。
【3】$led_array = R::getAll('select * from leds'); 查詢數據庫得到LED數據包的全部內容,getAll返回一個索引數組。
【4】 echo json_encode( $led_array , JSON_NUMERIC_CHECK); 請注意mysql的整形轉到PHP時將變爲string,若是沒有JSON_NUMERIC_CHECK選項,那可能會得到{「id」:"1",....},這確定不是你所願意看到的。
【簡單測試】
可經過瀏覽器,cURL工具,瀏覽器HTTP插件進行測試。
圖1 使用瀏覽器得到全部LED信息
4. GET方法得到單個LED信息
【代碼片斷】
- $app->get('/leds/:id', function ($id) use ($app) {
- try {
-
- $led_single = R::getRow('select status from leds where id = :id',array(':id'=>$id));
- if ($led_single) {
- $app->response()->header('Content-Type', 'application/json');
-
- echo json_encode( $led_single, JSON_NUMERIC_CHECK);
- }
- else {
- $app->response()->status(404);
- }
- }
- catch (ResourceNotFoundException $e) {
- $app->response()->status(404);
- }
- catch (Exception $e) {
- $app->response()->status(400);
- $app->response()->header('X-Status-Reason', $e->getMessage());
- }
- });
【代碼解釋】
【1】$app->get('/leds/:id', function ($id) use ($app) id做爲參數,能夠輸入數字1或2等。
【2】$led_single = R::getRow('select status from leds where id = :id',array(':id'=>$id));
select status from leds where id = :id 爲SQL查詢語句,和通常的SQL語句不一樣的是出現:id,array(':id'=>$id)該語句實現了SQL語句中的:id和輸入參數id的綁定關係。在這裏只查詢status內容,其餘內容忽略。
【3】echo json_encode( $led_single, JSON_NUMERIC_CHECK); JSON格式輸出,請主意使用JSON_NUMERIC_CHECK選項。
【簡單測試】
使用curl工具測試,在windows 控制檯中輸入如下命令:
圖2 使用cURL工具得到單個LED信息
5. PUT更新單個LED信息
【代碼片斷】
- $app->put('/leds/:id', function ($id) use ($app) {
- try {
-
- $request = $app->request();
- $body = $request->getBody();
- $input = json_decode($body);
-
-
- $led = R::findOne('leds', 'id=?', array($id));
-
-
- if ($led) {
- $led->status = (string)$input->status;
- R::store($led);
- } else {
- throw new ResourceNotFoundException();
- }
- } catch (ResourceNotFoundException $e) {
- $app->response()->status(404);
- } catch (Exception $e) {
- $app->response()->status(400);
- $app->response()->header('X-Status-Reason', $e->getMessage());
- }
- });
【代碼分析】
【1】得到HTTP請求中的內容並進行解碼,json_decode老是返回一個PHP對象而不是數組,全部後面對於input的操做須要使用->符號。
$request = $app->request();
$body = $request->getBody();
$input = json_decode($body);
【2】$led = R::findOne('leds', 'id=?', array($id)); R::findOne老是返回一個對象,後面的操做須要使用->符號。
【3】$led->status = (string)$input->status; 修改status。
【4】R::store($led); 從新存儲led信息。
【簡單測試】
使用cURL工具測試,請求的內容爲{"status":"off"},請求的方法爲PUT。在windows控制檯下輸入如下命令:
注意:1)因爲該HTTP負載並無返回值,全部curl指令中加入-i選項,意爲顯示HTTP響應首部。
2)PUT方法必須大寫。
圖3 使用cURL更新單個LED狀態
圖4 編號爲1的LED狀態發生改變
6.樹莓派 實現LED網絡控制
親愛的朋友,若是您還不熟悉樹莓派的話,能夠參考:
經過樹莓派實現網絡控制的方法也很是簡單,樹莓派不停的向服務器(在局域網中,IP爲192.168.1.100)發送GET請求,服務器查詢數據庫以JSON格式返回LED信息,樹莓派根據JSON數據包的內容控制LED燈,on爲點亮,off爲熄滅。
【1】樹莓派發送HTTP請求 GET /leds/1
【2】服務器返回HTTP響應 {「status」:"off"}或{「status」:"on"}
【3】樹莓派根據status控制LED設備
【代碼片斷】
- import requests
- import smbus
- import RPi.GPIO as GPIO
- import time
- bus = smbus.SMBus(1)
- apiurl = 'http://192.168.1.100/leds/1'
- while True:
-
- r = requests.get(apiurl)
-
- print(r.text)
-
-
- led = r.json
-
- if led['status'] == 'on':
- print("led on")
- bus.write_byte( 0x20 , 1 )
- else:
- print("led off")
- bus.write_byte( 0x20 , 0 )
-
- time.sleep(5)
【代碼測試】
因爲沒有作前端,全部只能經過cURL指令改變LED的status。改變數據庫中LED的status以後,樹莓派上擴展板的真實LED狀態便會發生變化。前端控制頁面請期待後續博文。
圖5 測試結果LED狀態發生改變
7.其餘遐想
本文只是想闡述REST框架的建立和使用,樹莓派的使用並非本文的重點(樹莓派讓我擴展了知識面)。除了樹莓派以外還可使用其餘設備「享用」這個REST服務,例如
arduino平臺——入門簡單,加上ENC28J60可替代本文樹莓派的功能。
8.參考資料
9.關於我本身
本人是一名嵌入式工程師,專一於物聯網領域。雖然是一名嵌入式工程師,可是因爲物聯網的多領域交叉性,不得不讓本身多學一些WEB方面的知識。對於工程師來講學習新的知識絕對是有必要的,
工程師沒過過去只有去創造。
Email:xukai19871105@126.com