Skip to content
  • MySensors
  • OpenHardware.io
  • Categories
  • Recent
  • Tags
  • Popular
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Brand Logo
  1. Home
  2. Troubleshooting
  3. Auto resend on NACK

Auto resend on NACK

Scheduled Pinned Locked Moved Troubleshooting
23 Posts 6 Posters 2.0k Views 6 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • skywatchS skywatch

    I decided it would be good to have nodes automatically resend data if no ack is received. Seemed like a good idea. But I cannot get it to compile.

    I decided to use a switch case to implement a step-by-step 'send and test' procedure, but not having much luck.

    Can anyone tell me where I have gone wrong on this please?

    /*
     * D9,D10,D11,D12,D13 - NRF
     * D7 = Fridge AM2302
     * D6 = Freezer AM2302
     */
    // Enable debug prints
    //#define MY_DEBUG 
    #define MY_RADIO_RF24
    #define MY_RF24_CHANNEL (97)
    #define MY_NODE_ID 18
    #define MY_PARENT_NODE_ID 0
    #define MY_PARENT_NODE_IS_STATIC
    //#define MY_REPEATER_FEATURE
    //#define MY_SIGNING_ATSHA204
    //#define MY_SIGNING_REQUEST_SIGNATURES 
    #include <Wire.h>
    #include <LiquidCrystal_I2C.h>
    #include <SPI.h>
    #include <DHT.h>
    #include <MySensors.h>  
    
    
    // Set this offset if the sensor has a permanent small offset to the real temperatures
    #define CHILD_ID_FGEHUM 0
    #define CHILD_ID_FGETEMP 2
    #define CHILD_ID_FZRHUM 1
    #define CHILD_ID_FZRTEMP 3
    
    // Sleep time between sensor updates (in milliseconds)
    // Must be >1000ms for DHT22 and >2000ms for DHT11
    static const uint64_t UPDATE_INTERVAL = 1*15000;
    unsigned long last_sent_time = 0;
    unsigned long sent_time = 5*60000;
    bool metric = true;
    
    MyMessage msgFgeHum (CHILD_ID_FGEHUM,  V_HUM);
    MyMessage msgFgeTemp(CHILD_ID_FGETEMP, V_TEMP);
    MyMessage msgFzrHum (CHILD_ID_FZRHUM,  V_HUM);
    MyMessage msgFzrTemp(CHILD_ID_FZRTEMP, V_TEMP);
    DHT dht;    //Fridge
    DHT dht1;   //Freezer 
    int fgehum=0;
    int fzrhum=0;
    int P=0;
    int filter=1;
    int send_ack = 1;
    float fgetemp=5;//Fridge
    float fzrtemp=-20; //Freezer
    float fgetemplast = 0;
    float fzrtemplast = 0;
    //D7 = Fridge AM2302
    //D6 = Freezer AM2302
    
    //setup I2C to LCD
    #define I2C_ADDR    0x27 
    #define BACKLIGHT_PIN     3
    #define En_pin  2
    #define Rw_pin  1
    #define Rs_pin  0
    #define D4_pin  4
    #define D5_pin  5
    #define D6_pin  6
    #define D7_pin  7 
    
    LiquidCrystal_I2C	lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin);
    
    
    
    void setup() { 
     
       SPI.begin();
       dht.setup(7);  // Fridge data pin 7
       dht1.setup(6); // Freezer data pin 6
       lcd.begin (16,2); 
           
    // Switch on the backlight
    lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE);
    lcd.setBacklight(255);
          lcd.setCursor(0,0);
          lcd.print(F("     Andrews    ")); 
          lcd.setCursor(0,1);
          lcd.print(F(" Fridge Freezer "));
          delay(3000);
          lcd.clear();
          lcd.setCursor(0,0);
          lcd.print(F(" Ver. MYS-v1.4  "));
          delay(2500);
          lcd.clear();
          lcd.setCursor(0,0);
          lcd.print(F("Fge "));  
          lcd.setCursor(0,1);
          lcd.print(F("Fzr "));
          lcd.setCursor(12,0);
          lcd.print(F("H"));
          lcd.setCursor(12,1);
          lcd.print(F("H"));
          lcd.setCursor(15,0);
          lcd.print(F("%"));
          lcd.setCursor(15,1);
          lcd.print(F("%"));
    }
    
    void presentation()  
    { 
      // Send the sketch version information to the gateway
      sendSketchInfo("MYS-FridgeFreezer", "1.4");
    
      // Register all sensors to gw (they will be created as child devices)
      present(CHILD_ID_FGEHUM, S_HUM, "Fridge Hum", true);
      wait(200);
      present(CHILD_ID_FZRHUM, S_HUM, "Freezer Hum", true);
      wait(200);
      present(CHILD_ID_FGETEMP, S_TEMP, "Fridge Temp", true);
      wait(200);
      present(CHILD_ID_FZRTEMP, S_TEMP, "Freezer Temp", true); 
      
      metric = getControllerConfig().isMetric;
    }
    
    void loop(){
      
      //sensor fridge
      delay(dht.getMinimumSamplingPeriod());
      int fgehum = dht.getHumidity();
      float fgetemp = dht.getTemperature();
      constrain (fgetemp, -30.0, 40.0);
      
      //sensor freezer
      delay(dht1.getMinimumSamplingPeriod());
      int fzrhum = dht1.getHumidity();
      float fzrtemp = dht1.getTemperature(); 
      constrain (fzrtemp, -40.0, 40.0);
      
       // Filter spurious readings and spikes.
        
       if (filter == 0)
       {
         if (fgetemp > (fgetemplast + 0.3) || fgetemp < (fgetemplast - 0.3))
         fgetemp = fgetemplast; 
         else
         fgetemplast = fgetemp;
         
         if (fzrtemp > (fzrtemplast + 1) || fzrtemp < (fzrtemplast - 1))
         fzrtemp = fzrtemplast;   
         else 
         fzrtemplast = fzrtemp;
       }
         
         if (filter == 1)
         {
         fgetemplast = fgetemp;
         fzrtemplast = fzrtemp;
         filter = 0;   
         }      
              
          lcd.setCursor(13,0);
          lcd.print(fgehum);
          lcd.setCursor(13,1);
          lcd.print(fzrhum);
                
         //Fridge Display
           LCD (fgetemp, 0, 4);  //var, line no, position of +/-
         //Freezer Display
           LCD (fzrtemp, 1, 4);  //var, line no, position of +/-    
    
        //Send data to gateway every 5 mins....
     
        if ((millis() - last_sent_time) > sent_time)
        {   
        last_sent_time = millis();
        //Send data to gateway... 
        switch (send_ack){
        case 1:
        send(msgFgeHum.set(fgehum),true);
        if (send(msg.set(fgehum)),true){
        send_ack = 2;
        }
        else {
        send(msgFgeHum.set(fgehum),true);
        }
        wait(200);
        break;
        case 2:
        send(msgFzrHum.set(fzrhum),true);
        if (send(msg.set(fzrhum)),true){
        send_ack = 3;
        }
        else {
        send(msgFzrHum.set(fzrhum),true);
        }
        wait(200);
        break;
        case 3:
        send(msgFgeTemp.set(fgetemp, 1),true);
        if (send(msg.set(fgetemp)),true){
        send_ack = 4;
        }
        else{
        send(msgFgeTemp.set(fgetemp, 1),true);
        }
        wait(200);
        break;
        case 4:
        send(msgFzrTemp.set(fzrtemp, 1),true);
        if (send(msg.set(fzrtemp)),true){
        send_ack = 1;
        }
        else{ 
        send(msgFzrTemp.set(fzrtemp, 1),true);
        wait(200);
        }
        break;
        }
      }
      // Sleep for a while to save energy
      sleep(UPDATE_INTERVAL); 
     
    }
    
    

    Here are the compiler error messages....

    Arduino: 1.8.9 (Windows 10), Board: "Arduino/Genuino Uno"
    
    C:\Users\captain\Documents\Arduino\MYS-Fridgefreezer-v1.5\MYS-Fridgefreezer-v1.5.ino: In function 'void loop()':
    
    MYS-Fridgefreezer-v1.5:175:14: error: 'msg' was not declared in this scope
    
         if (send(msg.set(fgehum)),true){
    
                  ^
    
    MYS-Fridgefreezer-v1.5:185:14: error: 'msg' was not declared in this scope
    
         if (send(msg.set(fzrhum)),true){
    
                  ^
    
    MYS-Fridgefreezer-v1.5:195:14: error: 'msg' was not declared in this scope
    
         if (send(msg.set(fgetemp)),true){
    
                  ^
    
    MYS-Fridgefreezer-v1.5:205:14: error: 'msg' was not declared in this scope
    
         if (send(msg.set(fzrtemp)),true){
    
                  ^
    
    exit status 1
    'msg' was not declared in this scope
    
    This report would have more information with
    "Show verbose output during compilation"
    option enabled in File -> Preferences.
    
    mfalkviddM Offline
    mfalkviddM Offline
    mfalkvidd
    Mod
    wrote on last edited by mfalkvidd
    #2

    @skywatch I don't completely understand the intention of your code, so I can't say which of the existing messages (msgFgeHum, msgFgeTemp, msgFzrHum, msgFzrTemp) you intend to use when you use the non-existent msg variable. But I don't userstand why you call send once without checking the return value and then once again when checking the return value. Doing that will cause two messages to be sent.

    With that said, as almost everyone else (including myself), you seem to have misunderstood how the ack parameter in the send call works. Setting it to true (or false) will never affect the return value of send. You'll need to implement the receive() function to handle echoed message.

    See https://forum.mysensors.org/post/33832 for my journey in trying to untangle the differentt acknowledgements.

    skywatchS 1 Reply Last reply
    0
    • mfalkviddM mfalkvidd

      @skywatch I don't completely understand the intention of your code, so I can't say which of the existing messages (msgFgeHum, msgFgeTemp, msgFzrHum, msgFzrTemp) you intend to use when you use the non-existent msg variable. But I don't userstand why you call send once without checking the return value and then once again when checking the return value. Doing that will cause two messages to be sent.

      With that said, as almost everyone else (including myself), you seem to have misunderstood how the ack parameter in the send call works. Setting it to true (or false) will never affect the return value of send. You'll need to implement the receive() function to handle echoed message.

      See https://forum.mysensors.org/post/33832 for my journey in trying to untangle the differentt acknowledgements.

      skywatchS Offline
      skywatchS Offline
      skywatch
      wrote on last edited by skywatch
      #3

      @mfalkvidd Thanks for the fast reply.

      Is there a clear example anywhere of how to achieve reliable delivery?

      I just need to know that the message got to the controller (or GW if that is the best we can do) and resend if not.

      Thanks.

      Thinking about what you said, would this do it???

       switch (send_ack){
          case 1:
          send(msgFgeHum.set(fgehum),true);
          receive()
          if (send(msg.set(fgehum)),true){
          send_ack = 2;
          }
          wait(200);
          break;
      

      This would send the message, go to receive, test if ack was sent by receiver, if it was increment to next case and continue after 200ms.
      If no ack it would re-send the message and then run the receive and test again.
      Or not... ???

      mfalkviddM 2 Replies Last reply
      0
      • skywatchS skywatch

        @mfalkvidd Thanks for the fast reply.

        Is there a clear example anywhere of how to achieve reliable delivery?

        I just need to know that the message got to the controller (or GW if that is the best we can do) and resend if not.

        Thanks.

        Thinking about what you said, would this do it???

         switch (send_ack){
            case 1:
            send(msgFgeHum.set(fgehum),true);
            receive()
            if (send(msg.set(fgehum)),true){
            send_ack = 2;
            }
            wait(200);
            break;
        

        This would send the message, go to receive, test if ack was sent by receiver, if it was increment to next case and continue after 200ms.
        If no ack it would re-send the message and then run the receive and test again.
        Or not... ???

        mfalkviddM Offline
        mfalkviddM Offline
        mfalkvidd
        Mod
        wrote on last edited by mfalkvidd
        #4

        @skywatch I am not aware of any unfortunately.

        If you don't have any repeaters, the return value of send will tell you that the node got an hardware ack from the gateway.

        If you have repeaters, you'll need software ack. Such an acknowledgement will ask the gateway to echo back the message, When the message is echoed back, the receive() function on the node will be triggered. You can examine the contents of the echoed message and match it against the message(s) the node has sent. You'll need to implement a timer or similar on the node to resend if the node doesn't receive the echo.

        None of these methods will provide acknowledgement from the controller.

        The best way to get acknowledgement from the controller is probably to let the node set a value, wait a bit and then ask the controller for the value. If the value is correct, the controller probably received the message.

        I say probably, because depending on what data you send you could get an old value that happens to be the same as the new value. Example: Door is opened. The node sends true to the controller, but the message is lost along the way. The door is closed before the message times out so the node sends false to the controller. The node then asks the controller for the value for the door and receives false. Is this the new false or the an old false that was sent yesterday when the door was closed? Impossible to know. But good for the burglar who got in undetected.

        1 Reply Last reply
        1
        • skywatchS skywatch

          @mfalkvidd Thanks for the fast reply.

          Is there a clear example anywhere of how to achieve reliable delivery?

          I just need to know that the message got to the controller (or GW if that is the best we can do) and resend if not.

          Thanks.

          Thinking about what you said, would this do it???

           switch (send_ack){
              case 1:
              send(msgFgeHum.set(fgehum),true);
              receive()
              if (send(msg.set(fgehum)),true){
              send_ack = 2;
              }
              wait(200);
              break;
          

          This would send the message, go to receive, test if ack was sent by receiver, if it was increment to next case and continue after 200ms.
          If no ack it would re-send the message and then run the receive and test again.
          Or not... ???

          mfalkviddM Offline
          mfalkviddM Offline
          mfalkvidd
          Mod
          wrote on last edited by
          #5

          @skywatch hard to say if your code would work without context. But you should never call receive() yourself, so that part is definitely wrong.

          1 Reply Last reply
          1
          • electrikE Offline
            electrikE Offline
            electrik
            wrote on last edited by
            #6

            This line
            send(msgFgeHum.set(fgehum),true)
            Should be
            if (send(msgFgeHum.set(fgehum) == true)

            1 Reply Last reply
            1
            • alowhumA Offline
              alowhumA Offline
              alowhum
              Plugin Developer
              wrote on last edited by
              #7

              Here's some ACK experiment code, might be useful. I've left all the messy stuff in, might be interesting.

              The important thing is the retry counter. When a message is sent this is set to 3. If there is no acknowledgement, the message will be sent again, and the counter goes to 2. When it reaches 0 it stops trying to resend.

              If an ACK message is received, it also sets the counter to 0 - resending is not required anymore.

              /**
               * The MySensors Arduino library handles the wireless radio link and protocol
               * between your home built sensors/actuators and HA controller of choice.
               * The sensors forms a self healing radio network with optional repeaters. Each
               * repeater and gateway builds a routing tables in EEPROM which keeps track of the
               * network topology allowing messages to be routed to nodes.
               *
               * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
               * Copyright (C) 2013-2015 Sensnology AB
               * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
               *
               * Documentation: http://www.mysensors.org
               * Support Forum: http://forum.mysensors.org
               *
               * This program is free software; you can redistribute it and/or
               * modify it under the terms of the GNU General Public License
               * version 2 as published by the Free Software Foundation.
               *
               *******************************
               *
               * REVISION HISTORY
               * Version 1.0 - Henrik Ekblad
               *
               * DESCRIPTION
               * Example sketch showing how to control physical relays.
               * This example will remember relay state after power failure.
               * http://www.mysensors.org/build/relay
               * 
               * 
               * 
               * Only sends a quick pulse via a reed relay. Useful to hack other devices with push 
               * buttons. In my case, a cheap IKEA dishwasher that didn't have a timer.
               */
              
              // security
              //#define MY_SIGNING_SIMPLE_PASSWD   "changeme"
              //#define MY_ENCRYPTION_SIMPLE_PASSWD "changeme"
              
              //#define MY_RF24_DATARATE RF24_250KBPS // Slower datarate offers more range. Only the + version of the radio supports 250kbps
              //#define MY_RF24_DATARATE RF24_1MBPS               
              //#define MY_RF24_DATARATE RF24_2MBPS
              
              //#define CE_PIN   10
              //#define CSN_PIN 9
              
              // Enable debug prints to serial monitor
              #define MY_DEBUG
              
              // Enable and select radio type attached
              //#define MY_RADIO_RFM69
              #define MY_RADIO_NRF24
              
              //#define MY_RF24_PA_LEVEL RF24_PA_MIN
              #define MY_RF24_PA_LEVEL RF24_PA_LOW
              
              
              // Enable repeater functionality for this node
              //#define MY_REPEATER_FEATURE
              
              #include <MySensors.h>
              
              // MySensors children
              #define DEVICE_STATUS_ID 0                          // The first 'child' of this device is a text field that contains status updates.
              #define RELAY_1_CHILD_ID 1 // MySensors child ID
              #define DONE_CHILD_ID 2 // MySensors child ID
              
              #define RELAY_1_PIN  3  // 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
              #define PULSELENGTH 500 // How long the pulse should last (how long the button should be pressed).
              
              #define LOOPDURATION 600000
              #define ON_TOO_LONG 9 // If it's been on for X * 10 minutes, then it should send a message.
              #define RADIO_DELAY 150 // Keeps the bad Chinese radio happy / supplied with stable power.
              
              byte loopCounter = 0;
              boolean state = 0;
              byte retryCounter = 3;
              
              MyMessage charmsg(DEVICE_STATUS_ID, V_TEXT);        // Sets up the message format that we'll be sending to the MySensors gateway later. The first part is the ID of the specific sensor module on this node. The second part tells the gateway what kind of data to expect.
              MyMessage relaymsg(RELAY_1_CHILD_ID, V_STATUS);
              MyMessage donemsg(DONE_CHILD_ID, V_TRIPPED);
              
              
              
              void before()
              {
              	//for (int pin=0; pin < NUMBER_OF_RELAYS; pin++) {
              		// Then set relay pins in output mode
              	//	pinMode(pin + RELAY_1_PIN, OUTPUT);
              		// Set relay to last known state (using eeprom storage)
              	//	digitalWrite(pin, LOW);
              	//}
                  pinMode(RELAY_1_PIN, OUTPUT);
                  // Set relay to last known state (using eeprom storage)
                  digitalWrite(RELAY_1_PIN, LOW);
               
              }
              
              
              void presentation()
              {
              	// Send the sketch version information to the gateway and Controller
              	sendSketchInfo(F("Dishwasher"), F("1.1")); wait(RADIO_DELAY);
                present(DEVICE_STATUS_ID, S_INFO, F("Status")); wait(RADIO_DELAY); 
                present(RELAY_1_CHILD_ID, S_BINARY, F("Start")); wait(RADIO_DELAY);
                present(DONE_CHILD_ID, S_MOTION, F("Done?")); wait(RADIO_DELAY);
              
                //send(relaymsg.setSensor(RELAY_1_CHILD_ID).set( RELAY_OFF )); wait(200);
              	//for (int i=0; i<NUMBER_OF_RELAYS; i++) {
              		// Register all sensors to gw (they will be created as child devices)
              		//present(sensor, S_BINARY, F("Start")); wait(100);
                  //send(relaymsg.setSensor(RELAY_1).set( RELAY_OFF )); wait(100);
              	//}
              }
              
              
              void setup()
              {
                wait(1000);
                Serial.begin(115200);
                Serial.println(F("Hello world, I am a dish washer."));
              
                if(isTransportReady()){
                  Serial.println(F("Connected to gateway"));
              
                send(charmsg.setSensor(DEVICE_STATUS_ID).set( F("Dishwasher turned on"))); wait(RADIO_DELAY);  
                send(relaymsg.set(state?false:true), true); wait(RADIO_DELAY); // Send new state and request ack back
                send(donemsg.setSensor(DONE_CHILD_ID).set(0)); wait(RADIO_DELAY);
                  
                }else{
                  Serial.println(F("Not connected to gateway"));
                }  
              }
              
              
              void loop()
              {
              
                static unsigned long lastLoopTime = 0;            // Holds the last time the main loop ran.
                if (millis() - lastLoopTime > LOOPDURATION) {
                  lastLoopTime = millis();
                  sendHeartbeat();
              
                  // Having fun with status messages
                  if( loopCounter < 251 ){
                    loopCounter++;
                  }
                  if( loopCounter == ON_TOO_LONG ){
                      send(charmsg.setSensor(DEVICE_STATUS_ID).set( F("Probably done"))); wait(RADIO_DELAY);  
                      send(donemsg.setSensor(DONE_CHILD_ID).set(1)); wait(RADIO_DELAY);
                  }
                  if( loopCounter == ON_TOO_LONG * 2){
                      send(charmsg.setSensor(DEVICE_STATUS_ID).set( F("Turn me off please"))); wait(RADIO_DELAY);  
                  }
                  if( loopCounter == ON_TOO_LONG * 3){
                      send(charmsg.setSensor(DEVICE_STATUS_ID).set( F("PLEEAASE turn me off!"))); wait(RADIO_DELAY);
                  }
                  
                  if( loopCounter == 250){
                      send(charmsg.setSensor(DEVICE_STATUS_ID).set( F("OMG I am still on??"))); wait(RADIO_DELAY);  
                  }
                }
              
                //if( retryCounter > 0 ){
                //  retryCounter--;
                //  send(relaymsg.set(0), true); wait(RADIO_DELAY);  // Send new state and request ack back
                //}
              
              }
              
              /*
              void messageRepeat(MyMessage &message, bool ack = true) {
                int repeat = 1;
                int repeats = 10;
                int repeatdelay = 0;
                boolean sendOK = false;
              
                SerialPrint("Sending message of child ");
                SerialPrintln(message.sensor);
              
                while ((sendOK == false) and (repeat < repeats)) {
                  if (send(message, ack)) {
                    sendOK = true;
                    SerialPrint("Send OK");
                  } else {
                    sendOK = false;
                    SerialPrint("Send ERROR ");
                    SerialPrint(repeat);
                    repeatdelay += RADIO_DELAY;
                  }
              
                  if (ack == true) {
                    SerialPrintln(" With ack ");
                  } else {
                    SerialPrintln(" Without ack ");
                  }
              
                  repeat++;
                  wait(repeatdelay);
                }
              }
              */
              
              
              
              void receive(const MyMessage &message)
              {
              	// We only expect one type of message from controller. But we better check anyway.
              
                Serial.print("Incoming message for child: ");
                Serial.println(message.sensor);
              
                if (message.isAck() && message.sensor == RELAY_1_CHILD_ID) { // We got the ACK!
                  Serial.println("- Received ACK for relay");
                  retryCounter = 0;
                }
                else{
                  // Change relay state
                  Serial.println("-Gateway wants to change relay position");
                	if (message.type==V_STATUS) {
                		
                    Serial.print ("-Received V_status:");
                    Serial.println(message.getBool());
                    
                    if( message.sensor == RELAY_1_CHILD_ID ){
                      boolean desiredState = message.getBool()?RELAY_ON:RELAY_OFF;
                        if(desiredState == RELAY_ON){
                        //digitalWrite(message.sensor-1+RELAY_1_PIN, RELAY_ON);
                        //wait(PULSELENGTH);
                        //digitalWrite(message.sensor-1+RELAY_1_PIN, RELAY_OFF);
                        Serial.print ("-Switching relay on...");
                        digitalWrite(RELAY_1_PIN, RELAY_ON);
                        wait(PULSELENGTH);
                        Serial.println ("Switching relay off.");
                        digitalWrite(RELAY_1_PIN, RELAY_OFF);
                        retryCounter = 3;
                        }
                    }
                		//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
                	}
                }
              }
              
              1 Reply Last reply
              1
              • M Offline
                M Offline
                Marek
                wrote on last edited by
                #8

                You have:
                if (send(msg.set(fgehum)),true)

                Should be:
                if (send(msg.set(fgehum),true))

                Regards
                Marek L.

                1 Reply Last reply
                1
                • skywatchS Offline
                  skywatchS Offline
                  skywatch
                  wrote on last edited by
                  #9

                  @electrik & @Marek - Are you both sure about that? It seems to me that both those statements are doing what was intended.

                  @alowhum Thank you again for an example - I will get around to looking at it in detail soon I hope.

                  1 Reply Last reply
                  0
                  • electrikE Offline
                    electrikE Offline
                    electrik
                    wrote on last edited by
                    #10

                    @skywatch said in Auto resend on NACK:

                    @electrik & @Marek - Are you both sure about that? It seems to me that both those statements are doing what was intended.

                    Now that I see it again, I'm not so sure anymore actually.

                    In your code you used the variable msg. That should be one of msgFgeHum, msgFgeTemp, msgFzrHum, msgFzrTemp.
                    That is why the compiler complains msg is unknown.

                    You also enabled the ack message, this is just a software acknowledge, while the send function returns the status of the hardware acknowledge. So if you check with

                    if (send(msgFgeHum.set(fgehum),true))
                    {
                    // this is sent ok
                    }
                    else
                    {
                    // sending failed
                    }
                    

                    you check if the hardware acknowledge was successful. The software ack should be tested differently and some more logic is needed for it.

                    Hope this helps

                    1 Reply Last reply
                    2
                    • alowhumA Offline
                      alowhumA Offline
                      alowhum
                      Plugin Developer
                      wrote on last edited by
                      #11

                      @electrik Is this a correct understanding?

                      • Hardware ACK is just that is reaches the next node in the network, right? It could be a repeater saying "I got something from you". It doesn't 100% guarantee that it reached the controller correctly.
                      • Software ACK is the controller sending back the exact same message you sent, but this time with the ACK bit set to true? It goes up and down your entire network. It's the best way to be sure that the message reached the controller, since you could theoretically even check if the message details are still the same as when you sent it.

                      Both will happen when you set ACK to true in your send() function?

                      So:
                      if (send(msgFgeHum.set(fgehum),true)) is just checking the hardware ACK, meaning it got sent away ok.

                      And then for software ACK you should use the receive function to check for a returning "echo" message:

                      void receive(const MyMessage &message)
                      {
                      	// We only expect one type of message from controller. But we better check anyway.
                      
                        Serial.print("Incoming message for child: ");
                        Serial.println(message.sensor);
                      
                        if (message.isAck() && message.sensor == RELAY_1_CHILD_ID) { // We got the ACK!
                          Serial.println("- Received ACK for relay");
                          retryCounter = 0;
                        }
                      

                      Is this a correct summary?

                      mfalkviddM 1 Reply Last reply
                      1
                      • alowhumA Offline
                        alowhumA Offline
                        alowhum
                        Plugin Developer
                        wrote on last edited by
                        #12

                        As a quick follow-up: is this a message stating that the hardware ACK failed?

                        362547 !TSF:MSG:SEND,27-27-0-0,s=3,c=1,t=37,pt=2,l=2,sg=0,ft=0,st=NACK:120

                        mfalkviddM 1 Reply Last reply
                        0
                        • alowhumA alowhum

                          As a quick follow-up: is this a message stating that the hardware ACK failed?

                          362547 !TSF:MSG:SEND,27-27-0-0,s=3,c=1,t=37,pt=2,l=2,sg=0,ft=0,st=NACK:120

                          mfalkviddM Offline
                          mfalkviddM Offline
                          mfalkvidd
                          Mod
                          wrote on last edited by
                          #13

                          @alowhum yes

                          1 Reply Last reply
                          0
                          • electrikE Offline
                            electrikE Offline
                            electrik
                            wrote on last edited by
                            #14

                            @alowhum said in Auto resend on NACK:

                            Hardware ACK is just that is reaches the next node in the network, right? It could be a repeater saying "I got something from you". It doesn't 100% guarantee that it reached the controller correctly.

                            Yes exactly

                            @alowhum said in Auto resend on NACK:

                            Software ACK is the controller sending back the exact same message you sent, but this time with the ACK bit set to true? It goes up and down your entire network. It's the best way to be sure that the message reached the controller, since you could theoretically even check if the message details are still the same as when you sent it.

                            Yes

                            @alowhum said in Auto resend on NACK:

                            Both will happen when you set ACK to true in your send() function?

                            Yes correct again

                            @alowhum said in Auto resend on NACK:

                            Is this a correct summary?

                            I didn't use the software ack myself but I think this last point is also correct.

                            1 Reply Last reply
                            1
                            • alowhumA alowhum

                              @electrik Is this a correct understanding?

                              • Hardware ACK is just that is reaches the next node in the network, right? It could be a repeater saying "I got something from you". It doesn't 100% guarantee that it reached the controller correctly.
                              • Software ACK is the controller sending back the exact same message you sent, but this time with the ACK bit set to true? It goes up and down your entire network. It's the best way to be sure that the message reached the controller, since you could theoretically even check if the message details are still the same as when you sent it.

                              Both will happen when you set ACK to true in your send() function?

                              So:
                              if (send(msgFgeHum.set(fgehum),true)) is just checking the hardware ACK, meaning it got sent away ok.

                              And then for software ACK you should use the receive function to check for a returning "echo" message:

                              void receive(const MyMessage &message)
                              {
                              	// We only expect one type of message from controller. But we better check anyway.
                              
                                Serial.print("Incoming message for child: ");
                                Serial.println(message.sensor);
                              
                                if (message.isAck() && message.sensor == RELAY_1_CHILD_ID) { // We got the ACK!
                                  Serial.println("- Received ACK for relay");
                                  retryCounter = 0;
                                }
                              

                              Is this a correct summary?

                              mfalkviddM Offline
                              mfalkviddM Offline
                              mfalkvidd
                              Mod
                              wrote on last edited by mfalkvidd
                              #15

                              @alowhum said in Auto resend on NACK:

                              Both will happen when you set ACK to true in your send() function?

                              This is incorrect. Setting ACK to true in the send() function will enable software ACK.

                              Hardware ACK is not affected by the vale of ACK in the send() function.

                              1 Reply Last reply
                              2
                              • alowhumA Offline
                                alowhumA Offline
                                alowhum
                                Plugin Developer
                                wrote on last edited by
                                #16

                                @mfalkvidd Then how is hardware ACK enabled? I that what you enable in the presentation?

                                present(TEXT_CHILD_ID, S_INFO, F("Status"),true);

                                I always thought that enabling it in presentation() just means you didn't have to do it manually anymore, that it would be done for all messages of that child.

                                Or it hardware ACK always on? And it's just a matter of whether you use the return of the send function or not?

                                mfalkviddM 1 Reply Last reply
                                1
                                • alowhumA alowhum

                                  @mfalkvidd Then how is hardware ACK enabled? I that what you enable in the presentation?

                                  present(TEXT_CHILD_ID, S_INFO, F("Status"),true);

                                  I always thought that enabling it in presentation() just means you didn't have to do it manually anymore, that it would be done for all messages of that child.

                                  Or it hardware ACK always on? And it's just a matter of whether you use the return of the send function or not?

                                  mfalkviddM Offline
                                  mfalkviddM Offline
                                  mfalkvidd
                                  Mod
                                  wrote on last edited by mfalkvidd
                                  #17

                                  @alowhum said in Auto resend on NACK:

                                  Or it hardware ACK always on? And it's just a matter of whether you use the return of the send function or not?

                                  Exactly.

                                  There might be some way to turn it off, but I don't know how.

                                  1 Reply Last reply
                                  2
                                  • alowhumA Offline
                                    alowhumA Offline
                                    alowhum
                                    Plugin Developer
                                    wrote on last edited by
                                    #18

                                    Thanks.

                                    While we're on the subject: is there any built-in retry functionality for the hardware and/or software ACK? I believe if you set the ACK bit in the send function, then the hardware ACK will try to re-send the message a few times? I seem to remember seeing the ft value increase by one each time after a NACK.
                                    2070 TSF:MSG:SEND,27-27-0-0,s=255,c=3,t=24,pt=1,l=1,sg=0,ft=0,st=OK:1
                                    I suspect this hardware-retry only works if you set the ACK to true?

                                    And another one:

                                    Does the isTransportReady() function check..
                                    A. If the radio works
                                    B. If there is a connection to a neighbour (repeater or gateway)
                                    C. If a handshake had been made with the controller

                                      if(isTransportReady()){
                                        Serial.println(F("Connected to gateway!"));
                                      }
                                      else {
                                        Serial.println(F("! NO CONNECTION"));
                                      }
                                    
                                    mfalkviddM 1 Reply Last reply
                                    1
                                    • alowhumA alowhum

                                      Thanks.

                                      While we're on the subject: is there any built-in retry functionality for the hardware and/or software ACK? I believe if you set the ACK bit in the send function, then the hardware ACK will try to re-send the message a few times? I seem to remember seeing the ft value increase by one each time after a NACK.
                                      2070 TSF:MSG:SEND,27-27-0-0,s=255,c=3,t=24,pt=1,l=1,sg=0,ft=0,st=OK:1
                                      I suspect this hardware-retry only works if you set the ACK to true?

                                      And another one:

                                      Does the isTransportReady() function check..
                                      A. If the radio works
                                      B. If there is a connection to a neighbour (repeater or gateway)
                                      C. If a handshake had been made with the controller

                                        if(isTransportReady()){
                                          Serial.println(F("Connected to gateway!"));
                                        }
                                        else {
                                          Serial.println(F("! NO CONNECTION"));
                                        }
                                      
                                      mfalkviddM Offline
                                      mfalkviddM Offline
                                      mfalkvidd
                                      Mod
                                      wrote on last edited by
                                      #19

                                      @alowhum again, setting the ACK parameter in the send call will NEVER affect hardware ack.

                                      For nrf24, up to 15 retries will be done by the hardware ack.

                                      1 Reply Last reply
                                      0
                                      • mfalkviddM Offline
                                        mfalkviddM Offline
                                        mfalkvidd
                                        Mod
                                        wrote on last edited by mfalkvidd
                                        #20

                                        isTransportReady will return true if the node has seen a valid route to the gateway and there have been fewer than MY_TRANSPORT_MAX_TSM_FAILURES transport failures since the node saw the valid route. I do not know what constitutes a transport failure though. I think "Failed uplink counter" (ft= in the log) is the counter that's used for comparison.

                                        The controller is not involved in isTransportReady

                                        So maybe something between B and C.

                                        1 Reply Last reply
                                        0
                                        • alowhumA Offline
                                          alowhumA Offline
                                          alowhum
                                          Plugin Developer
                                          wrote on last edited by
                                          #21

                                          @mfalkvidd Thank you so much for the explanation! I feel I'm getting a grasp on things.

                                          1 Reply Last reply
                                          1
                                          Reply
                                          • Reply as topic
                                          Log in to reply
                                          • Oldest to Newest
                                          • Newest to Oldest
                                          • Most Votes


                                          22

                                          Online

                                          11.7k

                                          Users

                                          11.2k

                                          Topics

                                          113.1k

                                          Posts


                                          Copyright 2025 TBD   |   Forum Guidelines   |   Privacy Policy   |   Terms of Service
                                          • Login

                                          • Don't have an account? Register

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • MySensors
                                          • OpenHardware.io
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular