-
Function Timer library now available on platformio
09/29/2024 at 18:31 • 0 comments -
GIT REPO NOW PUBLIC
09/02/2024 at 04:56 • 0 commentsSorry for the oversite, Github makes repository private by default: https://github.com/diyaquanauts/BackcountryBeacon
-
A simple task manager
08/26/2024 at 09:23 • 0 commentsThis project brings in
FunctionTimer
—maybe the simplest task manager ever use for Arduino. It's designed to schedule repetitive tasks effortlessly, and honestly I find myself copying it into most Arduino projects.
Essentially, all this library does is check how much time has elapsed since the last time it ran. If the correct amount of time has run, it runs the function again. We're basically justif ( millis() - last > schedulePeriod){ last = mills(); runFunction(); }
Only now I have a built up class for it! This is the whole class:
class FunctionTimer{ public: void (* func_ptr)(); int update_time; int last; FunctionTimer(void (* _func_ptr)(), int _update_time){ func_ptr = _func_ptr; update_time = _update_time; last = 0; } void service() { if ((millis() - last) > update_time) { func_ptr(); last = millis(); } } };
In our project,
FunctionTimer
helps us keep track of various tasks that need to run at different intervals. Here’s what we’re doing with it:- Turning off the display after a period of inactivity
- Monitoring ISR flags for our user button
- Disconnecting stale server connections
- Parsing GPS data regularly
Here’s how simple it is to implement:
FunctionTimer screenMonitor(checkIfScreenInactive, 10000); FunctionTimer buttonMonitor(buttonHandler, 100); FunctionTimer heapMonitor(logHeap, 10000); FunctionTimer connectionMonitor(&checkForStaleConnections, 1000); FunctionTimer gpsReader(readGPS, 1000); void loop() { connectionMonitor.service(); heapMonitor.service(); gpsReader.service(); buttonMonitor.service(); screenMonitor.service(); vTaskDelay(1); // Yield to the scheduler }
One key point: functions triggered by the timer can block others, potentially delaying critical tasks, especially in Arduino's single-threaded environment. To avoid this, it's essential to ensure that functions are quick and non-blocking.
You can dig deeper into this little helper here: https://github.com/diyaquanauts/BackcountryBeacon/tree/main/firmware/include
-
Resource monitoring with 'express-like' middlewares
08/26/2024 at 08:53 • 0 commentsThis project uses the ESPAsyncWebServer to implement all of its server functions. Its a truly wonderful library and is incredibly powerful.
However, after doing a few years of node + express + react programming, I found myself yearning for express-like middlewares. Rather than have to add redundant logic in each route manually for the webserver, I wanted to be able to declare a 'middleware' that would run for every request. So I created a small library to try it out!
For example, our esp32 server can really only handle one request at a time. Anything more, and the heap seems to leak, or watchdog timers timeout.
We can now create a middleware to send a 503 code if our server resources our low. This also prevents the esp32 from trying to process too many requests at once.CREATE_MIDDLEWARE(monitorResources, { size_t freeHeap = ESP.getFreeHeap(); const size_t criticalHeapThreshold = 170000; if (freeHeap < criticalHeapThreshold) { Serial.printf("Free Heap: %u bytes. Sending 503\n", freeHeap); request->send(503, "text/plain", "Service Unavailable: Low Memory, Please Try Again Later"); return; } next(); });
And then later in our code we can literally:
AsyncWebServer server(80); MiddlewareHandler app(server); ... app.use(monitorResources);
This seems to be working well! And I am pretty happy with it!
However, the library does violoate one my rules for firmware: minimize/eliminate dynamic memory.
If ever there was a time to not get fancy, and just hard code routes, on a tiny microcontroller seems like the time.
You can learn more about the library here: https://github.com/diyaquanauts/BackcountryBeacon/tree/main/firmware/includeBetter yet, suggest a better alternative method!
-
USGS Topo Tile Cache Explorer
08/26/2024 at 08:35 • 0 commentsA big part of the project is determining what map tiles need to be downloaded for any given state.
Computing what tiles are needed is actually rather computationally expensive.
Essentially, we create a bounding box for the geojson polygon that contains the state outline. Then we iterate through through the tiles at the bounding for every zoom level (until zoom level 9) to build the list of required map tiles for the state. After zoom level 9, we assume that every tile below the current calculated tiles need to be included.
You can see and explore the outcome of this process here on the state of Hawaii: https://cache-explorer.netlify.app/
We can really only show to zoom level 12 on the netlify app, as bigger zoom levels make the cache file hundreds of megabytes.
This could be because the required maps are saved in JSON, which is intuitive but not space efficient:{ "12": { "456": [789, 790, 791], "457": [789, 790] }, "13": { "912": [345, 346], "913": [345] } }
You can learn more about this process here:
https://github.com/diyaquanauts/BackcountryBeacon/tree/main/tileDownloader