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.

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.

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

Thank you for the Homeyscript.

I just got my reTerminal and Homey and got some questions since I’m a real newbie.

I copied (and updated based on my API-key and device id) your Homeyscript but I dont understand what I have to do in Sensecraft hmi? Is there a base template to use or can you provide more information about that part?

Steps for Homey integration in HMI using a Homey script:

  • execute script on Homey (I do this every hour with an advanced flow)
  • go to SenseCraft HMI and create a new page
  • go to the menu Data and select “Push to SenseCraft”
  • push the button “Test & Load Fields”
  • when the Homey script went well, you will see on the right of this screen all Homey fields selected in the script
  • select one or more of these fields, and push the button Confirm
  • now the values will be visible on the page.

Thank you so much, it worked like a charm!