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; } }
-
@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
-
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.
-
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.