Once I tested the Sonoff switch with the standard functionallity, I needed to go further and this is the objective of this mini-project… manage this Wi-Fi switch with my voice.

The steps to achieve this objective was:

  • Hack the Sonoff firmware in order to upload my own code
  • Connect it to my OpenHAB server
  • Configure HomeKit in OpenHAB
  • Create necessary rules in OpenHAB for manage the switch with Siri

 

Let’s go!

 

For the first point, I followed next instructable: http://www.instructables.com/id/Como-Conectar-El-SONOFF-WiFi-Switch-a-Ioadafruitco/

(Update 11/02/2017) Another interesting post: https://community.openhab.org/t/itead-sonoff-switches-and-sockets-cheap-esp8266-wifi-mqtt-hardware/15024

 

The steps of this instructable was clear and easily understandable… broadly were:

  • Material:

     

  • Bringing the Module in Flash ModeThe “brain” of the Sonoff Module (normally the ESP8266) needs to be put into Flash Mode. This is done, by pulling the GPIO0 pin to GND while the chip is booting. On most modules the installed control button is connected to GPIO0 and GND, making entering Flash Mode very easy. On other modules you will need to connect pins on the PCB.

    To bring a Sonoff module into Flash Mode:

    1. Disconnect serial programmer and power)
    2. Connect GPIO0 and GND (e.g. Press the button)
    3. Connect serial programmer
    4. Release GPIO0 (after one-two seconds)

 

  • Procedure:
      • Open Sonoff enclosure (just introducing some thin tool like a knife)
      • Locate the pin holes (5-PIN) in the middle of the PCB
      • Solder the Break Away Headers
      • Connect the USB to TTL programmer paying attention to the order of the pins:

        (for 4-PIN Sonoff models, starts by 2nd PIN)
      • Connect CP2102 USB to our computer and open Arduino IDE with the next configuration:
      • This is the code that I uploaded to my Sonoff (Github source: https://github.com/wifixCode/mqtt_sonoff/blob/master/mqtt_sonoff.ino):
    /***************************************************
      Adafruit MQTT Library ESP8266 Example
      Must use ESP8266 Arduino from:
        https://github.com/esp8266/Arduino
      Works great with Adafruit's Huzzah ESP board & Feather
      ----> https://www.adafruit.com/product/2471
      ----> https://www.adafruit.com/products/2821
      Adafruit invests time and resources providing this open source code,
      please support Adafruit and open-source hardware by purchasing
      products from Adafruit!
      Written by Tony DiCola for Adafruit Industries.
      MIT license, all text above must be included in any redistribution
     ****************************************************/
    
    
    
    
    #include <ESP8266WiFi.h>
    #include "Adafruit_MQTT.h"
    #include "Adafruit_MQTT_Client.h"
    
    /************************* WiFi Access Point *********************************/
    
    #define WLAN_SSID       "---ssid---"
    #define WLAN_PASS       "---password---"
    
    /************************* Adafruit.io Setup *********************************/
    
    #define AIO_SERVER      "---OpenHAB-IP-Server---"      
    #define AIO_SERVERPORT  1883                   // use 8883 for SSL
    #define AIO_USERNAME    "---mqtt-user---"
    #define AIO_KEY         "---mqtt-password---"
    
    /************ Global State (you don't need to change this!) ******************/
    
    // Create an ESP8266 WiFiClient class to connect to the MQTT server.
    WiFiClient client;
    // or... use WiFiFlientSecure for SSL
    //WiFiClientSecure client;
    
    // Store the MQTT server, username, and password in flash memory.
    // This is required for using the Adafruit MQTT library.
    const char MQTT_SERVER[]   = AIO_SERVER;
    const char MQTT_USERNAME[] = AIO_USERNAME;
    const char MQTT_PASSWORD[] = AIO_KEY;
    
    // Setup the MQTT client class by passing in the WiFi client and MQTT server and login details.
    Adafruit_MQTT_Client mqtt(&client, MQTT_SERVER, AIO_SERVERPORT, MQTT_USERNAME, MQTT_PASSWORD);
    
    /****************************** Feeds ***************************************/
    
    // Setup a feed called 'onoff' for subscribing to changes.
    const char ONOFF_FEED[] = AIO_USERNAME "/feeds/onoff";
    Adafruit_MQTT_Subscribe onoffbutton = Adafruit_MQTT_Subscribe(&mqtt, ONOFF_FEED);
    Adafruit_MQTT_Publish onOff = Adafruit_MQTT_Publish(&mqtt, ONOFF_FEED);//Manual switch
    
    /*************************** Sketch Code ************************************/
    
    // Bug workaround for Arduino 1.6.6, it seems to need a function declaration
    // for some reason (only affects ESP8266, likely an arduino-builder bug).
    void MQTT_connect();
    
    #define RELAY 12
    #define LED 13
    #define SWITCH 0
    
    boolean toggle = false;
    
    void setup() {
      Serial.begin(115200);
      delay(10);
      pinMode(RELAY, OUTPUT);
      pinMode(LED, OUTPUT);
      digitalWrite(LED, HIGH);
      pinMode(SWITCH, INPUT_PULLUP);
    
      Serial.println(F("Adafruit MQTT SONOFF Demo"));
    
      // Connect to WiFi access point.
      Serial.println(); Serial.println();
      Serial.print("Connecting to ");
      Serial.println(WLAN_SSID);
    
      WiFi.begin(WLAN_SSID, WLAN_PASS);
      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
        toggle = !toggle;
        digitalWrite(LED, toggle);
      }
      Serial.println();
    
      Serial.println("WiFi connected");
      Serial.println("IP address: "); Serial.println(WiFi.localIP());
      digitalWrite(LED, HIGH);
      // Setup MQTT subscription for onoff feed.
      mqtt.subscribe(&onoffbutton);
    }
    
    uint32_t x=0;
    
    uint8_t lastStateSwitch = 0;
    
    void relay(char* onof){
      String state = String(onof);
      if((digitalRead(RELAY) != HIGH) && (state == "ON")){
        digitalWrite(RELAY, HIGH);//On relay
        digitalWrite(LED, LOW);//On led
      }else if((digitalRead(RELAY) == HIGH) && (state == "OFF")){
        digitalWrite(RELAY, LOW);//Off relay
        digitalWrite(LED, HIGH);//Off led
      }else{
        Serial.print("I got this = ");
        Serial.println(onof);
      }
    }//end relay
    
    void manualRelay(){
      if(!digitalRead(SWITCH)){
        lastStateSwitch = !lastStateSwitch;//Update switch state
        if(lastStateSwitch){
          if (! onOff.publish("ON")) {
            Serial.println(F("Failed"));
          } else {
            Serial.println(F("OK!"));
          }//end if
        }else{
          if (! onOff.publish("OFF")) {
            Serial.println(F("Failed"));
          } else {
            Serial.println(F("OK!"));
          }//end if    
        }//end if
      }//end if
    }//end manualRelay
    
    void loop() {
      // Ensure the connection to the MQTT server is alive (this will make the first
      // connection and automatically reconnect when disconnected).  See the MQTT_connect
      // function definition further below.
      MQTT_connect();
    
      // this is our 'wait for incoming subscription packets' busy subloop
      // try to spend your time here
    
      Adafruit_MQTT_Subscribe *subscription;
      while ((subscription = mqtt.readSubscription(5000))) {
        if (subscription == &onoffbutton) {
          Serial.print(F("Got: "));
          Serial.println((char *)onoffbutton.lastread);
          relay((char *)onoffbutton.lastread);
        }
      }
    
      manualRelay();
    
      // Now we can publish stuff!
    
    
      // ping the server to keep the mqtt connection alive
      // NOT required if you are publishing once every KEEPALIVE seconds
      /*
      if(! mqtt.ping()) {
        mqtt.disconnect();
      }
      */
    }
    
    
    
    // Function to connect and reconnect as necessary to the MQTT server.
    // Should be called in the loop function and it will take care if connecting.
    void MQTT_connect() {
      int8_t ret;
    
      // Stop if already connected.
      if (mqtt.connected()) {
        return;
      }
    
      Serial.print("Connecting to MQTT... ");
    
      uint8_t retries = 3;
      while ((ret = mqtt.connect()) != 0) { // connect will return 0 for connected
           Serial.println(mqtt.connectErrorString(ret));
           Serial.println("Retrying MQTT connection in 5 seconds...");
           mqtt.disconnect();
           delay(5000);  // wait 5 seconds
           retries--;
           if (retries == 0) {
             // basically die and wait for WDT to reset me
             while (1);
           }
      }
      Serial.println("MQTT Connected!");
    }
    • With this code:
      • Sonoff switchs on when receive an string “ON” via MQTT
      • Sonoff switchs off when receive an string “OFF” via MQTT
      • Sonoff switchs on/off when you press the button on the enclosure during 3 seconds.

 

 

