I managed to get it working, I created one Advanced Virtual Device and within this device 4 Number fields.
I also created 6 Variables
Then I (ChatGPT) created a script, and this was a first time right script:
// ========================================
// Warmtepomp kWh verdelen per modus
// Met automatische dagreset
// Gebruikt cumulatieve kWh-meterstand
// ========================================
// =====================
// INSTELLINGEN
// =====================
// Naam van je Homey-device met de cumulatieve kWh-waarde
const ENERGY_DEVICE_NAME = 'Warmtepomp pm';
// Capability voor cumulatief energieverbruik in kWh
// Meestal is dit 'meter_power'
const ENERGY_CAPABILITY = 'meter_power';
// Tijdzone voor dagreset
const TIME_ZONE = 'Europe/Amsterdam';
// Logic variabele waarin de huidige modus staat
const MODE_VARIABLE_NAME = 'HP Modus';
// Logic variabele waarin we de vorige totaalstand bewaren
const PREVIOUS_TOTAL_VARIABLE_NAME = 'HP Vorige totaal kWh';
// Logic tekstvariabele waarin we bijhouden wanneer de laatste dagreset was
const LAST_RESET_DATE_VARIABLE_NAME = 'HP Laatste reset datum';
// Logic variabelen waarin we de kWh per modus optellen
const TARGET_VARIABLES = {
verwarmen: 'HP kWh Verwarmen',
koelen: 'HP kWh Koelen',
warmwater: 'HP kWh Warmwater',
standby: 'HP kWh Standby',
};
// Beveiliging tegen rare sprongen.
// Als je script elke minuut draait, is 5 kWh per run extreem hoog.
const MAX_DELTA_KWH = 5;
// =====================
// HULPFUNCTIES
// =====================
async function getDeviceByName(deviceName) {
const devices = await Homey.devices.getDevices();
for (const device of Object.values(devices)) {
if (device.name === deviceName) {
return device;
}
}
throw new Error(`Device niet gevonden: ${deviceName}`);
}
async function getLogicVariableByName(variableName) {
const variables = await Homey.logic.getVariables();
for (const variable of Object.values(variables)) {
if (variable.name === variableName) {
return variable;
}
}
throw new Error(`Logic variabele niet gevonden: ${variableName}`);
}
async function getLogicValue(variableName) {
const variable = await getLogicVariableByName(variableName);
return variable.value;
}
async function setLogicValue(variableName, value) {
const variable = await getLogicVariableByName(variableName);
await Homey.logic.updateVariable({
id: variable.id,
variable: {
value: value,
},
});
}
function normalizeMode(value) {
if (value === null || value === undefined) {
return 'standby';
}
const mode = String(value).toLowerCase().trim();
if (mode === 'verwarmen' || mode === 'heating' || mode === 'heat') {
return 'verwarmen';
}
if (mode === 'koelen' || mode === 'cooling' || mode === 'cool') {
return 'koelen';
}
if (
mode === 'warmwater' ||
mode === 'tapwater' ||
mode === 'tap water' ||
mode === 'dhw'
) {
return 'warmwater';
}
if (mode === 'standby' || mode === 'stand-by' || mode === 'idle') {
return 'standby';
}
return 'standby';
}
function round(value, decimals) {
const factor = Math.pow(10, decimals);
return Math.round(value * factor) / factor;
}
function getTodayDateKey() {
const parts = new Intl.DateTimeFormat('nl-NL', {
timeZone: TIME_ZONE,
year: 'numeric',
month: '2-digit',
day: '2-digit',
}).formatToParts(new Date());
const year = parts.find(part => part.type === 'year').value;
const month = parts.find(part => part.type === 'month').value;
const day = parts.find(part => part.type === 'day').value;
return `${year}-${month}-${day}`;
}
async function resetDailyCounters() {
for (const variableName of Object.values(TARGET_VARIABLES)) {
await setLogicValue(variableName, 0);
}
}
// =====================
// HOOFDSCRIPT
// =====================
// 1. Lees huidige totaalstand van de warmtepomp
const energyDevice = await getDeviceByName(ENERGY_DEVICE_NAME);
if (!energyDevice.capabilitiesObj[ENERGY_CAPABILITY]) {
throw new Error(
`Capability '${ENERGY_CAPABILITY}' niet gevonden op device '${ENERGY_DEVICE_NAME}'.`
);
}
const currentTotalRaw = energyDevice.capabilitiesObj[ENERGY_CAPABILITY].value;
const currentTotalKwh = Number(currentTotalRaw);
if (isNaN(currentTotalKwh)) {
throw new Error(`Ongeldige totaalstand: ${currentTotalRaw}`);
}
// 2. Lees vorige totaalstand
const previousTotalRaw = await getLogicValue(PREVIOUS_TOTAL_VARIABLE_NAME);
const previousTotalKwh = Number(previousTotalRaw);
// 3. Vandaag bepalen
const todayDateKey = getTodayDateKey();
let lastResetDateRaw = await getLogicValue(LAST_RESET_DATE_VARIABLE_NAME);
let lastResetDate = '';
if (lastResetDateRaw !== null && lastResetDateRaw !== undefined) {
lastResetDate = String(lastResetDateRaw).trim();
}
// 4. Eerste run herkennen
if (!previousTotalKwh || previousTotalKwh <= 0 || isNaN(previousTotalKwh)) {
await setLogicValue(PREVIOUS_TOTAL_VARIABLE_NAME, currentTotalKwh);
await setLogicValue(LAST_RESET_DATE_VARIABLE_NAME, todayDateKey);
log('Eerste run of vorige totaalstand was leeg.');
log(`Huidige totaalstand opgeslagen: ${currentTotalKwh} kWh`);
log(`Resetdatum opgeslagen: ${todayDateKey}`);
log('Er is nog niets geboekt.');
return {
status: 'first_run',
currentTotalKwh: currentTotalKwh,
resetDate: todayDateKey,
};
}
// 5. Als resetdatum nog leeg is, alleen vullen en verder normaal doorgaan
if (!lastResetDate) {
await setLogicValue(LAST_RESET_DATE_VARIABLE_NAME, todayDateKey);
lastResetDate = todayDateKey;
log(`Resetdatum was leeg en is gezet naar: ${todayDateKey}`);
}
// 6. Automatische dagreset
if (lastResetDate !== todayDateKey) {
await resetDailyCounters();
// Belangrijk:
// vorige totaalstand gelijkzetten aan huidige fysieke meterstand
// zodat de nieuwe dag vanaf deze stand begint.
await setLogicValue(PREVIOUS_TOTAL_VARIABLE_NAME, currentTotalKwh);
await setLogicValue(LAST_RESET_DATE_VARIABLE_NAME, todayDateKey);
log('Dagreset uitgevoerd.');
log(`Vorige resetdatum: ${lastResetDate}`);
log(`Nieuwe resetdatum: ${todayDateKey}`);
log(`Nieuwe startstand: ${currentTotalKwh} kWh`);
log('Alle dagtellers zijn op 0 gezet.');
return {
status: 'daily_reset',
previousResetDate: lastResetDate,
newResetDate: todayDateKey,
newStartTotalKwh: currentTotalKwh,
};
}
// 7. Bereken verschil sinds vorige run
let deltaKwh = currentTotalKwh - previousTotalKwh;
// 8. Bescherming tegen meter-reset of negatieve waarde
if (deltaKwh < 0) {
await setLogicValue(PREVIOUS_TOTAL_VARIABLE_NAME, currentTotalKwh);
log('Waarschuwing: totaalstand is lager dan vorige totaalstand.');
log(`Vorige totaalstand: ${previousTotalKwh} kWh`);
log(`Huidige totaalstand: ${currentTotalKwh} kWh`);
log('Waarschijnlijk meter-reset. Er is niets geboekt.');
return {
status: 'meter_reset_detected',
previousTotalKwh: previousTotalKwh,
currentTotalKwh: currentTotalKwh,
};
}
// 9. Bescherming tegen onrealistisch grote sprong
if (deltaKwh > MAX_DELTA_KWH) {
await setLogicValue(PREVIOUS_TOTAL_VARIABLE_NAME, currentTotalKwh);
log('Waarschuwing: onrealistisch grote kWh-sprong.');
log(`Delta: ${deltaKwh} kWh`);
log('Er is niets geboekt om foutieve telling te voorkomen.');
return {
status: 'delta_too_large',
previousTotalKwh: previousTotalKwh,
currentTotalKwh: currentTotalKwh,
deltaKwh: deltaKwh,
};
}
// 10. Als er geen nieuw verbruik is, alleen vorige stand bijwerken
if (deltaKwh === 0) {
await setLogicValue(PREVIOUS_TOTAL_VARIABLE_NAME, currentTotalKwh);
log('Geen nieuw verbruik sinds vorige run.');
log(`Totaalstand: ${currentTotalKwh} kWh`);
return {
status: 'no_delta',
currentTotalKwh: currentTotalKwh,
resetDate: todayDateKey,
};
}
// 11. Lees huidige modus
const rawMode = await getLogicValue(MODE_VARIABLE_NAME);
const mode = normalizeMode(rawMode);
if (!TARGET_VARIABLES[mode]) {
throw new Error(`Geen doelvariabele gevonden voor modus: ${mode}`);
}
// 12. Tel delta op bij juiste teller
const targetVariableName = TARGET_VARIABLES[mode];
const currentModeTotalRaw = await getLogicValue(targetVariableName);
const currentModeTotal = Number(currentModeTotalRaw) || 0;
const newModeTotal = currentModeTotal + deltaKwh;
const newModeTotalRounded = round(newModeTotal, 3);
await setLogicValue(targetVariableName, newModeTotalRounded);
// 13. Sla huidige totaalstand op als vorige totaalstand
await setLogicValue(PREVIOUS_TOTAL_VARIABLE_NAME, currentTotalKwh);
// 14. Log resultaat
log(`Modus: ${mode}`);
log(`Vorige totaalstand: ${previousTotalKwh} kWh`);
log(`Huidige totaalstand: ${currentTotalKwh} kWh`);
log(`Delta: ${round(deltaKwh, 4)} kWh`);
log(`${targetVariableName}: ${newModeTotalRounded} kWh`);
log(`Resetdatum: ${todayDateKey}`);
return {
status: 'ok',
mode: mode,
previousTotalKwh: previousTotalKwh,
currentTotalKwh: currentTotalKwh,
deltaKwh: round(deltaKwh, 4),
targetVariableName: targetVariableName,
newModeTotal: newModeTotalRounded,
resetDate: todayDateKey,
};
In short:
- The physical kWh meter remains cumulative.
- The script calculates the delta since the previous run.
- The delta is assigned to the currently active mode.
- The mode is stored in a Logic variable.
- The script runs every minute and also when the mode changes.
- The daily mode counters are reset automatically once per day.
New question I have, is there a way to show all 4 PM’s in the Energy tab? Now it shows the Main device, and by clicking on this device is shows the 4 PM’s. I expected to see the 4 PM’s separate in the Energy tab.