Skip to content

epaper29.tc

EPaper 2.9" Display Controller & Data Logger

Source on GitHub

// EPaper 2.9" Display Controller & Data Logger
// Sensors + EPaper display + 24h logging + WebChart + UDP globals

// 24h data logging arrays (96 x 15-min intervals)
// Index 0 = ring buffer position pointer, 1-96 = data
persist float aco2[97];
persist float atvc[97];
persist float tmpa[97];
persist float axhum[97];

// Sensor readings — shared via UDP (auto-send on assignment)
global float wtemp = 0.0;
global float whumi = 0.0;
global float wtvoc = 0.0;
global float wco2 = 0.0;

// Local sensor readings (not shared)
float eco2 = 0;
float ahum = 0.0;

// Received via UDP from other devices
global float bpress = 0.0;
global float sedc = 0.0;
global float wrga = 0.0;
global float wrgh = 0.0;
global float wrgg = 0.0;
global float atmp = 0.0;
global float pwl = 0.0;

// Averaging accumulators
float tmps = 0.0;
float hums = 0.0;
float tvcs = 0.0;
float co2s = 0.0;
int mcnt = 0;

// State
int last_m15 = -1;
int cnt = 0;

char dt[128];
char lbl[32];

void read_sensors() {
    wtemp = sensorGet("BME280#Temperature");
    whumi = sensorGet("BME280#Humidity");
    bpress = sensorGet("BME280#Pressure");
    wtvoc = sensorGet("SGP30#TVOC");
    eco2 = sensorGet("SGP30#eCO2");
    ahum = sensorGet("BME280#AbsHumidity");
    wco2 = sensorGet("SCD30#CarbonDioxide");
}

void update_display() {
    // Row 1: Temperature, Humidity, Pressure, Time
    sprintf(dt, "[f1p7x0y5]%.1f C", wtemp);
    dspText(dt);
    sprintf(dt, "[p7x70y5]%.1f %% [x250y5t] ", whumi);
    dspText(dt);
    //dspText("[x250y5t]");
    sprintf(dt, "[p11x140y5]%.1f hPa", bpress);
    dspText(dt);

    // Row 2: TVOC, eCO2, Abs Humidity
    sprintf(dt, "[p18x30y25]TVOC: %.1f ppb", wtvoc);
    dspText(dt);
    sprintf(dt, "[p18x160y25]eCO2: %.1f ppm", eco2);
    dspText(dt);
    sprintf(dt, "[p18c26l5]ahum: %.1f g^m3", ahum);
    dspText(dt);

    // solar inverters
    sprintf(dt, "[p25c1l5]WR 1 (Dach)  : %.1f W", sedc);
    dspText(dt);
    sprintf(dt, "[p25c1l6]WR 2 (Garage): %.1f W", -wrga);
    dspText(dt);
    sprintf(dt, "[p25c1l7]WR 3 (G-Haus): %.1f W", -wrgh);
    dspText(dt);
    sprintf(dt, "[p25c1l8]WR 4 (Garten): %.1f W", -wrgg);
    dspText(dt);

    // CO2
    sprintf(dt, "[p25c1l10]CO2          : %.0f ppm", wco2);
    dspText(dt);

    sprintf(dt, "[x170y95r120:30f2p6x185y100] %.0f %", pwl);
    dspText(dt);

    sprintf(dt, "[f0s2p10x210y70] %.0f C", atmp);
    dspText(dt);


    // Flush to EPaper
    dspText("[d]");
}

void EverySecond() {
    read_sensors();
    cnt = cnt + 1;

    // Accumulate for averaging
    tmps = tmps + wtemp;
    hums = hums + whumi;
    tvcs = tvcs + wtvoc;
    co2s = co2s + wco2;
    mcnt = mcnt + 1;

    // 15-minute data logging
    int m15 = (tasm_hour * 60 + tasm_minute) / 15 + 1;
    if (m15 != last_m15 && last_m15 > 0) {
        if (mcnt > 0) {
            aco2[last_m15] = co2s / (float)mcnt;
            atvc[last_m15] = tvcs / (float)mcnt;
            tmpa[last_m15] = tmps / (float)mcnt;
            axhum[last_m15] = hums / (float)mcnt;
            saveVars();
        }
        mcnt = 0;
        co2s = 0.0;
        tvcs = 0.0;
        tmps = 0.0;
        hums = 0.0;
    }
    last_m15 = m15;

    // Sync graph position with time
    int pos = m15;
    if (pos >= 96) {
        pos = 0;
    }

    // Update display every 10 seconds
    int ups = tasm_uptime;
    if (ups % 10 == 0) {
        update_display();
    }

    // EPaper refresh every 5 min (prevent ghosting)
    if (ups % 300 == 0) {
        dspText("[Id]");
        dspText("[id]");
    }

    // Sensor readings auto-send via UDP on assignment (global float)
}

void web_label(int idx) {
    LGetString(idx, lbl);
    dt = "{s}";
    dt += lbl;
    dt += "{m}";
    webSend(dt);
}

void WebCall() {
    web_label(0);
    sprintf(dt, "%.1f C{e}", wtemp);
    webSend(dt);
    web_label(1);
    sprintf(dt, "%.1f %{e}", whumi);
    webSend(dt);
    web_label(20);
    sprintf(dt, "%.1f g/m3{e}", ahum);
    webSend(dt);
    web_label(4);
    sprintf(dt, "%.0f ppm{e}", wco2);
    webSend(dt);
    web_label(2);
    sprintf(dt, "%.1f hPa{e}", bpress);
    webSend(dt);
    sprintf(dt, "{s}Heap{m}%d kb{e}", tasm_heap/1024);
    webSend(dt);
}

void WebPage() {
    WebChartSize(640, 200);
    // Dual Y-axis: TVOC (left 0-3000 ppb) + CO2 (right 0-2000 ppm)
    WebChart(0, "Air Quality", "TVOC|ppb", 0xFF0000, atvc[0], 96, atvc, 0, 15, 0.0, 3000.0);
    WebChart(0, "", "CO2|ppm", 0x0000FF, aco2[0], 96, aco2, 0, 15, 0.0, 2000.0);
    // Dual Y-axis: Humidity (left 0-100 %) + Temperature (right 0-40 C)
    WebChart(0, "Climate", "Humidity|%", 0xFF0000, axhum[0], 96, axhum, 1, 15, 0.0, 100.0);
    WebChart(0, "", "Temperature|C", 0x0000FF, tmpa[0], 96, tmpa, 1, 15, 0.0, 40.0);
}

int main() {
    // Initial display setup: clear, draw separator lines
    dspText("[zD0]");
    dspText("[x0y20h296x0y40h296]");
    dspText("[d]");

    // Set initial time slot
    last_m15 = (tasm_hour * 60 + tasm_minute) / 15 + 1;

    print("EPaper display started\n");
    return 0;
}