2017/05/28
4桁7セグで遊ぶ(7)
前回の続きです。今回、UART通信でWi-FiモジュールのESP8266へデータを飛ばして、iPadからデータを確認できるようにしました。基本的には以前のブログに記載のArduinoのサンプルプログラムAdvancedWebserverを利用しました。
完成品は写真の通りです。


PICプログラムの変更点は、気温、気圧、湿度、不快指数のデータ転送する際に、それぞれT、P、H、Dの識別子を追加したこと。受け取るESP8266側で何のデータが転送されたかを識別させるためです。一点はまってしまったのは、小数点データの文字変換の際にsprintf関数を使ってうまく行かなかった点。しばらくこんな表示で悩んでいました。

//temperature_s: char型, temperature_f: float型調べてみないと分からないことが多くありますね。
sprintf(temperature_s, "%2.1f", temperature_f); //NG
dtostrf(temperature_f,5,1,temperature_s); //OK
プログラムは、それぞれの計測項目について、過去40データ分をグラフに表示させます。グラフはサンプルプログラムのままScalable Vector Graphics(SVG)形式で描画しています。コードはいろいろ詰め込みすぎてかなりごちゃごちゃしていますが・・。
#include <ESP8266WiFi.h>このテーマ、長々とやってきましたが、ようやく一通り目処が立ちましたので、クローズにしたいと思います。
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char *ssid = "*****"; //user setting
const char *password = "*****"; //user setting
ESP8266WebServer server ( 80 );
IPAddress ip( 192, 168, 11, 200 );
IPAddress subnet( 255, 255, 255, 0 );
char buff[16];
char buff_temp[16];
char temperature[16];
char atmospheric_pressure[16];
char humidity[16];
char discomfort_index[16];
int counter = 0;
float temperature_f[40];
float atmospheric_pressure_f[40];
float humidity_f[40];
float discomfort_index_f[40];
void drawGraph() {
String out = "";
char temp[800];
int ost_x = 100;
int ost_y = 20;
float Tmax = 30.0;
float Tmin = 20.0;
float Pmax = 1010.0;
float Pmin = 990.0;
float Hmax = 80.0;
float Hmin = 30.0;
float Dmax = 85.0;
float Dmin = 65.0;
char lbl[5];
out += "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" width=\"500\" height=\"820\">\n";
for(int i=0;i<4;i++){
sprintf(temp, "<rect x=\"%d\" y=\"%d\" width=\"400\" height=\"160\" fill=\"rgb(204, 204, 255)\" stroke-width=\"1\" stroke=\"rgb(0, 0, 0)\" />\n",ost_x,ost_y+200*i);
out += temp;
for(int j=0;j<3;j++){
sprintf(temp, "<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" fill=\"none\" stroke=\"gray\" stroke-width=\"1\" stroke-dasharray=\"5 5\" />\n", ost_x, ost_y+200*i+40*(j+1), ost_x+400, ost_y+200*i+40*(j+1));
out += temp;
}
}
out += "<g stroke=\"black\">\n";
for(int i=0;i<5;i++){ //y目盛
memset(lbl,'\0',strlen(lbl));
dtostrf(Tmax-i*(Tmax-Tmin)/4,5,1,lbl);
sprintf(temp, "<text x=\"%d\" y=\"%d\">%s</text>\n", 65, ost_y+i*40,lbl);
out += temp;
memset(lbl,'\0',strlen(lbl));
dtostrf(Pmax-i*(Pmax-Pmin)/4,5,0,lbl);
sprintf(temp, "<text x=\"%d\" y=\"%d\">%s</text>\n", 65, 200+ost_y+i*40,lbl);
out += temp;
memset(lbl,'\0',strlen(lbl));
dtostrf(Hmax-i*(Hmax-Hmin)/4,5,1,lbl);
sprintf(temp, "<text x=\"%d\" y=\"%d\">%s</text>\n", 65, 400+ost_y+i*40,lbl);
out += temp;
memset(lbl,'\0',strlen(lbl));
dtostrf(Dmax-i*(Dmax-Dmin)/4,5,1,lbl);
sprintf(temp, "<text x=\"%d\" y=\"%d\">%s</text>\n", 65, 600+ost_y+i*40,lbl);
out += temp;
}
//yラベル
sprintf(temp, "<text writing-mode=\"tb\" x=\"45\" y=\"%d\">%s</text>\n",50,"気温[℃]");
out += temp;
sprintf(temp, "<text writing-mode=\"tb\" x=\"45\" y=\"%d\">%s</text>\n",250,"気圧[㍱]");
out += temp;
sprintf(temp, "<text writing-mode=\"tb\" x=\"45\" y=\"%d\">%s</text>\n",450,"湿度[%]");
out += temp;
sprintf(temp, "<text writing-mode=\"tb\" x=\"45\" y=\"%d\">%s</text>\n",650,"不快指数[%]");
out += temp;
for (int x=38;x>-1;x--) { //グラフプロット
int Ty1 = 160 + ost_y - (int)((temperature_f[x+1]-Tmin)*160.0/(Tmax-Tmin));
int Ty2 = 160 + ost_y - (int)((temperature_f[x]-Tmin)*160.0/(Tmax-Tmin));
if(Ty1>160+ost_y){Ty1=160+ost_y;}
if(Ty2>160+ost_y){Ty2=160+ost_y;}
if(Ty1<ost_y){Ty1=ost_y;}
if(Ty2<ost_y){Ty2=ost_y;}
sprintf(temp, "<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" stroke-width=\"1\" />\n", (39-x)*10+ost_x, Ty1, (39-x+1)*10+ost_x, Ty2);
out += temp;
int Py1 = 360 + ost_y - (int)((atmospheric_pressure_f[x+1]-Pmin)*160.0/(Pmax-Pmin));
int Py2 = 360 + ost_y - (int)((atmospheric_pressure_f[x]-Pmin)*160.0/(Pmax-Pmin));
if(Py1>360+ost_y){Py1=360+ost_y;}
if(Py2>360+ost_y){Py2=360+ost_y;}
if(Py1<ost_y+200){Py1=ost_y+200;}
if(Py2<ost_y+200){Py2=ost_y+200;}
sprintf(temp, "<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" stroke-width=\"1\" />\n", (39-x)*10+ost_x, Py1, (39-x+1)*10+ost_x, Py2);
out += temp;
int Hy1 = 560 + ost_y - (int)((humidity_f[x+1]-Hmin)*160.0/(Hmax-Hmin));
int Hy2 = 560 + ost_y - (int)((humidity_f[x]-Hmin)*160.0/(Hmax-Hmin));
if(Hy1>560+ost_y){Hy1=560+ost_y;}
if(Hy2>560+ost_y){Hy2=560+ost_y;}
if(Hy1<ost_y+400){Hy1=ost_y+400;}
if(Hy2<ost_y+400){Hy2=ost_y+400;}
sprintf(temp, "<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" stroke-width=\"1\" />\n", (39-x)*10+ost_x, Hy1, (39-x+1)*10+ost_x, Hy2);
out += temp;
int Dy1 = 760 + ost_y - (int)((discomfort_index_f[x+1]-Dmin)*160.0/(Dmax-Dmin));
int Dy2 = 760 + ost_y - (int)((discomfort_index_f[x]-Dmin)*160.0/(Dmax-Dmin));
if(Dy1>760+ost_y){Dy1=760+ost_y;}
if(Dy2>760+ost_y){Dy2=760+ost_y;}
if(Dy1<ost_y+600){Dy1=ost_y+600;}
if(Dy2<ost_y+600){Dy2=ost_y+600;}
sprintf(temp, "<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" stroke-width=\"1\" />\n", (39-x)*10+ost_x, Dy1, (39-x+1)*10+ost_x, Dy2);
out += temp;
}
out += "</g>\n</svg>\n";
server.send ( 200, "image/svg+xml", out);
}
void handleRoot() {
char temp[1000];
int sec = millis() / 1000;
int min = sec / 60;
int hr = min / 60;
snprintf ( temp, 1000,
"<html>\
<head>\
<meta http-equiv='refresh' content='5'/>\
<title>BME280 Measure</title>\
<style>\
body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; }\
</style>\
</head>\
<body>\
<h2>BME280 Measurement</h2>\
<h2><p>Uptime: %02d:%02d:%02d</p></h2>\
<h2><p>Temperature: %s [°C]</p></h2>\
<h2><p>Atmospheric pressure: %s [hPa]</p></h2>\
<h2><p>Humidity: %s [%]</p></h2>\
<h2><p>Discomfort Index: %s [%]</p></h2>\
<img src=\"/test.svg\" />\
</body>\
</html>",
hr, min % 60, sec % 60,temperature,atmospheric_pressure,humidity,discomfort_index
);
server.send ( 200, "text/html", temp );
}
void handleNotFound() {
String message = "File Not Found\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += ( server.method() == HTTP_GET ) ? "GET" : "POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for ( uint8_t i = 0; i < server.args(); i++ ) {
message += " " + server.argName ( i ) + ": " + server.arg ( i ) + "\n";
}
server.send ( 404, "text/plain", message );
}
void setup ( void ) {
//変数初期化
for(int i=0;i<40;i++){
temperature_f[i]=0.0;
atmospheric_pressure_f[i]=0.0;
humidity_f[i]=0.0;
discomfort_index_f[i]=0.0;
}
Serial.begin ( 19200 );
WiFi.mode(WIFI_AP);
WiFi.softAPConfig(ip, ip, subnet);
WiFi.softAP(ssid, password);
server.begin();
server.on ( "/", handleRoot );
server.on ( "/test.svg", drawGraph );
server.on ( "/inline", []() {
server.send ( 200, "text/plain", "this works as well" );
} );
server.onNotFound ( handleNotFound );
server.begin();
Serial.println ( "HTTP server started" );
}
void loop ( void ) {
if(Serial.available()>0){
if(counter == 0){memset(buff,'\0',strlen(buff));}
char data = Serial.read();
buff[counter] = data;
if (data == '\n'){
buff[counter]='\0';
memset(buff_temp,'\0',strlen(buff_temp));
strncpy(buff_temp,buff,strlen(buff)-2); //T, P, H, Dの文字削除
if(strstr(buff,"T") != NULL){ //気温
for(int i=38;i>-1;i--){temperature_f[i+1] = temperature_f[i];}
temperature_f[0] = atof(buff_temp) / 10.0;
memset(temperature,'\0',strlen(temperature));
dtostrf(temperature_f[0],5,1,temperature);
}
else if(strstr(buff,"P") != NULL){ //気圧
for(int i=38;i>-1;i--){atmospheric_pressure_f[i+1] = atmospheric_pressure_f[i];}
if(buff_temp[0]=='9'){
atmospheric_pressure_f[0] = atof(buff_temp) / 100.0;
}else{
atmospheric_pressure_f[0] = atof(buff_temp) / 10.0;
}
memset(atmospheric_pressure,'\0',strlen(atmospheric_pressure));
dtostrf(atmospheric_pressure_f[0],5,0,atmospheric_pressure);
}
else if(strstr(buff,"H") != NULL){ //湿度
for(int i=38;i>-1;i--){humidity_f[i+1] = humidity_f[i];}
humidity_f[0] = atof(buff_temp) / 10.0;
memset(humidity,'\0',strlen(humidity));
dtostrf(humidity_f[0],5,1,humidity);
}
else if(strstr(buff,"D") != NULL){ //不快指数
for(int i=38;i>-1;i--){discomfort_index_f[i+1] = discomfort_index_f[i];}
discomfort_index_f[0] = atof(buff_temp) / 100.0;
memset(discomfort_index,'\0',strlen(discomfort_index));
dtostrf(discomfort_index_f[0],5,1,discomfort_index);
}
counter = 0;
}
else{
counter++;
}
}
server.handleClient();
}