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 แล้วครับ


วันศุกร์ที่ 30 กันยายน พ.ศ. 2559

Handwriting - มาฝึกเขียน Japanese alphabet กัน

มาฝึกเขียนตัวอักษรญี่ปุ่นกัน ช่วงนี้เตรียมสอบญี่ปุ่น แต่ยังจำตัวอักษรไม่ค่อยได้เลย ต้องหาที่ระบาย แต่ปัญหาคือว่างฝึกก็มีแค่ตอนนั่งรถกลับบ้าน จะฝึกเขียนยังไงล่ะเนี่ย มีโอกาสไปเจอของดีเข้ามันจะทำการแปลง Canvas ไปเป็นอักขระ(ถ้าเราวาดใก้ลเคียงนะ) เลยยกมันมาไว้ในนี้ซะเลย เผื่อมีใครสนใจฝึก

เขียนตัวอักษรด้านล่างเลย

ความหนาของเส้น 10

ภาษา :


ผล :

วันอาทิตย์ที่ 25 กันยายน พ.ศ. 2559

การใช้งาน PuTTY ขั้นต้น

    PuTTY เป็น SSL และ telnet client หรือ พูดง่ายๆ เป็นตัวช่วยในการเชื่อมต่อไปยังอีกเครื่องผ่านหน้า console ดำๆ ด้วย Windows ขั้นตอนที่กำลังจะกล่าวถึง อ้างถึงการ connect ไปยัง Amazon Web Services (AWS) เท่านั้นนะครับ หากใครใช้งานอย่างอื่น ลองประยุกต์ใช้กันดูนะครับ

การติดตั้ง

    ตัว PuTTY ที่เราสนใจมี 2 ตัวด้วยกันคือ putty.exe และ puttygen.exe ซึ่งใช้งานต่างกันโดย
putty.exe - เป็นตัวหลักที่ใช้ในการ connect ไปยังอีกเครื่องผ่านหน้า console
puttygen.exe - เป็นตัวจัดการ key ที่ใช้ในการ access ไปยัง AWS (ผมจะถูกถึงแค่การแปลง .pem เป็น .pkk เพื่อใช้กับ FileZilla เท่านั้น สามารถติดตามได้ในส่วนของ FileZilla) 
     คุณสามารถ download ผ่านทาง ลิงค์นี้


การตั้งค่า

    1. ทำการ run putty.exe 
    2. ที่แถบด้านซ้าย ไปที่ Connection -> SSH -> Auth พื้นที่ด้านขวา เลือก Browse...

    3. เลือก key ที่ได้จาก AWS (.pem ซึ่ง download ได้ตอนเปิด instance) 
    4. ที่แถบด้านขวา ไปที่ Session ใส่ IP ของ instance ที่เราเปิดไว้ใน AWS console
    5. ที่หัวข้อ Saved Session ใส่ชื่อตามต้องการ แล้วกด Save เพื่อที่ครั้งหน้า จะได้โหลดมาใช้ได้เลย

การเชื่อมต่อ

    หลังจาก config ค่าทั้งหมดแล้ว กด Open แล้วหน้า console ดำๆจะแสดงขึ้นมา โดยส่วนใหญ่ถ้าไม่ได้ ตั้งค่าอะไรมาก่อนที่ AWS ก็จะใช้รหัส "ubuntu" ในการเข้าถึง AWS

เท่านี้คุณก็สามารถเชื่อต่อกับ instance ของคุณที่เปิดขึ้นบน AWS ได้แล้ว บทความต่อๆไปจะมา support การใช้งาน secure shell(SSH) client ดังกล่าวให้ง่ายขึ้น รอติดตามด้วยนะครับ

ทำ Real-Time web application บน Amazon Web Services(AWS) ด้วย Node.js + Socket.IO

บทความนี้จะกล่าวถึงการ coding เพื่อทำ WebSocket ด้วย Node.js และ framework ที่ชื่อ Socket.io บน AWS EC2 เท่านั้น ไม่มีบริการอื่นเข้ามาเกี่ยวข้อง  ซึ่งภาษาที่ใช้จะเป็น JavaScript ทั้งหมด
ข้อดี สามารถปรับเปลี่ยนแก้ไขการทำงานต่างๆด้วยตนเองได้ทั้งหมด
ข้อเสีย อาจต้องใช้เวลาในการเรียนเพิ่มขึ้นรู้สำหรับผู้เริ่มต้นหรือไม่มีความคุ้นเคยกับ AWS, Unix Environment และ JavaScript 

