martin-ger / ESP8266-WiFi-Socket

Custom SW for the OBI "Wifi Stecker Schuko"
64 stars 7 forks source link

OTA Flashing? #1

Open repomaa opened 6 years ago

repomaa commented 6 years ago

Nice to see old professors from the uni doing useful tinkering with consumer products ;)

Have you tried intercepting any OTA updates as a way to flash the ESP without having to open up and solder the pin header to it? Or is it the usual IOT product which was never designed to get any updates.

Also take a look at marvinroger/homie-esp8266 It's perfect for these kinds of things and brings you easy configuration, mqtt, some metrics and OTA out of the box.

martin-ger commented 6 years ago

Thank you for the old professor... ;-)

Actually, I havn't thought about reverse engineering the various stock firmwares. Trying to analyze the default cloud communication might be interesting. As it has only 1MB flash it has perhaps not OTA. If it had, it is most probably not secured by TLS...

Will think about it. Nice work for a student's thesis... ;-)

melvinisken commented 6 years ago

That's quite easy in the end. Just add a few lines to include the WebUpdate feature that is already included in the ESP library. You then have a small webserver running which you can use to upload new code (as long the sketch size is max 1/2 of the available memory). The link is YourDeviceIPAddress/update. You can then upload the compiled *.bin file (e.g. OBISocket.ino.bin) from the Arduino IDE compile folder. After upload it restarts with the new firmware loaded.

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <PubSubClient.h>

//WebUpdate
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <ESP8266HTTPUpdateServer.h>

// Controller-Type in IDE: Wemos D1 mini Lite

// WiFi Settings

const char* ssid = "YourSSID";
const char* password = "YourPassword";

//WebUpdate
const char* host = "obisocket0-webupdate";

// MQTT Settings
const char* mqtt_server = "YourBroker";
const char* mqtt_command_topic = "obisocket/0/command";
const char* mqtt_status_topic = "obisocket/0/status";

bool relay_status = false;

WiFiClient espClient;
PubSubClient client(espClient);

// WebUpdate
ESP8266WebServer httpServer(80);
ESP8266HTTPUpdateServer httpUpdater;

void setRelay(bool new_status){
  relay_status = new_status;

  if (relay_status){
    digitalWrite(12, 0);
    delay(50);
    digitalWrite(12, 1);
  } else {
    digitalWrite(5, 0);
    delay(50);
    digitalWrite(5, 1);
  }

  client.publish(mqtt_status_topic, relay_status?"1":"0", true);

  //Serial.print("relay ");
  //Serial.println(relay_status?"on":"off");
}

void setup(void){
  Serial.begin(115200); 
  delay(200);

  // Setting the I/O pin modes

  pinMode(14, INPUT); // Push button
  pinMode(4, OUTPUT); // Blue LED
  pinMode(5, OUTPUT); // Relay off
  pinMode(12, OUTPUT); // Relay on

  delay(200);
  setRelay(true);
  setRelay(false);

  // Connecting to a WiFi network

  Serial.println();
  Serial.println("Connecting to WiFi");

  WiFi.mode(WIFI_OFF);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(100);
    Serial.print(".");
  }

  Serial.println();
  Serial.print("WiFi connected with ip ");
  Serial.println(WiFi.localIP());
  digitalWrite(4, 1);

  client.setServer(mqtt_server, 1883);
  client.setCallback(mqttCallback);

  // WebUpdate
  MDNS.begin(host);
  httpUpdater.setup(&httpServer);
  httpServer.begin();
  MDNS.addService("http", "tcp", 80);
  Serial.printf("HTTPUpdateServer ready! Open http://%s.local/update in your browser\n", host);
}

void mqttCallback(char* topic, byte* payload, unsigned int length) {
  if (length == 0) return;

  setRelay((char)payload[0] == '1');
}

void mqttReconnect() {
  String clientID = "OBISocket_";
  clientID += WiFi.macAddress();

  Serial.print("Connect to MQTT-Broker");
  if (client.connect(clientID.c_str())) {
    Serial.print("connected as clientID:");
    Serial.println(clientID);

    client.subscribe(mqtt_command_topic);
    client.publish(mqtt_status_topic, relay_status?"1":"0", true);

  } else {
    Serial.print("failed: ");
    Serial.println(client.state());
  }
}

bool inp_status = 1;

void loop(void){
  bool inp = digitalRead(14);
  if (inp == 0 and inp != inp_status) {
    setRelay(!relay_status);
  }
  inp_status = inp;

  // WebUpdate
  httpServer.handleClient();

  if (!client.connected()) {
    mqttReconnect();
  }
  client.loop();

  delay (50);
} 

One last remark: I didn't know which type of ESP to choose, but "Wemos D1 mini Lite" seems to work quite well. Maybe you can add this note to the Readme document (or the correct settings if this one is not correct).

martin-ger commented 6 years ago

Thank you for the hint. Actually, I havn't done anything wih the Arduino OTA so far. Btw, do you have any experience with the resulution of the ".local" address on Linux (or Windows) as these do not support mDNS by default, as far as I know?

Also I think, the first idea from jreinert was, to hack any OTA mechanism of the stock firmware of the socket switch in order to be able to reflash it without opening it and soldering.

melvinisken commented 6 years ago

I'm no expert in Arduino OTA, I just used this code in a few of my smarthome sensors and so far it works quite well. I also didn't test the mDNS stuff, I just use IPs in my home network.

Ah, ok, I didn't get that right. Unfortunately I don't have any un-flashed plugs anymore and I didn't test the original software, so I can't check if there is any OTA functionality out of the box..

repomaa commented 6 years ago

Thank you for the old professor... ;-)

Haha. I couldn't resist after seeing your github name. :)

Also I think, the first idea from jreinert was, to hack any OTA mechanism of the stock firmware of the socket switch in order to be able to reflash it without opening it and soldering.

Exactly.

OTA updates (if any) will probably be done via polling to a centralized update server. I also doubt that it will have any serious security, but you never know.

If what I'm suspecting is correct, it will most likely contact the update server just after booting so it should be easy enough to sniff the communication with tcpdump/wireshark.

There's also open specification of how the update server should respond and which headers it should set (MD5 sum for one):

https://esp8266.github.io/Arduino/versions/2.0.0/doc/ota_updates/ota_updates.html#http-server

This is all assuming that the stock firmware is built using the arduino toolchain. Could be something else which would be trickier.

I still have to get my hands on a plug to test this all this out. Will report back, when I've got the chance to stop by an OBI with the plugs in stock.