Sonoff Wireless Smart Switch

https://www.itead.cc/sonoff-wifi-wireless-switch.html

Anyone had any experience with these yet? They seem like awesome little devices for toggling a device on and off. They even have a wifi controlled E27 light bulb base as well.

https://www.itead.cc/slampher-wifi-wireless-light-holder.html

They are SUPER cheap as well.

Curious to know if these can just integrate directly into HA via MQTT without having to re-flash the device.

To be honest I didn’t actually try with the firmware shipped on the device, but it was super easy to flash the new firmware from: https://github.com/arendst/Sonoff-MQTT-OTA-Arduino

Sorry for not actually answering your question… :slight_smile:

With the custom firmware these devices are awesome. Especially for $4.

1 Like

Hey speakquietly,

i just reflash my sonoff with your recommendation (Sonoff-MQTT-OTA-Arduino github)

its working great thru the ESP web server platform, but when im trying to integrate it with my HA, from some reason it not respond to any HA mqtt command.

even when im trying to copy the full topic sent by sonoff to mqtt, and send it via HA switch it not work.

any ideas?

im using HA with mosquitto MQTT

thanks!

I think I made some modifications. Here is my switch config, and the arduino code.

- platform : mqtt
  name: "Ceiling Fan"
  state_topic: "stat/sonoff_fan/POWER"
  command_topic: "cmnd/sonoff_fan/POWER"
  payload_on: "On"
  payload_off: "Off"
  optimistic: false
  retain: true

Arduino:

/*
 * Sonoff and Wkaku by Theo Arends
 *

#define PROJECT                "sonoff_fan" //This is where the mqtt topic comes from
#define VERSION                0x01000C00   // 1.0.12
#define CFG_HOLDER             0x20160520   // Change this value to load default configurations

// Wifi
#define STA_SSID               "SSID"
#define STA_PASS               "PASSCODE"
#define WIFI_HOSTNAME          "esp-%06x-%s"

// Syslog
#define LOG_LEVEL_NONE         0
#define LOG_LEVEL_ERROR        1
#define LOG_LEVEL_INFO         2
#define LOG_LEVEL_DEBUG        3
#define LOG_LEVEL_DEBUG_MORE   4

#define SYS_LOG_HOST           "sidnas2"
#define SYS_LOG_PORT           514
#define SYS_LOG_LEVEL          LOG_LEVEL_NONE
#define SERIAL_LOG_LEVEL       LOG_LEVEL_NONE

// Ota
#if (ARDUINO >= 168)
  #define OTA_URL              "http://sidnas2:80/api/arduino/"PROJECT".ino.bin"
#else
  #define OTA_URL              "http://sidnas2:80/api/arduino/"PROJECT".cpp.bin"
#endif

// MQTT
#define MQTT_HOST              "MQTT_HOST"
#define MQTT_PORT              MQTT_PORT

#define MQTT_CLIENT_ID         "DVES_%06X"  // Also fall back topic using Chip Id = last 6 characters of MAC address
#define MQTT_USER              "MQTT_USERNAME"
#define MQTT_PASS              "MQTT_PASSWORD"

#define SUB_PREFIX             "cmnd"
#define PUB_PREFIX             "stat"
#define MQTT_GRPTOPIC          PROJECT"s"   // Group topic
#define MQTT_TOPIC             PROJECT

// Application
#define MQTT_SUBTOPIC          "POWER"
#define APP_TIMEZONE           1            // +1 hour (Amsterdam)
#define APP_POWER              0            // Saved power state Off

// End of user defines **************************************************************************

#define SERIAL_IO                           // Enable serial command line
#define STATES                 10           // loops per second
#define MQTT_RETRY_SECS        10           // Seconds to retry MQTT connection

//#define LED_PIN                2            // GPIO 2 = Blue Led (0 = On, 1 = Off) - ESP-12
#define LED_PIN                13           // GPIO 13 = Green Led (0 = On, 1 = Off) - Sonoff
//#define LED_PIN                16           // NodeMCU
#define REL_PIN                12           // GPIO 12 = Red Led and Relay (0 = Off, 1 = On)
#define KEY_PIN                0            // GPIO 00 = Button
#define PRESSED                0
#define NOT_PRESSED            1

#define WIFI_STATUS            0
#define WIFI_SMARTCONFIG       1

#ifdef DEBUG_ESP_PORT
#define DEBUG_MSG(...) DEBUG_ESP_PORT.printf( __VA_ARGS__ )
#else
#define DEBUG_MSG(...) 
#endif

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266httpUpdate.h>
#include <PubSubClient.h>
extern "C" uint32_t _SPIFFS_start;

struct SYSCFG {
  unsigned long cfg_holder;
  unsigned long saveFlag;
  unsigned long version;
  byte          seriallog_level;
  byte          syslog_level;
  char          syslog_host[32];
  char          sta_ssid[32];
  char          sta_pwd[64];
  char          otaUrl[80];
  char          mqtt_host[32];
  char          mqtt_grptopic[32];
  char          mqtt_topic[32];
  char          mqtt_topic2[32];
  char          mqtt_subtopic[32];
  int8_t        timezone;
  uint8_t       power;
} sysCfg;

struct TIME_T {
  uint8_t       Second;
  uint8_t       Minute;
  uint8_t       Hour;
  uint8_t       Wday;   // day of week, sunday is day 1
  uint8_t       Day;
  uint8_t       Month;
  char          MonthName[4];
  uint16_t      Year;
  unsigned long Valid;
} rtcTime;

char Version[16];
char Hostname[32];
uint8_t mqttcounter = 0;
unsigned long timerxs = 0, timersec = 0;
int state = 0;
int otaflag = 0;
int restartflag = 0;
int smartconfigflag = 0;
int heartbeatflag = 0;
int heartbeat = 0;

WiFiClient espClient;
PubSubClient mqttClient(espClient);
WiFiUDP portUDP;   // syslog

int blinks = 1;
uint8_t blinkstate = 1;

uint8_t lastbutton = NOT_PRESSED;
uint8_t holdcount = 0;
uint8_t multiwindow = 0;
uint8_t multipress = 0;

/*********************************************************************************************\
 * Syslog
\*********************************************************************************************/
void syslog(const char *message)
{
  char mess[168], str[200];

  portUDP.beginPacket(sysCfg.syslog_host, SYS_LOG_PORT);
  strncpy(mess, message, 167);
  mess[168] = 0;
  sprintf_P(str, PSTR("%s %s"), Hostname, mess);
  portUDP.write(str);
  portUDP.endPacket();
}

