Moisture Sensor and relay node. Relay becomes unresponsive



  • Hi There,

    I'm new to the MySensors world. I've successfully brought up a gw node connected to my vera and 2 sensor nodes; a barometric pressure sensor outside, and a temperature sensor inside the house all connected to my Veralite controller running UI5.

    I have since then dove into trying to get my next project working, a sensor node with a relay and a home made moisture sensor.

    After trying just the relay first, i got that up and enrolled in my vera. Yay! i could send and receive data into Vera and i could locally control my relay with a button. Cool! So the next step was to work on adding my moisture sensor. This has been troublesome for me.

    After hours of working on it over the weekend, i successfully got the second sensor on the node to add to Vera!

    However, after just a couple button presses of the "light switch" from the web UI, or from my AuthomationHD app, the relay will not work. It seems as if the information is not making it to my node.

    Below is my code. Anyone have any ideas?

    I've been browsing the forum and the MySensors API, but i'm a bit stumped.

    I've also noticed that my moisture sensor is not staying within the range i have mapped (at least as it reports to Vera web UI). Perhaps that has to do with how the S_HUM and V_HUM templates work? Anyone know where i can find more info on these?

    Right now i'm using a bare ATmega328P so i dont have Serial debugging until another ESB TTL module arrives from China (had to use my one that i had to get the gw working since i had a clone nano and Vera didn't understand the chipset of the onboard USB)

    #include <MySensor.h>
    #include <SPI.h>
    #include <Bounce2.h>
    //#include "Bounce2.h"
    
    char SKETCH_NAME[] = "Patio Plant Node";
    char SKETCH_VERSION[] = "0.5";
    
    
    // Define Relay states
    #define RELAY_ON 1                      // switch around for realy HIGH/LOW state
    #define RELAY_OFF 0
    
    // Define MySensor gateway
    MySensor gw;
    
    // Define relays
    #define noRelays 1
    const int relayPin[] = {4};          //  switch around pins to your desire
    const int buttonPin[] = {3};      //  switch around pins to your desire
    
    class Relay   // relay class, store all relevant data (equivalent to struct)
    {
      public:
        int buttonPin;                   // physical pin number of button
        int relayPin;             // physical pin number of relay
        byte oldValue;                    // last Values for key (debounce)
        boolean relayState;               // relay status (also stored in EEPROM)
    };
    
    Relay Relays[noRelays];
    Bounce debouncer[noRelays];
    MyMessage msg[noRelays];
    
    // Define Moisture Sensor
    
    #define SENSOR_PIN A0
    #define VOLTAGE_FLIP_PIN_1 7
    #define VOLTAGE_FLIP_PIN_2 8
    #define SENSOR_CHILD 2
    
    MyMessage sensorMsg(SENSOR_CHILD, V_HUM);
    
    long interval = 5000;      //define timer to delay between reads (60 seconds)
    long previousMillis = 0;    // initialize timer for sense soil method
    
    
    void setup() {
      // setup sensor as a repeater node. allows for relay functionality by being able to receive messages from Vera
      gw.begin(incomingMessage, AUTO, true);
      delay(250);
      gw.sendSketchInfo(SKETCH_NAME, SKETCH_VERSION);
      delay(250);
    
      // Initialize Relays with corresponding buttons
      for (int i = 0; i < noRelays; i++) {
        Relays[i].buttonPin = buttonPin[i];              // assign physical pins
        Relays[i].relayPin = relayPin[i];
        msg[i].sensor = i;                          // initialize messages
        msg[i].type = V_LIGHT;
        debouncer[i] = Bounce();                        // initialize debouncer
        debouncer[i].attach(buttonPin[i]);
        debouncer[i].interval(5);
        pinMode(Relays[i].buttonPin, INPUT_PULLUP);
        pinMode(Relays[i].relayPin, OUTPUT);
        Relays[i].relayState = gw.loadState(i);                                   // retrieve last values from EEPROM
        digitalWrite(Relays[i].relayPin, Relays[i].relayState ? RELAY_ON : RELAY_OFF); // and set relays accordingly
        gw.send(msg[i].set(Relays[i].relayState ? true : false));                 // make controller aware of last status
        gw.present(i, S_LIGHT);    // present sensor to gateway
        delay(250);
      }
    
      // Initialize moisture sensor and components
      
      pinMode(VOLTAGE_FLIP_PIN_1, OUTPUT);
      pinMode(VOLTAGE_FLIP_PIN_2, OUTPUT);
      pinMode(SENSOR_PIN, INPUT);
      gw.present(SENSOR_CHILD, S_HUM);    // present sensor to gateway
      delay(250);
    }
    
    
    void loop()
    {
      gw.process();
      // relay part
      for (byte i = 0; i < noRelays; i++) {
        debouncer[i].update();
        byte value = debouncer[i].read();
        if (value != Relays[i].oldValue && value == 0) {
          Relays[i].relayState = !Relays[i].relayState;
          digitalWrite(Relays[i].relayPin, Relays[i].relayState ? RELAY_ON : RELAY_OFF);
          gw.send(msg[i].set(Relays[i].relayState ? true : false));
          gw.saveState( i, Relays[i].relayState );
        }                 // save sensor state in EEPROM (location == sensor number)
    
        Relays[i].oldValue = value;
      }
      //moisture sensor part
      int oldValue = 0;
      int soilReading = soilReading + senseSoil(SENSOR_PIN, VOLTAGE_FLIP_PIN_1, VOLTAGE_FLIP_PIN_2); // perform soil reading
      if (isnan(soilReading)) {
        Serial.println("Failed reading moisture level");
      } else if (soilReading != oldValue) {
        oldValue = soilReading;
        gw.send(sensorMsg.set(soilReading));
        Serial.print("H: ");
        Serial.print(soilReading);
      } 
      
    }
    
    
    //// ************************************************* ////
    //              Process Incoming Message                 //
    //// ************************************************* ////
    void incomingMessage(const MyMessage & message) {
    
      if (message.type == V_LIGHT) {
        if (message.sensor < noRelays) {          // check if message is valid for relays..... previous line  [[[ if (message.sensor <=noRelays){ ]]]
          Relays[message.sensor].relayState = message.getBool();
          digitalWrite(Relays[message.sensor].relayPin, Relays[message.sensor].relayState ? RELAY_ON : RELAY_OFF); // and set relays accordingly
          gw.saveState( message.sensor, Relays[message.sensor].relayState ); // save sensor state in EEPROM (location == sensor number)
        }
      }
    }
    
    //// ************************************************* ////
    //              Flip Polarity Method                     //
    //// ************************************************* ////
    /*
      this method flips the polarity of the of the digital
      output pins to help accurately provide a soil moisture reading
    
    */
    void flipPolarity(boolean flip, int flip1, int flip2)
    {
      if (flip) {
        digitalWrite(flip1, HIGH);
        digitalWrite(flip2, LOW);
      } else {
        digitalWrite(flip1, LOW);
        digitalWrite(flip2, HIGH);
      }
    }
    
    //// ************************************************* ////
    //              Sense Soil Method                        //
    //// ************************************************* ////
    /*
       When this method runs, a timer will start. when the timer
       exceeds the interval time set, the reading part will begin
    
       during the interval reading, the flip polarity method will run
       and grab a reading. Then, the flip polarity method will run again
       and the grab a second reading.
    
       Last, get an average and return value to the requester.
    */
    int senseSoil(int sensorPin, int flip1, int flip2)
    {
      unsigned long currentMillis = millis(); // set currentMillis to current time
    
      if ((currentMillis - previousMillis) > interval) // run rest of method when timer exceeds interval time
      {
        previousMillis = currentMillis;
        flipPolarity(true, flip1, flip2);
        delay(250);
        int val1 = analogRead(sensorPin);
        delay(250);
        flipPolarity(false, flip1, flip2);
        delay(250);
        int val2 = 1023 - analogRead(sensorPin  );
        delay(250);
    
        int averageSoilReading = (val1 + val2) / 2;
        // map the sensor range to a range of four options:
        int range = map(averageSoilReading, 0, 1023, 0, 100);
        return range;
      }
    }
    

  • Contest Winner

    @rchamp the reason for the unresponsive appears to be in the senseSoil() function.

    In this function you call 4 times delay(250). and a delay(x) in Arduino means do nothing for x milliseconds. So sensesoil function call takes 1 second and is called every 60 seconds. During this second your button presses are not recorded and no MySensors messages are being received.

    You better use the MySensors delay function called gw.wait(); Now the gw.process function is called during the 250ms waiting and the MySensors messages are processes (including the incomming ones).

    The range problems is located in this line of code (i think)

    int soilReading = soilReading + senseSoil(SENSOR_PIN, VOLTAGE_FLIP_PIN_1, VOLTAGE_FLIP_PIN_2); // perform soil reading
    

    Here you're adding the new moister reading up to the previous reading. I think this was meant:

    int soilReading = senseSoil(SENSOR_PIN, VOLTAGE_FLIP_PIN_1, VOLTAGE_FLIP_PIN_2); // perform soil reading
    


  • @BartE

    Thank you,

    I changed the code to this:

     previousMillis = currentMillis;
        flipPolarity(true, flip1, flip2);
        gw.wait(10);
        int val1 = analogRead(sensorPin);
        gw.wait(10);
        flipPolarity(false, flip1, flip2);
        gw.wait(10);
        int val2 = 1023 - analogRead(sensorPin  );
        gw.wait(10);
    

    and

    int soilReading = senseSoil(SENSOR_PIN, VOLTAGE_FLIP_PIN_1, VOLTAGE_FLIP_PIN_2); // perform soil reading
    

    At first, it seems to work. but then again after a couple of minutes the issue comes up.

    I've commented out my moisture sensor code and the relay works flawlessly. I might end of caving and use one of those prebuilt moisture modules i've seen others use, but i wish i understood why my code isn't working. I'm by no means a programmer. 😕


  • Hardware Contributor

    Always hard to say - but seeing issues with relay quite often my advice is to look over the power/ground and radio.

    • The radio is very power sensitive and it can help adding/changing caps GND/VCC on the radio.
    • How you wire the ground from the relay can also make a difference. I have had relays jamming when i ran ground trough the arduino and not straight to source. Also the opposite that it didnt work well if I didnt have ground through the arduino.
    • Range, when you send a on-command there is a ack going back which needs to be ok. Follow your serial logs in node and gateway to find out if the radio traffic is ok - or put a repeater in between.
    • Power - I have had Arduinos (mostly Pro Mini) that was a little to weak to trigger the relay... 😞 It needs 5v but my pin 5 was only giving 4.7V and some tries resulted in a unsuccessful relay switch even if the logs told me so. To test this you can upload a sketch doing nothing else but setting the pin to high and low with a delay in between.

Log in to reply
 

Suggested Topics

  • 1
  • 3
  • 2
  • 3
  • 2
  • 1

0
Online

11.4k
Users

11.1k
Topics

112.7k
Posts