I see this is an old thread, but thought I'd chime in.
For an example implementation of a finite state machine, there are libraries built for this or you can use simple loop timers with if statements to "poll" sections of code instead of using ANY delays. Delays stop execution and waste your MCU time, preventing it from doing anything else, as already mentioned. Checking for wifi or serial messages can then execute with higher priority. An example pseudo-code would look like:
int update_ms = 500;
int last_update_ms;
setup{
last_update_ms = millis(); // or 0, to execute immediately
}
loop{
if(millis() - last_update_ms >= update_ms){
last_update_ms = millis();
execute_thing();}
check_for_wifi_msg();
}
There are libraries that do this essential behavior for you with more eloquence, as well, such as PollingTimer. I'm often surprised this isn't given as tool early on when people learn Arduino/ MCU programming, or in example codes. It is easy and so powerful.
You could accomplish the same "finite state machine" functionality with a real-time operating system built for microcontrollers. I can recommend FreeRTOS as a user-friendly entry to this. This makes your single core machine work like a multi-core machine, with a task scheduler. You can define several continually running while loops that the RTOS thread handler then interleaves for consistent execution. You could have 1 thread for your RF and 1 thread for your WiFi, with set execution rates, and RTOS handles the rest, e.g. it will try to fit RF reads inside of the Wifi loop whenever it can find downtime. This will likely make your Wifi loop somewhat longer as a sacrifice.
You can get started with these:
FreeRTOS Kernel Quick Start Guide
The FreeRTOS Reference Manual
Other solutions, which I won't elaborate on here include using a multi-core chip, like a ESP32, or to make use of WiFi interrupts to break out of other execution. Though, I do not know if this is specifically supported on the nRF24L01+.