void addLog(byte loglevel, const char *line)
{
  DEBUG_MSG("DebugMsg %s\n", line);  
#ifdef SERIAL_IO
  if (loglevel <= sysCfg.seriallog_level) Serial.println(line);
#endif
  if ((WiFi.status() == WL_CONNECTED) && (loglevel <= sysCfg.syslog_level)) syslog(line);
}

void addLog(byte loglevel, String& string)
{
  addLog(loglevel, string.c_str());
}

/********************************************************************************************/

void mqtt_publish(const char* topic, const char* data)
{
  char log[300];
  
  mqttClient.publish(topic, data);
  sprintf_P(log, PSTR("MQTT: %s = %s"), strchr(topic,'/')+1, data);     // Skip topic prefix
  addLog(LOG_LEVEL_INFO, log);
  mqttClient.loop();  // Solve LmacRxBlk:1 messages
  blinks++;
}

void mqtt_connected()
{
  char stopic[40], svalue[40];

  sprintf_P(stopic, PSTR("%s/%s/#"), SUB_PREFIX, sysCfg.mqtt_topic);
  mqttClient.subscribe(stopic);
  mqttClient.loop();  // Solve LmacRxBlk:1 messages
  sprintf_P(stopic, PSTR("%s/%s/#"), SUB_PREFIX, sysCfg.mqtt_grptopic);
  mqttClient.subscribe(stopic);
  mqttClient.loop();  // Solve LmacRxBlk:1 messages
  sprintf_P(stopic, PSTR("%s/"MQTT_CLIENT_ID"/#"), SUB_PREFIX, ESP.getChipId());  // Fall back topic
  mqttClient.subscribe(stopic);
  mqttClient.loop();  // Solve LmacRxBlk:1 messages

  sprintf_P(stopic, PSTR("%s/%s/NAME"), PUB_PREFIX, sysCfg.mqtt_topic);
  sprintf_P(svalue, PSTR("Sonoff switch"));
  mqtt_publish(stopic, svalue);
  sprintf_P(stopic, PSTR("%s/%s/VERSION"), PUB_PREFIX, sysCfg.mqtt_topic);
  sprintf_P(svalue, PSTR("%s"), Version);
  mqtt_publish(stopic, svalue);
  sprintf_P(stopic, PSTR("%s/%s/FALLBACKTOPIC"), PUB_PREFIX, sysCfg.mqtt_topic);
  sprintf_P(svalue, PSTR(MQTT_CLIENT_ID), ESP.getChipId());
  mqtt_publish(stopic, svalue);
}

