Loggerの製作-03-測定と改良

前回製作したLoggerで畑の温度を測定してみました。結果は以下の通り。

一週間測定予定が21時時間で終了していました。正確には4本のプローブで測定を開始し、21時間後まで測定していた様だが、その後は測定値が全て−0.1℃となっていました。測定回数は一週間分有ったので、測定自体は行っていた様ですが値が全て−0.1℃でした。

色々調べてやっと原因が分かりました。ESP8266のI2C回路が壊れた様です。最初は測定中雨が降ったので、外にあるADT7140 の故障と予想したのですが、ADT7410は問題有りませんでした。そこで新しいESP8266に変えたら問題無く動きました。AD変換や値の表示等は動いていたので、ESP8266に問題無いと思っていたのですがI2Cのみの故障の様です。測定器を回収に畑に行った時、測定器が結露して湿っていました。測定器の蓋を開けると、ESP8266のICを覆っている金属のカバーが若干曇った様に見え、これって多分錆びだと思います。

今回分かった事。

  • プラスチックの容器に本体を入れたがこれでは水分が入ってくる。
  • 水分が入るとESP8266の故障の原因になる。
  • I2C回路が約21時間で壊れたが、その他は正常なので測定自体は一週間続いた
  • 測定前約5.4Vだった電池が測定後は約5.2V。消費電力が比較的少ない。
  • 測定が安定する前は、測定プローブを絞って使った方が良い。4個も同時に測る必要は無い。

下記の対策をしてもう一度トライします。

  1. 容器を今回の様な簡易型の蓋では無く、防水が出来る蓋に変える。
  2. 4個の中から測定に使うプローブを指定出来る様にする。

今回は、測定するプローブを選択出来る様にスケッチを変更します。

外見はほぼ同じなのですが、各プローブ測定値表示の先端チェックボックスを付けチェックされているプローブのみ測定する様に変更しました。

これがデフォルト画面ですが、デフォルトではどのプローブも選択されていません。選択されていない時には、測定値として xx.x ‘Cを表示します。この状態で”Measure”ボタンを押しても表示は変わりません。

例えば、48番と4a番のプローブにチェックをいれて、”Measure”ボタンを押すと

の様に、チェックされたプローブの温度を測定します。その他の仕様は前回と同じです。今回改良したスケッチ


#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <Wire.h>
#include <FS.h>

#define Adt_On    0
#define Adt_Off   3
#define Mic_Min   60000000

/* Set these to your desired credentials. */
const char *ssid = "ESP8266";
const char *password = "12345678";

ESP8266WebServer server(80);
int s_state = 0;

String index_Dt =
                  "<!DOCTYPE html>\n<html>\n<head>\n"
                  "<title>ESP8266 Logger</title>\n"
                  "<style type='text/css'>\n"
                  "button.bt1 {background:#90ee90;font-size:60px;padding:10px;margin:20px;border-radius:30px;box-shadow:4px 4px #555;}\n"
                  "input.temp {scale:3;vertical-align:middle;}\n</style>\n</head>\n<body>\n<center>\n"
                  "<div style='width:550px; background-color:#d8a373; border-style:solid; border-radius:30px; border-color:#6b3f31'>\n"
                  "<span style='font-size:85px'><b><i><u>Temp Logger</u></i></b></span>\n"
                  "<div style='font-size:60px'>\n<span>---Temp---</span><br>\n"
                  "<input type='checkbox' id='30' class='temp' /><span id='48'></span><br>\n"
                  "<input type='checkbox' id='31' class='temp' /><span id='49'></span><br>\n"
                  "<input type='checkbox' id='32' class='temp' /><span id='4a'></span><br>\n"
                  "<input type='checkbox' id='33' class='temp' /><span id='4b'></span><br>\n"
                  "<span id='p_volt'></span><br>\n"
                  "<form method='get'>\n"
                  "<button type='submit' name='10' id='t10' onclick='onBtnM_S(0)' class='bt1'>Measure</button><br>\n"
                  "</form>\n"
                  "<form method='get'>\n"
                  "<input type='number' max='71' id='d_time' style='font-size:40px;width:100px;' name='1'/>\n"
                  "<button type='submit' name='2' id='t1' onclick='onBtnM_S(1)' class='bt1'>Start</button><br>\n"
                  "</form>\n"
                  "<a style='font-size:60px' href='./data.txt' download='data.txt'>Download</a><br>\n"
                  "<a style='font-size:60px' href='./data1.txt' download='data1.txt'>Backup</a><br>\n"
                  "</div>\n</div>\n</center>\n<script>\nfunction onBtnM_S(mode) {\n"
                  "var a=0;\nvar b=1;\n"
                  "for(c=30; c<34; c ++){\nif(document.getElementById(String(c)).checked) a |= b;\nb <<= 1;}\n"
                  "if(mode) document.getElementById('t1').value = a;\nelse document.getElementById('t10').value = a;}\n";
                  
