아두이노프로세싱 프로그래밍

NodeMCU WiFi 웹서버가 생성한 실시간가변저항 전압데이터를 스마트 폰에서 구글차트 그래프 작성 II:

coding art 2017. 1. 24. 19:16
728x90

바로 앞 예제는 구글 차트에서 제공하는 이미 정해진 7개의 점 데이터를 그래프 기능을 사용하여 스마트 폰에서 그래프를 그려 보았다.
본 예제에서는 NodeMCU에 설치된 가변저항을 서서히 돌림으로 인해 가변 저항 양단에 걸리는 실시간으로 변동되는 전압 데이터를 구글 그래프로 나타내고자 한다.
프로그램 중간에 하나의 전압 데이터를 생성하고 다음 데이터를 생성하기까지의 시간지연을 500ms 즉 0.5초로 두었다.
일곱 개의 점 데이터를 생성하고자 하면 이때의 점 데이터는 2부터 8까지 증가하는 정수 i를 x좌표로 하고 analogRead(A0)에 의해 읽은 전압 데이터를 100으로 나누어 y좌표로 삼기로 한다. 그렇다면 전압데이터는 약 0∼10까지의 범위를 가지게 된다.
100으로 나누는 이유는 만약 전압데이터가 거의 변동이 없이 1023 근처에 머물 경우 그래프 작성 시에 그래프 작성 높이 범위가 900에서 1100 사이로 제한될 수 있다. 그러다가 1000에서 0까지 전압 값이 급변하게 되면 그래프 작성 영역이 0에서 1000으로 변경되게 된다. 즉 Data Refresh 할 때에 그래프 틀이 바뀌게 된다. 각자가 필요하다면 프로그램을 수정하여 구글 차트의 그래프 작성 요령을 확인해 보기 바란다.
본 예제에서는 0에서 10까지 범위를 대상으로 가변 저항을 돌려 실시간으로 변동이 일어나는 전압 데이터를 관찰해 보기로 한다.
앞 예제와 프로그램 구조가 거의 변동이 없기 때문에 변동되는 부분만의 프로그램을 제시하기로 한다.


구글 차트 예제의 점 데이터 부분 프로그램

client.println("[2, 2.5],");
client.println("[3, 3],");
client.println("[4, 4],");
client.println("[5, 4],");
client.println("[6, 3],");
client.println("[7, 2.5],");
client.println("[8, 3]");
client.println("]);");


위의 프로그램을 다음과 같이 변경한다. for를 사용한 loop 문 다음에 한 번 더 되풀이되는 프로그램은 좌표 데이터 기술의 마지막에 콤마(,)가 없어야하기 때문이다.

for(int i=2;i<8;i++){
// 아나로그입력 생성(0-1023):1023=3.3V
int val = analogRead(A0)/100;
client.println("[");
client.print(i);
client.print(",");
client.print(val);
client.println("],");
delay(500);
};
int i = 8;
int val = analogRead(A0)/100;
client.println("[");
client.print(i);
client.print(",");
client.print(val);
client.println("]");
client.println("]);");


그 다음에 작성하려는 점 데이터 수 가 7개이므로 그 하단에 수평 축 즉 hAxis에서 최대치 maxValue를 8로 수정하기로 한다. 10으로 할 경우 추가로 있지도 않은 마지막 데이터 2개를 계속해서 출력하는 것으로 보인다.

client.println("hAxis: { minValue: 0, maxValue: 8 },");


전압 데이터 하나를 출력 후 지연 시간이 500ms 이므로 여유있게 가변 저항을 돌려 보도록 한다.
이미 설명하였듯이 0에서 8까지 7개의 점 데이터가 매끈하게 그래프로 작성되었다. 점 한 개 당 프로그램 연산 시간 및 지연 시간 500ms를 합쳐 점 7개를 작도함에 약 5초를 넘지 않으나 네트워크를 타고 데이터가 넘어 오는 시간이 있으며 아울러 구글 차트가 이들 데이터 전체를 받은 후 한 번에 그래프를 작성한다.
그래서 한 점 한 점 실시간으로 작성하지는 않으니 주의하기 바란다.
아울러 구글 차트 프로그램 구문에 y좌표 값 최대치에 대한 제한 설정이 없는 것으로 보아 일단 작성할 데이터를 전부 받은 후 그래프의 가로 축 세로 축 범위를 설정하는 듯하다.


