Sending MQTT messages within rate limits

Cayenne MQTT messages are currently rate limited to 60 messages each minute. If your client code sends messages at a higher rate it will have messages dropped and if it continues to send messages above the limit can run the risk of being disconnected or blocked.

In order to keep your client sending messages below the limits make sure you only send data at intervals. For embedded devices like Arduino this means you should not send data by just using a virtualWrite() call within the main loop(). Doing this will result in the function being called to send data every time through the loop() which can cause thousands of messages being sent each minute. In order to send messages at intervals there a few methods you can use:

  1. The built-in CAYENNE_OUT_DEFAULT() and CAYENNE_OUT() functions.
    This method is probably the simplest since these functions are designed to automatically run at intervals (currently every 15 seconds). To use them just declare them in your program and include a write function to send data to Cayenne:

    CAYENNE_OUT_DEFAULT()
    { 
       Cayenne.virtualWrite(0, millis());
    }
    

    CAYENNE_OUT_DEFAULT() can be used for most situations but if you want to use specific functions for different channels you can use CAYENNE_OUT(channel) functions instead.

  2. Manually calculating the interval to send data.
    This method allows you to determine the intervals yourself rather than using the set interval the CAYENNE_OUT functions use. To do this with Arduino you can just use the built-in millis() function to check the elapsed time and send data at the required interval:

    unsigned long lastMillis = 0;
    
    void setup() {
       Serial.begin(9600);
       Cayenne.begin(username, password, clientID);
    }
    
    void loop() {
       Cayenne.loop();
       
       //Publish data every 10 seconds (10000 milliseconds). Change this value to publish at a different interval.
       if(millis() - lastMillis > 10000) {
          lastMillis = millis();
          Cayenne.virtualWrite(0, lastMillis);
       }
    }
    
  3. A timer function.
    This method requires including a timer class in your code to run a function at the specified interval. For an example showing how to use a timer class see the SendDataOnTimer example sketch: Cayenne-MQTT-Arduino/SendDataOnTimer.ino at master · myDevicesIoT/Cayenne-MQTT-Arduino · GitHub.

  4. Only send data when it changes.
    This method can be used for sensors that have values that do not change very often. In that case you can just send the data when it changes and prevent a lot of unnecessary messages. Though that may affect the graph display so if you plan to use graphing for the sensor you may want to use one of the other methods to send data at regular intervals. If you don’t care about regular data points though you can just keep track of the previous state of the sensor and update it when it changes:

    int previousState = -1;
    int currentState = -1;
    
    void setup()
    {
    	Serial.begin(9600);
    	Cayenne.begin(username, password, clientID);
    }
    
    void loop()
    {
    	Cayenne.loop();
    
    	// Check the sensor state and send data when it changes.
    	currentState = digitalRead(4);
    	if (currentState != previousState) {
    		Cayenne.virtualWrite(0, currentState);
    		previousState = currentState;
    	}
    }
    

When sending data make sure you keep it within the current limit of 60 messages per minute if you don’t want data dropped or your client disconnected. This means that if, for instance, you wanted to send data for 10 different sensors you should either send each sensor’s data separately at most each second or if you want to send them all at once make sure you only do it at most every 10 seconds.

The examples above are based on the Cayenne MQTT Arduino library but the same rate limits apply for any other clients, like the Cayenne MQTT Python library or any third party MQTT libraries used to connect to Cayenne. So if using those you should also make sure that data is sent at appropriate intervals.

6 Likes

How can we check if our device has been disconnected or blocked?

1 Like

Right now you can only tell if it’s blocked if you are unable to connect to the server within the 10 minute period. That should only happen if you’ve disconnected/reconnected 50 times within 10 minutes. I believe the plan is to add some notification in the UI but I’m not sure when that will be implemented.

1 Like

Can’t we just add for example delay(10000); ?

Hi I ‘think’ you could in theory now on the MQTT, (on the old Arduino version I think it caused issue/instability with disconnects) but in reality even though it ‘could’ work now it would be a really bad idea - putting a 10 second delay in your main loop will slow you loop down terribly, as the delay will prevent the code moving forward. Learning how to use millis() is a really worthwhile thing, as once you ‘get it’ it will allow you to do so much more, trust me I spent months avoiding it and now I can use it, things are so much better.

The examples /methods given above are the best explanations I have seen so far.

2 Likes

Yes, @paulminize’s answer is correct. The last time I was playing with it if you go over 2 seconds you start to get disconnects from the server.

Hi
This has resolved the issue with monitoring a door sensor and sending an immediate state change to the Dashboard, but how can I push a button state change from the Dashboard to the Arduino to cause an immediate (under one second delay) activation of a relay?