/* Just a little test message.  Go to http://192.168.4.1 in a web browser
   connected to this access point to see it.
*/
// Arduino I2C  SCL:A5  SDA:A4

void handleRoot() {
  String buf,cmd;
  double inter_time;
  float d_temp; 
  int a,b,c,fl;
  File dataFile;
  char temp[16];
  uint32_t offset,m_data;

    fl=0;
    cmd=server.argName(0);
    switch(cmd.toInt())
    {
      case 1:   // Start Log
                cmd=server.arg("1");
                m_data=cmd.toInt();
                offset=0;             // interval time
                ESP.rtcUserMemoryWrite(offset, &m_data, sizeof(m_data)) ;
                offset=4; m_data=0;   // measurement No.
                ESP.rtcUserMemoryWrite(offset, &m_data, sizeof(m_data)) ;
                cmd=server.arg("2");
                s_state=cmd.toInt();

                fl=1;
                break;
                
      case 10:  // Start Log
                cmd=server.arg("10");
                s_state=cmd.toInt();
                break;
    }
                
    buf=index_Dt;
    b=1; c=30;   
    for(a=0x48; a<0x4c; a++)
    {
      buf += ("document.getElementById('" + String(a,HEX) + "').innerHTML=\"---" + String(a,HEX) + ": ");
      if(s_state & b)
      {
        dtostrf(get_Temp(a), 5, 1,temp);
        cmd=temp;
      }
      else cmd = "xx.x";
      cmd += (" 'C\";\ndocument.getElementById('" + String(c) + "').checked=");

      if(s_state & b) cmd += "true;\n";
      else cmd += "false;\n";
      
      buf += cmd;
      b <<= 1; c ++;
    }
    
    dtostrf(Battery_chk(), 5, 2,temp);
    cmd=temp;
    buf += ("document.getElementById('p_volt').innerHTML=\"Battery: " + cmd +  " V\";\n");

    if(fl)
      if(digitalRead(14))
      {
        buf += "alert('Switch is AP position');";
        fl=0;
      }
    
    buf += "history.pushState(null,null,'/');\n</script>\n</body>\n</html>";

    server.send(200, "text/html", buf);
    
    if(fl)
    {
      Serial.println("Start");
      SPIFFS.remove("/data.txt");
      SPIFFS.remove("/data1.txt");
      get_save_Temp();
      Adt_ope_mode(Adt_Off);
      
      offset=8; m_data=s_state;   // Sencer State
      ESP.rtcUserMemoryWrite(offset, &m_data, sizeof(m_data)) ;
      
      offset=0;             // interval time
      ESP.rtcUserMemoryRead(offset, &m_data, sizeof(m_data)) ;
      inter_time = m_data * Mic_Min;
      ESP.deepSleep(inter_time);
      delay(500);
    }
}

