Cookie Consent

วันอาทิตย์ที่ 9 ตุลาคม พ.ศ. 2559

Example code for NodeMCU to connect with server side by using Socket.io and Arduino IDE

In this case, I'm using washo4evr's librady.
Please refer to https://github.com/washo4evr/Socket.io-v1.x-Library

Create folder name ~\SocketIOClient and download SocketIOClient.cpp and SocketIOClient.h to your library directory of Arduino.
Ex. C:\Program Files (x86)\Arduino\libraries\SocketIOClient\


/* [NEED] --- Include something need, example WiFi library, Arduino --- */

#include <SocketIOClient.h>

/* [NEED] --- Declare something need, example WiFi library --- */

SocketIOClient client;

StaticJsonBuffer<200> jsonBuffer;
JsonObject& root = jsonBuffer.createObject();

extern String RID;
extern String Rname;
extern String Rcontent;

char hostip[] = "YOUR_HOST_IP";
int port = YOUR_PORT_NUMBER;

void setup();
void loop();

void setup() {

  /* [NEED] --- Initial anything that you want --- */

  /* [NEED] --- Try to connect to WiFi --- */

  if (!client.connect(hostip, port)) {
    Serial.println("connection failed");
  }
  if (client.connected()){
    client.send("connection", "message", );
  }
}

void loop() {
  if(client.monitor()){

    // Ex. Sending side(package from server)
    //     socket.emit("EVENT_NAME", { "ATTRIBUTE_OF_OBJ" : SOMETHING });

    if(RID == "EVENT_NAME"){
      if(Rname == "ATTRIBUTE_OF_OBJ"){ 
        Serial.print("Got " + Rcontent);
        // Output : Got SOMETHING
      }
    }
  }
}

วันอังคารที่ 4 ตุลาคม พ.ศ. 2559

แสดงข้อมูลบนกราฟแบบ real-time บน AmChart ผ่านทาง Socket.io

( ข้อมูลบางส่วนมีการอ้างอิงถึงเรื่อง real-time web app. )


ข้อมูลแบบ real-time แต่ละคนคงมีที่มาแตกต่างกันไป แต่เนื่องมาจากผมเล่นพวก IoT เอา NodeMCU กับ Socket.io มาวัดค่า something ได้ค่ามาและ แวปแรกที่นึกถึงการแสดงผลบนกราฟ ก็คือ AmChart นั่นเอง เพราะมันสวย, ฟรี(กรณีนี้คือต้องยอมให้เขาติดชื่อโลโก้ของเขาไว้บน chart ของเรา), มีลูกเล่นและรูปแบบของ chart ให้เลือกมากมาย

หลังจากตัดสินใจแล้วว่าใช้ AmChart ก็มาเลือก chart ใน style ที่ใช่กันก่อนที่ลิงค์นี้ https://www.amcharts.com/demos/ เมื่อเลือก chart เสร็จแล้วกด "View Demo Source" ดูครับ เราสามารถเอา code ชุดนี้ไปลอง run บนเครื่องตัวเอง เพื่อให้รู้การทำงาน และจะได้ปรับแต่งให้เข้ากับข้อมูลของเราในภายหลัง

ในขั้นตอนนี้ผมเลือก "Smoothed Line Chart" จากนนั้นมาเตรียม code ฝั่งหน้าเว็บกัน

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    
    <meta http-equiv="X-UA-Compatible" content="IE=edge">    
    <meta name="viewport" content="width=device-width, initial-scale=1">    
    <title>Real-Time tracking data</title>    

    <style>      
      <!--       
      |       
      |      
      | เอา style ของ chart มาใส่ตรงนี้       
      |       
      |      
      -->    
    </style>    
   
    <!-- jQuery ตรงนี้ผมเพิ่มเข้ามาต่างหาก 
         ไม่เกี่ยวกับ AmChart แค่ต้องการทำให้ใช้งาน 
         javascript ง่ายขึ้นเท่านั้น -->    
    <script src="http://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script>    

    <!-- Library สำหรับใช้งาน socket.io -->    
    <script src="https://cdn.socket.io/socket.io-1.4.5.js"></script>    
  
      <!--       
      |       
      |      
      | วาง tag script ของ AmChart ไว้บริเวณนี้       
      |       
      |      
      -->    

    <script>      
      $(document).ready(function(){        
        <!-- กำหนดการเชื่อมต่อกับ server ด้วย socket.io -->        
        var socket = io('YOUR_SERVER_IP:8081/');        
        
        <!--         
        |         
        |        
        | วาง config ของ AmChart ไว้บริเวณนี้         
        |         
        |        
        -->      
      });    
      </script>  
    </head>
  <body>
    
    <!--     
    |     
    |    
    | เอา chart ที่เป็น tag div วางบริเวณนี้    
    |     
    |    
    -->
  </body>
</html>


ภายใน <!-- ??? --> เป็น syntax สำหรับ comment ใน HTML นะครับ เราสามารถ copy code ตัวอย่างดังกล่าวมาวาง block ด้านบนได้เลย ก็จะได้เชยชม chart สวยๆกันแล้วครับ

