FloKra 6 years ago
parent
commit
a0048e21ff

+ 10 - 3
src/WiFiSwitch/PersWiFiManager.cpp

@@ -46,9 +46,16 @@ void PersWiFiManager::handleWiFi() {
   }
 
   //if failed or not connected and time is up
-  if ((WiFi.status() == WL_CONNECT_FAILED) || ((WiFi.status() != WL_CONNECTED) && ((millis() - _connectStartTime) > (1000 * WIFI_CONNECT_TIMEOUT)))) {
-    startApMode();
-    _connectStartTime = 0; //reset connect start time
+  //if ((WiFi.status() == WL_CONNECT_FAILED) || ((WiFi.status() != WL_CONNECTED) && ((millis() - _connectStartTime) > (1000 * WIFI_CONNECT_TIMEOUT)))) {
+  if ((WiFi.status() == WL_CONNECT_FAILED) || ((WiFi.status() != WL_CONNECTED))) {
+    if(((millis() - _connectStartTime) > (1000 * WIFI_CONNECT_TIMEOUT))) {
+      startApMode();
+      _connectStartTime = 0; //reset connect start time
+    }
+    //else {
+      //retrying...
+//      attemptConnection();
+  //  }
   }
 
 } //handleWiFi

+ 2 - 2
src/WiFiSwitch/PersWiFiManager.h

@@ -5,7 +5,7 @@
 #include <ESP8266WebServer.h>
 #include <DNSServer.h>
 