void mqtt_reconnect()
{
  char stopic[40], svalue[40], log[80];

  mqttcounter = MQTT_RETRY_SECS;
  addLog(LOG_LEVEL_INFO, "MQTT: Attempting connection");
  sprintf(svalue, MQTT_CLIENT_ID, ESP.getChipId());
  sprintf_P(stopic, PSTR("%s/%s/lwt"), PUB_PREFIX, sysCfg.mqtt_topic);
  if (mqttClient.connect(svalue, MQTT_USER, MQTT_PASS, stopic, 0, 0, "offline")) {
    addLog(LOG_LEVEL_INFO, "MQTT: Connected");
    mqttcounter = 0;
    mqtt_connected();
  } else {
    sprintf_P(log, PSTR("MQTT: Connect failed, rc %d. Retry in %d seconds"), mqttClient.state(), mqttcounter);
    addLog(LOG_LEVEL_DEBUG, log);
  }
}

void mqttDataCb(char* topic, byte* data, unsigned int data_len)
{
  int i, grpflg = 0;
  char *str, *p, *mtopic = NULL, *type = NULL;
  char stopic[40], svalue[240];

  int topic_len = strlen(topic);
  char topicBuf[topic_len +1]; 
  char dataBuf[data_len +1]; 
  char dataBufUc[data_len +1]; 
  
  memcpy(topicBuf, topic, topic_len);
  topicBuf[topic_len] = 0;

  memcpy(dataBuf, data, data_len);
  dataBuf[data_len] = 0;

  sprintf_P(svalue, PSTR("MQTT: Receive topic %s, data %s"), topicBuf, dataBuf);
  addLog(LOG_LEVEL_DEBUG, svalue);

  i = 0;
  for (str = strtok_r(topicBuf, "/", &p); str && i < 3; str = strtok_r(NULL, "/", &p)) {
    switch (i++) {
    case 0:  // cmnd
      break;
    case 1:  // Topic / GroupTopic / DVES_123456
      mtopic = str;
      break;
    case 2:  // Text
      type = str;
    }
  }
  if (!strcmp(mtopic, sysCfg.mqtt_grptopic)) grpflg = 1;
  if (type != NULL) for(i = 0; i < strlen(type); i++) type[i] = toupper(type[i]);

  for(i = 0; i <= data_len; i++) dataBufUc[i] = toupper(dataBuf[i]);

  sprintf_P(svalue, PSTR("MQTT: DataCb Topic %s, Group %d, Type %s, data %s (%s)"),
    mtopic, grpflg, type, dataBuf, dataBufUc);
  addLog(LOG_LEVEL_DEBUG, svalue);

  if (type != NULL) {
    sprintf_P(stopic, PSTR("%s/%s/%s"), PUB_PREFIX, sysCfg.mqtt_topic, type);
    strcpy(svalue, "Error");

    uint16_t payload = atoi(dataBuf);
    if (!strcmp(dataBufUc,"OFF")) payload = 0;
    if (!strcmp(dataBufUc,"ON")) payload = 1;
    if (!strcmp(dataBufUc,"TOGGLE")) payload = 2;

    if (!strcmp(type,"STATUS")) {
      switch (payload) {
      case 1:
        sprintf_P(svalue, PSTR("%s, "MQTT_CLIENT_ID", %s, %s, %d, %d"),
          sysCfg.mqtt_grptopic, ESP.getChipId(), sysCfg.otaUrl, sysCfg.mqtt_host, heartbeat, sysCfg.saveFlag);
        break;  
      case 2:
        sprintf_P(svalue, PSTR("Version %s, Boot %d, SDK %s"),
          Version, ESP.getBootVersion(), ESP.getSdkVersion());
        break;
      case 3:
        sprintf_P(svalue, PSTR("Seriallog %d, Syslog %d, LogHost %s, SSId %s, Password %s"),
          sysCfg.seriallog_level, sysCfg.syslog_level, sysCfg.syslog_host, sysCfg.sta_ssid, sysCfg.sta_pwd);
        break;
      case 4:
        sprintf_P(svalue, PSTR("Sketch size %d, Free %d (Heap %d), Spiffs start %d, Flash size %d (%d)"),
          ESP.getSketchSize(), ESP.getFreeSketchSpace(), ESP.getFreeHeap(), (uint32_t)&_SPIFFS_start - 0x40200000,
          ESP.getFlashChipRealSize(), ESP.getFlashChipSize());
        break;
      case 5: {
        IPAddress ip = WiFi.localIP();
        IPAddress gw = WiFi.gatewayIP();
        IPAddress nm = WiFi.subnetMask();
        sprintf_P(svalue, PSTR("Hostname %s, IP %u.%u.%u.%u, Gateway %u.%u.%u.%u, Subnetmask %u.%u.%u.%u"),
          Hostname, ip[0], ip[1], ip[2], ip[3], gw[0], gw[1], gw[2], gw[3], nm[0], nm[1], nm[2], nm[3]);
        break;
      }
      default:
        sprintf_P(svalue, PSTR("%s, %s, %s, %s, %d, %d"),
          Version, sysCfg.mqtt_topic, sysCfg.mqtt_topic2, sysCfg.mqtt_subtopic, sysCfg.power, sysCfg.timezone);
      }
    }
    else if (!grpflg && !strcmp(type,"UPGRADE")) {
      if ((data_len > 0) && (payload == 1)) {
        otaflag = 3;
        sprintf_P(svalue, PSTR("Upgrade %s"), Version);
      }
      else
        sprintf_P(svalue, PSTR("1 to upgrade"));
    }
    else if (!grpflg && !strcmp(type,"OTAURL")) {
      if ((data_len > 0) && (data_len < 80))
        strcpy(sysCfg.otaUrl, (payload == 1) ? OTA_URL : dataBuf);
      sprintf_P(svalue, PSTR("%s"), sysCfg.otaUrl);
    }
    else if (!strcmp(type,"SERIALLOG")) {
      if ((data_len > 0) && (payload >= LOG_LEVEL_NONE) && (payload <= LOG_LEVEL_DEBUG_MORE)) {
        sysCfg.seriallog_level = payload;
      }
      sprintf_P(svalue, PSTR("%d"), sysCfg.seriallog_level);
    }
    else if (!strcmp(type,"SYSLOG")) {
      if ((data_len > 0) && (payload >= LOG_LEVEL_NONE) && (payload <= LOG_LEVEL_DEBUG_MORE)) {
        sysCfg.syslog_level = payload;
      }
      sprintf_P(svalue, PSTR("%d"), sysCfg.syslog_level);
    }
    else if (!strcmp(type,"LOGHOST")) {
      if ((data_len > 0) && (data_len < 32)) {
        strcpy(sysCfg.syslog_host, (payload == 1) ? SYS_LOG_HOST : dataBuf);
        restartflag = 2;
      }
      sprintf_P(svalue, PSTR("%s"), sysCfg.syslog_host);
    }
    else if (!grpflg && !strcmp(type,"SSID")) {
      if ((data_len > 0) && (data_len < 32)) {
        strcpy(sysCfg.sta_ssid, (payload == 1) ? STA_SSID : dataBuf);
        restartflag = 2;
      }
      sprintf_P(svalue, PSTR("%s"), sysCfg.sta_ssid);
    }
    else if (!grpflg && !strcmp(type,"PASSWORD")) {
      if ((data_len > 0) && (data_len < 64)) {
        strcpy(sysCfg.sta_pwd, (payload == 1) ? STA_PASS : dataBuf);
        restartflag = 2;
      }
      sprintf_P(svalue, PSTR("%s"), sysCfg.sta_pwd);
    }
    else if (!grpflg && !strcmp(type,"MQTTHOST")) {
      if ((data_len > 0) && (data_len < 32)) {
        strcpy(sysCfg.mqtt_host, (payload == 1) ? MQTT_HOST : dataBuf);
        restartflag = 2;
      }
      sprintf_P(svalue, PSTR("%s"), sysCfg.mqtt_host);
    }
    else if (!strcmp(type,"GROUPTOPIC")) {
      if ((data_len > 0) && (data_len < 32)) {
        for(i = 0; i <= data_len; i++)
          if ((dataBuf[i] == '/') || (dataBuf[i] == '+') || (dataBuf[i] == '#')) dataBuf[i] = '_';
        sprintf_P(svalue, PSTR(MQTT_CLIENT_ID), ESP.getChipId());
        if (!strcmp(dataBuf, svalue)) payload = 1;
        strcpy(sysCfg.mqtt_grptopic, (payload == 1) ? MQTT_GRPTOPIC : dataBuf);
        restartflag = 2;
      }
      sprintf_P(svalue, PSTR("%s"), sysCfg.mqtt_grptopic);
    }
    else if (!grpflg && !strcmp(type,"TOPIC")) {
      if ((data_len > 0) && (data_len < 32)) {
        for(i = 0; i <= data_len; i++)
          if ((dataBuf[i] == '/') || (dataBuf[i] == '+') || (dataBuf[i] == '#')) dataBuf[i] = '_';
        sprintf_P(svalue, PSTR(MQTT_CLIENT_ID), ESP.getChipId());
        if (!strcmp(dataBuf, svalue)) payload = 1;
        strcpy(sysCfg.mqtt_topic, (payload == 1) ? MQTT_TOPIC : dataBuf);
        restartflag = 2;
      }
      sprintf_P(svalue, PSTR("%s"), sysCfg.mqtt_topic);
    }
    else if (!grpflg && !strcmp(type,"BUTTONTOPIC")) {
      if ((data_len > 0) && (data_len < 32)) {
        for(i = 0; i <= data_len; i++)
          if ((dataBuf[i] == '/') || (dataBuf[i] == '+') || (dataBuf[i] == '#')) dataBuf[i] = '_';
        sprintf_P(svalue, PSTR(MQTT_CLIENT_ID), ESP.getChipId());
        if (!strcmp(dataBuf, svalue)) payload = 1;
        strcpy(sysCfg.mqtt_topic2, (payload == 1) ? MQTT_TOPIC : dataBuf);
      }
      sprintf_P(svalue, PSTR("%s"), sysCfg.mqtt_topic2);
    }
    else if (!grpflg && !strcmp(type,"SMARTCONFIG")) {
      if ((data_len > 0) && (payload == 1)) {
        blinks = 1999;
        smartconfigflag = 1;
        sprintf_P(svalue, PSTR("Smartconfig started"));
      } else
        sprintf_P(svalue, PSTR("1 to start smartconfig"));
    }
    else if (!grpflg && !strcmp(type,"RESTART")) {
      if ((data_len > 0) && (payload == 1)) {
        restartflag = 2;
        sprintf_P(svalue, PSTR("Restarting"));
      } else
        sprintf_P(svalue, PSTR("1 to restart"));
    }
    else if (!grpflg && !strcmp(type,"RESET")) {
      switch (payload) {
      case 1: 
        restartflag = 11;
        sprintf_P(svalue, PSTR("Reset and Restarting"));
        break;
      case 2:
        restartflag = 12;
        sprintf_P(svalue, PSTR("Erase, Reset and Restarting"));
        break;
      default:
        sprintf_P(svalue, PSTR("1 to reset"));
      }
    }
    else if (!strcmp(type,"TIMEZONE")) {
      if ((data_len > 0) && (payload >= -12) && (payload <= 12)) {
        sysCfg.timezone = payload;
        rtc_timezone(sysCfg.timezone);
      }
      sprintf_P(svalue, PSTR("%d"), sysCfg.timezone);
    }
    else if ((!strcmp(type,"LIGHT")) || (!strcmp(type,"POWER"))) {
      sprintf(sysCfg.mqtt_subtopic, "%s", type);
      if ((data_len > 0) && (payload >= 0) && (payload <= 2)) {
        switch (payload) {
        case 0: // Off
        case 1: // On
          sysCfg.power = payload;
          break;
        case 2: // Toggle
          sysCfg.power ^= 1;
          break;
        }
        digitalWrite(REL_PIN, sysCfg.power);
      }
      strcpy(svalue, (sysCfg.power) ? "On" : "Off");
    }
    else {
      type = NULL;
    }
    if (type == NULL) {
      blinks = 1;
      sprintf_P(stopic, PSTR("%s/%s/SYNTAX"), PUB_PREFIX, sysCfg.mqtt_topic);
      if (!grpflg)
        strcpy_P(svalue, PSTR("Status, Upgrade, Otaurl, Restart, Reset, Smartconfig, Seriallog, Syslog, LogHost, SSId, Password, MqttHost, GroupTopic, Topic, ButtonTopic, Timezone, Light, Power"));
      else
        strcpy_P(svalue, PSTR("Status, GroupTopic, Timezone, Light, Power"));
    }
    mqtt_publish(stopic, svalue);
  }
}

