ESP8266 MQTT gateway + sonoff_MQTT code + vera + HA_Bridge + Alexa, oh my



  • Hi guys, I have been playing with a sonoff using MQTT and a Mosquitto server on my Synology diskstation.

    But could not see a way to get control of the sonoff on my vera (with Mysensors) as it does not support MQTT.

    I started to play with the ESP8266 MQTT gateway, the gateway has an NRF radio but is Not connected to the vera as an actual gateway.

    (I just opened a second page on Mysensors to check something and saw Efflon posted a MQTT Sonoff post but his uses home assistant which supports MQTT so I think mine is different enough to keep going)

    Ok so, here is the working chain:

    • "Alexa switch on mains plug 1"

    • Alexa talks to HA Bridge (also running on my Synology) where mains plug 1 is the friendly name of Vera virtual switch device no 181 id 20;10 parent 3

    • HA Bridge talks to Vera in html to switch on the Virtual switch with id 20;10 (I have a 433Txnode with id 20 and 6 switches) with parent id 3(Mysensors plugin)

    • Message then goes out the Mysensors serial gateway and is broadcast over NRF (20/10/1/1/2 1)

    • The ESP8266_MQTT_gateway picks up the message on NRF and sends it on to the MQTT broker (mygateway1-out/20/10/1/1/2 with message 1)

    • The SONOFF unit is subscribed to the broker and picks up the message and switches on.

    if you press the button on the sonoff it works in reverse as far as Vera, sending a message to mygateway1-in/20/10/1/1/2 0 or 1 switching the state of the virtual switch.

    The ESP8266 MQTT gateway code was unchanged.

    Sonoff MQTT code from esp8266.com

    The only change was to the topic name

    /*
    
     It connects to an MQTT server then:
      - on 0 switches off relay
      - on 1 switches on relay
      - on 2 switches the state of the relay
    
      - sends 0 on off relay
      - sends 1 on on relay
    
     It will reconnect to the server if the connection is lost using a blocking
     reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to
     achieve the same result without blocking the main loop.
    
     The current state is stored in EEPROM and restored on bootup
    
    */
    
    #include <ESP8266WiFi.h>
    #include <PubSubClient.h>
    #include <Bounce2.h>
    #include <EEPROM.h>
    
    
    const char* ssid = "ssid";
    const char* password = "password";
    const char* mqtt_server = "broker IP address";
    
    WiFiClient espClient;
    PubSubClient client(espClient);
    long lastMsg = 0;
    char msg[50];
    int value = 0;
    
    //const char* outTopic = "Sonoff1out";
    const char* outTopic = "mygateway1-in/20/10/1/1/2";
    //const char* inTopic = "Sonoff1in";
    const char* inTopic = "mygateway1-out/20/10/1/1/2";
    
    int relay_pin = 12;
    int button_pin = 0;
    bool relayState = LOW;
    
    // Instantiate a Bounce object :
    Bounce debouncer = Bounce(); 
    
    
    void setup_wifi() {
    
      delay(10);
      // We start by connecting to a WiFi network
      Serial.println();
      Serial.print("Connecting to ");
      Serial.println(ssid);
    
      WiFi.begin(ssid, password);
    
      while (WiFi.status() != WL_CONNECTED) {
        extButton();
        for(int i = 0; i<500; i++){
          extButton();
          delay(1);
        }
        Serial.print(".");
      }
      digitalWrite(13, LOW);
      delay(500);
      digitalWrite(13, HIGH);
      delay(500);
      digitalWrite(13, LOW);
      delay(500);
      digitalWrite(13, HIGH);
      Serial.println("");
      Serial.println("WiFi connected");
      Serial.println("IP address: ");
      Serial.println(WiFi.localIP());
    }
    
    void callback(char* topic, byte* payload, unsigned int length) {
      Serial.print("Message arrived [");
      Serial.print(topic);
      Serial.print("] ");
      for (int i = 0; i < length; i++) {
        Serial.print((char)payload[i]);
      }
      Serial.println();
    
      // Switch on the LED if an 1 was received as first character
      if ((char)payload[0] == '0') {
        digitalWrite(relay_pin, LOW);   // Turn the LED on (Note that LOW is the voltage level
        Serial.println("relay_pin -> LOW");
        relayState = LOW;
        EEPROM.write(0, relayState);    // Write state to EEPROM
        EEPROM.commit();
      } else if ((char)payload[0] == '1') {
        digitalWrite(relay_pin, HIGH);  // Turn the LED off by making the voltage HIGH
        Serial.println("relay_pin -> HIGH");
        relayState = HIGH;
        EEPROM.write(0, relayState);    // Write state to EEPROM
        EEPROM.commit();
      } else if ((char)payload[0] == '2') {
        relayState = !relayState;
        digitalWrite(relay_pin, relayState);  // Turn the LED off by making the voltage HIGH
        Serial.print("relay_pin -> switched to ");
        Serial.println(relayState); 
        EEPROM.write(0, relayState);    // Write state to EEPROM
        EEPROM.commit();
      }
    }
    
    void reconnect() {
      // Loop until we're reconnected
      while (!client.connected()) {
        Serial.print("Attempting MQTT connection...");
        // Attempt to connect
        if (client.connect("ESP8266Client")) {
          Serial.println("connected");
          // Once connected, publish an announcement...
          client.publish(outTopic, "Sonoff1 booted");
          // ... and resubscribe
          client.subscribe(inTopic);
        } else {
          Serial.print("failed, rc=");
          Serial.print(client.state());
          Serial.println(" try again in 5 seconds");
          // Wait 5 seconds before retrying
          for(int i = 0; i<5000; i++){
            extButton();
            delay(1);
          }
        }
      }
    }
    
    void extButton() {
      debouncer.update();
       
       // Call code if Bounce fell (transition from HIGH to LOW) :
       if ( debouncer.fell() ) {
         Serial.println("Debouncer fell");
         // Toggle relay state :
         relayState = !relayState;
         digitalWrite(relay_pin,relayState);
         EEPROM.write(0, relayState);    // Write state to EEPROM
         if (relayState == 1){
          client.publish(outTopic, "1");
         }
         else if (relayState == 0){
          client.publish(outTopic, "0");
         }
       }
    }
    
    void setup() {
      EEPROM.begin(512);              // Begin eeprom to store on/off state
      pinMode(relay_pin, OUTPUT);     // Initialize the relay pin as an output
      pinMode(button_pin, INPUT);     // Initialize the relay pin as an output
      pinMode(13, OUTPUT);
      relayState = EEPROM.read(0);
      digitalWrite(relay_pin,relayState);
      
      debouncer.attach(button_pin);   // Use the bounce2 library to debounce the built in button
      debouncer.interval(50);         // Input must be low for 50 ms
      
      digitalWrite(13, LOW);          // Blink to indicate setup
      delay(500);
      digitalWrite(13, HIGH);
      delay(500);
      
      Serial.begin(115200);
      setup_wifi();                   // Connect to wifi 
      client.setServer(mqtt_server, 1883);
      client.setCallback(callback);
    }
    
    void loop() {
    
      if (!client.connected()) {
        reconnect();
      }
      client.loop();
      extButton();
    }
    
    //- See more at: http://www.esp8266.com/viewtopic.php?f=29&t=8746#sthash.vhv33y8Q.dpuf
    

    You don't need to add any extra gateways to Vera, you just add Virtual Switches and program each sonoff (or any other ESP8266) with the different Broker topics needed.



  • @stephenmhall Cool! With my Sonoff example there is not a must to use HASS or mqtt. A MYS gateway or a standard mqtt broker would work fine. Anyway, as long as things work, life is good 😄 . What I don't understand is where the mqtt broker is running?



  • Broker is running on my Synology Diskstation, keeps it all in house as it were. The HA bridge is just there to allow Alexa to control Vera devices.



  • @stephenmhall aha! But vera runs MYS? Then using my code with the ESP8266 wifi sketch should work without all in-between stuff? (just guessing)..



  • @Efflon I don't think it would, I'm assuming your Home Assistant controller is telling the sonoff to switch using MQTT with your config code

    mysensors:
      gateways:
        - device: mqtt
          persistence_file: '/home/homeassistant/.homeassistant/sonoff.json'
          topic_in_prefix: 'sonoff-out'
          topic_out_prefix: 'sonoff-in'
      debug: false
      optimistic: false
      persistence: true
      retain: true
      version: 2.0
    

    The problem is the Vera controller does not speak MQTT at all, there is a plugin to send device statuses out to a Broker but it's not two way. So all you could do is send the fact that the switch is on or off, but not change it.

    This gets round that by sending out a MySensors message which is then converted into MQTT to switch the Sonoff. so the Vera does not need to know about MQTT and the Sonoff units do not need to know about MySensors.



  • @stephenmhall What I mean is by using the ESP8266 wifi sketch with my presentation etc. code (not the top mqtt parts) the sonoff will talk standard "MYS ethernet code" with your MYS controller.

    Untested example code:

    /**
     * The MySensors Arduino library handles the wireless radio link and protocol
     * between your home built sensors/actuators and HA controller of choice.
     * The sensors forms a self healing radio network with optional repeaters. Each
     * repeater and gateway builds a routing tables in EEPROM which keeps track of the
     * network topology allowing messages to be routed to nodes.
     *
     * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
     * Copyright (C) 2013-2015 Sensnology AB
     * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
     *
     * Documentation: http://www.mysensors.org
     * Support Forum: http://forum.mysensors.org
     *
     * This program is free software; you can redistribute it and/or
     * modify it under the terms of the GNU General Public License
     * version 2 as published by the Free Software Foundation.
     *
     *******************************
     *
     * REVISION HISTORY
     * Version 1.0 - Henrik EKblad
     * Contribution by a-lurker and Anticimex,
     * Contribution by Norbert Truchsess <norbert.truchsess@t-online.de>
     * Contribution by Ivo Pullens (ESP8266 support)
     *
     * DESCRIPTION
     * The EthernetGateway sends data received from sensors to the WiFi link.
     * The gateway also accepts input on ethernet interface, which is then sent out to the radio network.
     *
     * VERA CONFIGURATION:
     * Enter "ip-number:port" in the ip-field of the Arduino GW device. This will temporarily override any serial configuration for the Vera plugin.
     * E.g. If you want to use the defualt values in this sketch enter: 192.168.178.66:5003
     *
     * LED purposes:
     * - To use the feature, uncomment any of the MY_DEFAULT_xx_LED_PINs in your sketch, only the LEDs that is defined is used.
     * - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved
     * - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly
     * - ERR (red) - fast blink on error during transmission error or recieve crc error
     *
     * See http://www.mysensors.org/build/esp8266_gateway for wiring instructions.
     * nRF24L01+  ESP8266
     * VCC        VCC
     * CE         GPIO4
     * CSN/CS     GPIO15
     * SCK        GPIO14
     * MISO       GPIO12
     * MOSI       GPIO13
     * GND        GND
     *
     * Not all ESP8266 modules have all pins available on their external interface.
     * This code has been tested on an ESP-12 module.
     * The ESP8266 requires a certain pin configuration to download code, and another one to run code:
     * - Connect REST (reset) via 10K pullup resistor to VCC, and via switch to GND ('reset switch')
     * - Connect GPIO15 via 10K pulldown resistor to GND
     * - Connect CH_PD via 10K resistor to VCC
     * - Connect GPIO2 via 10K resistor to VCC
     * - Connect GPIO0 via 10K resistor to VCC, and via switch to GND ('bootload switch')
     *
      * Inclusion mode button:
     * - Connect GPIO5 via switch to GND ('inclusion switch')
     *
     * Hardware SHA204 signing is currently not supported!
     *
     * Make sure to fill in your ssid and WiFi password below for ssid & pass.
     */
    
    
    // Enable debug prints to serial monitor
    #define MY_DEBUG
    
    // Use a bit lower baudrate for serial prints on ESP8266 than default in MyConfig.h
    #define MY_BAUD_RATE 9600
    
    // Enables and select radio type (if attached)
    #define MY_RADIO_NRF24
    //#define MY_RADIO_RFM69
    
    #define MY_GATEWAY_ESP8266
    
    #define MY_ESP8266_SSID "MySSID"
    #define MY_ESP8266_PASSWORD "MyVerySecretPassword"
    
    // Enable UDP communication
    //#define MY_USE_UDP
    
    // Set the hostname for the WiFi Client. This is the hostname
    // it will pass to the DHCP server if not static.
    // #define MY_ESP8266_HOSTNAME "sensor-gateway"
    
    // Enable MY_IP_ADDRESS here if you want a static ip address (no DHCP)
    //#define MY_IP_ADDRESS 192,168,178,87
    
    // If using static ip you need to define Gateway and Subnet address as well
    #define MY_IP_GATEWAY_ADDRESS 192,168,178,1
    #define MY_IP_SUBNET_ADDRESS 255,255,255,0
    
    // The port to keep open on node server mode
    #define MY_PORT 5003
    
    // How many clients should be able to connect to this gateway (default 1)
    #define MY_GATEWAY_MAX_CLIENTS 2
    
    // Controller ip address. Enables client mode (default is "server" mode).
    // Also enable this if MY_USE_UDP is used and you want sensor data sent somewhere.
    //#define MY_CONTROLLER_IP_ADDRESS 192, 168, 178, 68
    
    // Enable inclusion mode
    #define MY_INCLUSION_MODE_FEATURE
    
    // Enable Inclusion mode button on gateway
    // #define MY_INCLUSION_BUTTON_FEATURE
    // Set inclusion mode duration (in seconds)
    #define MY_INCLUSION_MODE_DURATION 60
    // Digital pin used for inclusion mode button
    #define MY_INCLUSION_MODE_BUTTON_PIN  3
    
    
    // Set blinking period
    // #define MY_DEFAULT_LED_BLINK_PERIOD 300
    
    // Flash leds on rx/tx/err
    // Led pins used if blinking feature is enabled above
    #define MY_DEFAULT_ERR_LED_PIN 16  // Error led pin
    #define MY_DEFAULT_RX_LED_PIN  16  // Receive led pin
    #define MY_DEFAULT_TX_LED_PIN  16  // the PCB, on board LED
    
    #if defined(MY_USE_UDP)
    #include <WiFiUdp.h>
    #endif
    
    #include <ESP8266WiFi.h>
    
    #include <MySensors.h>
    
    #include <Bounce2.h>
    
    #define BUTTON_PIN 0  // Sonoff pin number for button
    #define RELAY_PIN 12  // Sonoff pin number for relay 
    #define LED_PIN 13    // Sonoff pin number for LED
    #define RELAY_ON 1
    #define RELAY_OFF 0
    #define LED_ON 0
    #define LED_OFF 1
    
    // Id of the sensor child
    #define CHILD_ID 0
    
    Bounce debouncer = Bounce(); 
    int oldValue = 0;
    bool state = false;
    
    MyMessage msg(CHILD_ID,V_STATUS);
    
    void setup()  
    {  
      // Setup the button
      pinMode(BUTTON_PIN, INPUT_PULLUP);
    
      // After setting up the button, setup debouncer
      debouncer.attach(BUTTON_PIN);
      debouncer.interval(5);
    
      // Make sure relays and LED are off when starting up
      digitalWrite(RELAY_PIN, RELAY_OFF);
      digitalWrite(LED_PIN, LED_OFF);
    
      // Then set relay pins in output mode
      pinMode(RELAY_PIN, OUTPUT);
      pinMode(LED_PIN, OUTPUT);   
    }
    
    void presentation()  {
      // Send the sketch version information
      sendSketchInfo("Sonoff", "1.0");
      // Register sensor
      present(CHILD_ID, S_BINARY);
      // Send the current state
      send(msg.set(state?true:false));
      // Blink when ready
      blink();
    }
    
    
    void loop()
    {
      debouncer.update();
      // Get the update value
      int value = debouncer.read();
      if (value != oldValue && value==0) {
        // Toggle the state
        state = state?false:true;
        // Change relay state
        digitalWrite(RELAY_PIN, state?RELAY_ON:RELAY_OFF);
        // Change LED state
        digitalWrite(LED_PIN, state?LED_ON:LED_OFF);
        // Send new state
        send(msg.set(state)); 
      }
      oldValue = value;
    }
    
    void receive(const MyMessage &message)
    {
      // We only react on status messages from the controller
      // to this CHILD_ID.
      if (message.type==V_STATUS  && message.sensor==CHILD_ID) {
        // Change relay state
        // Only switch if the state is new
        if (message.getBool() != state) {
          state = message.getBool();
          // Change relay state
          digitalWrite(RELAY_PIN, state?RELAY_ON:RELAY_OFF);
          // Change LED state
          digitalWrite(LED_PIN, state?LED_ON:LED_OFF);
           // Send the current state
          send(msg.set(state));  
        }
      }
    }
    
    void blink()
    {
      digitalWrite(LED_PIN, digitalRead(LED_PIN)?LED_ON:LED_OFF);
      wait(200);
      digitalWrite(LED_PIN, digitalRead(LED_PIN)?LED_ON:LED_OFF);
      wait(200);
      digitalWrite(LED_PIN, digitalRead(LED_PIN)?LED_ON:LED_OFF);
      wait(200);
      digitalWrite(LED_PIN, digitalRead(LED_PIN)?LED_ON:LED_OFF);
    }
    


  • Would it not need to be added to the Vera as another gateway? I only have a serial gateway on the vera at the moment, I seem to remember I had problems the last time I tried to upgrade to an esp8266 ethernet Gateway and had to go back to the old serial one.

    Mysensor plugin is reporting version 1.5 lib 2.0.0



  • @stephenmhall ahh, serial gateway. Then just forget all I wrote... 😄



  • Switches working well but I can't get Temperature to update on a device.

    When switching on a sonoff locally it sends

    mygateway1-in/20/10/1/1/2/1
    

    to the MQTT broker, which immediately causes the switch on the device in Vera to show on, this is passed back out and is sent back to the sonoff.

    However I cannot get a temperature device to update. I send

    mygateway1-in/50/1/1/0/0/20.70
    

    to the Broker but get no change. I can send an html command to update the temp fine.

    here is the Vera device parameters.
    alt text

    I have tried sending to the in and the out topic just to be sure.

    Does anyone have a log from an actual temp node showing the message passed to the gateway just in case someting is not right with my message?

    Also is there a way to monitor the serial messages passed into the Vera from the gateway to check the messages are passing?


 

354
Online

8.0k
Users

8.8k
Topics

94.4k
Posts