Opendata 實作

可以利用一些網路服務來操控智慧插座之後,就來玩點比較進階的功能,這篇將會介紹在網頁裡常常使用的 Opendata ( 開放資料 ),並且使用這些 Opendata 來操控智慧插座。

取得 Opendata

基本上縣市政府網站,都有提供不少 Opendata 的資訊讓開發者使用,許多開發者喜歡到「政府資料開放平臺」上面去挖寶,或是「台北市政府資料開放平臺」,這兩個平台的開放資料都是相當完整且容易介接。

政府資料開放平臺:http://data.gov.tw/

政府資料開放平臺

台北市政府資料開放平臺:http://data.taipei/

台北市政府資料開放平臺

而這篇文章將會使用政府資料開放平臺裡的「空氣品質即時污染指標」作為資料來源,因為手邊不見得隨時都會有空氣污染偵測器 ( 也不便宜 ),所以透過每個小時由氣象局偵測的資訊,也可作為基本的預警與提醒功能。

空氣品質即時污染指標

點選 JSON 的格式,這就是待會我要使用的。

JSON 格式

此外,在這邊列出一些我覺得還滿實用,至少都是每小時更新的 Opendata,有興趣就可以參考我後面的做法自行做串接。

使用 Opendata ( 網頁前端 )

要直接在「網頁前端」使用 Opendata,最快的做法大概就是使用 jQuery ,這邊用了 .get 的方法,只要三行,剛剛的 JSON 資料就全部進到網頁裡了。( 使用 console.log 顯示 )

$.get('http://opendata2.epa.gov.tw/AQX.json',function(e){
  console.log(e);
});

程式:http://bin.webduino.io/diqeh/1/edit?html,js,output

在網頁前端使用 Opendata

因為資料是陣列的格式,所以藉由 forEach 就可以去判斷陣列每個元素的內容,然後指篩選出高雄市的資料。

$.get('http://opendata2.epa.gov.tw/AQX.json',function(e){
  e.forEach(function(o){
    if(o.County=='高雄市'){
      console.log(o);
    }
  });
});

程式:http://bin.webduino.io/desec/1/edit?html,js,output

指篩高雄市資料

不過只有在 console.log 裡面顯示實在沒有很好閱讀,最終還是得呈現在網頁裡,所以我先在網頁裡放個 div 作為顯示區域,接著就可以透過 append 把資料加到網頁裡面。

var $content = $('#content');
$.get('http://opendata2.epa.gov.tw/AQX.json',function(e){
  e.forEach(function(o){
    if(o.County=='高雄市'){
      console.log(o);
      $content.append('< '+o.SiteName+' > PM2.5:'+o['PM2.5']+', PM10:'+o.PM10+'<br/>');
    }
  });
});

程式:http://bin.webduino.io/sibu/1/edit?html,js,output

把資料加到網頁裡

更進階一點,也可以做成下拉選單,選擇之後再呈現對應的資訊,當資料載入之後,透過 filter 做篩選,不然你可能會有十幾個「新北市」出現在選單裡,然後再根據選擇的縣市,把感測器所在的區域資料顯示在網頁裡。

var $content = $('#content');
var $select = $('#select');
var $btn = $('#btn');
var county = [];
var result;
$.get('http://opendata2.epa.gov.tw/AQX.json',function(data){
  console.log(data);
  data.forEach(function(e,i){
    county[i] = e.County;
  });
  result=county.filter(function(element, index, arr){
    return arr.indexOf(element)=== index;
  });
  //篩選出縣市名稱(不然會很多重複)
  result.forEach(function(e){
    $select.append('<option value="'+e+'">'+e+'</option>');
  }); 

  $btn.on('click',function(){
    var s = $select.val();
    $content.html(''); //清空內容
    data.forEach(function(e,i){
      //挑選對應的縣市顯示
      if(e.County == s){
        $content.append('< '+e.SiteName+' > PM2.5:'+e['PM2.5']+' , PM10: '+e.PM10+'<br/>');
      }
    });
  });
});

程式:http://bin.webduino.io/juru/1/edit?html,js,output

資料做成下拉選單

使用 OpenData ( Node.js )

剛剛的範例是透過網頁前端運行,如果想要 24 小時偵測,可能就得依賴後端了,這邊介紹一個 Node.js 的套件「get-json」,就可以做到剛剛像網頁前端一樣的事情。 程式只要這樣寫,就可以每 10 秒抓一次氣象局的資料囉!

var getJSON = require('get-json')

_getJSON();

setInterval(function(){
    _getJSON();
},10000);

function _getJSON(){
    getJSON('http://opendata2.epa.gov.tw/AQX.json',function(error, response){
      response.forEach(function(e,i){
        if(e.SiteName=='前鎮'){
            console.log('前鎮, PM2.5:'+e['PM2.5']+' , PM10:'+e.PM10);
        };
      });
    });
}

使用 Node.js 的 get-json 套件

Opendata + Webduino ( 網頁前端 )

知道如何獲取資料並且應用之後,就要來寫點判斷式,接著再對應的狀態下,透過 Webduino 點亮燈泡,首先看到 HTML 的部分,一開始先引入對應的 JavaScript,然後放入兩個下拉選單、一個顯示文字的區域用來顯示數值,最後就是一個提示文字,如果空污指數太高就會顯示,同時點亮燈泡。