void setup() {
  String buf;
  File dataFile;
  uint32_t offset,m_data;
  double inter_time;
  
    delay(500);
    Serial.begin(115200);
    Serial.println();

    Wire.begin(); 
    Serial.println("I2C started");

    SPIFFS.begin();
    Serial.println("SPIFFS started");

    offset=8;             // Senser State
    ESP.rtcUserMemoryRead(offset, &m_data, sizeof(m_data)) ;
    s_state = m_data;
      
    Adt_ope_mode(Adt_On);
    delay(500);

    pinMode(14,INPUT);
    if(digitalRead(14)){
      Serial.print("Configuring access point...");
      // You can remove the password parameter if you want the AP to be open. 
      WiFi.softAP(ssid, password);

      IPAddress myIP = WiFi.softAPIP();
      Serial.print("AP IP address: ");
      Serial.println(myIP);
      server.on("/", handleRoot);
      server.onNotFound(handleWebRequests); //Set setver all paths are not found so we can handle as per URI
      server.begin();
      Serial.println("HTTP server started");

      pinMode(13,OUTPUT);
      digitalWrite(13, HIGH);
      s_state = 0;
    }
    else{
      get_save_Temp();
      Serial.println("Measured");
      
      Adt_ope_mode(Adt_Off);
      
      offset=0;             // interval time
      ESP.rtcUserMemoryRead(offset, &m_data, sizeof(m_data)) ;
      inter_time = m_data * Mic_Min;
      ESP.deepSleep(inter_time);
      delay(500);
    }
}

float Battery_chk()
{
  float d_temp; 
  int a;

    d_temp=0;
    for(a=0; a<5; a++)
    {
      d_temp += (system_adc_read() * 9.822 / 1024);
      delay(100);
    }
    
    return d_temp/5;
}

void Adt_ope_mode(int data)
{
  int a,b;

    data <<= 5;
    b=1;
    for(a=0x48; a<0x4c; a++)
    {
      if(s_state & b)
      {
        Wire.beginTransmission(a);
        Wire.write(0x03);
        Wire.write(data);
        Wire.endTransmission();
      }
      b <<= 1;
    }
}

void loop() {
  
  server.handleClient();

}

void handleWebRequests()
{
  String dataType = "text/plain";
  String path;
  File dataFile;
   
    path = server.uri();
    if(path.endsWith(".txt")) dataType = "text/plain";
    else if(path.endsWith(".css")) dataType = "text/css";
    else if(path.endsWith(".js")) dataType = "application/javascript";
    else if(path.endsWith(".png")) dataType = "image/png";
    else if(path.endsWith(".gif")) dataType = "image/gif";
    else if(path.endsWith(".jpg")) dataType = "image/jpeg";
    delay(5);
    
    dataFile = SPIFFS.open(path.c_str(), "r");
    server.streamFile(dataFile, dataType);
    dataFile.close();
    delay(5);
}

float get_Temp(int addr)
{
  short int data;
  float f_data;
  
    Wire.requestFrom(addr, 2);
    data = Wire.read() << 8;  
    data |= Wire.read();      
    data >>= 3;                          
    f_data = (float)data  / 16.0;          
    return f_data;
}

void get_save_Temp()
{
  float f_data[4];
  int a,b,c;
  uint32_t offset,m_data;

    c=1;
    for(b=0; b<4; b++)
    {
      if(s_state & c) 
      {
        f_data[b]=0;
        for(a=0; a<5; a++)
        {
          f_data[b] += get_Temp(0x48 + b);
          delay(300);
        }
        f_data[b] /= 5;
      }
      c <<= 1;  
    }

    offset=4;             
    ESP.rtcUserMemoryRead(offset, &m_data, sizeof(m_data)) ;
    save_data("/data.txt",f_data,m_data);
    save_data("/data1.txt",f_data,m_data);
    m_data += 1;
    ESP.rtcUserMemoryWrite(offset, &m_data, sizeof(m_data)) ;
    
}

void save_data(String fn, float *data, uint32_t m_data)
{
  File dataFile;
  char temp[16]; 
  String str_time;
  int a,b;
  
    dataFile = SPIFFS.open(fn, "a");
    dataFile.print(String(m_data) + ",");
    b=1;
    for(a=0; a<4; a++)
    {
      if(s_state & b)
      {
        dtostrf(data[a], 5, 1,temp);
        str_time = temp;
      }
      else str_time = " xx.x";
      
      if(a != 3) dataFile.print(str_time + ",");
      else dataFile.println(str_time);
      b <<= 1;
    }
    dataFile.close();
}

これで4本のプローブを付けずに済みました。先ずはこのスケッチで部屋の温度を測定して見ます。