DHT + Relay Sketch



  • Hi,

    I am trying to combine a DHT sensor with a Relay module in one sketch. I already looked up the example of how to combine two IDEs together and used some of its information. However, once I combine the sketches and upload it to Arduino, I can see an error in my SerialPort:

    0_1473504434530_upload-7938b4b4-a234-4087-beda-e8ac305c9e37

    Also when I am running the sketch and let it to communicate with GW, my HA (controller) doesnt recognise any entity for my relay !

    Any help would be much appreciated!
    This is the current sketch:

    // Enable debug prints
    #define MY_DEBUG
    
    // Enable and select radio type attached 
    #define MY_RADIO_NRF24
    //#define MY_RADIO_RFM69
    //#define MY_RS485
     
    #include <SPI.h>
    #include <MySensors.h>  
    #include <DHT.h>
    
    // Set this to the pin you connected the DHT's data pin to
    #define DHT_DATA_PIN 3
    
    // Set this offset if the sensor has a permanent small offset to the real temperatures
    #define SENSOR_TEMP_OFFSET 0
    
    // Sleep time between sensor updates (in milliseconds)
    // Must be >1000ms for DHT22 and >2000ms for DHT11
    static const uint64_t UPDATE_INTERVAL = 60000;
    
    // Force sending an update of the temperature after n sensor reads, so a controller showing the
    // timestamp of the last update doesn't show something like 3 hours in the unlikely case, that
    // the value didn't change since;
    // i.e. the sensor would force sending an update every UPDATE_INTERVAL*FORCE_UPDATE_N_READS [ms]
    static const uint8_t FORCE_UPDATE_N_READS = 10;
    
    #define CHILD_ID_HUM 0
    #define CHILD_ID_TEMP 1
    #define CHILD_ID_RLAY 2
    
    #define RELAY_1  4  // Arduino Digital I/O pin number for first relay (second on pin+1 etc)
    #define NUMBER_OF_RELAYS 1 // Total number of attached relays
    #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
    
    float lastTemp;
    float lastHum;
    uint8_t nNoUpdatesTemp;
    uint8_t nNoUpdatesHum;
    bool metric = true;
    
    MyMessage msgHum(CHILD_ID_HUM, V_HUM);
    MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
    
    DHT dht;
    
    void before() { 
      for (int sensor=1, pin=RELAY_1; sensor<=NUMBER_OF_RELAYS;sensor++, pin++) {
        // Then set relay pins in output mode
        pinMode(pin, OUTPUT);   
        // Set relay to last known state (using eeprom storage) 
        digitalWrite(pin, loadState(sensor)?RELAY_ON:RELAY_OFF);
      }
    }
    
    void presentation()  
    { 
      // Send the sketch version information to the gateway
      sendSketchInfo("TempHumidRelay", "1.1");
      
      // Register all sensors to gw (they will be created as child devices)
      present(CHILD_ID_RLAY, S_LIGHT);
      present(CHILD_ID_HUM, S_HUM);
      present(CHILD_ID_TEMP, S_TEMP);
      
      metric = getConfig().isMetric;
    }
    
    
    void setup()
    {
      dht.setup(DHT_DATA_PIN); // set data pin of DHT sensor
      if (UPDATE_INTERVAL <= dht.getMinimumSamplingPeriod()) {
        Serial.println("Warning: UPDATE_INTERVAL is smaller than supported by the sensor!");
      }
      // Sleep for the time of the minimum sampling period to give the sensor time to power up
      // (otherwise, timeout errors might occure for the first reading)
      sleep(dht.getMinimumSamplingPeriod());
    }
    
    void receive(const MyMessage &message) {
      // We only expect one type of message from controller. But we better check anyway.
      if (message.type==V_LIGHT) {
         // Change relay state
         digitalWrite(message.sensor-1+RELAY_1, message.getBool()?RELAY_ON:RELAY_OFF);
         // Store state in eeprom
         saveState(message.sensor, message.getBool());
         // Write some debug info
         Serial.print("Incoming change for sensor:");
         Serial.print(message.sensor);
         Serial.print(", New status: ");
         Serial.println(message.getBool());
       }
    } 
    
    void loop()      
    {  
      // Force reading sensor, so it works also after sleep()
      dht.readSensor(true);
      
      // Get temperature from DHT library
      float temperature = dht.getTemperature();
      if (isnan(temperature)) {
        Serial.println("Failed reading temperature from DHT!");
      } else if (temperature != lastTemp || nNoUpdatesTemp == FORCE_UPDATE_N_READS) {
        // Only send temperature if it changed since the last measurement or if we didn't send an update for n times
        lastTemp = temperature;
        if (!metric) {
          temperature = dht.toFahrenheit(temperature);
        }
        // Reset no updates counter
        nNoUpdatesTemp = 0;
        temperature += SENSOR_TEMP_OFFSET;
        send(msgTemp.set(temperature, 1));
    
        #ifdef MY_DEBUG
        Serial.print("T: ");
        Serial.println(temperature);
        #endif
      } else {
        // Increase no update counter if the temperature stayed the same
        nNoUpdatesTemp++;
      }
    
      // Get humidity from DHT library
      float humidity = dht.getHumidity();
      if (isnan(humidity)) {
        Serial.println("Failed reading humidity from DHT");
      } else if (humidity != lastHum || nNoUpdatesHum == FORCE_UPDATE_N_READS) {
        // Only send humidity if it changed since the last measurement or if we didn't send an update for n times
        lastHum = humidity;
        // Reset no updates counter
        nNoUpdatesHum = 0;
        send(msgHum.set(humidity, 1));
        
        #ifdef MY_DEBUG
        Serial.print("H: ");
        Serial.println(humidity);
        #endif
      } else {
        // Increase no update counter if the humidity stayed the same
        nNoUpdatesHum++;
      }
    
      // Sleep for a while to save energy
      sleep(UPDATE_INTERVAL); 
    }
    

  • Contest Winner

    @mehrdad.silatani The serial monitor is telling you, that it's not able to connect to your gateway (FPAR). This most likely a power issue and some ways to solve it are:

    • add a 47uf or 100uf capacitor to the radio (see build page)
    • try powering the components from an external adapter.

    Hope you can get it to work!



  • @TheoL THank you for your reply, I already have 47uF capacitor connected to the radio module, and its already running on an external power supply.

    All being said, I suspect, I am missing something in the sketch.

    Cheers,
    Mehrdad



  • Ok, I made one step forward. Now the two sketches are combined and I managed to get the HA to recognise the attributes. However, in HA, the temperature sensor keeps appear as a switch !

    0_1473548173348_upload-842b69f8-da2b-4434-80db-7c75b9309d03

    This is my sketch:

    #define MY_DEBUG
    #define MY_RADIO_NRF24
    #define MY_REPEATER_FEATURE
    #define MY_NODE_ID 1
    
     
    #include <SPI.h>
    #include <MySensors.h>
    #include <Bounce2.h>
    #include <DHT.h>
    
    // Set this to the pin you connected the DHT's data pin to
    #define DHT_DATA_PIN 3
    
    // Set this offset if the sensor has a permanent small offset to the real temperatures
    #define SENSOR_TEMP_OFFSET 0
    
    // Sleep time between sensor updates (in milliseconds)
    // Must be >1000ms for DHT22 and >2000ms for DHT11
    static const uint64_t UPDATE_INTERVAL = 60000;
    
    // Force sending an update of the temperature after n sensor reads, so a controller showing the
    // timestamp of the last update doesn't show something like 3 hours in the unlikely case, that
    // the value didn't change since;
    // i.e. the sensor would force sending an update every UPDATE_INTERVAL*FORCE_UPDATE_N_READS [ms]
    static const uint8_t FORCE_UPDATE_N_READS = 10;
    
    #define CHILD_ID_HUM 0
    #define CHILD_ID_TEMP 1
    #define CHILD_ID_RLAY 2
    
    #define RELAY_PIN  4
    #define RELAY_ON 1
    #define RELAY_OFF 0
    
    Bounce debouncer = Bounce();
    bool state = false;
    bool initialValueSent = false;
    
    float lastTemp;
    float lastHum;
    uint8_t nNoUpdatesTemp;
    uint8_t nNoUpdatesHum;
    bool metric = true;
    
    MyMessage msgHum(CHILD_ID_HUM, V_HUM);
    MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
    MyMessage msgRlay(CHILD_ID_RLAY, V_STATUS);
    
    DHT dht;
    
    void presentation()   
    { 
      // Send the sketch version information to the gateway
      sendSketchInfo("TempHumidRelay", "1.1");
      
      // Register all sensors to gw (they will be created as child devices)
      present(CHILD_ID_HUM, S_HUM);
      present(CHILD_ID_TEMP, S_TEMP);
      present(CHILD_ID_RLAY, S_BINARY);
    
      metric = getConfig().isMetric;
    }
    
    void setup()
    {
      dht.setup(DHT_DATA_PIN); // set data pin of DHT sensor
      if (UPDATE_INTERVAL <= dht.getMinimumSamplingPeriod()) {
        Serial.println("Warning: UPDATE_INTERVAL is smaller than supported by the sensor!");
      }
      // Sleep for the time of the minimum sampling period to give the sensor time to power up
      // (otherwise, timeout errors might occure for the first reading)
      //sleep(dht.getMinimumSamplingPeriod());
      
      // Make sure relays are off when starting up
      digitalWrite(RELAY_PIN, RELAY_OFF);
      pinMode(RELAY_PIN, OUTPUT);
    }
    
    void loop()      
    {  
        if (!initialValueSent) {
        Serial.println("Sending initial value");
        send(msgRlay.set(state?RELAY_ON:RELAY_OFF),2);
        Serial.println("Requesting initial value from controller");
        request(CHILD_ID_RLAY, V_STATUS);
        wait(2000, C_SET, V_STATUS);
      }
      if (debouncer.update()) {
        if (debouncer.read()==LOW) {
          state = !state;
          // Send new state and request ack back
          send(msgRlay.set(state?RELAY_ON:RELAY_OFF), true);
        }
      }
      dht.readSensor(true);
      float temperature = dht.getTemperature();
      if (isnan(temperature)) {
        Serial.println("Failed reading temperature from DHT!");
      } 
      else if (temperature != lastTemp || nNoUpdatesTemp == FORCE_UPDATE_N_READS) {
        // Only send temperature if it changed since the last measurement or if we didn't send an update for n times
        lastTemp = temperature;
        if (!metric) {
          temperature = dht.toFahrenheit(temperature);
        }
        nNoUpdatesTemp = 0;
        temperature += SENSOR_TEMP_OFFSET;
        send(msgTemp.set(temperature, 1));
        
        #ifdef MY_DEBUG
        Serial.print("T: ");
        Serial.println(temperature);
        #endif
      } else {
        // Increase no update counter if the temperature stayed the same
        nNoUpdatesTemp++;
      }
    
      // Get humidity from DHT library
      float humidity = dht.getHumidity();
      if (isnan(humidity)) {
        Serial.println("Failed reading humidity from DHT");
      } else if (humidity != lastHum || nNoUpdatesHum == FORCE_UPDATE_N_READS) {
        // Only send humidity if it changed since the last measurement or if we didn't send an update for n times
        lastHum = humidity;
        // Reset no updates counter
        nNoUpdatesHum = 0;
        send(msgHum.set(humidity, 1));
        
        #ifdef MY_DEBUG
        Serial.print("H: ");
        Serial.println(humidity);
        #endif
      } else {
        // Increase no update counter if the humidity stayed the same
        nNoUpdatesHum++;
      }
     wait(2000);
    }
    
    void receive(const MyMessage &message) {
      if (message.isAck()) {
         Serial.println("This is an ack from gateway");
      }
    
      if (message.type == V_STATUS) {
        if (!initialValueSent) {
          Serial.println("Receiving initial value from controller");
          initialValueSent = true;
        }
        // Change relay state
        state = (bool)message.getInt();
        digitalWrite(RELAY_PIN, state?RELAY_ON:RELAY_OFF);
        send(msgRlay.set(state?RELAY_ON:RELAY_OFF,2));
      }
    }
    

    I would really sincerely appreciate if someone can shed some light on what I am doing wrong !

    Plus, I read mysensors website millions time but still I can't find clear description of some of the functions that are being used in V2 of the library, any idea where I can look up functions used in mysensors examples ?

    Cheers


  • Mod

    @mehrdad.silatani the sketch looks good to me, but I don't use HA so I don't know what could go wrong there.

    The functions should be documented at https://www.mysensors.org/download/sensor_api_20
    Let us know if any function is missing, or if some aspect is poorly presented.



  • @mfalkvidd Thank you so much for your comment. I already checked the link you send me and it is very insightful but I guess I am still too beginner to find my solution from those explanations.

    Since you asked about missing functions, I couldn't find any description on " C_SET".

    Also if you don't mind I would like to ask for your help to understand some of the functions used in my code. These are the functions I am not fully understanding;

    • "send(msgHum.set(humidity, 1))"
      What is the action of that number "1" after the payload (i.e. humidity)? can it be any number ?

    • "send(msgRlay.set(state?RELAY_ON:RELAY_OFF),2)"
      I fully understand up to the part of "send(msgRlay.set" but what happens in "state?RELAY_ON:RELAY_OFF" and also again what is that number "2" at the end doing ?( I randomly typed 2) .... I suspect, in "state?RELAY_ON:RELAY_OFF" it asks the Arduino that which state is true and use that, is that correct?

    • "send(msgRlay.set(state?RELAY_ON:RELAY_OFF), true)"
      What is the "true" at the end of the line doing?

    • "wait(2000, C_SET, V_STATUS)"
      This is where I came across the "C_SET"

    • "state = (bool)message.getInt()"
      I can guess that this line is trying to extract the information of the relay state from the received msg, but I really don't know what is the breakdown of the logic in it (e.g. does adding (bool) at the front of the message.getInt() means only accept boolean type data ? .... )

    • "debouncer.update()"
      I really dont quite get what happens in this line ...

    Sorry for asking too many questions :) .. I am really loving to work with "mysensors" and I am trying to make sure I understand what happens in my codes :)


  • Mod

    @mehrdad.silatani said:

    Also if you don't mind I would like to ask for your help to understand some of the functions used in my code. These are the functions I am not fully understanding;

    Great questions! I'll answer them here now and see if I can get the documentation page updated later.

    • "send(msgHum.set(humidity, 1))"
      What is the action of that number "1" after the payload (i.e. humidity)? can it be any number ?

    That number is the number of decimals to include in the message. So if the humidity is 57.5484, using 1 will send 57.5. Using 2 will send 57.55 (correctly rounded).

    • "send(msgRlay.set(state?RELAY_ON:RELAY_OFF),2)"
      I fully understand up to the part of "send(msgRlay.set" but what happens in "state?RELAY_ON:RELAY_OFF" and also again what is that number "2" at the end doing ?( I randomly typed 2) .... I suspect, in "state?RELAY_ON:RELAY_OFF" it asks the Arduino that which state is true and use that, is that correct?
    state?RELAY_ON:RELAY_OFF
    

    This is called a conditional operator. If state is true, the first value (RELAY_ON) will be used. If state is false, the second value (RELAY_OFF) will be used. This is shorthand for

    if(state)
        return RELAY_ON;
    else
        return RELAY_OFF;
    

    More information: http://www.tutorialspoint.com/cplusplus/cpp_conditional_operator.htm
    The number 2 is, just like before, the number of decimals. For a relay you can omit the number, just use

    send(msgRlay.set(state?RELAY_ON:RELAY_OFF))
    
    • "send(msgRlay.set(state?RELAY_ON:RELAY_OFF), true)"
      What is the "true" at the end of the line doing?

    From https://www.mysensors.org/download/sensor_api_20#sending-data :
    ack - Set this to true if you want destination node to send ack back to this node. Default is not to request any ack.

    The ack stuff has confused me immensely. MySensors has two types of ack. They are both called ack but they work very differently. https://forum.mysensors.org/topic/3346/discussion-reliable-delivery/ documents my road from confusion to clarity.

    • "wait(2000, C_SET, V_STATUS)"
      This is where I came across the "C_SET"

    https://www.mysensors.org/download/sensor_api_20#waiting describes the second parameter as
    cmd - The command type to wait for
    The commands are defined at https://github.com/mysensors/MySensors/blob/e1ccba22d8fe5b6604bc6428ca950e4336654784/core/MyMessage.h#L45 So waiting for C_SET means that you want for an incoming command (message) that wants to set a variable. In this case, set the value of the relay.

    • "state = (bool)message.getInt()"
      I can guess that this line is trying to extract the information of the relay state from the received msg, but I really don't know what is the breakdown of the logic in it (e.g. does adding (bool) at the front of the message.getInt() means only accept boolean type data ? .... )

    Not quite. It converts to integer to a bool. So if the integer is 0, the result will be false. If the integer is not zero, the result will be true. More details: http://stackoverflow.com/questions/31551888/casting-int-to-bool-in-c-c

    • "debouncer.update()"
      I really dont quite get what happens in this line ...

    This updates the value from a switch, avoiding contact bounces. More information: https://github.com/thomasfredericks/Bounce2/wiki

    Sorry for asking too many questions :) .. I am really loving to work with "mysensors" and I am trying to make sure I understand what happens in my codes :)

    No worries, we're all here to learn :)



  • @mfalkvidd WOW ! I am blown away by your detailed answers !!! Nothing is more satisfying than plain answers to puzzling questions :smile: Thank you so so much !!!

    Meanwhile, by using my "MYSController". I figured out that the sketch is reporting right values as you pointed out before;

    0_1473586525559_upload-00eadcf7-e899-40cc-b362-dec912d2442b

    So what I did was to check my "mysensors.json" ... I noticed there are traces of my old sensor node still embedded in the "mysensors.json". So I deleted the file and let the HA to create a new one from scratch ! and then Volla ! HA started to recognise the sensors and switch separately !

    0_1473586257481_upload-f6491b85-7e83-44a3-9259-c554518b47eb

    I know everyone here are helping and volunteers, but I thought I will just share my suggestion with you wonderful people, I think it would be invaluable to mysensors users to be able to refer to a language reference page similar to the arduino's website; "https://www.arduino.cc/en/Reference/HomePage"

    Again, THANK YOU so much for your elaborated answers !

    Cheers,
    Mehrdad


  • Mod

    @mehrdad.silatani great that you found and solved the problem. Thanks for sharing! And thanks for your kind words.

    Great suggestion on the Arduino reference. It will be included in the next update of https://www.mysensors.org/about/arduino



  • One last question !!! :smile:

    Now that I opened up my "mysensors.json", it made me curious about some of the information in it. Currently it shows;

    {"0": {"sketch_name": null, "sensor_id": 0, "children": {}, "battery_level": 0, "sketch_version": null, "protocol_version": "2.0.0", "type": 18}, "1": {"sketch_name": "TempHumidRelay", "sensor_id": 1, "children": {"0": {"id": 0, "description": "", "values": {"1": "51.0"}, "type": 7}, "1": {"id": 1, "description": "", "values": {"0": "21.0"}, "type": 6}, "2": {"id": 2, "description": "", "values": {"2": "0"}, "type": 3}}, "battery_level": 0, "sketch_version": "1.1", "protocol_version": "2.0.0", "type": 18}}
    

    Inside the "values" brackets, I know the second numbers are the reported values (i.e. payload), but what is the first number in the bracket ? {"0": "21.0"} , {"1": "51.0"} or {"2": "0"}

    And finally what are the definition of "type": 18 , "type": 3 , "type": 7 and "type":6 ?

    Cheers,
    Mehrdad


Log in to reply
 

Looks like your connection to MySensors Forum was lost, please wait while we try to reconnect.