สิ่งที่ต้องใช้


Framework

    Node.js [https://nodejs.org/en/]    

เป็น JavaScript runtime ที่สร้างบน Chrome's V8 JavaScript engine พัฒนาโดย Google (ตามอ่านรายละเอียดได้ ที่นี่) การทำงานของ Node.js จะเป็นในลักษณะ event-driven และ non-blocking ซึ่งทำให้มันมีประสิทธิภาพและไม่หนักเครื่อง โดยมี library package มากมายที่ผู้พัฒนาจากทั่วโลกทำขึ้นมา support ในงานต่าง เราสามารถติดตั้งด้วยคำสั่ง npm และที่สำคัญคือเป็น open source

     Socket.io [http://socket.io/]    

เป็น JavaScript framework ที่ใช้ในการส่งข้อมูลแบบ real-time แบบ bidirectional และ เป็น event-based ที่ค่อนข้างเร็วและเสถียร แต่ Socket.io อาจจะไม่เหมาะสมกับการเชื่อมต่อหลายๆ connection (1,000+ connection) หากจำต้องใช้ WebSocket ในงานของคุณจริงๆ อาจต้อง config เพิ่มเติมหรือใช้งาน framework หรือ engine ตัวอื่นมา support ครับ 

การติดตั้ง

    หลังจากติดตั้ง Node.js แล้วให้ทำการเปิดหน้า console ขึ้นมาโดยกด WinKey + R พิมพ์ cmd แล้ว Enter แล้วทำการ check ว่า Node.js ใช้งานได้หรือไม่โดยพิมพ์
node -v

แสดง version ของ Node.js

ถ้า console return version ของ Node.js ได้เป็นอันใช้ได้ครับ ทำการติดตั้ง Socket.io และ Express.js โดยพิมพ์

npm install --save socket.io
npm install --save express

เราใส่ --save ด้วยเพื่อที่ทำการติดตั้งลงบน directory ที่เราต้องการเท่านั้น (กรณีไม่ใส่ มันจะทำการติดตั้งไว้ที่ default path ข้อดีคือ run ได้ทุก project แต่ข้อเสียคือตอนที่นำ project ไปใช้ที่อื่น จำต้อง copy package ดังกล่าวติดไปด้วย เพื่อความสะดวกจึงใส่ option --save ไปด้วย) รอจนกระทั่งติดตั้งเสร็จ

Coding


    เราจะเริ่มจาก implement ฝั่ง server ก่อน ตามด้วยฝั่ง client โดย source code 2 files นี้อยู่ใน folder หรือ directory เดียวกัน ดูได้จาก code ตัวอย่างด้านล่าง (คำอธิบายดูได้จาก comment ใน code นะครับ)

  File name : server.js
// เรียกใช้ framework สำหรับ web application var express = require('express'); var app = express(); // กำหนดให้เชื่อต่อกับ server ด้วย http var http = require('http').Server(app); // ใช้งาน socket protocal ผ่านทาง http var io = require('socket.io')(http); // กำหนด port ในการเข้าถึง server var port = 8090; app.get("/", function(req, res) { res.sendFile(__dirname + '/index.html'); }); // input/output สำหรับการเข้าถึง web io.on('connection', function(socket){ // รอรับ object หรือ message ผ่าน event ชื่อ 'send-whatever' จาก client socket.on('send-whatever', function(data) { console.log('Got message : ' + data); // ส่ง object -> [ 'server received : ' ตามด้วย data ] ผ่าน event ชื่อ 'receive-whatever' ไปยัง client socket.emit('receive-whatever', 'server received : ' + data); }); }); // รอรับข้อมูลจาก client ผ่านทาง http://[host IP]:[port] http.listen(port, function(){ console.log('listening on *:' + port); });
    ทำการ run code ฝั่ง server โดยพิมพ์คำสั่งในหน้า console ว่า

node server.js

    ตอนนี้ server จะรอรับการเชื่อมต่อจาก client เรามาดู code ฝั่ง web client กัน

  File name : index.html
<!DOCTYPE html> <html> <head> <!-- กำหนดคุณสมบัติของหน้า web --> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- ชื่อ web --> <title>Real-Time web application</title> <!-- Library zone --> <!-- Bootstrap : Latest compiled and minified CSS --> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> <!-- jQuery --> <script src="http://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script> <!-- Bootstrap : Latest compiled and minified JavaScript --> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script> <!-- Socket.io --> <script src="https://cdn.socket.io/socket.io-1.4.5.js"></script> <!-- กำหนด function การทำงานต่างๆในนี้ --> <script> // รอจนโหลดหน้า web เสร็จจึงค่อยทำ $(document).ready(function(){ // เชื่อมต่อ websocket ด้วย IP(ตัวอย่างเช่น 52.123.456.78) ของ instance บน AWS var socket = io('http://52.123.456.78:8090/'); // เมื่อกดปุ่ม 'Send' ข้อความที่ tag id 'textMsg' จะถูก get ค่าและส่งไปยัง server $("#sendBtn").click(function(){ socket.emit('send-whatever', $("#textMsg").val()); }); // รอรับการตอบกลับจาก server ผ่าน event ชื่อ 'receive-whatever' socket.on('receive-whatever', function(data){ // แล้ยวทำการเพิ่มข้อความในหน้าเว็บลงใน element id 'listMsg' $("#listMsg").append('<li class="list-group-item">' + data + '</li>'); }); }); </script> </head> <body> <!-- หน้าตา web --> <div class="wrapper"> <div class="container"> <div class="row text-center"> <div class=".col-md-4"></div> <div class=".col-md-4"> <h2>Real-Time message</h2> <div class="input-group"> <span class="input-group-btn"> <button class="btn btn-default" type="button" id="sendBtn">Send</button> </span> <input id="textMsg" type="text" class="form-control" placeholder="sending your message here..."> </div><!-- /input-group --> </div> <div class=".col-md-4"></div> </div> <div class="row text-center"> <ul id="listMsg" class="list-group"> </ul> </div> </div> </div> </body> </html> 
    ผลลัพธ์ที่ได้คือ server จะตอบกลับ client ด้วยสิ่งเดียวกับที่ client ส่งมายัง server

การใช้งาน FileZilla ขั้นต้น


บทความนี้อ้างถึงการเข้าถึง Amazon Web Services(AWS) เป็นหลัก ผู้ที่ใช้งาน service ประเภทอื่นลองประยุกต์ใช้ดูนะครับ

FileZilla ถูกใช้เป็นตัว transfer file จากเครื่องๆหนึ่งไปยังอีกเครื่องหนึ่ง ซึ่ง support การเชื่อมต่อได้หลายรูปแบบ ในที่นี้จะกล่าวถึงการเชื่อมต่อแบบ SSH ที่มีความปลอดภัยสูงผ่าน private key ที่ถูกแปลงมาจาก .pem ด้วย puttygen.exe เพื่อเข้าถึง instance ของเราใน AWS  

การติดตั้ง

    ติดตั้งลง directory ที่คุณต้องการได้ทุกที่ คุณสามารถ download FileZilla ได้ ที่นี่

การตั้งค่า

    1. ทำการเพิ่ม private key (.ppk) โดยไปที่ Edit -> Setting -> SFTP -> Add key file... แล้วทำการเลือก key ที่ได้จาก AWS กรณีที่ยังไม่ทำการแปลง .pem เป็น .ppk ตัว FileZilla จะทำการแปลงให้ครับ


    2. กำหนด IP ที่ใช้ประจำโดยไปที่ File -> Site Manager...
    3. ทำการใส่ IP ของ instance ที่เราใช้ ส่วนของการ login เลือก Normal แล้วใส่ User เป็น ubuntu หลังจากนี้ทุกครั้งคุณก็แค่เลือก instance ที่คุณใช้ ไม่ต้อง set ใหม่ทุกรอบ



การใช้งาน

    ผู้ที่พัตนา website หรือ ฝั่ง client รวมถึงผู้ที่ดูแลฝั่ง server จะมีการใช้งานหลักๆคือ upload script หรือ source code ที่ตนพัฒนาไปยัง host หรือ instance ที่ใช้งานอยู่ โดยการเชื่อมต่อไปยัง IP ที่ตั้งค่าเอาไว้ หลังจากนั้นโปรแกรมจะโชว์ directory ที่มีทั้งหมดของเรา(ซ้าย)และ instance ที่เราเชื่อมต่อ(ขวา) ถ้าต้องการ upload file ก็สามารถทำการลาก file วางลงใน directory ที่ต้องการทางช่องขวาได้เลย