Thingspeak에서 샘플 처리 타임이 최소 15초였으나 본 프로그램 수행에서는 적어도 1초 이하로 단축되었음을 확인할 수 있으며 아울러 이 그래프 작성을 위해 구글차트가 내부적으로 구글 스프레드쉬트에 데이터를 시간기록과 함께 저장한 것으로 추정된다. 그래프로 작성된 데이터를 다시 복구하기 위해서는 구글 스프레드쉬트 사용법에 대한 이해가 필요하리라 보며 이러한 점들이 명확해지면 데이터 서버 역할을 하는 스마트 폰에서 보다 빠른 속도로 데이터를 처리할 수 있을 것이다.




//Webserver_nodemcu_googlechart_01

 #include <ESP8266WiFi.h>

 const char* ssid = "android1234";
 const char* password = "dddddddddd";

 int ledPin = 2; //
 
 WiFiServer server(80);

 void setup() {
   Serial.begin(115200);
   delay(10);

   pinMode(ledPin, OUTPUT);
   digitalWrite(ledPin, HIGH);

   // Set WiFi to station mode and disconnect from an AP if it was previously connected
   WiFi.mode(WIFI_STA);
   WiFi.disconnect();
   delay(100);

   Serial.println("Setup done");

   // Connect to WiFi network
   Serial.println();
   Serial.println();
   Serial.print("Connecting to ");
   Serial.println(ssid);

   WiFi.begin(ssid, password);

   while (WiFi.status() != WL_CONNECTED) {
     delay(500);
     Serial.print(".");
   }
   Serial.println("");
   Serial.println("WiFi connected");

   // Start the server
   server.begin();
   Serial.println("Server started");

   // Print the IP address
   Serial.print("Use this URL to connect: ");
   Serial.print("http://");
   Serial.print(WiFi.localIP());
   Serial.println("/");

 }

 void loop() {
   // Check if a client has connected
   WiFiClient client = server.available();
   if (!client) {
     return;
   }

   // Wait until the client sends some data
   Serial.println("new client");
   while(!client.available()){
     delay(1);
   }

   // Read the first line of the request
   String request = client.readStringUntil('\r');
   Serial.println(request);
   client.flush();

   // Match the request

   int value = LOW;
   if (request.indexOf("/LED=ON") != -1)  {
     digitalWrite(ledPin, LOW);
     value = HIGH;
   }

 // Set ledPin according to the request


   // Return the response
   client.println("HTTP/1.1 200 OK");
   client.println("Content-Type: text/html");
   client.println(""); //  do not forget this one
   client.println("<!DOCTYPE HTML>");
   client.println("<html>");

client.println(" <head>");
client.println("<script type='text/javascript' src='https://www.gstatic.com/charts/loader.js'></script>");
client.println("<script type='text/javascript'>");
client.println("google.charts.load('current', {packages:['corechart']});");
client.println("google.charts.setOnLoadCallback(drawChart);");
client.println("function drawChart() {");
client.println("var data = google.visualization.arrayToDataTable");
client.println("([['X', 'Y'],");
for(int i=2; i<8; i++)  {
// 아나로그입력 생성(0-1023):1023=3.3V
int val = analogRead(A0)/100;
client.println("[");
client.print(i);
client.print(",");
client.print(val);
client.println("],");
delay(500);
};
int i = 8;
int val = analogRead(A0)/100;
client.println("[");
client.print(i);
client.print(",");
client.print(val);
client.println("]");
client.println("]);");


client.println("var options = {");
client.println("legend: 'none',");
client.println("hAxis: { minValue: 0, maxValue: 8 },");
client.println("curveType: 'function',");
client.println("pointSize: 20,");
client.println("};");

client.println("var chart = new google.visualization.LineChart(document.getElementById('chart_div'));");
client.println("chart.draw(data, options);");
client.println("}");
client.println("</script>");
client.println("</head>");
client.println("<body>");
client.println("<div id='chart_div' style='width: 900px; height: 500px;'></div>");
client.println("  </body>");

   client.println("<br><br>");
   client.println("<a href=\"/on\"\"><button>Data Refresh </button></a><br />");          
   client.println("</html>");
   delay(1);
   Serial.println("Client disonnected");
   Serial.println("");

 }//끝