New e-paper display non-DIY with Homey integration

New SenseCraft HMI release v1.2.0 (=screen designer for Seeed e-paper displays) and firmware v1.0.8: release notes.
Short: More templates, more third-party data integrations, more out-of-the-box logic, inproved api connections (not every Homey field has to be defined with a separate api connection, but still room for improvements).

In the meantime, there are several new template integrations (which I haven’t tried myself), such as Google Calendar:

List with more templates/integrations.

New article about these e-paper displays on Dutch tech site Tweakers.

1 Like

The latest version of the SenseCraft HMI screen designer allows you to send data from Homey to the e-paper screen. This version also includes many new features (release notes here) for creating screens.

I created a Homey script that collects all data needed from various devices. With a single POST command, all the data is available as fields in the screen designer.

It’s even possible to generate a chart (I use the free and fast Quickchart generator in Homey script) and send the resulting URL to the screen. The chart below isn’t a Power-by-the-Hour energy prices chart (that didn’t look nice on the screen), but was generated with Quickchart.

2 Likes

Hi Amersfoort, good work! Can you share your posting homey script?

This Homey script gets all data needed for the 2 Seeed SenseCraft HMI screens below (except the graph).

const url = 'https://sensecraft-hmi-api.seeed.cc/api/v1/user/device/push_data';
const apiKey = 'xxxxxxxxxx'; //fill Seeed api key

//function: get capability from device
const getVal = (dev, cap, unit = "", decimals = 1) => {
    try {
        if (!dev) return "N/B";
        const val = dev.makeCapabilityInstance(cap).value;
        if (val === null || val === undefined) return "N/B";
        
        if (typeof val === 'number') {
            return val.toFixed(decimals).replace('.', ',') + (unit ? ` ${unit}` : "");
        }
        return val + (unit ? ` ${unit}` : "");
    } catch (e) {
        return "N/B";
    }
};

// 1. Get base data Homey
const devices = await Homey.devices.getDevices({ $skipCache: true });
const rawVariables = await Homey.logic.getVariables();
const variablesArray = Object.values(rawVariables);
const allDevs = Object.values(devices);

// 2. Helper for variables (Logic)
const getVar = (name) => {
    const v = variablesArray.find(v => v.name === name);
    return v ? v.value : null;
};

// 3. Get devices based on name
const d = {
    hw: allDevs.find(i => i.name === 'Elektra en Gas'),
    water: allDevs.find(i => i.name === 'Water'),
    enphase: allDevs.find(i => i.name === 'Enphase VD'),
    zonneplan: allDevs.find(i => i.name === 'Zonneplan p1'),
    shelly: allDevs.find(i => i.name === 'Shelly HT Gen3'),
    knmi: allDevs.find(i => i.name === 'KNMI'),
    weer: allDevs.find(i => i.name === 'Weerstation'),
    regen: allDevs.find(i => i.name === 'Regenmeter'),
    prijzen: allDevs.find(i => i.name === 'Elektra dagprijzen')
};