-#define WIFI_CONNECT_TIMEOUT 30
+#define WIFI_CONNECT_TIMEOUT 60
 
 class PersWiFiManager {
 
@@ -49,4 +49,4 @@ class PersWiFiManager {
 };//class
 
 #endif
-
+

+ 73 - 32
src/WiFiSwitch/WiFiSwitch.ino

@@ -21,8 +21,8 @@
 #define BUTTON2_HOLD_PAYLOAD_OUT "TOGGLE"
 #define BUTTON3_HOLD_PAYLOAD_OUT "TOGGLE"
 #define DOMOTICZ_IN_TOPIC "domoticz/in"
-#define DOMOTICZ_OUT_TOPIC "domoticz/out"
-#define DOMOTICZ_IDX_1 209
+#define DOMOTICZ_OUT_TOPIC "domoticz/outTEST"
+#define DOMOTICZ_IDX_1 0
 #define DOMOTICZ_IDX_2 0
 #define DOMOTICZ_IDX_3 0
 
@@ -70,30 +70,36 @@
 #endif
 
 
-
-
 // config variables - do not change here!
-char deviceName[30]; // = "123456789012345678901234567890"; // 30 chars
-char mqtt_server[30]; //  = "123456789012345678901234567890"; // 30 chars
+char deviceName[31];
+char http_user[31];
+char http_pass[31];
+char mqtt_server[41];
 int mqtt_port = MQTT_PORT;
-char mqtt_topic_in[30]; //  = "123456789012345678901234567890"; // 30 chars
-char mqtt_topic_out[30]; //  = "123456789012345678901234567890"; // 30 chars
-char mqtt_topic_out_hold_1[30]; //  = "123456789012345678901234567890"; // 30 chars
-char mqtt_topic_out_hold_2[30]; //  = "123456789012345678901234567890"; // 30 chars
-char mqtt_topic_out_hold_3[30]; //  = "123456789012345678901234567890"; // 30 chars
-//char+ mqtt_payload_out_hold[3] = { BUTTON1_HOLD_PAYLOAD_OUT, BUTTON2_HOLD_PAYLOAD_OUT, BUTTON3_HOLD_PAYLOAD_OUT };
-char mqtt_payload_out_hold_1[30]; //  = "123456789012345678901234567890"; // 30 chars
-char mqtt_payload_out_hold_2[30]; //  = "123456789012345678901234567890"; // 30 chars
-char mqtt_payload_out_hold_3[30]; //  = "123456789012345678901234567890"; // 30 chars
+char mqtt_user[31];
+char mqtt_pass[31];
+char mqtt_willTopic[51];
+int mqtt_willQos;
+boolean mqtt_willRetain;
+char mqtt_willMsg[31];
+int usedRelaisCount = RELAIS_COUNT;
+int usedButtonsCount = BUTTONS_COUNT;
+char mqtt_topic_in[51];
+char mqtt_topic_out[51];
+char mqtt_topic_out_hold_1[51];
+char mqtt_topic_out_hold_2[51];
+char mqtt_topic_out_hold_3[51];
+char mqtt_payload_out_hold_1[31];
+char mqtt_payload_out_hold_2[31];
+char mqtt_payload_out_hold_3[31];
 int domoticzIdx[3] = {DOMOTICZ_IDX_1, DOMOTICZ_IDX_2, DOMOTICZ_IDX_3}; // initially set to 0, must be defined in config
-char domoticz_out_topic[30]; //  = "123456789012345678901234567890"; // 30 chars
+char domoticz_out_topic[51];
 
 int relais_impulse[3] = {RELAIS1_IMPULSE, RELAIS2_IMPULSE, RELAIS3_IMPULSE};
 
 // global variables
 long mqttLastReconnectAttempt = 0;
 
-int usedRelaisCount = RELAIS_COUNT;
 bool relais_state[RELAIS_COUNT];
 bool relais_setState[RELAIS_COUNT];
 
@@ -124,12 +130,11 @@ byte lastSwitchSource[3] = {0, 0, 0}; // 0 = button, 1 = serial/mqtt cmd, 2 = we
 unsigned long lastSwitchTime[3] = { 0, 0, 0 }; // this is set to millis() when relais was toggled by button or web. domoticz/out updates for this Idx are then filtered out for [dismissUpdateFromDomoticzTimeout]
 int dismissUpdateFromDomoticzTimeout = 1500;
 
-char cmdPayload[100]; // buffer for commands
+char cmdPayload[101]; // buffer for commands
 boolean cmdInQueue = false; // command is queued and will be processed next loop() run
 
-
-
-
+bool saveConfigToFlash = false;
+bool saveConfig2ToFlash = false;
 
 WiFiClient espClient;
 PubSubClient mqttclient(espClient);
@@ -158,18 +163,43 @@ void setup() {
   }
 
   // set config default parameters
-  strcpy(deviceName, DEVICE_NAME);
-  strcpy(mqtt_server, MQTT_SERVER);
-  strcpy(mqtt_topic_in, MQTT_TOPIC_IN);
-  strcpy(mqtt_topic_out, MQTT_TOPIC_OUT);
-  strcpy(mqtt_topic_out_hold_1, BUTTON1_HOLD_TOPIC_OUT);
-  strcpy(mqtt_topic_out_hold_2, BUTTON2_HOLD_TOPIC_OUT);
-  strcpy(mqtt_topic_out_hold_3, BUTTON3_HOLD_TOPIC_OUT);
-  strcpy(mqtt_payload_out_hold_1, BUTTON1_HOLD_PAYLOAD_OUT);
-  strcpy(mqtt_payload_out_hold_2, BUTTON2_HOLD_PAYLOAD_OUT);
-  strcpy(mqtt_payload_out_hold_3, BUTTON3_HOLD_PAYLOAD_OUT);
-  strcpy(domoticz_out_topic, DOMOTICZ_OUT_TOPIC); // changeable subscription topic, as domoticz supports different flat/hierarchical out-topics
+  strlcpy(deviceName, DEVICE_NAME, 31);
+  strlcpy(mqtt_server, MQTT_SERVER, 41);
+  strlcpy(mqtt_topic_in, MQTT_TOPIC_IN, 51);
+  strlcpy(mqtt_topic_out, MQTT_TOPIC_OUT, 51);
+  strlcpy(mqtt_topic_out_hold_1, BUTTON1_HOLD_TOPIC_OUT, 51);
+  strlcpy(mqtt_topic_out_hold_2, BUTTON2_HOLD_TOPIC_OUT, 51);
+  strlcpy(mqtt_topic_out_hold_3, BUTTON3_HOLD_TOPIC_OUT, 51);
+  strlcpy(mqtt_payload_out_hold_1, BUTTON1_HOLD_PAYLOAD_OUT, 31);
+  strlcpy(mqtt_payload_out_hold_2, BUTTON2_HOLD_PAYLOAD_OUT, 31);
+  strlcpy(mqtt_payload_out_hold_3, BUTTON3_HOLD_PAYLOAD_OUT, 31);
+  strlcpy(domoticz_out_topic, DOMOTICZ_OUT_TOPIC, 51); // changeable subscription topic, as domoticz supports different flat/hierarchical out-topics
+
+  Serial.println("default config values loaded..");
+
+
+
+  SPIFFS.begin();
+
+  if (!SPIFFS.exists("/formatComplete.txt")) {
+    Serial.println("Please wait 30 secs for SPIFFS to be formatted");
+    SPIFFS.format();
+    Serial.println("Spiffs formatted");
+
+    File f = SPIFFS.open("/formatComplete.txt", "w");
+    if (!f) {
+      Serial.println("file open failed");
+    } else {
+      f.println("Format Complete");
+    }
+  } else {
+    Serial.println("SPIFFS is formatted. Moving along...");
+  }
 
+
+
+
+  //SPIFFS.format();
   // load config from SPIFFS file if exists
   if (!loadConfig()) {
     Serial.println("Failed to load config");
@@ -177,6 +207,12 @@ void setup() {
     Serial.println("Config loaded");
   }
 
+  if (!loadConfig2()) {
+    Serial.println("Failed to load config2");
+  } else {
+    Serial.println("Config2 loaded");
+  }
+
   // set relais pin modes
   for (int i = 0; i < RELAIS_COUNT; i++) {
     pinMode(relais_pins[i], OUTPUT);
@@ -225,10 +261,15 @@ void setup() {
   mqttClientInit();
 
   Serial.println("setup complete.");
+  delay(1000);
 } //void setup
 
+
+
 void loop() {
 
+  checkSaveConfigTriggered();
+
   relais_handleImpulseTimeout();
 
   //everySecond();

+ 2 - 2
src/WiFiSwitch/commands.ino

@@ -12,7 +12,7 @@ void serialEvent() {
     serBuffer[serBufferCount] = '\0'; // string nullterminieren
     Serial.print("serial cmd: ");
     Serial.println(serBuffer);
-    strcpy(cmdPayload, serBuffer);
+    strlcpy(cmdPayload, serBuffer, 101);
     cmdInQueue = true;
     evalCmd();
     serBufferCount = 0;
@@ -168,7 +168,7 @@ void evalCmd() {
       loadConfig();
     }
     else if (strncmp(cmdPayload, "getconf", 7) == 0) {
-      getConfig();
+      printConfig();
     }
 
 

+ 271 - 149
src/WiFiSwitch/config.ino

@@ -1,100 +1,136 @@
 
+bool setConfig(char* param, char* value) {
+  // sets the corresponding config variable for 'param' to new value
+  // does not trigger saving to flash
+  // does not distinguish between config and config2 as this is only split on flash and web-interface
 
+  Serial.print("setConfig - '");
+  Serial.print(param);
+  Serial.print("' to '");
+  Serial.print(value);
+  Serial.println("'");
 
-//const char* deviceName = DEVICE_NAME;
-//const char* mqtt_server = MQTT_SERVER;
-//const int mqtt_port = MQTT_PORT;
-//const char* mqtt_topic_in = MQTT_TOPIC_IN;
-//const char* mqtt_topic_out = MQTT_TOPIC_OUT;
-//const char* mqtt_topic_out_hold[3] = { BUTTON1_HOLD_TOPIC_OUT, BUTTON2_HOLD_TOPIC_OUT, BUTTON3_HOLD_TOPIC_OUT };
-//const char* mqtt_payload_out_hold[3] = { BUTTON1_HOLD_PAYLOAD_OUT, BUTTON2_HOLD_PAYLOAD_OUT, BUTTON3_HOLD_PAYLOAD_OUT };
-//const int domoticzIdx[3] = {DOMOTICZ_IDX_1, DOMOTICZ_IDX_2, DOMOTICZ_IDX_3}; // initially set to 0, must be defined in config
-
-
-bool loadConfig() {
-  File configFile = SPIFFS.open("/config.json", "r");
-  if (!configFile) {
-    Serial.println("Failed to open config file");
-    return false;
+  if ( strcmp(param, "devName") == 0 ) {
+    strlcpy(deviceName, value, 31);
+    //    deviceName[30] = '\0';
   }
-
-  size_t size = configFile.size();
-  if (size > 1024) {
-    Serial.println("Config file size is too large");
-    return false;
+  else if ( strcmp(param, "usedRelais") == 0 ) {
+    usedRelaisCount = atoi(value);
   }
-
-  // Allocate a buffer to store contents of the file.
-  std::unique_ptr<char[]> buf(new char[size]);
-
-  // We don't use String here because ArduinoJson library requires the input
-  // buffer to be mutable. If you don't use ArduinoJson, you may as well
-  // use configFile.readString instead.
-  configFile.readBytes(buf.get(), size);
-
-  StaticJsonBuffer<1000> jsonBuffer;
-  JsonObject& json = jsonBuffer.parseObject(buf.get());
-
-  if (!json.success()) {
-    Serial.println("Failed to parse config file");
-    return false;
+  else if ( strcmp(param, "usedButtons") == 0 ) {
+    usedButtonsCount = atoi(value);
+  }
+  else if ( strcmp(param, "mqttHost") == 0 ) {
+    strlcpy(mqtt_server, value, 41);
+    //mqtt_server[40] = '\0';
+  }
+  else if ( strcmp(param, "mqttPort") == 0 ) {
+    mqtt_port = atoi(value);
+  }
+  else if ( strcmp(param, "mqttUser") == 0 ) {
+    strlcpy(mqtt_user, value, 31);
+  }
+  else if ( strcmp(param, "mqttPass") == 0 ) {
+    strlcpy(mqtt_pass, value, 31);
+  }
+  else if ( strcmp(param, "willTop") == 0 ) {
+    strlcpy(mqtt_willTopic, value, 51);
+  }
+  else if ( strcmp(param, "willQos") == 0 ) {
+    mqtt_willQos = atoi(value);
+  }
+  else if ( strcmp(param, "willRet") == 0 ) {
+    if (atoi(value) == 1) mqtt_willRetain = true;
+    else mqtt_willRetain = false;
+  }
+  else if ( strcmp(param, "willMsg") == 0 ) {
+    strlcpy(mqtt_willMsg, value, 31);
+  }
+  else if ( strcmp(param, "inTop") == 0 ) {
+    strlcpy(mqtt_topic_in, value, 51);
+  }
+  else if ( strcmp(param, "outTop") == 0 ) {
+    strlcpy(mqtt_topic_out, value, 51);
+  }
+  else if ( strcmp(param, "outTop_hold1") == 0 ) {
+    strlcpy(mqtt_topic_out_hold_1, value, 51);
+  }
+  else if ( strcmp(param, "outTop_hold2") == 0 ) {
+    strlcpy(mqtt_topic_out_hold_2, value, 51);
+  }
+  else if ( strcmp(param, "outTop_hold3") == 0 ) {
+    strlcpy(mqtt_topic_out_hold_3, value, 51);
+  }
+  else if ( strcmp(param, "outPld_hold1") == 0 ) {
+    Serial.print("set outPld_hold1");
+    strlcpy(mqtt_payload_out_hold_1, value, 31);
+  }
+  else if ( strcmp(param, "outPld_hold2") == 0 ) {
+    Serial.print("set outPld_hold2");
+    strlcpy(mqtt_payload_out_hold_2, value, 31);
+  }
+  else if ( strcmp(param, "outPld_hold3") == 0 ) {
+    Serial.print("set outPld_hold3");
+    strlcpy(mqtt_payload_out_hold_3, value, 31);
+  }
+  else if ( strcmp(param, "domoIdx1") == 0 ) {
+    domoticzIdx[0] = atoi(value);
+  }
+  else if ( strcmp(param, "domoIdx2") == 0 ) {
+    domoticzIdx[1] = atoi(value);
+  }
+  else if ( strcmp(param, "domoIdx3") == 0 ) {
+    domoticzIdx[2] = atoi(value);
+  }
+  else if ( strcmp(param, "domoOutTop") == 0 ) {
+    strlcpy(domoticz_out_topic, value, 51);
+  }
+  else if ( strcmp(param, "impuls1") == 0 ) {
+    relais_impulse[0] = atoi(value);
+  }
+  else if ( strcmp(param, "impuls2") == 0 ) {
+    relais_impulse[1] = atoi(value);
+  }
+  else if ( strcmp(param, "impuls3") == 0 ) {
+    relais_impulse[2] = atoi(value);
   }
-
-  strcpy(deviceName, json["devName"]);
-  strcpy(mqtt_server, json["mqttHost"]);
-  mqtt_port = atoi(json["mqttPort"]);
-  strcpy(mqtt_topic_in, json["inTop"]);
-  strcpy(mqtt_topic_out, json["outTop"]);
-  strcpy(mqtt_topic_out_hold_1, json["outTop_hold1"]);
-  strcpy(mqtt_topic_out_hold_2, json["outTop_hold2"]);
-  strcpy(mqtt_topic_out_hold_3, json["outTop_hold3"]);
-  strcpy(mqtt_payload_out_hold_1, json["outPld_hold1"]);
-  strcpy(mqtt_payload_out_hold_2, json["outPld_hold2"]);
-  strcpy(mqtt_payload_out_hold_3, json["outPld_hold3"]);
-  domoticzIdx[0] = atoi(json["domoIdx1"]);
-  domoticzIdx[1] = atoi(json["domoIdx2"]);
-  domoticzIdx[2] = atoi(json["domoIdx3"]);
-  strcpy(domoticz_out_topic, json["domoOutTop"]);
-  relais_impulse[0] = atoi(json["impuls1"]);
-  relais_impulse[1] = atoi(json["impuls2"]);
-  relais_impulse[2] = atoi(json["impuls3"]);
-
-
-  //  deviceName = json["devName"];
-  //  mqtt_server = json["mqttHost"];
-  //  mqtt_port = atoi(json["mqttPort"]);
-  //  mqtt_topic_in = json["inTop"];
-  //  mqtt_topic_out = json["outTop"];
-  //  mqtt_topic_out_hold[0] = json["outTop_hold1"];
-  //  mqtt_topic_out_hold[1] = json["outTop_hold2"];
-  //  mqtt_topic_out_hold[2] = json["outTop_hold3"];
-  //  mqtt_payload_out_hold[0] = json["outPld_hold1"];
-  //  mqtt_payload_out_hold[1] = json["outPld_hold2"];
-  //  mqtt_payload_out_hold[2] = json["outPld_hold3"];
-  //  domoticzIdx[0] = atoi(json["domoIdx1"]);
-  //  domoticzIdx[1] = atoi(json["domoIdx2"]);
-  //  domoticzIdx[2] = atoi(json["domoIdx3"]);
-  //  domoticz_out_topic = json["domoOutTop"];
-  //  relais_impulse[0] = json["impuls1"];
-  //  relais_impulse[1] = json["impuls2"];
-  //  relais_impulse[2] = json["impuls3"];
-
-  Serial.println("Loaded config values:");
-  getConfig();
-  return true;
 }
 
-void getConfig() {
+void printConfig() {
+  // prints current config vars to serial
   Serial.print("devName: ");
   Serial.println(deviceName);
+  Serial.print("httpUser: ");
+  Serial.println(http_user);
+  Serial.print("httpPass: ");
+  Serial.println(http_pass);
   Serial.print("mqttHost: ");
   Serial.println(mqtt_server);
   Serial.print("mqttPort: ");
   Serial.println(mqtt_port);
+  Serial.print("mqttUser: ");
+  Serial.println(mqtt_user);
+  Serial.print("mqttPass: ");
+  Serial.println(mqtt_pass);
   Serial.print("inTop: ");
   Serial.println(mqtt_topic_in);
   Serial.print("outTop: ");
   Serial.println(mqtt_topic_out);
+  Serial.print("willTop: ");
+  Serial.println(mqtt_willTopic);
+  Serial.print("willQos: ");
+  Serial.println(mqtt_willQos);
+  Serial.print("willRet: ");
+  Serial.println(mqtt_willRetain);
+  Serial.print("willMsg: ");
+  Serial.println(mqtt_willMsg);
+  Serial.print("domoOutTop: ");
+  Serial.println(domoticz_out_topic);
+
+  Serial.print("usedRelais: ");
+  Serial.println(usedRelaisCount);
+  Serial.print("usedButtons: ");
+  Serial.println(usedButtonsCount);
   Serial.print("outTop_hold1: ");
   Serial.println(mqtt_topic_out_hold_1);
   Serial.print("outTop_hold2: ");
@@ -113,100 +149,175 @@ void getConfig() {
   Serial.println(domoticzIdx[1]);
   Serial.print("domoIdx3: ");
   Serial.println(domoticzIdx[2]);
-  Serial.print("domoOutTop: ");
-  Serial.println(domoticz_out_topic);
   Serial.print("impuls1: ");
   Serial.println(relais_impulse[0]);
   Serial.print("impuls2: ");
   Serial.println(relais_impulse[1]);
   Serial.print("impuls3: ");
   Serial.println(relais_impulse[2]);
+
+  Serial.println();
 }
 
+bool loadConfig() { // loadConfig 1
+  if (SPIFFS.exists("/config.json")) {
+    File configFile = SPIFFS.open("/config.json", "r");
+    if (!configFile) {
+      Serial.println("ERR: Failed to open file /config.json");
+      return false;
+    }
+    else {
+      Serial.println("file /config.json opened");
+      size_t size = configFile.size();
 
-bool setConfig(char* param, char* value) {
+      Serial.print("file size: ");
+      Serial.println(size);
 
-//  char buf[80];
-//  int len = strlen(value);
-//  for (int i = 0; i < len; i++) {
-//    buf[i] = value[i];
-//  }
-//  buf[len] = '\0';
+      if (size > 800) {
+        Serial.println("Config file size is too large");
+        return false;
+      }
 
-  Serial.print("param: ");
-  Serial.print(param);
-  Serial.print(", value: ");
-  Serial.println(value);
+      // Allocate a buffer to store contents of the file.
+      std::unique_ptr<char[]> buf(new char[size]);
 
-  if ( strcmp(param, "devName") == 0 ) {
-    strcpy(deviceName, value);
+      // We don't use String here because ArduinoJson library requires the input
+      // buffer to be mutable. If you don't use ArduinoJson, you may as well
+      // use configFile.readString instead.
+      configFile.readBytes(buf.get(), size);
+
+      StaticJsonBuffer<810> jsonBuffer;
+      JsonObject& json = jsonBuffer.parseObject(buf.get());
+
+      if (!json.success()) {
+        Serial.println("Failed to parse config file");
+        return false;
+      }
+
+      strlcpy(deviceName, json["devName"], 31);
+      strlcpy(http_user, json["httpUser"], 31);
+      strlcpy(http_pass, json["httpPass"], 31);
+      strlcpy(mqtt_server, json["mqttHost"], 41);
+      mqtt_port = atoi(json["mqttPort"]);
+      strlcpy(mqtt_user, json["mqttUser"], 31);
+      strlcpy(mqtt_pass, json["mqttPass"], 31);
+      strlcpy(mqtt_topic_in, json["inTop"], 51);
+      strlcpy(mqtt_topic_out, json["outTop"], 51);
+      strlcpy(mqtt_willTopic, json["willTop"], 51);
+      mqtt_willQos = atoi(json["willQos"]);
+      if (atoi(json["willRet"]) == 1) mqtt_willRetain = true;
+      else mqtt_willRetain = false;
+      strlcpy(mqtt_willMsg, json["willMsg"], 31);
+      strlcpy(domoticz_out_topic, json["domoOutTop"], 51);
+
+      Serial.println("Loaded config values:");
+      printConfig();
+      return true;
+    }
   }
-  else if ( strcmp(param, "mqttHost") == 0 ) {
-    strcpy(mqtt_server, value);
+  else {
+    Serial.println("file /config.json file does not exist");
+    return false;
   }
-    else if ( strcmp(param, "mqttPort") == 0 ) {
-      mqtt_port = atoi(value);
-    }
-    else if ( strcmp(param, "inTop") == 0 ) {
-      strcpy(mqtt_topic_in, value);
-    }
-    else if ( strcmp(param, "outTop") == 0 ) {
-      strcpy(mqtt_topic_out, value);
-    }
-    else if ( strcmp(param, "outTop_hold1") == 0 ) {
-      strcpy(mqtt_topic_out_hold_1, value);
-    }
-    else if ( strcmp(param, "outTop_hold2") == 0 ) {
-      strcpy(mqtt_topic_out_hold_2, value);
-    }
-    else if ( strcmp(param, "outTop_hold3") == 0 ) {
-      strcpy(mqtt_topic_out_hold_3, value);
-    }
-    else if ( strcmp(param, "outPld_hold1") == 0 ) {
-      Serial.print("set outPld_hold1");
-      strcpy(mqtt_payload_out_hold_1, value);
-    }
-    else if ( strcmp(param, "outPld_hold2") == 0 ) {
-      Serial.print("set outPld_hold2");
-      strcpy(mqtt_payload_out_hold_2, value);
-    }
-    else if ( strcmp(param, "outPld_hold3") == 0 ) {
-      Serial.print("set outPld_hold3");
-      strcpy(mqtt_payload_out_hold_3, value);
-    }
-    else if ( strcmp(param, "domoIdx1") == 0 ) {
-      domoticzIdx[0] = atoi(value);
-    }
-    else if ( strcmp(param, "domoIdx2") == 0 ) {
-      domoticzIdx[1] = atoi(value);
-    }
-    else if ( strcmp(param, "domoIdx3") == 0 ) {
-      domoticzIdx[2] = atoi(value);
-    }
-    else if ( strcmp(param, "domoOutTop") == 0 ) {
-      strcpy(domoticz_out_topic, value);
-    }
-    else if ( strcmp(param, "impuls1") == 0 ) {
-      relais_impulse[0] = atoi(value);
-    }
-    else if ( strcmp(param, "impuls2") == 0 ) {
-      relais_impulse[1] = atoi(value);
+
+
+} // loadConfig 1
+
+bool loadConfig2() {
+  if (SPIFFS.exists("/config2.json")) {
+    File configFile = SPIFFS.open("/config2.json", "r");
+    if (!configFile) {
+      Serial.println("ERR: Failed to open file /config2.json");
+      return false;
     }
-    else if ( strcmp(param, "impuls3") == 0 ) {
-      relais_impulse[2] = atoi(value);
+    else {
+      Serial.println("file /config2.json opened");
+      size_t size = configFile.size();
+      Serial.print("file size: ");
+      Serial.println(size);
+      if (size > 1195) {
+        Serial.println("Config file size is too large");
+        return false;
+      }
+
+      // Allocate a buffer to store contents of the file.
+      std::unique_ptr<char[]> buf(new char[size]);
+
+      // We don't use String here because ArduinoJson library requires the input
+      // buffer to be mutable. If you don't use ArduinoJson, you may as well
+      // use configFile.readString instead.
+      configFile.readBytes(buf.get(), size);
+
+      StaticJsonBuffer<810> jsonBuffer;
+      JsonObject& json = jsonBuffer.parseObject(buf.get());
+
+      if (!json.success()) {
+        Serial.println("Failed to parse config file");
+        return false;
+      }
+
+      usedRelaisCount = atoi(json["usedRelais"]);
+      usedButtonsCount = atoi(json["usedButtons"]);
+      strlcpy(mqtt_topic_out_hold_1, json["outTop_hold1"], 51);
+      strlcpy(mqtt_topic_out_hold_2, json["outTop_hold2"], 51);
+      strlcpy(mqtt_topic_out_hold_3, json["outTop_hold3"], 51);
+      strlcpy(mqtt_payload_out_hold_1, json["outPld_hold1"], 31);
+      strlcpy(mqtt_payload_out_hold_2, json["outPld_hold2"], 31);
+      strlcpy(mqtt_payload_out_hold_3, json["outPld_hold3"], 31);
+      domoticzIdx[0] = atoi(json["domoIdx1"]);
+      domoticzIdx[1] = atoi(json["domoIdx2"]);
+      domoticzIdx[2] = atoi(json["domoIdx3"]);
+      relais_impulse[0] = atoi(json["impuls1"]);
+      relais_impulse[1] = atoi(json["impuls2"]);
+      relais_impulse[2] = atoi(json["impuls3"]);
+
+      Serial.println("Loaded config values:");
+      printConfig();
+      return true;
     }
+  }
+  else {
+    Serial.println("file /config2.json file does not exist");
+    return false;
+  }
 }
 
 
-bool saveConfig() {
-  StaticJsonBuffer<1000> jsonBuffer;
+bool saveConfig() { // safeConfig
+  StaticJsonBuffer<810> jsonBuffer;
   JsonObject& json = jsonBuffer.createObject();
 
   json["devName"] = deviceName;
+  json["httpUser"] = http_user;
+  json["httpPass"] = http_pass;
   json["mqttHost"] = mqtt_server;
   json["mqttPort"] = mqtt_port;
+  json["mqttUser"] = mqtt_user;
+  json["mqttPass"] = mqtt_pass;
+  json["willTop"] = mqtt_willTopic;
+  json["willQos"] = mqtt_willQos;
+  json["willRet"] = mqtt_willRetain;
+  json["willMsg"] = mqtt_willMsg;
   json["inTop"] = mqtt_topic_in;
   json["outTop"] = mqtt_topic_out;
+
+  File configFile = SPIFFS.open("/config.json", "w");
+  if (!configFile) {
+    Serial.println("Failed to open config file for writing");
+    return false;
+  }
+
+  json.printTo(configFile);
+  return true;
+} // safeConfig
+
+
+bool saveConfig2() { // safeConfig2
+  StaticJsonBuffer<810> jsonBuffer;
+  JsonObject& json = jsonBuffer.createObject();
+
+  json["usedRelais"] = usedRelaisCount;
+  json["usedButtons"] = usedButtonsCount;
   json["outTop_hold1"] = mqtt_topic_out_hold_1;
   json["outTop_hold2"] = mqtt_topic_out_hold_2;
   json["outTop_hold3"] = mqtt_topic_out_hold_3;
@@ -221,12 +332,23 @@ bool saveConfig() {
   json["impuls2"] = relais_impulse[1];
   json["impuls3"] = relais_impulse[2];
 
-  File configFile = SPIFFS.open("/config.json", "w");
+  File configFile = SPIFFS.open("/config2.json", "w");
   if (!configFile) {
-    Serial.println("Failed to open config file for writing");
+    Serial.println("Failed to open config2 file for writing");
     return false;
   }
 
   json.printTo(configFile);
   return true;
+} // safeConfig2
+
+void checkSaveConfigTriggered() {
+  if (saveConfigToFlash) {
+    saveConfigToFlash = false;
+    saveConfig();
+  }
+  if (saveConfig2ToFlash) {
+    saveConfig2ToFlash = false;
+    saveConfig2();
+  }
 }

+ 84 - 62
src/WiFiSwitch/data/conf.htm

@@ -1,62 +1,84 @@
-<h3>Configuration</h3>
-MQTT Server:
-<span id="mqtthost"></span>
-<br/> MQTT Port:
-<span id="mqttport"></span>
-<br/> MQTT User:
-<span id="mqttuser"></span>
-<br/> MQTT Password:
-<span id="mqttpass"></span>
-
-<h6>Last updated
-	<span id="ut"></span> seconds ago.
-	<span id="status"></span>
-</h6>
-
-<h3>Update Data</h3>
-<form id="xform" onsubmit="return transmit(this)">
-	x:
-	<input type="number" name="x" />
-	<input type="submit" />
-</form>
-<form id="yform" onsubmit="return transmit(this)">
-	y:
-	<input type="text" name="y" />
-	<input type="submit" />
-</form>
-<form id="zform" onsubmit="return transmit(this)">
-	z:
-	<input type="text" name="z" />
-	<input type="submit" />
-</form>
-
-<a href="wifi.htm">WiFi settings</a>
-
-<script>
-	function g(i) { return document.getElementById(i) };
-	var xhttp, updateTime;
-
-	function transmit(f) {
-		if (!xhttp) { //prevent simultaneous requests
-			g("status").innerHTML = "updating...";
-			xhttp = new XMLHttpRequest();
-			xhttp.open("POST", "/api");
-			xhttp.send(f ? (new FormData(f)) : "");
-			xhttp.onreadystatechange = function () {
-				if (xhttp.readyState === XMLHttpRequest.DONE && xhttp.status === 200) {
-					var data = JSON.parse(xhttp.responseText);
-					g("x").innerHTML = data.x;
-					g("y").innerHTML = data.y;
-					g("z").innerHTML = data.z;
-					xhttp = null;
-					g("status").innerHTML = "";
-					updateTime = 0;
-				}
-			}
-		}
-		return false; //prevent form redirect
-	}
-	transmit();
-	setInterval(function () { g("ut").innerHTML = ++updateTime; }, 1000);
-	setInterval(transmit, 5000); //autoupdate display every 5s
-</script>
+<h3>Configuration</h3>
+
+<form id='reloadForm' onsubmit='return transmit(this)'>
+<input type='submit' value='reload current values'/>
+</form>
+  
+<form id='form1' onsubmit='return transmit(this)'>Device Name: <input type='text' name='devName' id='devName'/><input type='submit' value='Update'/></form>
+<form id='form2' onsubmit='return transmit(this)'>MQTT Server: <input type='text' name='mqttHost' id='mqttHost'/><input type='submit' value='Update'/></form>
+<form id='form3' onsubmit='return transmit(this)'>MQTT Port: <input type='number' name='mqttPort' id='mqttPort'/><input type='submit' value='Update'/></form>
+<form id='form4' onsubmit='return transmit(this)'>MQTT User: <input type='text' name='mqttUser' id='mqttUser'/><input type='submit' value='Update'/></form>
+<form id='form5' onsubmit='return transmit(this)'>MQTT Password: <input type='text' name='mqttPass' id='mqttPass'/><input type='submit' value='Update'/></form>
+<form id='form6' onsubmit='return transmit(this)'>In Topic: <input type='text' name='inTop' id='inTop'/><input type='submit'  value='Update'/></form>
+<form id='form7' onsubmit='return transmit(this)'>Out Topic: <input type='text' name='outTop' id='outTop'/><input type='submit' value='Update'/></form>
+<form id='form8' onsubmit='return transmit(this)'>Out Topic Hold 1: <input type='text' name='outTop_hold1' id='outTop_hold1'/><input type='submit' value='Update'/></form>
+<form id='form9' onsubmit='return transmit(this)'>Out Topic Hold 2: <input type='text' name='outTop_hold2' id='outTop_hold2'/><input type='submit' value='Update'/></form>
+<form id='form10' onsubmit='return transmit(this)'>Out Topic Hold 3: <input type='text' name='outTop_hold3' id='outTop_hold3'/><input type='submit' value='Update'/></form>
+<form id='form11' onsubmit='return transmit(this)'>Out Payload Hold 1: <input type='text' name='outPld_hold1' id='outPld_hold1'/><input type='submit' value='Update'/></form>
+<form id='form12' onsubmit='return transmit(this)'>Out Payload Hold 2: <input type='text' name='outPld_hold2' id='outPld_hold2'/><input type='submit' value='Update'/></form>
+<form id='form13' onsubmit='return transmit(this)'>Out Payload Hold 3: <input type='text' name='outPld_hold3' id='outPld_hold3'/><input type='submit' value='Update'/></form>
+<form id='form14' onsubmit='return transmit(this)'>Domoticz Idx 1: <input type='number' name='domoIdx1' id='domoIdx1'/><input type='submit' value='Update'/></form>
+<form id='form15' onsubmit='return transmit(this)'>Domoticz Idx 2: <input type='number' name='domoIdx2' id='domoIdx2'/><input type='submit' value='Update'/></form>
+<form id='form16' onsubmit='return transmit(this)'>Domoticz Idx 3: <input type='number' name='domoIdx3' id='domoIdx3'/><input type='submit' value='Update'/></form>
+<form id='form17' onsubmit='return transmit(this)'>Domoticz Out Topic: <input type='text' name='domoOutTop' id='domoOutTop'/><input type='submit'  value='Update'/></form>
+<form id='form18' onsubmit='return transmit(this)'>Relais Impulse 1: <input type='number' name='impuls1' id='impuls1'/><input type='submit' value='Update'/></form>
+<form id='form19' onsubmit='return transmit(this)'>Relais Impulse 2: <input type='number' name='impuls2' id='impuls2'/><input type='submit' value='Update'/></form>
+<form id='form20' onsubmit='return transmit(this)'>Relais Impulse 3: <input type='number' name='impuls3' id='impuls3'/><input type='submit' value='Update'/></form>
+
+<br>
+<form id='saveForm' onsubmit='return transmit(this)'>
+<input type='hidden' name='save' value='1'>
+<input type='submit' value='Save changes to Flash'/>
+</form>
+<form id='rebootForm' onsubmit='return transmit(this)'>
+<input type='hidden' name='reboot' value='1'>
+<input type='submit' value='Reboot'/>
+</form>
+
+
+<script>
+	function g(i) { return document.getElementById(i) };
+	var xhttp, updateTime;
+
+	function transmit(f) {
+		if (!xhttp) { //prevent simultaneous requests
+			//g('status').innerHTML = 'updating...';
+			xhttp = new XMLHttpRequest();
+			xhttp.open('POST', 'confdata');
+			xhttp.send(f ? (new FormData(f)) : '');
+			xhttp.onreadystatechange = function () {
+				if (xhttp.readyState === XMLHttpRequest.DONE && xhttp.status === 200) {
+					var data = JSON.parse(xhttp.responseText);
+					g('devName').value = data.devName
+					g('mqttHost').value = data.mqttHost;
+					g('mqttPort').value = data.mqttPort;
+					g('mqttUser').value = data.mqttUser;
+					g('mqttPass').value = data.mqttPass;
+					g('inTop').value = data.inTop;
+					g('outTop').value = data.outTop;
+					g('outTop_hold1').value = data.outTop_hold1;
+					g('outTop_hold2').value = data.outTop_hold2;
+					g('outTop_hold3').value = data.outTop_hold3;
+					g('outPld_hold1').value = data.outPld_hold1;
+					g('outPld_hold2').value = data.outPld_hold2;
+					g('outPld_hold3').value = data.outPld_hold3;
+					g('domoIdx1').value = data.domoIdx1;
+					g('domoIdx2').value = data.domoIdx2;
+					g('domoIdx3').value = data.domoIdx3;
+					g('domoOutTop').value = data.domoOutTop;
+					g('impuls1').value = data.impuls1;
+					g('impuls2').value = data.impuls2;
+					g('impuls3').value = data.impuls3;
+					
+					xhttp = null;
+					//g('status').innerHTML = '';
+					updateTime = 0;
+				}
+			}
+		}
+		return false; //prevent form redirect
+	}
+	transmit();
+	//setInterval(function () { g('ut').innerHTML = ++updateTime; }, 1000);
+	//setInterval(transmit, 5000); //autoupdate display every 5s
+</script>

+ 17 - 0
src/WiFiSwitch/data/conf.json

@@ -0,0 +1,17 @@
+{
+  "devName":"1234567890123456789012345678900",
+  "usedRelais":3,
+  "usedButtons":3,
+  "httpHost":"1234567890123456789012345678900",
+  "httpPass":"1234567890123456789012345678900",
+  "mqttHost":"12345678901234567890123456789012345678900",
+  "mqttPort":12345,
+  "mqttUser":"1234567890123456789012345678900",
+  "mqttPass":"1234567890123456789012345678900",
+  "inTop":"123456789012345678901234567890123456789012345678900",
+  "outTop":"123456789012345678901234567890123456789012345678900",
+  "willTop":"123456789012345678901234567890123456789012345678900",
+  "willQos":2,
+  "willRet":false,
+  "willMsg":"1234567890123456789012345678900",
+}

+ 14 - 0
src/WiFiSwitch/data/conf2.json

@@ -0,0 +1,14 @@
+{
+  "outTop_hold1":"123456789012345678901234567890123456789012345678900",
+  "outTop_hold2":"123456789012345678901234567890123456789012345678900",
+  "outTop_hold3":"123456789012345678901234567890123456789012345678900",
+  "outPld_hold1":"1234567890123456789012345678900",
+  "outPld_hold2":"1234567890123456789012345678900",
+  "outPld_hold3":"1234567890123456789012345678900",
+  "domoIdx1":12345,
+  "domoIdx2":12345,
+  "domoIdx3":12345,
+  "impuls1":12345,
+  "impuls2":12345,
+  "impuls3":12345
+}

+ 22 - 0
src/WiFiSwitch/data/confdata

@@ -0,0 +1,22 @@
+{
+  "devName":"Testname",
+  "mqttHost":"10.1.1.11",
+  "mqttPort":1883,
+  "mqttUser":"",
+  "mqttPass":"",
+  "inTop":"Test/Switch/cmd",
+  "outTop":"Test/Switch/status",
+  "outTop_hold1":"Test/Switch/hold",
+  "outTop_hold2":"Test/Switch/hold",
+  "outTop_hold3":"Test/Switch/hold",
+  "outPld_hold1":"TOGGLE",
+  "outPld_hold2":"TOGGLE",
+  "outPld_hold3":"TOGGLE",
+  "domoIdx1":209,
+  "domoIdx2":1,
+  "domoIdx3":0,
+  "domoOutTop":"domoticz/out",
+  "impuls1":0,
+  "impuls2":0,
+  "impuls3":0
+}

+ 27 - 0
src/WiFiSwitch/data/confdata_max

@@ -0,0 +1,27 @@
+{
+  "devName":"1234567890123456789012345678900",
+  "usedRelais":3,
+  "mqttHost":"12345678901234567890123456789012345678900",
+  "mqttPort":12345,
+  "mqttUser":"1234567890123456789012345678900",
+  "mqttPass":"1234567890123456789012345678900",
+  "inTop":"123456789012345678901234567890123456789012345678900",
+  "outTop":"123456789012345678901234567890123456789012345678900",
+  "willTop":"123456789012345678901234567890123456789012345678900",
+  "willQos":2,
+  "willRet":false,
+  "willMsg":"1234567890123456789012345678900",
+  "outTop_hold1":"123456789012345678901234567890123456789012345678900",
+  "outTop_hold2":"123456789012345678901234567890123456789012345678900",
+  "outTop_hold3":"123456789012345678901234567890123456789012345678900",
+  "outPld_hold1":"1234567890123456789012345678900",
+  "outPld_hold2":"1234567890123456789012345678900",
+  "outPld_hold3":"1234567890123456789012345678900",
+  "domoIdx1":12345,
+  "domoIdx2":12345,
+  "domoIdx3":12345,
+  "domoOutTop":"123456789012345678901234567890123456789012345678900",
+  "impuls1":12345,
+  "impuls2":12345,
+  "impuls3":12345
+}

+ 1 - 1
src/WiFiSwitch/domoticz.ino

@@ -22,7 +22,7 @@ void parseDomoticzOut() {
   int16_t nvalue;
   int16_t found = 0;
 
-  StaticJsonBuffer<400> jsonBuf;
+  StaticJsonBuffer<450> jsonBuf;
   JsonObject& domoticz = jsonBuf.parseObject(domoticzOutPayload);
   idx = domoticz["idx"];
   nvalue = domoticz["nvalue"];

+ 352 - 30
src/WiFiSwitch/httpServer.ino

@@ -25,7 +25,7 @@ static const char httpRoot[] PROGMEM =
   <a href='/update'>Firmware Update</a>
   <script>
   function g(i) { return document.getElementById(i) };
-  var xhttp, updateTime;
+  var xhttp, updateTime, reqTime, reqFin;
   var textA = 'AUS';
   var textE = 'EIN';
   
@@ -38,47 +38,228 @@ static const char httpRoot[] PROGMEM =
   function transmit(f) {
     if (!xhttp) { 
       g('status').innerHTML = 'l&auml;dt...';
+   reqTime = 0;
+    reqFin = false;
       xhttp = new XMLHttpRequest();
-   xhttp.timeout=2000;
+      xhttp.timeout = 2000;
       xhttp.open('POST', 'api');
       xhttp.send(f ? (new FormData(f)) : '');
+      xhttp.onreadystatechange = function () {
+      if (xhttp.readyState === XMLHttpRequest.DONE && xhttp.status === 200) {
+        var data = JSON.parse(xhttp.responseText);
+        g('ssid').innerHTML = data.ssid;
+        if(data.devname != undefined) g('devname').innerHTML = data.devname;
+        if(data.swState2 != undefined) g('sw2div').style.display='inline';
+        else g('sw2div').style.display='none';
+        if(data.swState3 != undefined) g('sw3div').style.display='inline';
+        else g('sw3div').style.display='none';
+        if(data.swState1 == '1') g('tbtn1').value = textE;
+        else g('tbtn1').value = textA;
+        if(data.swState2 == '1') g('tbtn2').value = textE;
+        else g('tbtn2').value = textA;
+        if(data.swState3 == '1') g('tbtn3').value = textE;
+        else g('tbtn3').value = textA;
+        xhttp = null;
+        updateTime = 0;
+    reqFin = true;
+        }
+    else{
+          if(!reqFin && reqTime > 10) {
+          xhttp = null;
+          reqFin = true;
+          }
+    }
+      }
+    }
+    return false;
+  }
+  transmit();
+  setInterval(function () { g('ut').innerHTML = ++updateTime; ++reqTime; }, 1000);
+  setInterval(transmit, 5000);
+</script>
+</body></html>)";
+
+
+static const char httpConfPage[] PROGMEM =
+  R"(<html><head><body>
+<h3>Configuration</h3>
+<input type='button' value='reload' onclick='return transmit()'/><br><br>
+<form id='form1' onsubmit='return transmit(this)'>
+Device Name: <input type='text' name='devName' id='devName'/><br>
+HTTP User *: <input type='text' name='httpUser' id='httpUser'/><br>
+HTTP Password *: <input type='password' name='httpPass' id='httpPass'/><br>
+MQTT Server *: <input type='text' name='mqttHost' id='mqttHost'/><br>
+MQTT Port *: <input type='number' name='mqttPort' id='mqttPort'/><br>
+MQTT User *: <input type='text' name='mqttUser' id='mqttUser'/><br>
+MQTT Password *: <input type='password' name='mqttPass' id='mqttPass'/><br>
+In Topic *: <input type='text' name='inTop' id='inTop'/><br>
+Out Topic: <input type='text' name='outTop' id='outTop'/><br>
+LastWill Topic *: <input type='text' name='willTop' id='willTop'/><br>
+LastWill Qos *: <input type='number' name='willQos' id='willQos'/><br>
+LastWill Retain *: <input type='checkbox' name='willRet' id='willRet'/><br>
+LastWill Message *: <input type='text' name='willMsg' id='willMsg'/><br>
+Domoticz Out Topic *: <input type='text' name='domoOutTop' id='domoOutTop'/><br>
+<br>
+<input type='submit' value='Save'/>
+</form>
+<form id='restartForm' onsubmit='return res()'>
+<input type='hidden' name='restart' value='1'>
+<input type='submit' value='Restart'/>
+</form>
+
+<script>
+ function g(i) { return document.getElementById(i) };
+  var xhttp, reqTime, reqFin, rxhttp;
+  
+  function res() {
+    rxhttp = new XMLHttpRequest();
+ rxhttp.timeout = 1000;
+  rxhttp.open('POST', 'restart');
+  rxhttp.send('');
+  rxhttp = null;
+  return false;
+  }
+
+  function transmit(f) {
+    if (!xhttp) {   
+    reqTime = 0;
+    reqFin = false;
+    
+    var wRet = g('willRet');
+    if (wRet.checked) wRet.value ='1';
+    else {
+    wRet.value = '0';
+    wRet.checked = true;
+    wRet.style.visibility = 'hidden';
+    }
+    
+      xhttp = new XMLHttpRequest();
+    xhttp.timeout = 2000;
+      xhttp.open('POST', 'confdata');
+      xhttp.send(f ? (new FormData(f)) : '');
       xhttp.onreadystatechange = function () {
         if (xhttp.readyState === XMLHttpRequest.DONE && xhttp.status === 200) {
           var data = JSON.parse(xhttp.responseText);
-          g('ssid').innerHTML = data.ssid;
-      if(data.devname != undefined) g('devname').innerHTML = data.devname;
-   
-    if(data.swState2 != undefined) g('sw2div').style.display='inline';
-    else g('sw2div').style.display='none';
-    if(data.swState3 != undefined) g('sw3div').style.display='inline';
-    else g('sw3div').style.display='none';
+          g('httpUser').value = data.httpUser;
+          g('httpPass').value = data.httpPass;
+      g('devName').value = data.devName
+          g('mqttHost').value = data.mqttHost;
+          g('mqttPort').value = data.mqttPort;
+          g('mqttUser').value = data.mqttUser;
+          g('mqttPass').value = data.mqttPass;
+          g('inTop').value = data.inTop;
+          g('outTop').value = data.outTop;
+          g('willTop').value = data.willTop;
+          g('willQos').value = data.willQos;
+          
+      if(data.willRet == 1) {
+      wRet.checked = true;
+      wRet.style.visibility = 'visible';
+      }
+      else {
+      wRet.checked = false;
+      wRet.style.visibility = 'visible';
+      }
       
-      if(data.swState1 == '1') g('tbtn1').value = textE;
-      else g('tbtn1').value = textA;
-    if(data.swState2 == '1') g('tbtn2').value = textE;
-      else g('tbtn2').value = textA;
-    if(data.swState3 == '1') g('tbtn3').value = textE;
-      else g('tbtn3').value = textA;
+          g('willMsg').value = data.willMsg;
+          g('domoOutTop').value = data.domoOutTop;
           xhttp = null;
-          updateTime = 0;
+      reqFin = true;
         }
+    else{
+          if(!reqFin && reqTime > 10) {
+          xhttp = null;
+          reqFin = true;
+          }
+    }
       }
     }
     return false;
   }
   transmit();
-  setInterval(function () { g('ut').innerHTML = ++updateTime; }, 1000);
-  setInterval(transmit, 5000);
+  setInterval(function () { ++reqTime; }, 1000);
 </script>
-  </body></html>)";
+</body></html>)";
 
+static const char httpConf2Page[] PROGMEM =
+  R"(<html><head><body>
+<h3>Configuration 2</h3>
+<input type='button' value='reload' onclick='return transmit()'/><br><br>
+<form id='form1' onsubmit='return transmit(this)'>
+used Relais: <input type='number' name='usedRelais' id='usedRelais'/><br>
+used Buttons: <input type='number' name='usedButtons' id='usedButtons'/><br>
+Out Topic Hold 1: <input type='text' name='outTop_hold1' id='outTop_hold1'/><br>
+Out Topic Hold 2: <input type='text' name='outTop_hold2' id='outTop_hold2'/><br>
+Out Topic Hold 3: <input type='text' name='outTop_hold3' id='outTop_hold3'/><br>
+Out Payload Hold 1: <input type='text' name='outPld_hold1' id='outPld_hold1'/><br>
+Out Payload Hold 2: <input type='text' name='outPld_hold2' id='outPld_hold2'/><br>
+Out Payload Hold 3: <input type='text' name='outPld_hold3' id='outPld_hold3'/><br>
+Domoticz Idx 1: <input type='number' name='domoIdx1' id='domoIdx1'/><br>
+Domoticz Idx 2: <input type='number' name='domoIdx2' id='domoIdx2'/><br>
+Domoticz Idx 3: <input type='number' name='domoIdx3' id='domoIdx3'/><br>
+Relais Impulse 1: <input type='number' name='impuls1' id='impuls1'/><br>
+Relais Impulse 2: <input type='number' name='impuls2' id='impuls2'/><br>
+Relais Impulse 3: <input type='number' name='impuls3' id='impuls3'/><br>
+<br>
+<input type='submit' value='Save'/>
+</form>
+<form id='rebootForm' onsubmit='return res()'>
+<input type='submit' value='Restart'/>
+</form>
+
+<script>
+ function g(i) { return document.getElementById(i) };
+  var xhttp, reqTime, reqFin, rxhttp;
+  
+  function res() {
+    rxhttp = new XMLHttpRequest();
+ rxhttp.timeout = 1000;
+  rxhttp.open('POST', 'restart');
+  rxhttp.send('');
+  rxhttp = null;
+  return false;
+  }
 
-static const char httpConfPage[] PROGMEM = 
-R"(<html><body>
-  <h1>WiFi Thermostat</h1>
-  <h2>Configuration</h2>
-  <a href='/'>Home</a>
-  </body></html>)";
+  function transmit(f) {
+    if (!xhttp) {
+      xhttp = new XMLHttpRequest();
+    xhttp.timeout = 2000;
+      xhttp.open('POST', 'confdata2');
+      xhttp.send(f ? (new FormData(f)) : '');
+      xhttp.onreadystatechange = function () {
+        if (xhttp.readyState === XMLHttpRequest.DONE && xhttp.status === 200) {
+          var data = JSON.parse(xhttp.responseText);
+          g('usedRelais').value = data.usedRelais;
+      g('usedButtons').value = data.usedButtons;
+      g('outTop_hold1').value = data.outTop_hold1;
+          g('outTop_hold2').value = data.outTop_hold2;
+          g('outTop_hold3').value = data.outTop_hold3;
+          g('outPld_hold1').value = data.outPld_hold1;
+          g('outPld_hold2').value = data.outPld_hold2;
+          g('outPld_hold3').value = data.outPld_hold3;
+          g('domoIdx1').value = data.domoIdx1;
+          g('domoIdx2').value = data.domoIdx2;
+          g('domoIdx3').value = data.domoIdx3;
+          g('impuls1').value = data.impuls1;
+          g('impuls2').value = data.impuls2;
+          g('impuls3').value = data.impuls3;
+          xhttp = null;
+      reqFin = false;
+        }
+      else {
+          if(!reqFin && reqTime > 10) {
+            xhttp = null;
+            reqFin = true;
+            }
+      }
+    }
+    }
+    return false;
+  }
+  transmit();
+  setInterval(function () { ++reqTime; }, 1000);
+</script>
+</body></html>)";
 
 void httpServerHandleRoot() {
   httpServer.send_P(200, "text/html", httpRoot);
@@ -88,6 +269,10 @@ void httpServerHandleConfPage() {
   httpServer.send_P(200, "text/html", httpConfPage);
 }
 
+void httpServerHandleConf2Page() {
+  httpServer.send_P(200, "text/html", httpConf2Page);
+}
+
 void httpServerHandleNotFound() {
   String message = "File Not Found\n\n";
   message += "URI: ";
@@ -107,7 +292,7 @@ void httpServerHandleNotFound() {
 void httpServerInit() {
   //handles commands from webpage, sends live data in JSON format
   httpServer.on("/api", []() {
-    //Serial.print("httpServer.on /api");
+    //Serial.println("httpServer.on /api");
     if (httpServer.hasArg("Btn1")) {
       lastSwitchSource[0] = 2;
       relaisToggle(0);
@@ -129,16 +314,149 @@ void httpServerInit() {
     JsonObject &json = jsonBuffer.createObject();
     json["ssid"] = WiFi.SSID();
     json["swState1"] = relais_state[0];
-    if(RELAIS_COUNT > 1) json["swState2"] = relais_state[1];
-    if(RELAIS_COUNT > 2) json["swState3"] = relais_state[2];
+    if (RELAIS_COUNT > 1) json["swState2"] = relais_state[1];
+    if (RELAIS_COUNT > 2) json["swState3"] = relais_state[2];
     json["devname"] = deviceName;
-    
+
     char jsonchar[200];
     json.printTo(jsonchar); //print to char array, takes more memory but sends in one piece
     httpServer.send(200, "application/json", jsonchar);
 
   }); //httpServer.on /api
 
+  httpServer.on("/restart", []() {
+    Serial.println("web triggered restart");
+    ESP.restart();
+  });
+
+  httpServer.on("/confdata", []() {
+    Serial.println("httpServer.on /confdata");
+
+    //    if (httpServer.hasArg("saveToFlash")) {
+    //      if (httpServer.arg("saveToFlash").toInt() == 1) {
+    //        Serial.println("web saveToFlash triggered");
+    //        //saveConfig();
+    //        saveConfigToFlash = true;
+    //      }
+    //    }
+    //    else if (httpServer.hasArg("restart")) {
+    //      if (httpServer.arg("restart").toInt() == 1) {
+    //        Serial.println("web restart triggered");
+    //        ESP.restart();
+    //      }
+    //    }
+    //    else {
+    for (int i = 0; i < httpServer.args(); i++) {
+      char bufName[20];
+      char bufValue[101];
+      httpServer.argName(i).toCharArray(bufName, 20);
+      httpServer.arg(i).toCharArray(bufValue, 101);
+
+      //if(strcmp(bufName, "willRet") == 0) {
+      //          willRetSet = true;
+      //      }
+
+      //if (strlen(bufName) > 0 && strlen(bufValue) > 0) {
+      if (strlen(bufName) > 0) {
+        Serial.print("web update ");
+        Serial.print(bufName);
+        Serial.print(" = ");
+        Serial.println(bufValue);
+        setConfig(bufName, bufValue);
+      }
+      saveConfigToFlash = true; // will be saved in next loop()
+      Serial.println("web triggered saveConfigToFlash");
+    }
+    //    }
+
+    //build json object of program data
+    StaticJsonBuffer<1000> jsonBuffer;
+    JsonObject &json = jsonBuffer.createObject();
+    json["devName"] = deviceName;
+    json["httpUser"] =  http_user;
+    json["httpPass"] =  http_pass;
+    json["mqttHost"] = mqtt_server;
+    json["mqttPort"] = mqtt_port;
+    json["mqttUser"] =  mqtt_user;
+    json["mqttPass"] =  mqtt_pass;
+    json["inTop"] = mqtt_topic_in;
+    json["outTop"] = mqtt_topic_out;
+    json["willTop"] = mqtt_willTopic;
+    json["willQos"] = mqtt_willQos;
+    json["willRet"] = mqtt_willRetain;
+    json["willMsg"] = mqtt_willMsg;
+    json["domoOutTop"] = domoticz_out_topic;
+
+    char jsonchar[1000];
+    json.printTo(jsonchar); //print to char array, takes more memory but sends in one piece
+    httpServer.send(200, "application/json", jsonchar);
+
+  }); //httpServer.on /confdata
+
+  httpServer.on("/confdata2", []() {
+    Serial.println("httpServer.on /confdata2");
+
+    //    if (httpServer.hasArg("saveToFlash")) {
+    //      if (httpServer.arg("saveToFlash").toInt() == 1) {
+    //        Serial.println("web saveToFlash triggered");
+    //        //saveConfig();
+    //        saveConfigToFlash = true;
+    //      }
+    //    }
+    //    else if (httpServer.hasArg("restart")) {
+    //      if (httpServer.arg("restart").toInt() == 1) {
+    //        Serial.println("web restart triggered");
+    //        ESP.restart();
+    //      }
+    //    }
+    //    else {
+    for (int i = 0; i < httpServer.args(); i++) {
+      char bufName[20];
+      char bufValue[101];
+      httpServer.argName(i).toCharArray(bufName, 20);
+      httpServer.arg(i).toCharArray(bufValue, 101);
+
+      //if(strcmp(bufName, "willRet") == 0) {
+      //          willRetSet = true;
+      //      }
+
+      //if (strlen(bufName) > 0 && strlen(bufValue) > 0) {
+      if (strlen(bufName) > 0) {
+        Serial.print("web update ");
+        Serial.print(bufName);
+        Serial.print(" = ");
+        Serial.println(bufValue);
+        setConfig(bufName, bufValue);
+      }
+      saveConfig2ToFlash = true;
+      Serial.println("web triggered saveConfig2ToFlash");
+    }
+    //    }
+
+    //build json object of program data
+    StaticJsonBuffer<1000> jsonBuffer;
+    JsonObject &json = jsonBuffer.createObject();
+    json["usedRelais"] = usedRelaisCount;
+    json["usedButtons"] = usedButtonsCount;
+    json["outTop_hold1"] = mqtt_topic_out_hold_1;
+    json["outTop_hold2"] = mqtt_topic_out_hold_2;
+    json["outTop_hold3"] = mqtt_topic_out_hold_3;
+    json["outPld_hold1"] = mqtt_payload_out_hold_1;
+    json["outPld_hold2"] = mqtt_payload_out_hold_2;
+    json["outPld_hold3"] = mqtt_payload_out_hold_3;
+    json["domoIdx1"] = domoticzIdx[0];
+    json["domoIdx2"] = domoticzIdx[1];
+    json["domoIdx3"] = domoticzIdx[2];
+    json["impuls1"] = relais_impulse[0];
+    json["impuls2"] = relais_impulse[1];
+    json["impuls3"] = relais_impulse[2];
+    char jsonchar[1000];
+    json.printTo(jsonchar); //print to char array, takes more memory but sends in one piece
+    httpServer.send(200, "application/json", jsonchar);
+
+  }); //httpServer.on /confdata2
+
+
   //get heap status, analog input value and all GPIO statuses in one json call
   httpServer.on("/info", HTTP_GET, []() {
     String json = "{";
@@ -155,10 +473,14 @@ void httpServerInit() {
     httpServerHandleRoot();
   });
 
-  httpServer.on("/config", []() {
+  httpServer.on("/conf", []() {
     httpServerHandleConfPage();
   });
 
+  httpServer.on("/conf2", []() {
+    httpServerHandleConf2Page();
+  });
+
   httpServer.onNotFound([]() {
     httpServerHandleNotFound();
   }); //httpServer.onNotFound

+ 58 - 14
src/WiFiSwitch/mqtt.ino

@@ -9,7 +9,8 @@ void mqttCallback(char* topic, byte* payload, unsigned int length) {
     Serial.println();*/
 
   if (strcmp(topic, mqtt_topic_in) == 0) { //if topic = mqtt_topic_in
-
+    Serial.print("received MQTT ");
+    Serial.println(mqtt_topic_in);
     for (int i = 0; i < length; i++) {
       cmdPayload[i] = (char)payload[i];
     }
@@ -22,34 +23,77 @@ void mqttCallback(char* topic, byte* payload, unsigned int length) {
 
   }//if topic = mqtt_topic_in
 
-  if ( useDomoticz ) {
-    if (strcmp(topic, DOMOTICZ_OUT_TOPIC) == 0) { //if topic = DOMOTICZ_OUT_TOPIC
-      if ( !domoticzOutParserBusy ) {
-        for (int i = 0; i < length; i++) {
-          domoticzOutPayload[i] = (char)payload[i];
-        }
-        domoticzOutPayload[length + 1] = '\0';
-        domoticzOutParseData = true; // parse domoticz data in the next loop()
+  //if ( useDomoticz ) {
+  if (strcmp(topic, domoticz_out_topic) == 0) { //if topic = DOMOTICZ_OUT_TOPIC
+    Serial.print("received MQTT ");
+    Serial.println(domoticz_out_topic);
+    if ( !domoticzOutParserBusy ) {
+      for (int i = 0; i < length; i++) {
+        domoticzOutPayload[i] = (char)payload[i];
       }
+      domoticzOutPayload[length + 1] = '\0';
+      domoticzOutParseData = true; // parse domoticz data in the next loop()
     }
   }
+  //}
 
 
 }//mqttCallback
 
+int mqttReconnects=0;
 
 boolean mqttReconnect() {
   // Create a random MQTT client ID
   String mqttClientId = "ESP8266Client-";
   mqttClientId += String(random(0xffff), HEX);
-  if (mqttclient.connect(mqttClientId.c_str())) {
-    Serial.println("MQTT connected");
+  boolean connRes;
+  Serial.print("MQTT connection with ");
+  if (strlen(mqtt_user) > 0 && strlen(mqtt_willTopic) == 0) {
+    // user and password, no Last Will
+    // boolean connect(const char* id, const char* user, const char* pass);
+    connRes = mqttclient.connect(mqttClientId.c_str(), mqtt_user, mqtt_pass);
+    Serial.println("user and password, no Last Will");
+  }
+  else if (strlen(mqtt_user) > 0 && strlen(mqtt_willTopic) > 0) {
+    // user, password and Last Will
+    // boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage);
+    connRes = mqttclient.connect(mqttClientId.c_str(), mqtt_user, mqtt_pass, mqtt_willTopic, mqtt_willQos, mqtt_willRetain, mqtt_willMsg);
+    Serial.println("user, password and Last Will");
+  }
+  else if (strlen(mqtt_user) == 0 && strlen(mqtt_willTopic) > 0) {
+    // Last Will but no user and password
+    // boolean connect(const char* id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage);
+    connRes = mqttclient.connect(mqttClientId.c_str(), mqtt_willTopic, mqtt_willQos, mqtt_willRetain, mqtt_willMsg);
+    Serial.println("Last Will but no user and password");
+  }
+  else {
+    // no user, password and no Last Will
+    Serial.println("no user, password and no Last Will");
+    connRes = mqttclient.connect(mqttClientId.c_str());
+  }
+
+
+  if (connRes) {
+    Serial.print("MQTT connected. Reconnects: ");
+    Serial.println(mqttReconnects);
+    
     // Once connected, publish an announcement...
-    mqttclient.publish(mqtt_topic_out, "connected");
+    char outMsg[30];
+    sprintf(outMsg, "connected, %d reconnects", mqttReconnects);
+    mqttclient.publish(mqtt_topic_out, outMsg);
+    //mqttclient.publish(mqtt_topic_out, "connected");
     // ... and resubscribe
-    mqttclient.subscribe(mqtt_topic_in);
-    mqttclient.subscribe(domoticz_out_topic);
+    Serial.println("Subscribed to:");
+    if (mqttclient.subscribe(mqtt_topic_in)) {
+      Serial.println(mqtt_topic_in);
+    }
+    if (useDomoticz && strlen(domoticz_out_topic) > 0) {
+      if (mqttclient.subscribe(domoticz_out_topic)) {
+        Serial.println(domoticz_out_topic);
+      }
+    }
   }
+  mqttReconnects++;
   return mqttclient.connected();
 } //mqttReconnect