SONOFF 5V RE5V1Cのファームウェアを書き換える

投稿者: | 9月 23, 2024

はじめに

リチウムイオン電池の容量試験をしているうちに、HTTPもしくはシリアル経由でON/OFFできるスイッチがあったら、かなりの自動化ができるなーって思ったので作ってみることにしました。
ESP32やESP8266等のボードでスマートスイッチを作っても良かったのですが、すでにスマートスイッチとしてある程度出来上がっているSONOFF 5V RE5V1Cを使うことにしました。

SONOFF RE5V1Cについて

以前に
SONOFF 5V RE5V1Cを使ってみた話
という記事である程度紹介しています。

まとめると
・Ewelinkというプラットフォーム
・電源は5V
・ESPESP8285が乗っているリレー
って感じです。

改造

簡単に制御できるようにHTTP、シリアルでリレーを制御できるようにします。
バックアップとして既に書き込まれているファームウェアを吸い出して、Arduinoで書いたコードを書き込むって感じです。

各種必要なピンを生やす

必要なピンは、
GPIO0・・・リセット時にGNDに落ちているとBOOTモードに入って書き込みができるようになります。
RXとTX・・・書き込みに必須なうえ、使いたいので必要です。
リセット・・・なくても電源の入りきりや、ピンセットでGNDとショートさせるとかでも行けますが、あると楽なので引き出します。

各種GPIOとリレーやLED、ボタンの関係は既に、先駆者が解析済みなので、それを参考にしました。
ESPHome Devices「Sonoff RE5V1C – 5V Relay Module」
このサイトによるとGPIO0は既にボタンに割り当てられているのでピンを引き出す必要はありません。RXとTXも表面のパッドERXとETXが割り当てられています。

今回は、ESP32-WROOM本体が壊れて、UART変換器が生きている開発ボードがあったので、ESP32-WROOMの電源のパターンをカットしたものをUART変換器とし、それに接続しました。リセットピンも開発ボードの裏面のパターンをカットして、使用できるようにしました。

ファームウェア吸い出し

以下の記事で実行した通りに吸い出しました。
AliExpressで買ったスマートスイッチ(ESP8285)にArduino IDEのスケッチを書き込む
何回か吸い出しして、md5が一致するか確認したほうがいいです。

コードを書く&書き込み

コードは自分の作成したライブラリである、
Arduino(ESP32,ESP8266,Raspberry Pi Pico W)にてCaptive Portalを利用してWiFiを設定するライブラリ
のサンプルコードである、Simple_Switchをちょっと改造して作成ました。シリアルでON/OFFと状態の確認ができるようにしました。このページの最下部にコードを乗せておきます。

書き込み時も、吸い出し時と同じ様にBOOTボタンを押しながらリセットをすると書き込みができるようになります。

筐体の作成

3Dプリンターで適当に作成しました。以前に、ESP32用のケースと、SONOFF RE5V1C用のケースの3Dモデルを作成していたので、それらを適当に組み合わせました。

バナナプラグをつけて完成です。

おわりに

いい感じに完成しました。これで、計測の自動化が捗ります。

コード

#include <Captive_Portal_WiFi_connector.h>
#include <LittleFS.h>
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>

#define MAIN_SW 0
#define RELAY_PIN 12
#define GREEN_LED 13

ESP8266WebServer server(80);

CPWiFiConfigure CPWiFi(MAIN_SW, -GREEN_LED, Serial);

bool led = false;

void sendStatus() {
  if (led) {
    Serial.println("ON");
  } else {
    Serial.println("OFF");
  }
}

void handleOn() {
  digitalWrite(RELAY_PIN, HIGH);
  led = true;
  server.send(200, "text/plain", "1\r\n");
  sendStatus();
}

void handleOff() {
  digitalWrite(RELAY_PIN, LOW);
  led = false;
  server.send(200, "text/plain", "0\r\n");
  sendStatus();
}

void handleStatus() {
  if (led) {
    server.send(200, "text/plain", "1\r\n");
  } else {
    server.send(200, "text/plain", "0\r\n");
  }
  Serial.print("status:");
  sendStatus();
}

void handleNotFound() {
  server.send(404, "text/plain", "This is HTTP_switch. To turn on is access to /on, off is /off, To get staus is /status.\r\n");
  Serial.println("404");
}

void setup() {
  pinMode(RELAY_PIN, OUTPUT);
  digitalWrite(RELAY_PIN, LOW);
  Serial.begin(115200);
  sprintf(CPWiFi.boardName, "BananaSwitch");
  sprintf(CPWiFi.htmlTitle, "BananaSwitch");
  if (!CPWiFi.begin()) {
    Serial.println("Fail to start Capitive_Portal_WiFi_configure");
    while (true) {}
  }
  WiFi.begin(CPWiFi.readSSID().c_str(), CPWiFi.readPASS().c_str());
  int count = 0;
  while (WiFi.status() != WL_CONNECTED) {
    if (count > 40) {
      Serial.println("WiFi connect Fail. reboot.");
      ESP.restart();
    }
    delay(1000);  //1sencods
    if (CPWiFi.readButton()) {
      ESP.restart();
    }
    Serial.print(".");
    if (!led) {
      digitalWrite(GREEN_LED, LOW);
      led = true;
    } else {
      digitalWrite(GREEN_LED, HIGH);
      led = false;
    }
    count++;
  }
  digitalWrite(GREEN_LED, HIGH);
  led = false;
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.print("IP is ");
  Serial.println(WiFi.localIP());
  // write what you want to do using WiFi
  server.on("/on", handleOn);
  server.on("/off", handleOff);
  server.on("/status", handleStatus);
  server.onNotFound(handleNotFound);
  server.begin();
  Serial.println("HTTP server started");
}

void syncLED() {
  if (led) {
    digitalWrite(RELAY_PIN, HIGH);
  } else {
    digitalWrite(RELAY_PIN, LOW);
  }
}

void handleSerial() {
  if (Serial.available()) {
    delay(5);
    String message = Serial.readStringUntil('\n');
    message.toUpperCase();
    if (message == "ON") {
      led = true;
      sendStatus();
    } else if (message == "OFF") {
      led = false;
      sendStatus();
    } else if (message == "STATUS") {
      Serial.print("status:");
      sendStatus();
    } else {
      Serial.println("?");
    }
  }
}

bool Button_flag = true;
bool oldButton_flag = true;

void handleButton() {
  oldButton_flag = Button_flag;
  Button_flag = digitalRead(MAIN_SW);
  if (!Button_flag && oldButton_flag) {
    if (CPWiFi.readButton()) {
      ESP.restart();
    }
    led = !led;
    sendStatus();
  }
}

void loop() {
  server.handleClient();
  syncLED();
  handleButton();
  handleSerial();
}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)