ETLAS: E-PAPER DASHBOARD

05 SEPTEMBER 2024

Repurposed e-reader prototype 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 prices from Polygon.io (max possible). Flask app on VPS relays feed; manages watchlist. Backend: httpd + htpasswd + FastCGI + Flask.

gui_plot_stocks() triggers watchdog; vTaskDelay() required. Stepped graph was easier to implement (under memory constraints), but the logic is hideous. Note to self: Refactor with Bresenham’s?

News: Channel NewsAsia RSS. MCU parses XML directly. Character glyphs stored as bitmaps in header files.

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;
}

Ghost in the machine: epd_init() stalls intermittently on first refresh() after flash. Toggling delay values in refresh() resolves it. If first refresh succeeds, it remains stable. Root cause unknown–suspected power supply issues from powering display via MCU.

Uptime: August 2024 - January 2026

Commit: a92c86a