先日作った身長測定器だが、3人まとめて測定後サーバーへ転送し、電源オフでデータ消えてしまうため測定時3人が揃っている必要があった。
それは面倒なので、測定データはESP8266のSPIFFSに一旦保存しサーバー転送後にデータをクリアする方式に変更した。
以下、ソースコード。
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <WebSocketsServer.h>
#include <Hash.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <FS.h>
#include <Adafruit_NeoPixel.h>
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <ESP_Adafruit_SSD1306.h>
#define PIN_D1 5
#define PIN_D2 4
#define PIN_D3 0
#define PIN_D4 2
#define PIN_D5 14
#define PIN_D6 12
#define PIN_D7 13
#define PIN_D8 15
#define BUILTIN_LED 2
const unsigned char pic_cloud[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0xfe, 0x03, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x18, 0x7e, 0x00, 0x00, 0x00, 0xe0, 0x00, 0xe0, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xe0, 0x00, 0xf0, 0x01, 0xf0, 0x00, 0x00, 0x00, 0xe0, 0x00, 0xf8, 0x03, 0xe0, 0x01, 0x00, 0x00, 0xf8, 0x00, 0xfc, 0x07, 0xc0, 0x01, 0x00, 0x00, 0x7e, 0x00, 0xfe, 0x0f, 0xc0, 0x03, 0x00, 0x00, 0x3f, 0x00, 0xef, 0x1e, 0x80, 0x03, 0x00, 0x00, 0x0f, 0x80, 0xe7, 0x3c, 0x80, 0x07, 0x00, 0x80, 0x07, 0xc0, 0xe3, 0x78, 0x80, 0x1f, 0x00, 0x80, 0x03, 0xc0, 0xe1, 0x70, 0x00, 0x3f, 0x00, 0xc0, 0x01, 0xc0, 0xe0, 0x60, 0x00, 0x78, 0x00, 0xc0, 0x01, 0x00, 0xe0, 0x00, 0x00, 0xf0, 0x00, 0xc0, 0x01, 0x00, 0xe0, 0x00, 0x00, 0xe0, 0x00, 0xc0, 0x01, 0x00, 0xe0, 0x00, 0x00, 0xe0, 0x01, 0xc0, 0x01, 0x00, 0xe0, 0x00, 0x00, 0xe0, 0x01, 0xc0, 0x01, 0x00, 0xe0, 0x00, 0x00, 0xe0, 0x01, 0xc0, 0x03, 0x00, 0xe0, 0x00, 0x00, 0xe0, 0x00, 0x80, 0x07, 0x00, 0x40, 0x00, 0x00, 0xf0, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x0f,
};
#include <VL53L0X.h>
VL53L0X sensor;
#include "I2Cdev.h"
#include "MPU6050.h"
MPU6050 accelgyro;
int16_t ax, ay, az;
char buff[32];
#define BTN_MODE PIN_D4 //connect switch, and to gnd
#define BTN_SEL PIN_D3 //connect switch, and to gnd
static const uint8_t ALT_SDA = PIN_D2;
static const uint8_t ALT_SCL = PIN_D1;
Adafruit_SSD1306 display(-1);
char oledstrbuff[64];
#if (SSD1306_LCDHEIGHT != 64)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif
ESP8266WiFiMulti WiFiMulti;
const char* ssid = "ssid";
const char* password = "password";
const char* host = "ESP8266";
int lastwifi;
unsigned long lastupdateMillis = 0;
bool freezedisplay = false;
int linefeeder = 0;
void oled_drawstr(int line,char *text){
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,line*10);
display.print(text);
display.display();
}
void oled_drawstr(char *text){
oled_drawstr(linefeeder++,text);
}
void oled_overwritestr(int line, char *text){
display.fillRect(0, line*10, 100, 10, BLACK);
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,line*10);
display.print(text);
display.display();
}
void oled_overwritestr_d(int line, char *text){
display.fillRect(0, line, 100, 10, BLACK);
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,line);
display.print(text);
display.display();
}
void oled_drawtext(int posx,int posy, int textsize, char *text){
display.setTextSize(textsize);
display.setTextColor(WHITE);
display.setCursor(posx,posy);
display.print(text);
}
bool wifi_setup(){
oled_drawstr("ESP8266 WiFi");
sprintf(oledstrbuff,"AP :%s",ssid);
oled_drawstr(oledstrbuff);
Serial.printf("AP SSID:%s", ssid);
WiFi.mode(WIFI_STA);
if (String(WiFi.SSID()) != String(ssid)) {
WiFi.begin(ssid, password);
}
int retrycount = 0;
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
retrycount++;
if (retrycount > 20){
return false;
oled_drawstr("conn timeout");
Serial.println("connection timeout");
return false;
}
}
Serial.println("");
lastwifi = WiFi.status();
IPAddress ip = WiFi.localIP();
sprintf(oledstrbuff,"IP :%d.%d.%d.%d",ip[0],ip[1],ip[2],ip[3]);
oled_drawstr(oledstrbuff);
byte mac[6];
WiFi.macAddress(mac);
sprintf(oledstrbuff,"MAC:%02X:%02X:%02X:%02X:%02X:%02X",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
oled_drawstr(oledstrbuff);
if (!MDNS.begin(host)) {
Serial.println("Error setting up MDNS responder!");
return false;
}
Serial.println("mDNS responder started");
WiFi.setSleepMode(WIFI_NONE_SLEEP);
if (WiFi.status() != WL_CONNECTED)
return false;
return true;
}
void setup() {
Serial.begin(74880);
Serial.print("\n");
Serial.setDebugOutput(true);
pinMode(BUILTIN_LED, OUTPUT);
digitalWrite(BUILTIN_LED, HIGH); //high to turn off
pinMode(BTN_MODE,INPUT_PULLUP);
pinMode(BTN_SEL,INPUT_PULLUP);
// WiFi.disconnect();
// WiFi.mode(WIFI_OFF);
// WiFi.forceSleepBegin();
initdata();
loaddata();
Wire.begin(ALT_SDA,ALT_SCL);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr
display.display();
delay(500);
display.clearDisplay();
wifi_setup();
//set sensor long range, high accuracy
sensor.setTimeout(5000);
sensor.init();
sensor.setTimeout(500);
sensor.setSignalRateLimit(0.1);
sensor.setVcselPulsePeriod(VL53L0X::VcselPeriodPreRange, 18);
sensor.setVcselPulsePeriod(VL53L0X::VcselPeriodFinalRange, 14);
sensor.setMeasurementTimingBudget(200000);
accelgyro.initialize();
Serial.println("Ready");
}
#define S_HOFFSET 240.0 //laser range sensor horizontal offset from measurement point, in mm
#define S_VOFFSET 2.0 //laser range sensor vertical offset from measurement point, in mm
#define degtorad(angleDegrees) (angleDegrees * M_PI / 180.0)
#define radtodeg(angleRadians) (angleRadians * 180.0 / M_PI)
//alternate
//radians = (degrees * 71) / 4068
//degrees = (radians * 4068) / 71
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define degconvert 57.2957786
#define averagenum 10
double averaging[averagenum];
int avindex = 0;
int xangle;
int yangle;
uint16_t distance;
double m_height = -1;
int misscount;
#define MODE_MEASURE 0
#define MODE_SELECT 1
#define MODE_SEND 2
char s_person[3][8] = {"Choujyo","Jijyo","Sanjyo"};
int m_mode = MODE_MEASURE; //mode
int m_person = 0; //selected person
bool m_measure = true; //measure on / pause
int m_pheight[3] = {0,0,0}; //measure per person
unsigned long btn_down_time = 0;
bool lastbtnmode = false;
bool lastbtnsel = false;
double calcheight(double hangle, double vangle, double olen){
double reslen = 0;
if (m_measure){
//hangle : horizontal angle
//vangle : vertical angle
//len : laser range, in mm
double len = olen + S_VOFFSET;
double hadjlen; //horizontal adjusted length
double aangle_r, aangle_d, hyplen;
double bangle_r, bangle_d;
hadjlen = cos(degtorad(hangle)) * len; //adjust horizontal length
aangle_r = atan2(hadjlen,S_HOFFSET);
aangle_d = radtodeg(aangle_r);
Serial.print("aangle:");
Serial.println(aangle_d);
hyplen = sqrt(S_HOFFSET*S_HOFFSET + hadjlen*hadjlen);
Serial.print("hyplen:");
Serial.println(hyplen);
if (vangle < 0){
if (aangle_d + abs(vangle) < 90){
bangle_d = 90 - aangle_d - abs(vangle);
bangle_r = degtorad(bangle_d);
reslen = cos(bangle_r) * hyplen;
}else if (aangle_d + abs(vangle) > 90){
bangle_d = (aangle_d + abs(vangle)) - 90;
bangle_r = degtorad(bangle_d);
reslen = cos(bangle_r) * hyplen;
}else{
reslen = hyplen;
}
}else if (vangle > 0){
bangle_d = 90 - (aangle_d - vangle);
bangle_r = degtorad(bangle_d);
reslen = cos(bangle_r) * hyplen;
}else //vertical flat
reslen = hadjlen;
Serial.print("bangle:");
Serial.println(bangle_d);
averaging[avindex] = reslen;
avindex = (avindex + 1) % averagenum;
}
reslen = 0;
for (int i=0;i<averagenum;i++) reslen += averaging[i];
reslen /= averagenum;
return reslen;
}
void checkprocessbtn() {
int btnstatemode = digitalRead(BTN_MODE);
int btnstatesel = digitalRead(BTN_SEL);
if (btnstatemode == LOW && !lastbtnmode){ //switch on
btn_down_time = millis();
lastbtnmode = true;
if (m_mode == MODE_MEASURE)
m_mode = MODE_SELECT;
else
m_mode = MODE_MEASURE;
freezedisplay = false;
}else if (btnstatemode == LOW){
if (millis() - btn_down_time > 2000){ //btn hold down over 2 sec
m_mode = MODE_SEND;
}
}else if (btnstatemode == HIGH){
lastbtnmode = false;
}
if (btnstatesel == LOW && !lastbtnsel){
lastbtnsel = true;
if (m_mode == MODE_MEASURE){
m_measure = !m_measure;
if (!m_measure){
m_pheight[m_person] = (m_height+5)/10; //save current measure to personal data. add 5 for rounding.
savedata(m_person,m_pheight[m_person]);
}
}else if (m_mode == MODE_SELECT){
m_person = (m_person + 1) % 3;
m_measure = true;
}else{
wifi_transferdata();
}
}else if (btnstatesel == HIGH){
lastbtnsel = false;
}
}
void wifi_transferdata(){
oled_overwritestr(5," Sending.");
uint16_t len;
String lendata;
lendata = "lendata=";
for (int i=0;i<3;i++){
if (m_pheight[i] <= 10)
lendata = lendata + "<td>---cm</td>";
else
lendata = lendata + "<td>" + m_pheight[i] + "cm</td>";
}
len = lendata.length();
WiFiClient client;
char buffer[512],chbuf[16];
Serial.println("Starting connection to server...");
oled_overwritestr(5," Sending..");
if (client.connect("server.name",80)){
oled_overwritestr(5," Sending...");
client.println(F("POST /lenlogger.php HTTP/1.1"));
client.println(F("Host: 192.168.0.1:80"));
client.println(F("Content-Type: application/x-www-form-urlencoded"));
client.print(F("Content-Length: "));
client.println(len);
client.println();
client.print(lendata);
client.println();
client.stop();
oled_overwritestr(5," Sending... OK");
for (int i=0;i<3;i++){
m_pheight[i] = 0;
savedata(i,0);
}
}else{
oled_overwritestr(5," Sending... NG");
oled_overwritestr(5," Conn Error");
}
freezedisplay = true;
}
int siglevel;
void updatedisplay(){
if (freezedisplay)
return;
display.clearDisplay();
unsigned long currentMillis = millis();
if (currentMillis - lastupdateMillis > 500){
//http://www.speedguide.net/faq/how-does-rssi-dbm-relate-to-signal-quality-percent-439
long rssi = WiFi.RSSI();
if (rssi <= -96)
siglevel = 1;
else if (rssi <= -85)
siglevel = 2;
else if (rssi <= -75)
siglevel = 3;
else
siglevel = 4;
lastupdateMillis = currentMillis;
}
display.fillRect(115, 2, 17, 11, BLACK);
if (siglevel >=1)
display.fillRect(117, 12, 2, 2, WHITE);
if (siglevel >=2)
display.fillRect(120, 10, 2, 4, WHITE);
if (siglevel >=3)
display.fillRect(123, 8, 2, 6, WHITE);
if (siglevel >=4)
display.fillRect(126, 6, 2, 8, WHITE);
if (m_mode == MODE_MEASURE){
oled_drawtext(7,0,1,s_person[m_person]);
if (!m_measure){
display.fillRect(0, 0, 2, 7, WHITE);
display.fillRect(3, 0, 2, 7, WHITE);
}
sprintf(buff,"H: % 2d%c",xangle,(char)247);
oled_drawtext(0,55,1,buff);
sprintf(buff,"V: % 2d%c",yangle,(char)247);
oled_drawtext(63,55,1,buff);
if (distance == 999)
sprintf(buff,"Dist: --- mm");
else
sprintf(buff,"Dist: %4dmm",distance);
oled_drawtext(0,45,1,buff);
if (xangle > 45 || xangle < -45){
oled_drawtext(30,10,4,"///");
}else if (yangle > 45 || yangle < -45){
oled_drawtext(30,10,4,"///");
}else{
if (distance == 999){
if (m_height == -1 || misscount > 5) //retain previous display for while
oled_drawtext(30,10,4,"---");
else{
sprintf(buff,"%3d",(int)m_height/10);
oled_drawtext(20,10,4,buff);
sprintf(buff,".%d",(int)m_height%10);
oled_drawtext(90,10,2,buff);
oled_drawtext(95,30,2,"cm");
}
}else{
m_height = calcheight(xangle,yangle,distance);
sprintf(buff,"%3d",(int)m_height/10);
oled_drawtext(20,10,4,buff);
sprintf(buff,".%d",(int)m_height%10);
oled_drawtext(90,10,2,buff);
oled_drawtext(95,30,2,"cm");
}
}
}else if (m_mode == MODE_SELECT){
oled_drawtext(5,5,1,"Select Person");
sprintf(buff,"%s%8s % 3dcm",m_person == 0?">>":" ",s_person[0],m_pheight[0]);
oled_drawtext(15,20,1,buff);
sprintf(buff,"%s%8s % 3dcm",m_person == 1?">>":" ",s_person[1],m_pheight[1]);
oled_drawtext(15,35,1,buff);
sprintf(buff,"%s%8s % 3dcm",m_person == 2?">>":" ",s_person[2],m_pheight[2]);
oled_drawtext(15,50,1,buff);
}else{
display.drawXBitmap(0,0,pic_cloud,64,32,WHITE);
oled_overwritestr(4," Send to Sever");
}
display.display();
}
void initdata(){
SPIFFS.begin();
//SPIFFS.format(); //only need to be done once
}
void savedata(int index,int data){
char fname[32];
sprintf(fname,"/data%d.txt",index);
File file = SPIFFS.open(fname, "w");
if (!file)
return;
sprintf(fname,"%d",data);
file.write((uint8_t*)&fname,32);
file.close();
}
void loaddata(){
char fname[32];
for (int i=0;i<3;i++){
sprintf(fname,"/data%d.txt",i);
if (SPIFFS.exists(fname)){
File file = SPIFFS.open(fname, "r");
if (file){
file.readBytes(fname,32);
m_pheight[i] = atoi(fname);
file.close();
}
}
}
}
void loop() {
checkprocessbtn();
if (m_mode == MODE_MEASURE && m_measure){
accelgyro.getAcceleration(&ax, &ay, &az);
yangle = atan2(ay, az)*degconvert;
xangle = atan2(-ax, az)*degconvert;
distance = sensor.readRangeSingleMillimeters();
if (sensor.timeoutOccurred() || distance > 8000){
distance = 999;
misscount++;
}else
misscount = 0;
}
updatedisplay();
}