ส่วนการ refresh chart ตามข้อมูลใหม่ที่รับเข้ามานั้น ผมให้มันทำงานใน callback function ของ socket.io แต่ก่อนอื่น เราจำเป็นต้อง config chart เล็กน้อยเสียก่อน ดังนี้

  1. ที่ dataProvider : ตัว demo จะให้ dummy data ในรูปของ object ใน array มาเพื่อจำลองการทำงาน เราจะเปลี่ยนเป็นตัวแปรที่ชื่อ chartData ซึ่งมันคือ object ตัวนึงที่ return มาจาก generateChartData function
  2. ที่ valueAxes, graphs : เราสามารถสร้างเส้น graph ได้หลายเส้นโดยการเพิ่มข้อมูลตรงส่วนนี้ลงไป
        var chartData = generateChartData();
    var chart = AmCharts.makeChart("chartdiv", {
        "type": "serial",
        "theme": "light",
        "marginRight": 80,
        "dataProvider": chartData,
        "synchronizeGrid":true,
        "valueAxes": [{
            "position": "left",
            "axisColor": "#2EFEF7",
            "title": "Analog"
        },{
            "position": "left",
            "axisColor": "#66FF00",
            "title": "Digital"
        }],
        "graphs": [{
            "id": "g1",
            "fillAlphas": 0.2,
            "lineColor": "#2EFEF7",
            "type": "smoothedLine",
            "valueField": "analog",
             "balloonText": "<div style='margin:3px; font-size:14px;'>Analog:<b>[[value]]</b></div>"
        },{
            "id": "g2",
            "lineColor": "#66FF00",
            "type": "smoothedLine",
            "valueField": "digital",
             "balloonText": "<div style='margin:3px; font-size:14px;'>Digital:<b>[[value]]</b></div>"
        }],
        "chartScrollbar": {
            "graph": "g1",
            "scrollbarHeight": 80,
            "backgroundAlpha": 0,
            "selectedBackgroundAlpha": 0.1,
            "selectedBackgroundColor": "#888888",
            "graphFillAlpha": 0,
            "graphLineAlpha": 0.5,
            "selectedGraphFillAlpha": 0,
            "selectedGraphLineAlpha": 1,
            "autoGridCount": true,
            "color": "#AAAAAA"
        },
        "chartCursor": {
            "categoryBalloonDateFormat": "HH:mm, DD MMMM",
            "cursorPosition": "mouse"
        },
        "categoryField": "date",
        "categoryAxis": {
            "minPeriod": "ss",
            "parseDates": true
        },
        "export": {
            "enabled": true,
             "dateFormat": "YYYY-MM-DD HH:mm:ss"
        }
    });

บางครั้งการรับข้อมูลมาวาดกราฟจำนวนมาก เส้นกราฟติดกันเกินไปอาจทำให้ดูไม่รู้เรื่องได้ เราสามารถกำหนดขอบเขตข้อมูลที่เอาไว้โชว์หรือเอาเท่าที่อยากดูเท่านั้น โดย set ให้ chart ทำการ zoom ไปที่ data เท่าที่เราต้องการเมื่อมีการอัพเดทข้อมูลลง chart

chart.addListener("dataUpdated", zoomChart);
zoomChart();

โดยที่ function generateChartData และ zoomChart เป็นดังนี้

  1. zoomChart : ผมให้ chart โชว์ข้อมูลย้อนหลังแค่ 10 ชุดข้อมูล
  2. generateChartData : ผมสร้าง array ว่างๆไว้ตัวนึง แล้วก็ดึง วันเวลาปัจจุบันมาเก็บไว้ พร้อมกับกำหนดค่าเริ่มต้นให้กับ chart โดยการยัด object { date: newDate, value: 0 } ลงไปใน array
  function zoomChart() {
    // different zoom methods can be used - zoomToIndexes, zoomToDates, zoomToCategoryValues
    chart.zoomToIndexes(chartData.length - 10, chartData.length);
  }

  // generate some random data, quite different range
  function generateChartData() {
    var chartData = [];
    currentDate = new Date();
    currentDate.setSeconds(currentDate.getDate());

    var newDate = new Date(currentDate);
    newDate.setSeconds(newDate.getSeconds());

    // add data item to the array

    chartData.push({
      date: newDate,
      value: 0
    });

    return chartData;
  }

มาถึงส่วนอัพเดทข้อมูลลง chart ครับ โดยจะรอรับค่าผ่าน event ในที่นี้ชื่อ "update_chart" แล้วนำค่าที่ได้ เลือกมาเฉพาะค่าที่เป็นค่า digital จาก NodeMCU ยัดใส่ array ที่เตรียมไว้(ข้อมูลทุกชุดจะถูกเก็บลงในตัวแปรตัวนี้) แล้วทำการ assign array ดังกล่าวให้กับ dataProvider แล้วทำการเรียก validateData function เพื่อทำการ redraw chart

  socket.on('update_chart', function(data){
    // Assume object 'data' to be:
    // data = { 
    //   analog: 300, 
    //   digital: 1023
    // }
    console.log(data);
    var newDate = new Date(currentDate);
    newDate.setSeconds(newDate.getSeconds() + 1);

    chartData.push({
      date: newDate,
      value: data.digital,
    });

    chart.dataProvider = chartData;

    chart.validateData();
  });

เท่านี้ก็จะได้เห็น real-time data ผ่านทาง AmChart แล้วครับ