What is the good wait() time ?



  • Hello,

    i have a node with 3 push-button in loop().
    without wait() , i don't receive messages from gateway.
    With wait(50) i receive message (but not all).
    with wait(500) i receive nothing.
    Is it normal ? I thought that wait() was for spending time for receive message. larger time should be larger time for receiving messages ?
    what is the ideal waiting time ?
    THnaks


  • Hardware Contributor

    Hello @tommies, do you use any delay in your loop ?
    Maybe you should post the code so it will be easier to help you fix it.



  • Here is it

    // Enable debug prints to serial monitor
    #define MY_DEBUG  
    #define MY_DEBUG_SERIAL
    
    // Enable and select radio type attached
    #define MY_RADIO_RF24
    //#define MY_RF24_PA_LEVEL RF24_PA_HIGH
    
    //set how long to wait for transport ready. in milliseconds
    #define MY_TRANSPORT_WAIT_READY_MS 1
    #define MY_NODE_ID     14
    
    //  neopixels pin
    #define PIN 6 
    
    // pin push button
    #define BUTTON_1 3  
    #define BUTTON_2 4
    #define BUTTON_3 5
    
    // variables for my sensors presentation
    #define CHILD_ID_BUTTON_1 1
    #define CHILD_ID_BUTTON_2 2
    #define CHILD_ID_BUTTON_3 3
    #define CHILD_ID_RGB 4
    #define redMem 0 // To store red color
    #define greenMem 1 //
    #define blueMem 2 //
    
    #include <Adafruit_NeoPixel.h>
    #include <MySensors.h>
    #include <Bounce2.h>
    
    
    // Neopixels parameters
    
    // Parameter 1 = number of pixels in strip
    // Parameter 2 = Arduino pin number (most are valid)
    // Parameter 3 = pixel type flags, add together as needed:
    //   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
    //   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
    //   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
    //   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
    Adafruit_NeoPixel strip = Adafruit_NeoPixel(12, PIN, NEO_GRB + NEO_KHZ800);
    
    // IMPORTANT: To reduce NeoPixel burnout risk, add 1000 uF capacitor across
    // pixel power leads, add 300 - 500 Ohm resistor on first pixel's data input
    // and minimize distance between Arduino and first pixel.  Avoid connecting
    // on a live circuit...if you must, connect GND first.
    
    // variables for debounce push buttons
    
    Bounce debouncer1 = Bounce(); 
    Bounce debouncer2 = Bounce();
    Bounce debouncer3 = Bounce();
    int oldValue1=0;
    bool state1;
    int oldValue2=0;
    bool state2;
    int oldValue3=0;
    bool state3;
    
    // variables for color change
    long hexColor = -1 ;
    int red = loadState(redMem); // to load red color memory on startup
    int green = loadState(greenMem);
    int blue = loadState(blueMem);
    long startTime;// timer for ping gateway
    
    // Change to V_LIGHT if you use S_LIGHT in presentation below
    MyMessage msgbutton1(CHILD_ID_BUTTON_1,V_STATUS);
    MyMessage msgbutton2(CHILD_ID_BUTTON_2,V_STATUS);
    MyMessage msgbutton3(CHILD_ID_BUTTON_3,V_STATUS);
    MyMessage msgrgb(CHILD_ID_RGB,V_RGB);
    MyMessage msgvar(CHILD_ID_RGB,V_VAR1);
    
    void setup() {
      Serial.begin (115200);
      pinMode(BUTTON_1, INPUT_PULLUP) ;
      pinMode(BUTTON_2, INPUT_PULLUP) ;
      pinMode(BUTTON_3, INPUT_PULLUP) ;
      
       // After setting up the button, setup debouncer 1
      debouncer1.attach(BUTTON_1);
      debouncer1.interval(5);
       // After setting up the button, setup debouncer 2
      debouncer2.attach(BUTTON_2);
      debouncer2.interval(5);
       // After setting up the button, setup debouncer 3
      debouncer3.attach(BUTTON_3);
      debouncer3.interval(5);
      
      #ifdef MY_DEBUG_SERIAL
      Serial.println( "Setup");
      Serial.print(red);
      Serial.print("|");
      Serial.print(green);
      Serial.print("|");
      Serial.print(blue);
      #endif
    
      strip.begin();
      strip.show(); // Initialize all pixels to 'off'
      startColor(); // if you want to change start and finish color modify this function.
      startTime = millis(); // initialization for the counter
    }
    
    void presentation() {
      // Send the sketch version information to the gateway and Controller
      sendSketchInfo("Iron Man Reactor", "1.0");
      // Register binary input sensor to gw (they will be created as child devices)
      present(CHILD_ID_BUTTON_1, S_BINARY);
      wait(100);
      present(CHILD_ID_BUTTON_2, S_BINARY);
      wait(100);
      present(CHILD_ID_BUTTON_3, S_BINARY);    
      wait(100);
      present (CHILD_ID_RGB, S_RGB_LIGHT);
    }
    
    void loop() {
     wait(50);
     
     // ask time to gateway to test connection each 30s
     #ifdef MY_DEBUG_SERIAL
      if (millis() - startTime > 30000){
      if (requestTime()) {
        Serial.println("Connection ok");
      }
      else {
        Serial.println("Connection lost");
      }
      startTime = millis();
      }
      #endif
      
      // Push button 1 
     debouncer1.update();
      // Get the update value
      int value1 = debouncer1.read();
      if (value1 != oldValue1 && value1==0) {
        colorWipe(strip.Color(0, 0, 255), 0); // blue
        saveState(redMem,0);
        saveState(greenMem,0);
        saveState(blueMem,255);
        red = loadState(redMem);
        green = loadState(greenMem);
        blue = loadState(blueMem);
    
     #ifdef MY_DEBUG_SERIAL
        Serial.print(red);
        Serial.print("|");
        Serial.print(green);
        Serial.print("|");
        Serial.println(blue);
     #endif    
      }
      oldValue1 = value1;
    
     // Push button 2 
     debouncer2.update();
      // Get the update value
      int value2 = debouncer2.read();
      if (value2 != oldValue2 && value2==0) {
        colorWipe(strip.Color(255, 0, 0), 0); // red
        saveState(redMem,0);
        saveState(greenMem,0);
        saveState(blueMem,255);
        
     #ifdef MY_DEBUG_SERIAL
        Serial.print(red);
        Serial.print("|");
        Serial.print(green);
        Serial.print("|");
        Serial.println(blue);
     #endif    
         
      }
      oldValue2 = value2;
        
        // Push button 3
     debouncer3.update();
      // Get the update value
      int value3 = debouncer3.read();
      if (value3 != oldValue3 && value3==0) {
        theaterChase(strip.Color(127, 127, 127), 50); // White
        startColor(); // return to saved color
        }
      oldValue3 = value3;
    
    }
    
    // Neopixels effects 
     
    // Start and finish color
    void startColor() {
      red = loadState(redMem);
      green = loadState(greenMem);
      blue = loadState(blueMem);
      colorWipe(strip.Color(red, green, blue), 0); // finish with saved 
    }
    
    void colorWipe(uint32_t c, uint8_t waiting) {
      for(uint16_t i=0; i<strip.numPixels(); i++) {
          strip.setPixelColor(i, c);
          strip.show();
          wait(waiting);
      }
      #ifdef MY_DEBUG_SERIAL
        Serial.print(red);
        Serial.print("|");
        Serial.print(green);
        Serial.print("|");
        Serial.println(blue);
      #endif
    }
    
    // colorWipe fonction modified for receive()
    void colorWipeRGB(long number) {
      long r = hexColor >> 16;
      long g = hexColor >> 8 & 0xFF;
      long b = hexColor & 0xFF;
      for (uint16_t i = 0; i < strip.numPixels(); i++) {
        strip.setPixelColor(i, r,g,b);
        strip.show();
      }
      #ifdef MY_DEBUG_SERIAL
        Serial.print(red);
        Serial.print("|");
        Serial.print(green);
        Serial.print("|");
        Serial.println(blue);
      #endif
    }
    void rainbow(uint8_t waiting) {
      uint16_t i, j;
    
      for(j=0; j<256; j++) {
        for(i=0; i<strip.numPixels(); i++) {
          strip.setPixelColor(i, Wheel((i+j) & 255));
        }
        strip.show();
        wait(waiting);
        
      }
       startColor(); // return to saved color
    }
    
    // Slightly different, this makes the rainbow equally distributed throughout
    void rainbowCycle(uint8_t waiting) {
      uint16_t i, j;
    
      for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
        for(i=0; i< strip.numPixels(); i++) {
          strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
        }
        strip.show();
        wait(waiting);
      }
       startColor(); // return to saved color
    }
    
    //Theatre-style crawling lights.
    void theaterChase(uint32_t c, uint8_t waiting) {
      for (int j=0; j<10; j++) {  //do 10 cycles of chasing
        for (int q=0; q < 3; q++) {
          for (int i=0; i < strip.numPixels(); i=i+3) {
            strip.setPixelColor(i+q, c);    //turn every third pixel on
          }
          strip.show();
         
          wait(waiting);
         
          for (int i=0; i < strip.numPixels(); i=i+3) {
            strip.setPixelColor(i+q, 0);        //turn every third pixel off
          }
        }
      }
      startColor(); // return to saved color
    }
    
    //Theatre-style crawling lights with rainbow effect
    void theaterChaseRainbow(uint8_t waiting) {
      for (int j=0; j < 256; j++) {     // cycle all 256 colors in the wheel
        for (int q=0; q < 3; q++) {
            for (int i=0; i < strip.numPixels(); i=i+3) {
              strip.setPixelColor(i+q, Wheel( (i+j) % 255));    //turn every third pixel on
            }
            strip.show();
           
            wait(waiting);
           
            for (int i=0; i < strip.numPixels(); i=i+3) {
              strip.setPixelColor(i+q, 0);        //turn every third pixel off
            }
        }
      }
       startColor(); // return to saved color
    }
    
    // Input a value 0 to 255 to get a color value.
    // The colours are a transition r - g - b - back to r.
    uint32_t Wheel(byte WheelPos) {
      WheelPos = 255 - WheelPos;
      if(WheelPos < 85) {
       return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
      } else if(WheelPos < 170) {
        WheelPos -= 85;
       return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
      } else {
       WheelPos -= 170;
       return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
      }
       startColor(); // return to saved color
    }
    
    void receive(const MyMessage &message)
    {
      Serial.println("message received");
      int val =0 ;
      if (message.sensor == CHILD_ID_RGB && message.type == V_RGB) {
        String hexstring = message.getString();
        Serial.print(hexstring);
        Serial.print("||");
        hexColor = strtol( &hexstring[0], NULL, 16);
        saveState(redMem,(hexColor >> 16));
        saveState(greenMem,(hexColor >> 8 & 0xFF));
        saveState(blueMem,(hexColor & 0xFF)); 
        colorWipeRGB(hexColor);
        Serial.print(loadState(redMem));
        Serial.print("|"); 
        Serial.print(loadState(greenMem));
        Serial.print("|");
        Serial.println(loadState(blueMem));
      }
      if (message.sensor == CHILD_ID_RGB && message.type == V_VAR2){
        String variable = message.getString();
        String sred = variable.substring(0,3);
        String sgreen = variable.substring(3,6);
        String sblue = variable.substring(6,9);
        saveState(redMem,int(sred.toInt()));
        saveState(greenMem,int(sgreen.toInt()));
        saveState(blueMem,int(sblue.toInt())); 
        startColor();
        
      }
      if (message.sensor == CHILD_ID_RGB && message.type == V_VAR1){
        String variable = message.getString();
        if (variable = "rainbow" )
          rainbow(20);
          
        if (variable = "rainbowCycle" )
          rainbowCycle(20);
          
        if (variable = "theaterChaseRainbow")
          theaterChaseRainbow(20);
      
        if (variable = "theaterChase")
          theaterChase(strip.Color(127, 127, 127), 50); // White
    
        startColor(); // return to saved color
      }
      // reception of message for buttons
      if (message.sensor == CHILD_ID_BUTTON_1){
          colorWipe(strip.Color(0, 0, 255), 0); // Red
      }
      if (message.sensor == CHILD_ID_BUTTON_2){
          colorWipe(strip.Color(0, 255, 0), 0); // Vert
      }
      if (message.sensor == CHILD_ID_BUTTON_3){
        theaterChase(strip.Color(127, 127, 127), 50); // White
        startColor(); // return to saved color
    
        }
    }```


  • I reply to myself.
    It works really better if i don't use the serial debug.



  • Add a short wait after sendSketchInfo and your last present too.

    I usually have 150 as the wait time.


  • Hardware Contributor

    when it's for presentation, it's not really a big deal to add such wait time. note for a a coincell batt powered node it would be better to use sleep..

    But in others application with some "critical" timing in user tasks, you could get some troubles like missing state changes, slower polling etc. as it doesn't make your sketch asynchronous..

    For longterm, I think it's not ideal to use such hack when getting comm issues. and also makes nodes slower (and perhaps jamming's easier too ?).


  • Mod

    @tommies You could give message queueing a try:

    • Connect the nRF24 IRQ pin to pin 2 on your Arduino
    • add #define MY_RF24_IRQ_PIN (2)
    • add #define MY_RX_MESSAGE_BUFFER_FEATURE
    • add #define MY_RX_MESSAGE_BUFFER_SIZE (10)
    • that last value may be lower (e.g. 5) when running out of memory

    This will listen to the interrupt from the nRF24 when a message comes in and immediately pause the running code to retrieve the message.
    Then your code continues and any messages stored will be processed outside the loop() function automatically.
    The wait() call(s) can be removed from your code.
    It might interfere with your NeoPixel update though, but there's only one way to find out 😉

    Refer to e.g. https://forum.mysensors.org/topic/7190/irq-pin-for-nrf24l01 for a discussion on message queueing.



  • @scalz I add the wait to make sure the radio has enough power without having to resort to adding a capacitor.


  • Mod

    @alowhum I don't think any wait time will ensure sufficient power in a reliable way. The nrf is too sensitive to power fluctuations to be used without a capacitor.



  • @yveaux
    interesting... i must take a look to this option.
    Thanks. 🙂


  • Hardware Contributor

    @alowhum said in What is the good wait() time ?:

    @scalz I add the wait to make sure the radio has enough power without having to resort to adding a capacitor.

    I already got it. But it seems you have a "design flaw", it's treating symptoms instead of root.. So it's not a great tip.
    For very simple case like a temperature sensor, it might seem handy and work, but not for all usercases, like I said, you add latency to your nodes.

    I prefer Yveaux advice. And if it's not enough:

    • hardware flaws
    • library bug..

    I also agree with mfalkvidd. If you don't want to tweak/solder stuff on any hw, then you might get troubles, or poor range when using different power supplies sources (noisy, etc) and wait() will be ineffective.



  • @yveaux Did it. wired Pin 2, removed wait() in my loop... works like a Harry Potter enchantment.
    now i need to find another PCB board with IRQ pin connected !!
    damned !
    Thanks
    now i must change my gateay



  • I already use PIN2 and/or PIN3 as wake up interrupt to wake up node in sleeping sensors.
    Is there any way to use interrupt in non sleeping node ?
    By the way, it would avoid to use loop fonction to detect push button change state.


  • Mod

    @tommies MySensors is using regular Arduino attachInterrupt/detachInterrupt to handle the nRF24 interrupts, so any other pin compatible with the Arduino interrupt system should work.



  • @scalz Interesting. But in reality I do see that adding a delay results in fewer NACK issues. What could that be?

    I also always place my radios in the Nano Wireless Board, which solves pretty much all the issues with power and wiring I had before.


 

271
Online

8.4k
Users

9.3k
Topics

97.9k
Posts