Second goal was the HomeKit plugin in OpenHAB and the connection of my sonoff.

For that, I follow the official OpenHAB documentation guidelines: http://docs.openhab.org/features/io/homekit/readme.html

    • Create config file in /etc/openhab2/services/homekit.cfg
    • Add the configuration relative to our device:
      org.openhab.homekit:port=9124
      org.openhab.homekit:pin=031-45-154
      org.openhab.homekit:useFahrenheitTemperature=true
      org.openhab.homekit:thermostatCoolMode=CoolOn
      org.openhab.homekit:thermostatHeatMode=HeatOn
      org.openhab.homekit:thermostatAutoMode=Auto
      org.openhab.homekit:thermostatOffMode=Off
      org.openhab.homekit:networkInterface=192.168.x.x

 

Additional Notes:

  • Clear pairing method of HomeKit will be executed in OGSI console:
    ssh karaf@localhost -p8101
    passw: karaf
  • Debug activation in OGSI console:
    log:set DEBUG
    log:set INFO
    logout
  • OpenHAB2 log file:
    tail -f /var/log/openhab2/openhab.log

 

And last but not least, I needed to add the OpenHAB rule to achieve the automation with my Sonoff switch:

  • Modify our items file: /etc/openhab2/items/default.items
  • Add the appropiate line:
    Switch	 SONOFF1		"Switch Sonoff1"				(Switches)	[ "Lighting" ]		{ mqtt="<[mosquitto:user/switches/sonoff1:state:default]" }

    (Especial attention to the order of the params, and the correct use of HomeKit tags: [ “Lighting” ]   )

  • Modify our rules file: /etc/openhab2/rules/default.rules
  • Add the rule:
    rule "Switch SONOFF1"
        when
            Item SONOFF1 changed
        then
            publish("mosquitto","user/switchs/sonoff1",SONOFF1.state.toString)
    	Thread::sleep(1000)
    end
  • Save the file and… enjoy!

 

 

Finally, I only had to open HomeKit App in my iPhone, and start the configuration:

Note that I have an DHT22 connected to my OpenHAB, and it is also published in HomeKit with a tag in my /etc/openhab2/items/default.items file:

Number     DHT22_Temp        "Temperature [%.2f ºC]"        (DHT22Sensors) [ "CurrentTemperature" ]    { mqtt="<[mosquitto:user/sensors/temperature:state:default]" }
Number     DHT22_Hum        "Humidity [%d] %"                (DHT22Sensors) [ "CurrentHumidity" ]        { mqtt="<[mosquitto:user/sensors/humidity:state:default]" }

 

And…  this was all!

Enjoy!!!