<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
<script src="https://webduino.io/components/webduino-js/dist/webduino-all.min.js"></script>
<script src="https://blockly.webduino.io/webduino-blockly.js"></script>
<script src="https://code.jquery.com/jquery-1.9.1.js"></script>
</head>
<body>
  <select id="county"></select>
  <select id="sitename"></select>
  <div id="content"></div>
  <h1 id="h"></h1>
</body>
</html>

JavaScript 的部分一開始先宣告一些變數,還有一個設定檔,如果今天數值大於我們設定黨的數字,就會亮燈並顯示空屋提示。

var $content = $('#content'),
    $county = $('#county'),
    $sitename = $('#sitename'),
    $h = $('#h'),
    $btn = $('#btn');

var county = [];
var site = {};
var result, led;

var config = {
  PM25 : 20,
  PM10 : 40
};

再來就是抓取開放資料的 json 檔,接著對資料做一些轉換,篩選出主要縣市 ( 台北市、新北市...等 ) 以及每個縣市對應的區域 ( 永和、中和...等 ),然後再改變選單的時候,把對應的數值顯示出來,如果數值比較高,就會點亮燈泡以及秀出「空氣污染超標!」的文字

boardReady('你的開發板 ID', function(board) {
  board.systemReset();
  board.samplingInterval = 250;
  led = getLed(board, 10);

  $.get('http://opendata2.epa.gov.tw/AQX.json',function(data){
    data.forEach(function(e,i){
      county[i] = e.County;
    });

    //篩選出父選單縣市名稱(不然會重複)
    result=county.filter(function(element, index, arr){
      return arr.indexOf(element)=== index;
    });

    //初始化父選單
    result.forEach(function(e){
      $county.append('<option value="'+e+'">'+e+'</option>');
    }); 

    //初始化子選單
    _select();

    //當父選單改變時,對應子選單內容
    $county.on('change',function(){
      _select();
    });

    $sitename.on('change',function(){
      _change();
    });

    function _select(){
      $sitename.html(''); //一開始先清空子選單
      data.forEach(function(e,i){
        //挑選對應的地區顯示
        if(e.County == $county.val()){
          $sitename.append('<option value="'+e.SiteName+'">'+e.SiteName+'</option>');
        }
        site[e.SiteName] = [e['PM2.5'],e.PM10];
      });
      _change();
    }

    function _change(){
      var name = site[$sitename.val()];
      $content.html('< '+$sitename.val()+' > PM2.5 ('+name[0]+'), PM10 ('+name[1]+')<br/>');
      if(name[0]>config.PM25 || name[1]>config.PM10){
        $h.text('空氣污染超標!');
        led.on();
      }else{
        $h.text('');
        led.off();
      }
    }

  });
});

完整程式碼:http://bin.webduino.io/sipod/1/edit?html,js,output

空污指數太高時點亮燈泡

Opendata + Webduino ( 後端 )

剛剛我們是使用前端的方法,繼續介紹 Webduino 後端的用法,如果你有印象,在「聊天室 ( 前後端實作 )」有介紹過 Webduino 後端的用法,首先你要先安裝對應的套件,這邊需要 get-jsonwebduino-jswebduino-blockly

npm install webduino-js webduino-blockly get-json

如果你想要在啟動的當下,也有類似對話視窗可以一一輸入資訊的話,可以多安裝 inquirer ( https://www.npmjs.com/package/inquirer )。

npm install inquirer

再來就免不了要寫程式了,最主要跟前端一樣,先抓取對應的縣市 PM2.5 數值,當數值大於多少的時候就亮燈,比較不同的是你可以用一個 setInterval 間隔一段時間抓取一次資料,就可以 24 小時放著讓它自動監控了。

require("webduino-js");
require("webduino-blockly");
var getJSON = require('get-json');
var inquirer = require("inquirer");

var pm = function(a,b,c,d){
    boardReady(a, function(board) {
      board.systemReset();
      board.samplingInterval = 250;
      led = getLed(board, b);

      console.log('裝置連線成功...');

        _getJSON();

        setInterval(function(){
            _getJSON();
        },10000);
    });

    function _getJSON(){
        getJSON('http://opendata2.epa.gov.tw/AQX.json',function(error, response){
          response.forEach(function(e,i){
            if(e.SiteName==d){
                console.log(d+', PM2.5:'+e['PM2.5']+' , PM10:'+e.PM10);
                if(e['PM2.5']>c){
                    led.on();
                }
            };
          });
        });
    }
};

var preguntas = [{
  type: 'input',
  name: 'device',
  message: 'Device ID?',
  default: '你的裝置 ID',
}, {
  type: 'input',
  name: 'led',
  message: 'LED pin?',
  default: '10'
}, {
  type: 'input',
  name: 'rate',
  message: 'PM2.5?',
  default: '20'
}, {
  type: 'input',
  name: 'site',
  message: '縣市名稱',
  default: '前鎮'
}];

inquirer.prompt(preguntas, function(answers) {
}).then(function(answers) {
  console.log(answers.device + ',' + answers.led + ',' + answers.rate + ',' + answers.site);
  pm(answers.device, answers.led * 1, answers.rate * 1, answers.site);
});

抓取對應的縣市 PM2.5 數值,當數值到達某程度時亮燈

小結

以上就是拿 Opendata 來做物聯網應用的範例,雖然說只是點亮一個燈泡,但如果我們可以透過 Webduino 把各種裝置給虛擬化、網路化、變數化,就可以輕鬆地用網頁前端或後端來操控了。