void send_button(char *cmnd)
{
  char stopic[128], svalue[128];
  char *token;

  token = strtok(cmnd, " ");
  if ((!strcmp(token,"light")) || (!strcmp(token,"power"))) strcpy(token, sysCfg.mqtt_subtopic);
  sprintf_P(stopic, PSTR("%s/%s/%s"), SUB_PREFIX, sysCfg.mqtt_topic2, token);
  token = strtok(NULL, "");
  sprintf_P(svalue, PSTR("%s"), (token == NULL) ? "" : token);
  mqtt_publish(stopic, svalue);
}

void do_cmnd(char *cmnd)
{
  char stopic[128], svalue[128];
  char *token;

  token = strtok(cmnd, " ");
  sprintf_P(stopic, PSTR("%s/%s/%s"), SUB_PREFIX, sysCfg.mqtt_topic, token);
  token = strtok(NULL, "");
  sprintf_P(svalue, PSTR("%s"), (token == NULL) ? "" : token);
  mqttDataCb(stopic, (byte*)svalue, strlen(svalue));
}

void send_power()
{
  char stopic[40], svalue[20];

  sprintf_P(stopic, PSTR("%s/%s/%s"), PUB_PREFIX, sysCfg.mqtt_topic, sysCfg.mqtt_subtopic);
  strcpy(svalue, (sysCfg.power == 0) ? "Off" : "On");
  mqtt_publish(stopic, svalue);
}

void send_updateStatus(const char* svalue)
{
  char stopic[40];
  
  sprintf_P(stopic, PSTR("%s/%s/UPGRADE"), PUB_PREFIX, sysCfg.mqtt_topic);
  mqtt_publish(stopic, svalue);
}

void every_second()
{
  char stopic[40], svalue[20];

  if (heartbeatflag) {
    heartbeatflag = 0;
    heartbeat++;
    sprintf_P(stopic, PSTR("%s/%s/HEARTBEAT"), PUB_PREFIX, sysCfg.mqtt_topic);
    sprintf_P(svalue, PSTR("%d"), heartbeat);
    mqtt_publish(stopic, svalue);
  }
}

const char commands[6][14] PROGMEM = {
  {"reset 1"},        // Hold button for more than 4 seconds
  {"light 2"},        // Press button once
  {"light 2"},        // Press button twice
  {"smartconfig 1"},  // Press button three times
  {"upgrade 1"},      // Press button four times
  {"restart 1"}};     // Press button five times

void stateloop()
{
  uint8_t button;
  char scmnd[20], log[30];
  
  timerxs = millis() + (1000 / STATES);
  state++;
  if (state == STATES) {             // Every second
    state = 0;
    every_second();
  }

  button = digitalRead(KEY_PIN);
  if ((button == PRESSED) && (lastbutton == NOT_PRESSED)) {
    multipress = (multiwindow) ? multipress +1 : 1;
    sprintf_P(log, PSTR("APP: Multipress %d"), multipress);
    addLog(LOG_LEVEL_DEBUG, log);
    blinks = 1;
    multiwindow = STATES /2;         // 1/2 second multi press window
  }
  lastbutton = button;
  if (button == NOT_PRESSED) {
    holdcount = 0;
  } else {
    holdcount++;
    if (holdcount == (STATES *4)) {  // 4 seconds button hold
      strcpy_P(scmnd, commands[0]);
      multipress = 0;
      do_cmnd(scmnd);
    }
  }
  if (multiwindow) {
    multiwindow--;
  } else {
    if ((!holdcount) && (multipress >= 1) && (multipress <= 5)) {
      strcpy_P(scmnd, commands[multipress]);
      if (strcmp(sysCfg.mqtt_topic2,"0") && (multipress == 1) && mqttClient.connected())
        send_button(scmnd);          // Execute command via MQTT using ButtonTopic to sync external clients
      else
        do_cmnd(scmnd);              // Execute command internally 
      multipress = 0;
    }
  }

  if ((blinks || restartflag || otaflag) && (!(state % ((STATES/10)*2)))) {
    if (restartflag || otaflag)
      blinkstate = 0;   // Stay lit
    else
      blinkstate ^= 1;  // Blink
    digitalWrite(LED_PIN, blinkstate);
    if (blinkstate) blinks--;
  }

  switch (state) {
  case (STATES/10)*2:
    if (otaflag) {
      otaflag--;
      if (otaflag <= 0) {
        otaflag = 255;
        ESPhttpUpdate.update(sysCfg.otaUrl);
        send_updateStatus(ESPhttpUpdate.getLastErrorString().c_str());
        restartflag = 2;
      }
    }
    break;
  case (STATES/10)*4:
    CFG_Save();
    if (restartflag) {
      if (restartflag == 11) {
        CFG_Default();
        restartflag = 2;
      }
      if (restartflag == 12) {
        CFG_Erase();
        restartflag = 1;
      }
      restartflag--;
      if (restartflag <= 0) ESP.restart();
    }
    break;
  case (STATES/10)*6:
    if (smartconfigflag) {
      smartconfigflag = 0;
      WIFI_Check(WIFI_SMARTCONFIG);
    } else {
      WIFI_Check(WIFI_STATUS);
    }
    break;
  case (STATES/10)*8:
    if ((WiFi.status() == WL_CONNECTED) && (!mqttClient.connected())) {
      if (!mqttcounter)
        mqtt_reconnect();
      else
        mqttcounter--;
    }
    break;
  }
}

