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. General Discussion
  3. Best practice for hardware ack and software ack when using a battery node

Best practice for hardware ack and software ack when using a battery node

Scheduled Pinned Locked Moved General Discussion
10 Posts 4 Posters 207 Views 3 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.
  • E Offline
    E Offline
    evb
    wrote on last edited by
    #1

    There are plenty of old and recent topics about the hard- and software ack, but I didn't find a best practice to follow :-(

    Let's begin with the documentation

    bool send (MyMessage & msg, const bool requestEcho = false )		
    Sends a message to gateway or one of the other nodes in the radio network
    
    Parameters
    * msg: Message to send
    * requestEcho: Set this to true if you want destination node to echo the message back to this node. Default is not to request echo. If set to true, the final destination will echo back the contents of the message, triggering the receive() function on the original node with a copy of the message, with message.isEcho() set to true and sender/destination switched.
    
    Returns
    Returns true if message reached the first stop on its way to destination.
    
    send(msg.set(value==HIGH ? 0 : 1));
    

    If the method send returns with true, the hardware ack did work.

    • battery node <==> gateway : we are sure, the message is delivered to the gateway
    • battery node <==> repeater <==> gateway : we are sure, the message is delivered to the repeater, but further on, we don't know.

    If the method send returns with false, the hardware ack did not work, the message is not delivered.
    So, what is here the best practice?
    Doing this for example in the battery node?

    if (!send(msg.set(value==HIGH ? 0 : 1)))
      if (!send(msg.set(value==HIGH ? 0 : 1)))
        if (!send(msg.set(value==HIGH ? 0 : 1)))
    

    3 times or 4 times or 5 times or...
    ==> a method who retries x times, goes to sleep for a short time, retries again, etc. ?
    It should be possible to combine this with the normal interrupt based sleep of the battery door node.

    How does the repeater node handles the hardware ack?
    Everything is handled by the mysensors library. Is there a way to do here the same in case of a failing hardware ack?
    ==> if each node (normal and repeater nodes) auto retries to deliver the message, we are sure that the message gets delivered.
    But then another the question arises, what if the repeater receives 10 messages from different nodes to forward and the repeater is still retrying to deliver the first? It must create a sort of queue and have enough memory to stock the messages...

    Is using the software ack better?

    send(msg.set(value==HIGH ? 0 : 1), true);
    

    and implement in the receive method the check of the returning message.
    But this means that a battery node must stay awake...
    What if no return ack message is received after 5 seconds or 10 seconds?
    Resend the message? But we are in the receive method, I don't know if we can send here messages???

    The reason for this question is a battery door node at the edge of reliable radio connection with the gateway. I did add a repeater node in the middle, but still sometimes the message gets lost...

    mfalkviddM 1 Reply Last reply
    0
    • E evb

      There are plenty of old and recent topics about the hard- and software ack, but I didn't find a best practice to follow :-(

      Let's begin with the documentation

      bool send (MyMessage & msg, const bool requestEcho = false )		
      Sends a message to gateway or one of the other nodes in the radio network
      
      Parameters
      * msg: Message to send
      * requestEcho: Set this to true if you want destination node to echo the message back to this node. Default is not to request echo. If set to true, the final destination will echo back the contents of the message, triggering the receive() function on the original node with a copy of the message, with message.isEcho() set to true and sender/destination switched.
      
      Returns
      Returns true if message reached the first stop on its way to destination.
      
      send(msg.set(value==HIGH ? 0 : 1));
      

      If the method send returns with true, the hardware ack did work.

      • battery node <==> gateway : we are sure, the message is delivered to the gateway
      • battery node <==> repeater <==> gateway : we are sure, the message is delivered to the repeater, but further on, we don't know.

      If the method send returns with false, the hardware ack did not work, the message is not delivered.
      So, what is here the best practice?
      Doing this for example in the battery node?

      if (!send(msg.set(value==HIGH ? 0 : 1)))
        if (!send(msg.set(value==HIGH ? 0 : 1)))
          if (!send(msg.set(value==HIGH ? 0 : 1)))
      

      3 times or 4 times or 5 times or...
      ==> a method who retries x times, goes to sleep for a short time, retries again, etc. ?
      It should be possible to combine this with the normal interrupt based sleep of the battery door node.

      How does the repeater node handles the hardware ack?
      Everything is handled by the mysensors library. Is there a way to do here the same in case of a failing hardware ack?
      ==> if each node (normal and repeater nodes) auto retries to deliver the message, we are sure that the message gets delivered.
      But then another the question arises, what if the repeater receives 10 messages from different nodes to forward and the repeater is still retrying to deliver the first? It must create a sort of queue and have enough memory to stock the messages...

      Is using the software ack better?

      send(msg.set(value==HIGH ? 0 : 1), true);
      

      and implement in the receive method the check of the returning message.
      But this means that a battery node must stay awake...
      What if no return ack message is received after 5 seconds or 10 seconds?
      Resend the message? But we are in the receive method, I don't know if we can send here messages???

      The reason for this question is a battery door node at the edge of reliable radio connection with the gateway. I did add a repeater node in the middle, but still sometimes the message gets lost...

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

      @evb basically you are trying to solve what's called "the two generals' problem", which has been proved to be unsolvable.

      Some corrections:

      If the method send returns with false, the hardware ack did not work, the message is not delivered.
      

      This statement above is incorrect. The message could very well have been delivered, but the ack was lost.

      if each node (normal and repeater nodes) auto retries to deliver the message, we are sure that the message gets delivered.
      

      This statement above is incorrect. By default , for nrf24, a node will retry 15 times and after that the send() function will return false. No more retries will be made after that. So even though auto retry is on by default, auto retry does not guarantee delivery.

      Is using the software ack better?
      

      This statement above is incorrect. MySensors does not have software ack. If you think software ack exists, you have been fooled, just like many many many many other MySensors users (myself included).

      Since you are trying to solve a proved insolvable problem, there are no best practices. Workarounds can be made, but each workaround would have to be tailored to the specific use case.

      E 1 Reply Last reply
      1
      • mfalkviddM mfalkvidd

        @evb basically you are trying to solve what's called "the two generals' problem", which has been proved to be unsolvable.

        Some corrections:

        If the method send returns with false, the hardware ack did not work, the message is not delivered.
        

        This statement above is incorrect. The message could very well have been delivered, but the ack was lost.

        if each node (normal and repeater nodes) auto retries to deliver the message, we are sure that the message gets delivered.
        

        This statement above is incorrect. By default , for nrf24, a node will retry 15 times and after that the send() function will return false. No more retries will be made after that. So even though auto retry is on by default, auto retry does not guarantee delivery.

        Is using the software ack better?
        

        This statement above is incorrect. MySensors does not have software ack. If you think software ack exists, you have been fooled, just like many many many many other MySensors users (myself included).

        Since you are trying to solve a proved insolvable problem, there are no best practices. Workarounds can be made, but each workaround would have to be tailored to the specific use case.

        E Offline
        E Offline
        evb
        wrote on last edited by
        #3

        Hi @mfalkvidd

        Ok, I understand your point. Did read trough plenty of topics on this ;-)
        Should be an article on the official website and not spread over so many different topics, hint, hint ;-)

        Ok, let change the title then to Best practice for the possible workarounds for hardware and software ack when using a battery node.

        Physically, because we are using radio, we can't have a 100% situation, but we can aim to it.

        • checking the return of the send method and retrying yourself x times by the sketch code, can already help to aim for the 100%.
          The radio nrf24 and I imagine also the rfm69?, does already hardware retries, together with the software user retries, will increase the possibility that the message is delivered... with the comment that a message may arrive several times on the controller!
          Is there a best practice in this workaround? Experiences from members?

        • can my first point also be done on a repeater? Because the 'repeating' is done by the library...
          Can we override or intercept this library behaviour?

        • the echo reply mechanism or what I'm calling the software ack
          That's the one I doubt to be usable in battery nodes, but maybe members have positive or negative experiences with this?

        1 Reply Last reply
        0
        • BearWithBeardB Offline
          BearWithBeardB Offline
          BearWithBeard
          wrote on last edited by BearWithBeard
          #4

          I think sending a message repeatedly is really only helpful for occasional hickups or connection issues. Say, somebody walks by a node and physically weakens or blocks the signal right when it attempts to send a message. Or the gateway / repeater is busy with another task, or reboots / reconnects for some reason.

          If the connection issue is persistent, because it is too far away from any parent node and you already know that you will need multiple TX attempts more often than not, the best practice would be to address the range issue itself, IMHO. Either increase the output power of the transceiver or, use (another) repeater with a higher receiving sensitivity. Remove the cause of the problem instead of fighting the symptoms.

          But I understand that you want certain nodes to be as reliable as possible. I address occasional connection issues on my coin cell powered contact nodes by attempting to send the state up to a limited number of times and with a decent pause inbetween attempts. If all those attempts fail, I increase a failedTxAttempts counter variable and send it separately as a crude "reliability indicator". If this occurs too often, I need to address the issue. That being said though, my nodes are fairly reliable. Last time I checked, 1 out of 1250 messages failed on average (0.08%).

          Here's a snippet from my contact node sketch. Hope it makes sense to you, I just copy and pasted it.
          Edit: I removed the functions and put everything inside the loop for brevity. I also added some comments.

          void loop()
          {
          	static bool contactState;
          	static uint8_t failedTxAttempts;
          
          	contactState = digitalRead(PIN_CONTACT);
          	
          	bool sent = false;
          	uint8_t txAttempt = 0;
          
          	// Attempt to send the contact state up to MAX_TX_ATTEMPT times
          	do
          	{
          		sent = send(msgContact.set(contactState));
          		if (!sent)
          		{
          			// Message didn't reach parent or didn't get ACK from parent
          			sleep(FAILED_TX_PAUSE); // Sleep for a while (500ms or so)
          			++txAttempt;
          		}
          		else
          		{
          			// Received ACK, give visual feedback
          			digitalWrite(PIN_LED_OK, HIGH);
          			sleep(MY_DEFAULT_LED_BLINK_PERIOD);
          			digitalWrite(PIN_LED_OK, LOW);
          		}
          	} while (!sent && txAttempt <= MAX_TX_ATTEMPTS); // MAX_TX_ATTEMPTS: 5
          	
          	if (!send)
          	{
          		// Contact state couldn't be sent, increase TX error counter
          		++failedTxAttempts;
          	}
          
          	if (failedTxAttempts != 0) 
          	{
          		// Report that there were contact state change(s), which failed to be sent
          		wait(TX_PAUSE);
          		if (send(msgFailedTxAttempts.set(failedTxAttemts)))
          		{
          			// Reset counter variable if ACK was received
          			failedTxAttempts = 0;
          		}
          	}
          	
          	// Do other stuff & sleep
          }
          

          A similiar goal to those failed TX indicators can be achieved using the internal indication handler. You can read more about it in this post. This can also be used on the gateway and repeaters. I don't know of any way to intercept or "force repeat" relayed messages on a repeater manually.

          Regarding the echo, I guess you could easily calculate how much requesting an echo would impact the battery life. Take a timestamp with millis() right before and after send() without requesting an echo and check how long it takes on average. I suspect this will be about 80ms. Then compare this to a message with an echo where you take the time right before sending and right after receiving the echo in receive(). The difference between the two times should roughly equal the time the transceiver spends in a high power state to listen for the echo.

          1 Reply Last reply
          0
          • E Offline
            E Offline
            evb
            wrote on last edited by
            #5

            @BearWithBeard thanks for your code samples, it confirms my own thoughts and gives a code guideline at the same time :-)

            @mfalkvidd, in the reply of @BearWithBeard, he linked to another topic post where you use the indication handler in your sketch.
            TxOk and TxErr are send to the controller. Their values are always incremented to infinity by your sketch?
            How do you interpret this at the controller?

            @sundberg84 says : INDICATION_GW_TX sounds like a good plan. This is a great tool I think for the future to evaluate and debug your network. I used S_CUSTOM and a utility meter (hourly) in HA to get the values.
            Do you have a code sample of your sketch? An example generally says more then 1000 words ;-)
            I think you send each time a value '1' when an error occurs, correct? And on the HA side you use the hourly utility meter integration to sum the values on a hourly base?

            mfalkviddM 1 Reply Last reply
            0
            • E evb

              @BearWithBeard thanks for your code samples, it confirms my own thoughts and gives a code guideline at the same time :-)

              @mfalkvidd, in the reply of @BearWithBeard, he linked to another topic post where you use the indication handler in your sketch.
              TxOk and TxErr are send to the controller. Their values are always incremented to infinity by your sketch?
              How do you interpret this at the controller?

              @sundberg84 says : INDICATION_GW_TX sounds like a good plan. This is a great tool I think for the future to evaluate and debug your network. I used S_CUSTOM and a utility meter (hourly) in HA to get the values.
              Do you have a code sample of your sketch? An example generally says more then 1000 words ;-)
              I think you send each time a value '1' when an error occurs, correct? And on the HA side you use the hourly utility meter integration to sum the values on a hourly base?

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

              @evb said in Best practice for hardware ack and software ack when using a battery node:

              TxOk and TxErr are send to the controller. Their values are always incremented to infinity by your sketch?
              How do you interpret this at the controller?

              Yes. A counter is good because missed messages don't matter very much.

              I don't do anything at all. But if I would do anything, I would probably calculate

              (new_counter_value - previous_counter_value)/(new_timestamp - previous_timestamp)
              

              and plot that, perhaps with some averaging over time, depending on how often the node sends.

              1 Reply Last reply
              0
              • E Offline
                E Offline
                evb
                wrote on last edited by
                #7

                A second thought about using the MySensors method indication.

                void indication(indication_t ind)
                {
                  switch (ind)
                  {
                    case INDICATION_TX:
                      txOK++;
                      break;
                    case INDICATION_ERR_TX:
                      txERR++;
                      break;
                  }
                }
                

                A successful or failed transmission of the error message itself, will also trigger this method, which then actually gives a wrong picture.
                Or has this been thought through too far? :thinking_face:

                mfalkviddM BearWithBeardB 2 Replies Last reply
                0
                • E evb

                  A second thought about using the MySensors method indication.

                  void indication(indication_t ind)
                  {
                    switch (ind)
                    {
                      case INDICATION_TX:
                        txOK++;
                        break;
                      case INDICATION_ERR_TX:
                        txERR++;
                        break;
                    }
                  }
                  

                  A successful or failed transmission of the error message itself, will also trigger this method, which then actually gives a wrong picture.
                  Or has this been thought through too far? :thinking_face:

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

                  @evb if an error message is transmitted in the ether, and no-one is around to acknowledge it, was it really sent?

                  skywatchS 1 Reply Last reply
                  0
                  • E evb

                    A second thought about using the MySensors method indication.

                    void indication(indication_t ind)
                    {
                      switch (ind)
                      {
                        case INDICATION_TX:
                          txOK++;
                          break;
                        case INDICATION_ERR_TX:
                          txERR++;
                          break;
                      }
                    }
                    

                    A successful or failed transmission of the error message itself, will also trigger this method, which then actually gives a wrong picture.
                    Or has this been thought through too far? :thinking_face:

                    BearWithBeardB Offline
                    BearWithBeardB Offline
                    BearWithBeard
                    wrote on last edited by
                    #9

                    @evb The indication handler will not only be triggered by the error message, but also by (almost) all internal messages, like registration requests, node and sensor presentation, nonce, discovery responses, find parent requests, OTA firmware upgrades and others. Basically everything that uses the default transportRouteMessage() function.

                    It's up to you if this gives a wrong picture. If you want to know how reliable the uplink of node is, it's exactly what you would want to use, isn't it? If you, on the other hand, only care about your own messages, or perhaps even only a few of them, you would propably want to avoid the indication handler, as it may result in "false positives".

                    It's basically the opposite of the "track only a single MyMessage object" approach I was showing above.

                    1 Reply Last reply
                    2
                    • mfalkviddM mfalkvidd

                      @evb if an error message is transmitted in the ether, and no-one is around to acknowledge it, was it really sent?

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

                      @mfalkvidd If the message was sent by a cat, maybe...... ;)

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


                      14

                      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