we are using the E-Series module in an industrial controller and have some problems with blocked user code in an environment with bad mobile connection. A display is and a frequency converter (via Modbus) are connected to the controller .
Both require regular communication within 100 ms.
As soon as the mobile connection breaks off, loop() is not executed for up to 30 seconds, while the E-Series tries to reconnect.
I have already implemented the following:
SYSTEM_MODE(MANUAL)
SYSTEM_THREAD(ENABLED)
Particle.connect() is called in setup().
Before each Particle.publish(), Particle.connected() is used to check whether the cloud connection exists.
With an existing connection and also with a completely deactivated connection everything works. But as soon as the E-Series module reconnects, loop() will not be executed for some time.
I have also tried to disable the GSM module after a disconnect with Cellular.off() and Particle.disconnect(). But this doesn’t really help. The user code is then still blocked for some time.
Is there a way that the execution of the user code/ loop() always has the highest priority and the cloud connection is only secondary?
It will likely be impossible to make sure your loop gets executed every 100 milliseconds without blocking. What I would do is flip things around so you run your modbus code in a separate thread so it’s not affected by the system thread or the application loop thread. If it needs to do things like publish it should put that data in a queue to be published from the loop thread.
The other option is to do the publish from a separate thread, such as by using:
Now i´ve moved most Things into a thread. loop() now only contains some i2C communication.
Now i have the same effect inside the thread. In some connection states now the thread is blocked. loop() runs normal (A debug string is sent via serial every second to visualize, if loop or thread is running)
Can reading the RSSI value somehow block the code?
I read Cellular.RSSI() every second, to get the actual connection quality
I now figured out, that the code is only blocking, if i get RSSI value =1.
What does RSSI =1 mean? Is seems like some strange connection state to me.
Yes, you need to call Cellular.RSSI() from a thread either dedicated to only that, or possibly shared with the thread that does the Particle.publish.
The reason is that Cellular.RSSI() needs to access the modem, and if the modem is blocked for another call, the RSSI call will block until the other call completes.
does that also mean, reading the RSSI too often, will block the modem unnecessarily?
I presume, that would also affect my Cellular connection and slow down reconnecting etc.?
It’s probably a good idea to only call it when Cellular.ready() is true, and avoid calling it too often. I might reduce the frequency a little, to a few seconds, at least.
Ok i think, now it´s working.
The following things solved the issue:
System_Mode is Semi automatic and Particle.thread is enabled
I moved all time critical tasks (like modbus communication) into a thread
The RSSI Value is only read every 60 Seconds and before reading Particle.connected() is checked
Before every call of Particle.publish() the cloud connection is checked with Particle.connected()
At first i tought, switching off and on the cellular modem and cloud connection in “system_mode manual” would help, but that created states of blocking everything for a long time.
So i figured out, that “Semi automatic” mode and leaving the cellular modem on and connected worked best for me.
I am working on a project for some state parks to help them monitor parking lot utilization to prevent over-crowding during the pandemic. In testing my system, it seemed that even with System.thread(Enabled), my Electron (3G) was blocking for up to 5 seconds when it connected and reported to Ubidots via WebHook causing me to miss counts. By moving my counts to the ISRs and by implementing your library, I was able to capture all the counts correctly.