// 4. Build data object for Seeed HMI
const data = {
    // --- ELEKTRA ---
    ElektraVermogenNu: getVal(d.hw, 'measure_power', 'W', 0),
    ElektraVerbruikVandaag: getVal(d.hw, 'meter_power.daily', 'kWh', 1),
    ElektraSolarNu: getVal(d.enphase, 'measure_power', 'W', 0),
    ElektraSolarVandaag: getVal(d.enphase, 'meter_power', 'kWh', 1),
    ElektraTerugleveringVandaag: getVal(d.zonneplan, 'meter_power.daily_production', 'kWh', 1),
    ElektraKostenVandaag: "€ " + getVal(d.zonneplan, 'meter_power.daily_cost', '', 2),
    
    // --- GAS & WATER ---
    GasVerbruikNu: getVal(d.hw, 'measure_gas', 'm3', 1),
    GasVandaag: getVal(d.zonneplan, 'meter_gas.daily', 'm3', 1),
    GasKostenVandaag: "€ " + getVal(d.zonneplan, 'meter_gas.daily_price', '', 2),
    
    // Water convert m3 to liter
    WaterVandaag: (() => {
        try {
            const m3 = d.water.makeCapabilityInstance('meter_water.daily').value;
            return (m3 * 1000).toFixed(0).replace('.', ',') + " L";
        } catch (e) { return "0 L"; }
    })(),

    // --- WEER BINNEN ---
    WeerTempHuiskamer: getVal(d.shelly, 'measure_temperature', '°C', 1),
    WeerLuchtvochtigheidHuiskamer: getVal(d.shelly, 'measure_humidity', '%', 1),

    // --- WEER BUITEN ---
    WeerTempBuiten: getVal(d.weer, 'measure_temperature', '°C', 1),
    WeerGevoelstemp: getVal(d.weer, 'measure_temperature.feelsLike', '°C', 1),
    WeerstationTempMin: (getVar("Minimum temperatuur") || 0).toFixed(1).replace('.', ',') + " °C",
    WeerstationTempMax: (getVar("Maximum temperatuur") || 0).toFixed(1).replace('.', ',') + " °C",
    
    // KNMI & Omgevingssensoren
    WeerZonOp: getVal(d.knmi, 'sun_up'),
    WeerZonOnder: getVal(d.knmi, 'sun_down'),
    WeerNuOmschrijving: getVal(d.knmi, 'recap'),
    WeerVerwachting: getVal(d.knmi, 'expected'),
    WeerRegenNu: "nu: " + getVal(d.regen, 'measure_rain.rate', 'mm/u', 1),
    WeerRegenVandaag: getVal(d.regen, 'measure_rain.daily', 'mm', 1),
    WeerLuchtvochtigheid: getVal(d.weer, 'measure_humidity', '%', 0),
    WeerKNMIVerwachtingMinTemp: getVal(d.knmi, 'expected_today_min_temp', '°C', 0),
    WeerKNMIVerwachtingMaxTemp: getVal(d.knmi, 'expected_today_max_temp', '°C', 0),
    WeerWindSnelheid: getVal(d.weer, 'measure_wind_strength', 'km/u', 0),
    WeerWindRichting: getVal(d.weer, 'measure_wind_direction'),
    WeerLuchtdruk: getVal(d.weer, 'measure_pressure', 'hPa', 0),
    WeerZonKans: getVal(d.knmi, 'expected_today_sunshine', '%', 0),
    WeerZonUV: getVal(d.weer, 'measure_ultraviolet', 'UVI', 0),
    WeerZonLux: getVal(d.weer, 'measure_luminance', 'lx', 0),

    // URLs
    ElektraprijzenUrl: getVar("StroomGrafiekURL") || ""
};

// 5. Get energy prices per hour (8 hours)
const huidigeTijd = new Date();
const startUur = huidigeTijd.getHours();

for (let i = 0; i <= 7; i++) {
    const uur = (startUur + i) % 24;
    const prijs = getVal(d.prijzen, 'meter_price_h' + i, '', 3);
    data[`ElektraPrijsTijd${i}`] = `${uur} uur: € ${prijs}`;
}

// 6. Generate update time
data.DatumTijd = "weerupdate: " + huidigeTijd.toLocaleDateString('nl-NL', {
    weekday: 'long', day: 'numeric', month: 'long', hour: '2-digit', minute: '2-digit'
}).replace(',', '') + " uur";

// 7. Send data to Seeed API
try {
    const response = await fetch(url, {
        method: 'POST',
        headers: { 
            'Content-Type': 'application/json', 
            'api-key': apiKey 
        },
        body: JSON.stringify({ 
            device_id: xxxxxxx, //fill in Seeed device id
            data: data 
        })
    });

    if (!response.ok) {
        const errText = await response.text();
        throw new Error(`HTTP ${response.status}: ${errText}`);
    }
    
    log('Succes: Data verzonden naar Seeed HMI');
    return true;
} catch (err) {
    console.error('Script error:', err.message);
    return false;
}