ETLAS: E-PAPER DASHBOARD

05 SEPTEMBER 2024

Repurposed the e-reader into something for regular use. News, stocks, weather dashboard. ESP32 NodeMCU D1 + 7.5” Waveshare e-paper + DHT22 sensor.

front back
front

Stocks: Two weeks EOD data from Polygon.io (max possible). Flask app on VPS manages watchlist, relays the feed. Backend: httpd + htpasswd + slowcgi + Flask.

gui_plot_stocks() plots a stepped graph; was easier to implement, but the code is hideous; triggers watchdog. vTaskDelay() prevents that.

NOTE: Refactor. Bresenham’s?

News: Channel NewsAsia RSS. MCU does the parsing. Didn’t plan to have a backend at the time. Now that I have one for stocks, should relay the feed for flexibility.

Weather: DHT22 single-wire protocol. 26µs/50µs/70µs pulses are too fast for standard ESP32 APIs. Bit-banged relative pulse widths (ported from ESP8266):

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[BUFLEN])
{
    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 < BUFLEN; 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;
}

epd_init() stalls intermittently on first refresh() after flash. Toggling delay values in refresh() resolves it. If the first refresh succeeds, it remains stable. Root cause unknown–suspect noisy power supply due to powering display via MCU.

Uptime: August 2024 - January 2026

Commit: a92c86a.