Humidity+Relay with button node



  • Hi,
    i started playing with Mysensors and Arduino and managed to make a Gateway and the relay/humidity node with the following code:

    #include <SPI.h>
    #include <MySensor.h>
    #include <DHT.h>
    
    #include <MySigningNone.h>
    #include <MyTransportNRF24.h>
    #include <MyTransportRFM69.h>
    #include <MyHwATMega328.h>
    
    #define NODE_ID 1
    #define CHILD_ID_HUM 0
    #define CHILD_ID_TEMP 1
    #define CHILD_ID_RELAY 2
    #define RELAY_PIN 3
    #define HUMIDITY_SENSOR_DIGITAL_PIN 2
    //unsigned long SLEEP_TIME = 30000; // Sleep time between reads (in milliseconds)
    
    #define RELAY_ON 1  // GPIO value to write to turn on attached relay
    #define RELAY_OFF 0 // GPIO value to write to turn off attached relay
    
    MyTransportNRF24 radio(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW);
    
    MyHwATMega328 hw;
    
    MySensor gw(radio, hw);
    
    DHT dht;
    float lastTemp;
    float lastHum;
    boolean metric = true;
    MyMessage msgHum(CHILD_ID_HUM, V_HUM);
    MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
    
    void setup()
    {
      gw.begin(incomingMessage, AUTO, true);
      dht.setup(HUMIDITY_SENSOR_DIGITAL_PIN);
      gw.sendSketchInfo("Combo", "1.0");
      gw.present(CHILD_ID_HUM, S_HUM);
      gw.present(CHILD_ID_TEMP, S_TEMP);
      gw.present(CHILD_ID_RELAY, S_LIGHT);
      metric = gw.getConfig().isMetric;
      pinMode(RELAY_PIN, OUTPUT);
      digitalWrite(RELAY_PIN, gw.loadState(1) ? RELAY_ON : RELAY_OFF);
    }
    
    void loop()
    {
      gw.process();
      delay(dht.getMinimumSamplingPeriod());
      float temperature = dht.getTemperature();
      if (isnan(temperature))
      {
        Serial.println("Failed reading temperature from DHT");
      } 
      else if (temperature != lastTemp) 
      {
        lastTemp = temperature;
        if (!metric) 
        {
          temperature = dht.toFahrenheit(temperature);
        }
        gw.send(msgTemp.set(temperature, 1));
        Serial.print("T: ");
        Serial.println(temperature);
      }
      float humidity = dht.getHumidity();
      if (isnan(humidity))
      {
        Serial.println("Failed reading humidity from DHT");
      } else if (humidity != lastHum)
      {
        lastHum = humidity;
        gw.send(msgHum.set(humidity, 1));
        Serial.print("H: ");
        Serial.println(humidity);
      }
    }
    
    void incomingMessage(const MyMessage &message) 
    {
      if (message.type == V_LIGHT) 
      {
        digitalWrite(RELAY_PIN, message.getBool() ? RELAY_ON : RELAY_OFF);
        gw.saveState(1, message.getBool());
        Serial.print("Incoming change for sensor:");
        Serial.print(message.sensor);
        Serial.print(", New status: ");
        Serial.println(message.getBool());
      }
    }
    

    Since this is copy/pasted from the forum, i am wondering if it is possible to incorporate a hardware button to control the relay. I tried adding code from the Relay with actuator example, but i failed to make it work, i can only turn the relay on with the button. I am using Domoticz as a controller. Any help would be welcome.



  • Hi @thecko,

    To answer you, yes it is totally possible. But to be able to help you more can you please share your sketch instead? The one that you added the relay code, with that we can help you find what is wrong.

    Regards



  • Thee sketch i used is:

    #include <SPI.h>
    #include <MySensor.h>
    #include <DHT.h>
    #include <Bounce2.h>
    
    #include <MySigningNone.h>
    #include <MyTransportNRF24.h>
    #include <MyTransportRFM69.h>
    #include <MyHwATMega328.h>
    
    #define NODE_ID 1
    #define CHILD_ID_HUM 0
    #define CHILD_ID_TEMP 1
    #define CHILD_ID_RELAY 2
    #define RELAY_PIN 3
    #define BUTTON_PIN 4
    #define HUMIDITY_SENSOR_DIGITAL_PIN 2
    //unsigned long SLEEP_TIME = 30000; // Sleep time between reads (in milliseconds)
    
    #define RELAY_ON 1  // GPIO value to write to turn on attached relay
    #define RELAY_OFF 0 // GPIO value to write to turn off attached relay
    
    MyTransportNRF24 radio(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW);
    
    MyHwATMega328 hw;
    
    MySensor gw(radio, hw);
    
    Bounce debouncer = Bounce(); 
    int oldValue=0;
    bool state;
    MyMessage msg(CHILD_ID_RELAY,V_LIGHT);
    
    DHT dht;
    float lastTemp;
    float lastHum;
    boolean metric = true;
    MyMessage msgHum(CHILD_ID_HUM, V_HUM);
    MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
    
    void setup()
    {
      gw.begin(incomingMessage, AUTO, true);
      dht.setup(HUMIDITY_SENSOR_DIGITAL_PIN);
      gw.sendSketchInfo("Combo", "1.0");
      gw.present(CHILD_ID_HUM, S_HUM);
      gw.present(CHILD_ID_TEMP, S_TEMP);
      pinMode(BUTTON_PIN,INPUT);
      digitalWrite(BUTTON_PIN,HIGH);
      debouncer.attach(BUTTON_PIN);
      debouncer.interval(5);
      gw.present(CHILD_ID_RELAY, S_LIGHT);
      metric = gw.getConfig().isMetric;
      digitalWrite(RELAY_PIN, RELAY_OFF);
      pinMode(RELAY_PIN, OUTPUT);
      state = gw.loadState(CHILD_ID_RELAY);
      digitalWrite(RELAY_PIN, state?RELAY_ON:RELAY_OFF);
      
    }
    
    
    
    void loop()
    {
      gw.process();
      debouncer.update();
      int value = debouncer.read();
      if (value != oldValue && value==0) {
          gw.send(msg.set(state?false:true), true); // Send new state and request ack back
      }
      oldValue = value;
      delay(dht.getMinimumSamplingPeriod());
      float temperature = dht.getTemperature();
      if (isnan(temperature))
      {
        Serial.println("Failed reading temperature from DHT");
      } 
      else if (temperature != lastTemp) 
      {
        lastTemp = temperature;
        if (!metric) 
        {
          temperature = dht.toFahrenheit(temperature);
        }
        gw.send(msgTemp.set(temperature, 1));
        Serial.print("T: ");
        Serial.println(temperature);
      }
      float humidity = dht.getHumidity();
      if (isnan(humidity))
      {
        Serial.println("Failed reading humidity from DHT");
      } else if (humidity != lastHum)
      {
        lastHum = humidity;
        gw.send(msgHum.set(humidity, 1));
        Serial.print("H: ");
        Serial.println(humidity);
      }
    }
    
    void incomingMessage(const MyMessage &message) 
    {
      if (message.type == V_LIGHT) 
      {
        digitalWrite(RELAY_PIN, message.getBool() ? RELAY_ON : RELAY_OFF);
        gw.saveState(1, message.getBool());
        Serial.print("Incoming change for sensor:");
        Serial.print(message.sensor);
        Serial.print(", New status: ");
        Serial.println(message.getBool());
      }
    }
    

    With this sketch i can control the relay with domoticz, but i can only activate the relay, not deactivate.
    I connected the button to GND pin and PIN4 on the Arduino.


  • Contest Winner

    @thecko Great to hear that you've got it working. The answer to your question is: Yet that's possible.

    What you need for it?

    1. Include Bounce2.h
    2. declare a bounce object in your setup
    3. do the following in your loop()
      a. read the debounced value of your switch
      b. if value changes, than invert current relay value

    With the Bounce library comes an Update-example which shows how you can do the above pseudo code.

    Hope it helps you.


  • Contest Winner

    @thecko said:

    The problem is in the "state" variable, you use the state variable to toggle but never save changed value

    so change this code snippet

       debouncer.update();
       int value = debouncer.read();
       if (value != oldValue && value==0) {
           gw.send(msg.set(state?false:true), true); // Send new state and request ack back
       }
       oldValue = value;
    

    to

       debouncer.update();
       int value = debouncer.read();
       if (value != oldValue && value==0) {
           gw.send(msg.set(gw.loadState(1)?false:true), true); // Send new state and request ack back
       }
       oldValue = value;
    

    and remove the state variable at all.

    Even better also remove the "oldValue" and "value" variables (the bounce2 library keeps the old value for you and debouncer.update(); returns true when the value was toggled )

       if (debouncer.update() && debouncer.read() == 0) {
           gw.send(msg.set(gw.loadState(1)?false:true), true); // Send new state and request ack back
       }
    


  • Hi, thank you for the suggestions, its working now!
    The final code looks like this:

    #include <SPI.h>
    #include <MySensor.h>
    #include <DHT.h>
    #include <Bounce2.h>
    
    #include <MySigningNone.h>
    #include <MyTransportNRF24.h>
    #include <MyTransportRFM69.h>
    #include <MyHwATMega328.h>
    
    #define NODE_ID 1
    #define CHILD_ID_HUM 0
    #define CHILD_ID_TEMP 1
    #define CHILD_ID_RELAY 2
    #define RELAY_PIN 3
    #define BUTTON_PIN 4
    #define HUMIDITY_SENSOR_DIGITAL_PIN 2
    //unsigned long SLEEP_TIME = 30000; // Sleep time between reads (in milliseconds)
    
    #define RELAY_ON 1  // GPIO value to write to turn on attached relay
    #define RELAY_OFF 0 // GPIO value to write to turn off attached relay
    
    MyTransportNRF24 radio(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW);
    
    MyHwATMega328 hw;
    
    MySensor gw(radio, hw);
    
    Bounce debouncer = Bounce(); 
    int oldValue=0;
    bool state;
    MyMessage msg(CHILD_ID_RELAY,V_LIGHT);
    
    DHT dht;
    float lastTemp;
    float lastHum;
    boolean metric = true;
    MyMessage msgHum(CHILD_ID_HUM, V_HUM);
    MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
    
    void setup()
    {
      gw.begin(incomingMessage, AUTO, true);
      dht.setup(HUMIDITY_SENSOR_DIGITAL_PIN);
      gw.sendSketchInfo("Combo", "1.0");
      gw.present(CHILD_ID_HUM, S_HUM);
      gw.present(CHILD_ID_TEMP, S_TEMP);
      pinMode(BUTTON_PIN,INPUT);
      digitalWrite(BUTTON_PIN,HIGH);
      debouncer.attach(BUTTON_PIN);
      debouncer.interval(5);
      gw.present(CHILD_ID_RELAY, S_LIGHT);
      metric = gw.getConfig().isMetric;
      digitalWrite(RELAY_PIN, RELAY_OFF);
      pinMode(RELAY_PIN, OUTPUT);
      state = gw.loadState(CHILD_ID_RELAY);
      digitalWrite(RELAY_PIN, state?RELAY_ON:RELAY_OFF);
      
    }
    
    
    
    void loop()
    {
      gw.process();
       debouncer.update();
       int value = debouncer.read();
       if (value != oldValue && value==0) {
           gw.send(msg.set(gw.loadState(1)?false:true), true); // Send new state and request ack back
       }
       oldValue = value;
      delay(dht.getMinimumSamplingPeriod());
      float temperature = dht.getTemperature();
      if (isnan(temperature))
      {
        Serial.println("Failed reading temperature from DHT");
      } 
      else if (temperature != lastTemp) 
      {
        lastTemp = temperature;
        if (!metric) 
        {
          temperature = dht.toFahrenheit(temperature);
        }
        gw.send(msgTemp.set(temperature, 1));
        Serial.print("T: ");
        Serial.println(temperature);
      }
      float humidity = dht.getHumidity();
      if (isnan(humidity))
      {
        Serial.println("Failed reading humidity from DHT");
      } else if (humidity != lastHum)
      {
        lastHum = humidity;
        gw.send(msgHum.set(humidity, 1));
        Serial.print("H: ");
        Serial.println(humidity);
      }
    }
    
    void incomingMessage(const MyMessage &message) 
    {
      if (message.type == V_LIGHT) 
      {
        digitalWrite(RELAY_PIN, message.getBool() ? RELAY_ON : RELAY_OFF);
        gw.saveState(1, message.getBool());
        Serial.print("Incoming change for sensor:");
        Serial.print(message.sensor);
        Serial.print(", New status: ");
        Serial.println(message.getBool());
      }
    }
    

    The only thing that remains is that the button needs to be pressed for about 2 secs to actuate. When measured with a multimeter, it takes about 2 secs to get from 1 to 0. Tried inserting a 4.7k resistor between PIN4 and the button, but still 2 sec for the button to actuate.


  • Contest Winner

    @thecko the button should connect pin D4 to ground when pressed and there should be no resistor needed since your sketch activates the internal pull up resistor with this line:

     digitalWrite(BUTTON_PIN,HIGH);
    


  • @BartE Is there any way to decrease the amount of time the button needs to be pushed ? Maybe my choice of the button is not good, will try another button when i come home?


  • Contest Winner

    @thecko the amount of time you have to wait is the result of this line

     delay(dht.getMinimumSamplingPeriod());
    

    Your sketch has to pass 5 times time delay (set by this line debouncer.interval(5);)
    before a button press is detected.
    Better use a while loop without a delay some something like this

    unsigned long lastCheckTimestamp = 0;
    
    // setup stuff
    
    void loop ()
    {
        gw.process();
        if (debouncer.update() && debouncer.read() == 0) {
           gw.send(msg.set(gw.loadState(1)?false:true), true); // Send new state and request ack back
        }
    
        // Check if the minimal sample period has been passed 
        if ((lastCheckTimestamp < (millis() - dht.getMinimumSamplingPeriod()) ) || lastCheckTimestamp > millis())
        {
    	  lastCheckTimestamp  = millis();
    
    	  // do the normal stuff after the delay
    	  float temperature = dht.getTemperature();
    	  if (isnan(temperature))
    	  {
    	    Serial.println("Failed reading temperature from DHT");
    	  } 
    	  else if (temperature != lastTemp) 
    	  {
    	    lastTemp = temperature;
    	    if (!metric) 
    	    {
    	      temperature = dht.toFahrenheit(temperature);
    	    }
    	    gw.send(msgTemp.set(temperature, 1));
    	    Serial.print("T: ");
    	    Serial.println(temperature);
    	  }
    	  float humidity = dht.getHumidity();
    	  if (isnan(humidity))
    	  {
    	    Serial.println("Failed reading humidity from DHT");
    	  } else if (humidity != lastHum)
    	  {
    	    lastHum = humidity;
    	    gw.send(msgHum.set(humidity, 1));
    	    Serial.print("H: ");
    	    Serial.println(humidity);
    	  }
       }
    }
    


  • When i try your sketch in this format:

    #include <SPI.h>
    #include <MySensor.h>
    #include <DHT.h>
    #include <Bounce2.h>
    
    #include <MySigningNone.h>
    #include <MyTransportNRF24.h>
    #include <MyTransportRFM69.h>
    #include <MyHwATMega328.h>
    
    #define NODE_ID 1
    #define CHILD_ID_HUM 0
    #define CHILD_ID_TEMP 1
    #define CHILD_ID_RELAY 2
    #define RELAY_PIN 3
    #define BUTTON_PIN 4
    #define HUMIDITY_SENSOR_DIGITAL_PIN 2
    //unsigned long SLEEP_TIME = 30000; // Sleep time between reads (in milliseconds)
    
    #define RELAY_ON 1  // GPIO value to write to turn on attached relay
    #define RELAY_OFF 0 // GPIO value to write to turn off attached relay
    
    MyTransportNRF24 radio(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW);
    
    MyHwATMega328 hw;
    
    MySensor gw(radio, hw);
    
    Bounce debouncer = Bounce(); 
    int oldValue=0;
    bool state;
    MyMessage msg(CHILD_ID_RELAY,V_LIGHT);
    
    DHT dht;
    float lastTemp;
    float lastHum;
    boolean metric = true;
    MyMessage msgHum(CHILD_ID_HUM, V_HUM);
    MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
    
    void setup()
    {
      gw.begin(incomingMessage, AUTO, true);
      dht.setup(HUMIDITY_SENSOR_DIGITAL_PIN);
      gw.sendSketchInfo("Combo", "1.0");
      gw.present(CHILD_ID_HUM, S_HUM);
      gw.present(CHILD_ID_TEMP, S_TEMP);
      pinMode(BUTTON_PIN,INPUT);
      digitalWrite(BUTTON_PIN,HIGH);
      debouncer.attach(BUTTON_PIN);
      debouncer.interval(5);
      gw.present(CHILD_ID_RELAY, S_LIGHT);
      metric = gw.getConfig().isMetric;
      digitalWrite(RELAY_PIN, RELAY_OFF);
      pinMode(RELAY_PIN, OUTPUT);
      state = gw.loadState(CHILD_ID_RELAY);
      digitalWrite(RELAY_PIN, state?RELAY_ON:RELAY_OFF);
      
    }
    
    
    unsigned long lastCheckTimestamp = 0;
    
    // setup stuff
    
    void loop()
    {
        gw.process();
        if (debouncer.update() && debouncer.read() == 0) {
           gw.send(msg.set(gw.loadState(1)?false:true), true); // Send new state and request ack back
        }
    
        // Check if the minimal sample period has been passed 
        if ((lastCheckTimestamp < (millis() - dht.getMinimumSamplingPeriod()) ) || lastCheckTimestamp > millis())
        {
          lastCheckTimestamp  = millis();
    
          // do the normal stuff after the delay
          float temperature = dht.getTemperature();
          if (isnan(temperature))
          {
            Serial.println("Failed reading temperature from DHT");
          } 
          else if (temperature != lastTemp) 
          {
            lastTemp = temperature;
            if (!metric) 
            {
              temperature = dht.toFahrenheit(temperature);
            }
            gw.send(msgTemp.set(temperature, 1));
            Serial.print("T: ");
            Serial.println(temperature);
          }
          float humidity = dht.getHumidity();
          if (isnan(humidity))
          {
            Serial.println("Failed reading humidity from DHT");
          } else if (humidity != lastHum)
          {
            lastHum = humidity;
            gw.send(msgHum.set(humidity, 1));
            Serial.print("H: ");
            Serial.println(humidity);
          }
       }
    }
    

    Forumhlp.ino: In function 'void setup()':
    Forumhlp:44: error: 'incomingMessage' was not declared in this scope
    'incomingMessage' was not declared in this scope

    Seems something is not right, tried deleting incomingMessage line, but no dice.


  • Contest Winner

    @thecko said:
    You have to add you original setup and incomingMessage function, i just was explaning how to alter the loop function.

    void incomingMessage(const MyMessage &message) 
    {
      if (message.type == V_LIGHT) 
      {
        digitalWrite(RELAY_PIN, message.getBool() ? RELAY_ON : RELAY_OFF);
        gw.saveState(1, message.getBool());
        Serial.print("Incoming change for sensor:");
        Serial.print(message.sensor);
        Serial.print(", New status: ");
        Serial.println(message.getBool());
      }
    }
    


  • @BartE Adding the extra code done the job, now its working great. Thank you for your help!

    The final working code if someone wonders is:

    #include <SPI.h>
    #include <MySensor.h>
    #include <DHT.h>
    #include <Bounce2.h>
    
    #include <MySigningNone.h>
    #include <MyTransportNRF24.h>
    #include <MyTransportRFM69.h>
    #include <MyHwATMega328.h>
    
    #define NODE_ID 1
    #define CHILD_ID_HUM 0
    #define CHILD_ID_TEMP 1
    #define CHILD_ID_RELAY 2
    #define RELAY_PIN 3
    #define BUTTON_PIN 4
    #define HUMIDITY_SENSOR_DIGITAL_PIN 2
    //unsigned long SLEEP_TIME = 30000; // Sleep time between reads (in milliseconds)
    
    #define RELAY_ON 1  // GPIO value to write to turn on attached relay
    #define RELAY_OFF 0 // GPIO value to write to turn off attached relay
    
    MyTransportNRF24 radio(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW);
    
    MyHwATMega328 hw;
    
    MySensor gw(radio, hw);
    
    Bounce debouncer = Bounce(); 
    int oldValue=0;
    bool state;
    MyMessage msg(CHILD_ID_RELAY,V_LIGHT);
    
    DHT dht;
    float lastTemp;
    float lastHum;
    boolean metric = true;
    MyMessage msgHum(CHILD_ID_HUM, V_HUM);
    MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
    
    void setup()
    {
      gw.begin(incomingMessage, AUTO, true);
      dht.setup(HUMIDITY_SENSOR_DIGITAL_PIN);
      gw.sendSketchInfo("Combo", "1.0");
      gw.present(CHILD_ID_HUM, S_HUM);
      gw.present(CHILD_ID_TEMP, S_TEMP);
      pinMode(BUTTON_PIN,INPUT);
      digitalWrite(BUTTON_PIN,HIGH);
      debouncer.attach(BUTTON_PIN);
      debouncer.interval(5);
      gw.present(CHILD_ID_RELAY, S_LIGHT);
      metric = gw.getConfig().isMetric;
      digitalWrite(RELAY_PIN, RELAY_OFF);
      pinMode(RELAY_PIN, OUTPUT);
      state = gw.loadState(CHILD_ID_RELAY);
      digitalWrite(RELAY_PIN, state?RELAY_ON:RELAY_OFF);
      
    }
    
    
    unsigned long lastCheckTimestamp = 0;
    
    // setup stuff
    
    void incomingMessage(const MyMessage &message) 
    {
      if (message.type == V_LIGHT) 
      {
        digitalWrite(RELAY_PIN, message.getBool() ? RELAY_ON : RELAY_OFF);
        gw.saveState(1, message.getBool());
        Serial.print("Incoming change for sensor:");
        Serial.print(message.sensor);
        Serial.print(", New status: ");
        Serial.println(message.getBool());
      }
    }
    
    void loop()
    {
        gw.process();
        if (debouncer.update() && debouncer.read() == 0) {
           gw.send(msg.set(gw.loadState(1)?false:true), true); // Send new state and request ack back
        }
    
        // Check if the minimal sample period has been passed 
        if ((lastCheckTimestamp < (millis() - dht.getMinimumSamplingPeriod()) ) || lastCheckTimestamp > millis())
        {
          lastCheckTimestamp  = millis();
    
          // do the normal stuff after the delay
          float temperature = dht.getTemperature();
          if (isnan(temperature))
          {
            Serial.println("Failed reading temperature from DHT");
          } 
          else if (temperature != lastTemp) 
          {
            lastTemp = temperature;
            if (!metric) 
            {
              temperature = dht.toFahrenheit(temperature);
            }
            gw.send(msgTemp.set(temperature, 1));
            Serial.print("T: ");
            Serial.println(temperature);
          }
          float humidity = dht.getHumidity();
          if (isnan(humidity))
          {
            Serial.println("Failed reading humidity from DHT");
          } else if (humidity != lastHum)
          {
            lastHum = humidity;
            gw.send(msgHum.set(humidity, 1));
            Serial.print("H: ");
            Serial.println(humidity);
          }
       }
    }
    

 

262
Online

7.8k
Users

8.7k
Topics

93.0k
Posts