【ESP8266】장시간 deepsleep하면 모바일 배터리가 OFF가 되는 건을 어떻게 든

소개



ESP8266의 deepsleep 모드는 너무 뛰어나 모바일 배터리로 운용하려고 하면 소비 전류가 너무 적어 부하가 없다고 판단되어 전원이 꺼지는 문제가 있습니다.

그렇다고 부하가 없다고 판단되지 않도록 단순히 deepsleep 시간을 단축하면 낭비 배터리가 낭비됩니다.

이 문제를 손쉽게 해결하는 방법을 생각해 보겠습니다.

여기서 해결책



모바일 배터리를 사용하는 것, 불필요한 하드웨어를 사용하지 않는 경우를 조건으로 하면, deepsleep의 시간을 단축하는 것은 피할 수 없습니다.

그러나 deepsleep에서 깨어난 후의 처리를 궁리하면, 전력의 낭비는 피할 수 있을 것 같습니다.

구체적으로는, 각성 후에 매회 처리를 하지 않고, 몇번에 1회만 처리를 하면 좋을 것 같습니다.

보통 매번 송신하는 경우의 소비 전력의 이미지는 이런 것입니다.



여러 번에 한 번만 송신 처리하는 경우의 소비 전력은 이렇게 됩니다.



WiFi 액세스 처리를 하는 경우는 네고로부터 통신 종료까지 몇 초간 풀 파워로 전기 먹어 버립니다만, 일어나 곧 자는 것만이라면 그렇게 먹지 않는다고 하는 전략입니다.

깨어난 것은 몇번째?



ESP8266의 내장 메모리는 deepsleep시에 전원이 꺼져 버리므로 이전 값을 기억할 수 없습니다. 즉, 일어난 일이 몇 번인지 기억하기 위해서, 보통의 변수를 사용할 수 없습니다.

그러나 내장 RTC 모듈에는 512바이트의 메모리가 있으며, 이는 deepsleep 중에도 유지됩니다.

RTC 메모리에 쓰기는ESP.rtcUserMemoryWrite(offset, &data, sizeof(data))그래서,
RTC 메모리에서 읽는 것은ESP.rtcUserMemoryRead(offset, &data, sizeof(data))입니다.

여기에 깨어난 횟수의 카운터 값을 넣습니다.

deepsleep에서 깨어나 전원이 켜졌는지



deepsleep로부터의 복귀시도, 전원 투입시와 같이 setup() 로 시작됩니다.
전원 투입시의 RTC 메모리의 내용은 부정이므로, RTC 메모리로부터는 「최초의 기동」을 알 수 없습니다. 따라서 RTC 메모리 이외의 부팅 이유를 조사해야 합니다.

시작 이유는 ESP.getResetReason()에서 확인할 수 있습니다.

반환값은 캐릭터 라인으로, deepsleep로부터의 복귀시는 "Deep-Sleep Wake" (이)가 돌아옵니다.

소스 코드 예



・deepsleep는 100초마다
・메인 처리는 6회마다(6*100=600으로, 10분마다)

여기에서의 메인의 처리는 htp://192.168.0.1/ 에 액세스 하는 것 뿐입니다.
실용하는 경우는 센서를 읽고 어딘가에 던지는 처리가 될 것입니다.

deepsleeptest.ino
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>

// ディープスリープ時間(マイクロ秒)
// モバイルバッテリーがOFFになる時間よりちょい短めに設定する
const uint32_t DEEP_SLEEP_uS = 1000*1000*100;

// 何回起きたら実際に送信処理するか、の値
const uint32_t SEND_INTERVAL = 6;

const char* ssid     = "your-ssid";
const char* password = "your-password";

// メインのお仕事
void mainJob() {
  Serial.print("[WiFi] connecting");
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    // WiFiアクセスポイントが死んでると、その間バッテリを浪費してしまうので、
    // リトライオーバーで諦める処理を入れたほうがいいかも
  }
  Serial.println(".");

  HTTPClient http;
  Serial.println("[HTTP] begin...");
  http.begin("http://192.168.0.1/");

  Serial.println("[HTTP] GET...");
  // start connection and send HTTP header
  int httpCode = http.GET();

  // httpCode will be negative on error
  if(httpCode > 0) {
    // HTTP header has been send and Server response header has been handled
    Serial.printf("[HTTP] GET... code: %d\r\n", httpCode);

    // file found at server
    if(httpCode == HTTP_CODE_OK) {
        String payload = http.getString();
        Serial.println(payload);
    }
  } else {
    Serial.printf("[HTTP] GET... failed, error: %s\r\n", http.errorToString(httpCode).c_str());
  }

  http.end();
}

void setup() {
  Serial.begin(74880);  // 起動時に合わせて74880bpsにする

  String resetReason = ESP.getResetReason();
  Serial.println(resetReason);

  uint32_t wakeupCounter;
  if ( resetReason == "Deep-Sleep Wake" ) {
    // deepsleepからの復帰だったら
    // RTCメモリからwakeupCounterを読み出して、+1
    ESP.rtcUserMemoryRead(0, &wakeupCounter, sizeof(wakeupCounter));
    wakeupCounter++;
  }
  else {
    // 電源ONからの起動だったら、wakeupCounterを初期化(1発目は即実行)
    wakeupCounter = SEND_INTERVAL;
  }
  Serial.print("wakeupCounter : ");
  Serial.println(wakeupCounter);

  if ( SEND_INTERVAL <= wakeupCounter ) {
    // カウンタが規定値以上 → カウンタクリアして、仕事する
    wakeupCounter=0;
    mainJob();
  }
  else {
    // モバイルバッテリーがOFFにならないようにするために起きただけ
    // (機種によっては、電流を流したフラグを確実に立てさせるため、delay()を入れたほうがいいかも?)
  }

  // RTCメモリにwakeupCounterを書き込む
  ESP.rtcUserMemoryWrite(0, &wakeupCounter, sizeof(wakeupCounter));

  // 寝る
  ESP.deepSleep(DEEP_SLEEP_uS, WAKE_RF_DEFAULT);
}

void loop() {
  // deepSleep呼んだ後も少し実行されちゃうけど、
  // ここの空ループでやり過ごす。
}

결론



IoT는 전원 확보가 목이 되기 쉽습니다.

이 기사의 방법은 최선이 아닐지도 모르지만, 간단하기 때문에 전자 공작의 입구의 작품에는 사용하기 쉽다고 생각합니다.

좋은 웹페이지 즐겨찾기