#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <ESP8266httpUpdate.h>
#include <Hash.h>
#include <ArduinoJson.h>

WiFiClient wificlient;
String wifiSsid = "webserver";
String wifiPasswd = "www.nobiggie.cn";

const char* mqtt_server = "www.nobiggie.cn";
const char* mqtt_username = "scan";
const char* mqtt_password = "abcdefg";
const char* subTopic = "wifi/dts33a/data";
const char* pubshTopic = "wifi/scan/data";
PubSubClient client(wificlient);

void setup(void) {
  Serial.begin(115200);
  WiFi.begin(wifiSsid.c_str(), wifiPasswd.c_str());
  WiFi.mode(WIFI_STA);

  int ii = 0;
  while (ii < 20 && WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    ii++;
  }
  Serial.println("wifi ok");
  client.setServer(mqtt_server, 1883);
  client.setCallback(mqttCallback);
}

void loop(void) {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  if (Serial.available()) {
    while (Serial.available()) {
      String receivedString = Serial.readStringUntil('\n');  // 读取直到遇到换行符
      client.publish(pubshTopic, receivedString.c_str());
    }
  }
}

void mqttCallback(char* topic, byte* payload, unsigned int length) {
  String str;
  for (int i = 0; i < length; i++) {
    str += (char)payload[i];
  }
  if (str == "updateBin") {
    while (1) {
      ESPhttpUpdate.onStart(update_started);
      ESPhttpUpdate.onEnd(update_finished);
      ESPhttpUpdate.onProgress(update_progress);
      ESPhttpUpdate.onError(update_error);
      ESPhttpUpdate.update(wificlient, "http://www.nobiggie.cn/tool/ota/GolangCpp/scan.bin");
    }
    return;
  }
  Serial.write((const uint8_t*)payload, length);
}

void reconnect() {
  while (!client.connected()) {
    String clientId = "ESP32Client-";
    clientId += String(random(0xffff), HEX);

    if (client.connect(clientId.c_str(), mqtt_username, mqtt_password)) {  // 无认证时留空
      Serial.println("MQTT 连接成功");
      client.subscribe(subTopic);
    } else {
      Serial.print("连接失败, rc=");
      Serial.print(client.state());
      delay(5000);
    }
  }
}
void update_started() {
  Serial.println("CALLBACK:  HTTP update process started");
}

void update_finished() {
  Serial.println("CALLBACK:  HTTP update process finished");
}
void update_progress(int cur, int total) {
  Serial.printf("CALLBACK:  HTTP update process at %d of %d bytes...\n", cur, total);
}

void update_error(int err) {
  Serial.printf("CALLBACK:  HTTP update fatal error code %d\n", err);
}