#ifdef SERIAL_IO
#define INPUT_BUFFER_SIZE          128

byte SerialInByte;
int SerialInByteCounter = 0;
char serialInBuf[INPUT_BUFFER_SIZE + 2];

void serial()
{
  while (Serial.available())
  {
    yield();
    SerialInByte = Serial.read();
    if (SerialInByte > 127) // binary data...
    {
      Serial.flush();
      SerialInByteCounter = 0;
      return;
    }
    if (isprint(SerialInByte))
    {
      if (SerialInByteCounter < INPUT_BUFFER_SIZE) // add char to string if it still fits
        serialInBuf[SerialInByteCounter++] = SerialInByte;
      else
        SerialInByteCounter = 0;
    }
    if (SerialInByte == '\n')
    {
      serialInBuf[SerialInByteCounter] = 0; // serial data completed
      Serial.println(serialInBuf);
      SerialInByteCounter = 0;
      do_cmnd(serialInBuf);
    }
  }
}
#endif

void setup()
{
  char log[128];

  Serial.begin(115200);
  delay(10);
  Serial.println();

  sprintf_P(Version, PSTR("%d.%d.%d"), VERSION >> 24 & 0xff, VERSION >> 16 & 0xff, VERSION >> 8 & 0xff);
  if (VERSION & 0x1f) {
    byte idx = strlen(Version);
    Version[idx] = 96 + (VERSION & 0x1f);
    Version[idx +1] = 0;
  }
  CFG_Load();
  if (sysCfg.version != VERSION) {  // Fix version dependent changes

    sysCfg.version = VERSION;
  }

  sprintf_P(Hostname, PSTR(WIFI_HOSTNAME), ESP.getChipId(), sysCfg.mqtt_topic);
  WIFI_Connect(Hostname);

  mqttClient.setServer(sysCfg.mqtt_host, MQTT_PORT);
  mqttClient.setCallback(mqttDataCb);

  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, blinkstate);

  pinMode(REL_PIN, OUTPUT);
  digitalWrite(REL_PIN, sysCfg.power);

  pinMode(KEY_PIN, INPUT_PULLUP);

  rtc_init(sysCfg.timezone);

  sprintf_P(log, PSTR("App: Project %s (Topic %s, Fallback "MQTT_CLIENT_ID", GroupTopic %s) Version %s"),
    PROJECT, sysCfg.mqtt_topic, ESP.getChipId(), sysCfg.mqtt_grptopic, Version);
  addLog(LOG_LEVEL_INFO, log);
}

void loop()
{
  if (millis() >= timersec) {
    timersec = millis() + 1000;
    rtc_second();
    if ((rtcTime.Minute == 2) && (rtcTime.Second == 30)) heartbeatflag = 1;
  }

  if (millis() >= timerxs) stateloop();

  mqttClient.loop();

#ifdef SERIAL_IO
  if (Serial.available()) serial();
#endif
  
  yield();
}

thanks for your help.
it working! :slight_smile:

1 Like

I have just flashed my first 6, i am really excited about these.

I did have issues flashing them initially, but it worked my more reliably when flashing using my windows laptop than my ubuntu machine.