No Ack reveive on gateway with button



  • Hi,

    I have a gateway (node 0) with associated buttons and relays. The relays work completely as I want, but I would like to receive an acknowledgment (ACK) for the buttons. Unfortunately whatever I do I am not getting any confirmations (ACK) from the controller (Domoticz 2020.2). It seems that the gateway also doesn't want to receive an acknowledgment (ACK) at all.

    What also doesn't work on the gateway is "MY_TRANSPORT_WAIT_READY_MS". As soon as the gateway starts, the messages are immediately sent, causing the buttons to assume the wrong status. For now I work around with a timer and a FIRST_LOOP boolean.

    The code is still a bit rough as it consists of a number of posts in this forum which I have put together. Finally, the gateway will be connected to the controller via the USB connector. But for troubleshooting it is easy that he communicates via the network connection with the controller.

    Arduino IDE 1.8.13 on Windows 10
    Mysensors Library 2.3.2
    Arduino MEGA with W5100 Ethernet
    Controller Domoticz 2020.2

    // General settings
    #define SKETCH_NAME "GatewayEthernet + I/O"
    #define SKETCH_VERSION "2.0"
    #define MY_DEBUG
    //#define MY_NODE_ID 10
    
    // NRF24 radio settings
    #define MY_RADIO_RF24
    #define MY_RF24_CHANNEL 83
    #define MY_RF24_PA_LEVEL RF24_PA_HIGH
    #define MY_RF24_CE_PIN 5
    #define MY_RF24_CS_PIN 6
    //#define MY_DEBUG_VERBOSE_RF24
    
    // Advanced settings
    #if F_CPU == 8000000L
      #define MY_BAUD_RATE 38400
    #endif
    
    // Common gateway settings
    #define MY_REPEATER_FEATURE
    
    // Ethernet gateway settings
    #define MY_GATEWAY_W5100
    
      // Gateway inclusion mode
      #define MY_INCLUSION_MODE_FEATURE
      #define MY_INCLUSION_MODE_DURATION 60
      #define MY_INCLUSION_BUTTON_FEATURE
      #define MY_INCLUSION_MODE_BUTTON_PIN 18
        
      // Gateway receiving buffer feature
      //#define MY_RX_MESSAGE_BUFFER_FEATURE
      //#define MY_RF24_IRQ_PIN 17
    
      #define MY_IP_ADDRESS 192, 168, 10, 63
      #define MY_IP_GATEWAY_ADDRESS 192, 168, 10, 254
      #define MY_IP_SUBNET_ADDRESS 255, 255, 255, 0
      #define MY_PORT 5003
      #define MY_MAC_ADDRESS 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
    
      #define MY_SOFTSPI
      #define MY_SOFT_SPI_SCK_PIN 14
      #define MY_SOFT_SPI_MISO_PIN 16
      #define MY_SOFT_SPI_MOSI_PIN 15
    
    
    // Gateway Leds settings
    #define MY_DEFAULT_LED_BLINK_PERIOD 300
    #define MY_DEFAULT_RX_LED_PIN  9
    #define MY_DEFAULT_TX_LED_PIN  8
    #define MY_DEFAULT_ERR_LED_PIN 7
    
    //Timeout in ms until transport is ready during startup
    #define MY_TRANSPORT_WAIT_READY_MS 60000
    
    //#include <SPI.h>
    #include <Ethernet.h>
    #include <MySensors.h>
    #include <Bounce2.h>
    
    #define FIRST_OUTPUT_PIN 32  // Digital pin number for first output
    #define NUMBER_OF_OUTPUTS 4  // Total number of outputs
    #define OUTPUT_ON 0          // GPIO value to write to turn output on
    #define OUTPUT_OFF 1         // GPIO value to write to turn output off
    
    #define FIRST_INPUT_PIN 22   // Digital pin number for first input
    #define NUMBER_OF_INPUTS 4   // Total number of inputs
    const uint8_t INPUT_PIN[] = {22, 23, 24, 25, 26, 27, 28, 29};
    Bounce debouncer[NUMBER_OF_INPUTS];
    MyMessage INPUT_MSG(0, V_TRIPPED);
    bool INPUT_OLD[NUMBER_OF_INPUTS] = {false};
    
    long CURRENT_MILLIS=millis();
    long DELAY_MILLIS=60000;
    bool FIRST_LOOP=true;
    
    
    void before() 
    {
      // Set all output pins and last know state
      for (int sensor=1, pin=FIRST_OUTPUT_PIN; sensor<=NUMBER_OF_OUTPUTS; sensor++, pin++) {
        pinMode(pin, OUTPUT);
        digitalWrite(pin, loadState(sensor)?OUTPUT_ON:OUTPUT_OFF);
      }
    }
    
    
    void presentation()
    {
    	// Send the sketch information
      sendSketchInfo(SKETCH_NAME, SKETCH_VERSION);
    
      // Register all outputs sensors
      for (int sensor=1; sensor<=NUMBER_OF_OUTPUTS; sensor++) {
        present(sensor, S_BINARY, "Output pin");
      }
      
      // Register all input sensors
      for (int sensor=1+NUMBER_OF_OUTPUTS; sensor<=NUMBER_OF_INPUTS+NUMBER_OF_OUTPUTS; sensor++) {
        present(sensor, S_DOOR, "Input pin");
      }
    }
    
    
    void setup()
    {
      // Setup all input pins, internal pull-up and debouncer
      for (int sensor=0, pin=FIRST_INPUT_PIN; sensor<NUMBER_OF_INPUTS; sensor++, pin++) {
        pinMode(pin,INPUT);
        digitalWrite(pin,HIGH);
        debouncer[sensor] = Bounce();
        debouncer[sensor].attach(INPUT_PIN[sensor]);
        debouncer[sensor].interval(10);
        INPUT_OLD[sensor] =  debouncer[sensor].read();
      }
    }
    
    
    void loop() 
    {
    	// Send tripped inputs
      bool INPUT_NEW[NUMBER_OF_INPUTS];
      for (int sensor=0; sensor<NUMBER_OF_INPUTS; sensor++) {
        if (FIRST_LOOP) {
          if (millis()-CURRENT_MILLIS>DELAY_MILLIS) {
            send(INPUT_MSG.setSensor(sensor+1+NUMBER_OF_OUTPUTS).set(INPUT_OLD[sensor]), true);
            
            Serial.print("Sensor: ");
            Serial.print(sensor+1+NUMBER_OF_OUTPUTS);
            Serial.print(", Status: ");
            Serial.println(INPUT_OLD[sensor]);
            
            if (sensor+1==NUMBER_OF_INPUTS) {
              FIRST_LOOP=false ;
              Serial.print("FIRST_LOOP: ");
              Serial.println(sensor+1) ;  
            }
          }
        }
        else { 
          debouncer[sensor].update();
          INPUT_NEW[sensor] = debouncer[sensor].read();
          
          if (INPUT_NEW[sensor] != INPUT_OLD[sensor]) {
            INPUT_OLD[sensor] = INPUT_NEW[sensor];
    
            Serial.print("Voor: ");
            Serial.println(INPUT_NEW[sensor]);
          
            int INVERT=INPUT_NEW[sensor];
            INVERT = !INVERT;
    
            Serial.print("Togle: ");
            Serial.println(INVERT);
          
            send(INPUT_MSG.setSensor(sensor+1+NUMBER_OF_OUTPUTS).set(INPUT_NEW[sensor]), true);
          } 
        }
      } 
    }
    
    
    void receive(const MyMessage &message)
    {
      if (message.isAck()) {
         Serial.println("Ack from gateway");
      }
        
      // We only accept messages for this node
      if(message.destination==getNodeId()) {
        // We only expect one type of message and echoed messages are not accepted
        if (message.getType()==V_STATUS && !message.isEcho()) {
          // We only accept output pins
          int RECEIVE_MSG = message.getSensor()-1+FIRST_OUTPUT_PIN;
          if (RECEIVE_MSG<FIRST_OUTPUT_PIN+NUMBER_OF_OUTPUTS) {
            // Change output state
            digitalWrite(RECEIVE_MSG, message.getBool()?OUTPUT_ON:OUTPUT_OFF);
            // Store state in eeprom
            saveState(message.getSensor(), message.getBool());
            #ifdef MY_DEBUG
              Serial.print("Node: ");
              Serial.print(getNodeId());
              Serial.print(", Output pin: ");
              Serial.print(RECEIVE_MSG);
              Serial.print(", Status: ");
              Serial.println(message.getBool());
            #endif
          }
        }
      }
    }
    


  • Welcome @mjchrist!

    Short answer: Check the return value of send() on the gateway, to see if a message has been successfully delivered an outgoing message (via Ethernet, MQTT, serial).

    Long answer: What you are referring to as an ACK should really be called echo instead to avoid confusion, because that is really what it does.

    bool send(MyMessage &msg, bool echo);

    If you set the echo parameter to true, you ask the destination node to echo the received payload back to the sending node. An echo is only being generated for messages that travel through the MySensors network. For example, if node 42 sends a message to the gateway (so that it can forward it to the controller), the gateway will echo the payload back to node 42. The same is true if the gateway is the sender and node 42 the destination.

    On the other hand, the boolean return value of send() will tell you that the sending node received an acknowledgment from the next hop. This next hop might be the destination if there's a direct connection between the two nodes, or any node that relays the message further to the destination, like a repeater.

    In the special case where the gateway sends a message (to the controller, so to speak), the return value of send() isn't the ACK from a MySensors-internal transport (like NRF24), but the confirmation that the message was successfully delivered via the outgoing transport layer which translates the message into a packet, a MQTT topic or string for the serial port.

    Oh, and by the way, please use isEcho() in favour of isAck(). The latter is misleading (IMHO) and deprecated. It will be removed with MySensors v3.

    And last but not least, MY_TRANSPORT_WAIT_READY_MS doesn't mean that the node (or gateway in this case) waits for n milliseconds until it starts establishing a connection (for the transceiver (NRF24), to be clear). Instead, it limits the time the node tries to establish a connection to n milliseconds, so that it can continue to work autonomously and do other stuff if it failed to do so.


Log in to reply
 

Suggested Topics

  • 3
  • 15
  • 3
  • 2
  • 1
  • 24

0
Online

11.2k
Users

11.1k
Topics

112.5k
Posts