先日作った身長測定器だが、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(); }