diff options
Diffstat (limited to '_site/projects/etlas/index.html')
| -rw-r--r-- | _site/projects/etlas/index.html | 160 |
1 files changed, 89 insertions, 71 deletions
diff --git a/_site/projects/etlas/index.html b/_site/projects/etlas/index.html index 6b2906b..ae30cb6 100644 --- a/_site/projects/etlas/index.html +++ b/_site/projects/etlas/index.html @@ -44,7 +44,9 @@ <h2 class="center" id="title">ETLAS: E-PAPER DASHBOARD</h2> <h6 class="center">05 SEPTEMBER 2024</h5> <br> - <div class="twocol justify"><p>Etlas is a weather, news, and stock price tracking system.</p> + <div class="twocol justify"><p>Etlas is a news, stock market, and weather tracker powered by an ESP32 NodeMCU +D1, featuring a 7.5-inch <a href="https://www.waveshare.com/" class="external" target="_blank" rel="noopener noreferrer">Waveshare</a> e-paper display and a +DHT22 sensor module.</p> <table style="border: none;"> <tr style="border: none;"> @@ -53,80 +55,96 @@ </tr> </table> -<h2 id="acknowledgements">Acknowledgements</h2> +<p>The top-left panel shows two weeks of end-of-day prices—the maximum the ESP32’s +SRAM can hold—from the Polygon.io API. The price feed is relayed through a +FastCGI-wrapped Flask app hosted on a VPS. This lets me configure stock symbols +in its application settings. The app cycles through them as requests come in +from the ESP32. Running the Flask app as a FastCGI process while exposing it +via httpd with htpasswd authentication keeps the server code simple and secure.</p> -<p>The e-paper display driver in the epd.c file of the project is derived from <a href="https://github.com/waveshareteam/e-Paper" class="external" target="_blank" rel="noopener noreferrer">Waveshare examples</a> for Arduino -and STM32 platforms.</p> - -<p>The exceptionally elegant algorithm in the file dht.c, which reads DHT22 sensor -data by comparing consecutive pulses, I ported directly from <a href="https://github.com/Fonger/ESP8266-RTOS-DHT" class="external" target="_blank" rel="noopener noreferrer">this</a> implementation for ESP8266 -modules to my ESP32. All credit for the algorithm belongs to them.</p> - -<h2 id="overview">Overview</h2> - -<p>Etlas comprises an embedded system featuring an ESP32 NodeMCU D1 -microcontroller, a 7.5″ <a href="https://www.waveshare.com/" class="external" target="_blank" rel="noopener noreferrer">Waveshare</a> e-paper display, a -DHT22 weather sensor, and a server backend consisting of a FastCGI-wrapped -Flask app. The following diagram outlines this system architecture.</p> +<p>The following diagram outlines the Etlas’s overall system architecture.</p> <p><img src="etlas_arch.png" alt="architecture" /></p> -<p>The embedded application, written in C with the help of the ESP-IDF v5.2.1, -connects to a (2.4GHz) WiFi network at startup and obtains time from an NTP -server. It then composites and updates an internal pixel buffer using data -acquired from various data sources and renders to the screen by writing to its -Serial Peripheral Interface.</p> - -<h2 id="price-curves">Price curves</h2> - -<p>On the e-paper display, the top-left panel displays end-of-day price curves -over two weeks from the <a href="https://polygon.io/" class="external" target="_blank" rel="noopener noreferrer">Polygon.io</a> API. The -microcontroller’s 512KB SRAM limits the price curves to two weeks. Instead of -using raster images for complex graphics—like e-paper projects often do—Etlas -computes the price curves from CSV data on the fly using the ESP32’s 160MHz -microprocessor. To avoid the overhead of floating-point arithmetic, all -computations are performed on integers. The <code class="language-plaintext highlighter-rouge">gui_plot_stocks()</code> function in the -gui.c file contains the rendering logic.</p> - -<p>Proxying the price feeds through the Flask app permits me to configure the -tickers I’m interested in via its application settings. The Flask app cycles -through the tickers in its configuration file as it receives requests from the -embedded software. The Flask app is secured with basic authentication -implemented using htpasswd and OpenBSD’s httpd web server. This FastCGI-wrapped -architecture dramatically reduces the complexity of the server code and -increases system reliability.</p> - -<h2 id="news-feed">News feed</h2> - -<p>The more prominent panel on the right displays news from <a href="https://www.channelnewsasia.com/" class="external" target="_blank" rel="noopener noreferrer">Channel News Asia</a>. The embedded program downloads -and parses the RSS feed before rendering it to the display. The character -glyphs used for rendering news are stored in header files in the sprites -directory as bitmaps. I created the glyphs manually by saving them as images in -GIMP and rasterizing them with ImageMagick.</p> - -<p>I connected the embedded system directly to the RSS feed to write less server -code (the focus of this project was the embedded system). In hindsight, -however, it limits the feeds from which Etlas can receive data. In a future -version, I will relay the RSS feed through the backend (like the stock prices) -to make it more flexible.</p> - -<h2 id="weather-data">Weather data</h2> - -<p>The bottom panels (middle and right) display the temperature and relative -humidity from a DHT22 sensor. The DHT22 driver, arguably the most interesting -part of the software, reads real-time sensor data by comparing relative pulse -widths. The pulses themselves are too quick for the ESP32 to reliably measure -directly.</p> - -<p>Much of the heavy lifting of acquiring, interpreting, and rendering data from -different data sources is performed on the microcontroller using less than 512 -KB of memory. The embedded software that makes that possible is written in C -using the ESP-IDF v5.2.1. My e-paper display driver is a port of Waveshare <a href="https://github.com/waveshareteam/e-Paper" class="external" target="_blank" rel="noopener noreferrer">examples</a> for Arduino -and STM32 platforms.</p> - -<p>I’ve been using Etlas daily (for a couple of hours on weekdays and all day on -weekends) since August 2024. As of October 2025, it’s been running reliably for -over a year.</p> +<p>The more prominent panel on the right of the display shows local and world news +from Channel NewsAsia. The MCU downloads and parses XML data from the RSS feed +directly before rendering it to the display. The character glyphs used are +stored as bitmaps in the sprites directory. I skipped the proxy for news to +avoid writing more server code, but in hindsight it limits the feeds Etlas can +handle. I will fix this in a future version.</p> + +<p>The middle and bottom right panels display the temperature and relative +humidity from the DHT22 sensor. The DHT22 uses pulse-width modulation to +transmit data to the host. The 26µs, 50µs, and 70µs pulses are too fast for the +ESP32 to measure reliably with standard APIs. Instead, the driver compares +relative pulse widths to differentiate zeros from ones:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>static inline int dht_await_pin_state(int state, int timeout) +{ + int t; + static const uint16_t delta = 1; + + for (t = 0; t < timeout; t += delta) { + ets_delay_us(delta); + if (gpio_get_level(DHT_PIN) == state) + return t; + } + return 0; +} + +static inline int dht_get_raw_data(unsigned char buf[DHT_DATA_LEN]) +{ + int rc; + unsigned char i, pwl, pwh; + + gpio_set_level(DHT_PIN, 0); + ets_delay_us(1100); + gpio_set_level(DHT_PIN, 1); + + if (!dht_await_pin_state(0, 40)) { + rc = 1; + xQueueSend(dht_evt_queue, &rc, (TickType_t) 0); + return 0; + } + if (!dht_await_pin_state(1, 80)) { + rc = 2; + xQueueSend(dht_evt_queue, &rc, (TickType_t) 0); + return 0; + } + if (!dht_await_pin_state(0, 80)) { + rc = 3; + xQueueSend(dht_evt_queue, &rc, (TickType_t) 0); + return 0; + } + + for (i = 0; i < DHT_DATA_LEN; i++) { + if (!(pwl = dht_await_pin_state(1, 50))) { + rc = 4; + xQueueSend(dht_evt_queue, &rc, (TickType_t) 0); + return 0; + } + if (!(pwh = dht_await_pin_state(0, 70))) { + rc = 5; + xQueueSend(dht_evt_queue, &rc, (TickType_t) 0); + return 0; + } + buf[i] = pwh > pwl; + } + return 1; +} +</code></pre></div></div> + +<p>I ported <a href="https://github.com/Fonger/ESP8266-RTOS-DHT" class="external" target="_blank" rel="noopener noreferrer">this</a> implementation from ESP8266 +to ESP32—all credit for the algorithm belongs to them.</p> + +<p>Etlas is a networked embedded system. All acquisition, processing, and +rendering of data are performed on the ESP32’s 160MHz microprocessor using less +than 512KB of SRAM. The embedded software that makes this possible is written +in C using ESP-IDF v5.2.1. The e-paper display driver is derived from Waveshare +<a href="https://github.com/waveshareteam/e-Paper" class="external" target="_blank" rel="noopener noreferrer">examples</a> for Arduino and STM32 +platforms.</p> + +<p>Etlas has been running reliably for over a year since August 2024.</p> <p>Files: <a href="source.tar.gz">source.tar.gz</a></p> </div> |
