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.
-
@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?
- Include Bounce2.h
- declare a bounce object in your setup
- 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.
-
@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.
-
@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?
-
@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 thisunsigned 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 scopeSeems something is not right, tried deleting incomingMessage line, but no dice.
-
@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); } } }