# Split heat pump power consumption by operating mode

**URL:** <https://community.homey.app/t/split-heat-pump-power-consumption-by-operating-mode/155704>\
**Category:** Energy\
**Tags:** energy, homeyscript, virtual-device, advancedflow, homey-energy\
**Created:** [June 3, 2026, 12:42pm UTC](https://community.homey.app/t/split-heat-pump-power-consumption-by-operating-mode/155704 "2026-06-03T12:42:05Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![Kenny\_S](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/kenny_s/32/80323_2.png) [@Kenny\_S](https://community.homey.app/u/Kenny_S)\
**Post date:** [June 3, 2026, 12:42pm UTC](https://community.homey.app/t/split-heat-pump-power-consumption-by-operating-mode/155704/1 "2026-06-03T12:42:05Z")

</div>

Hi all,

I would like to split up the power metering that I currently have running for my heat pump.

At the moment, I have one power meter installed that measures the total power consumption of the heat pump. However, since the heat pump has several operating modes, I would like to see how much energy is consumed per mode.

For example, the total cumulative consumption is **7.5 kWh** , but I would like to split this into something like:

- Cooling: **5.0 kWh**
- Tap water: **2.2 kWh**
- Idle / standby usage: **0.3 kWh**

I already created an **Advanced Virtual Device** for tap water.

 ![image](https://us1.discourse-cdn.com/flex025/uploads/athom/original/3X/c/5/c504e8681bec6edc2d8356d2b5c47bfb2e4f6f8e.png)

In an Advanced Flow, I can use IF cards to check which mode the heat pump is currently running in. But I am not sure what the best next step is after that.

How can I use the current heat pump mode to add the measured energy consumption to the correct virtual device or counter?

Thanks for helping out.

---

<div class="post-metadata">

**Author:** ![Kenny\_S](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/kenny_s/32/80323_2.png) [@Kenny\_S](https://community.homey.app/u/Kenny_S)\
**Post date:** [June 4, 2026, 8:07am UTC](https://community.homey.app/t/split-heat-pump-power-consumption-by-operating-mode/155704/2 "2026-06-04T08:07:49Z")

</div>

I managed to get it working, I created one **Advanced Virtual Device** and within this device 4 Number fields.

 ![image](https://us1.discourse-cdn.com/flex025/uploads/athom/original/3X/c/b/cb4e0773814259ba63a6a6dd07b1a4fb52d1ae67.png)

I also created 6 Variables

 ![image](https://us1.discourse-cdn.com/flex025/uploads/athom/original/3X/5/6/56a78f2633b4f93846cde15873638c965c604eab.png)

Then I (ChatGPT) created a script, and this was a first time right script:

```javascript
// ========================================
// 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.

 ![image](https://us1.discourse-cdn.com/flex025/uploads/athom/original/3X/a/2/a26533fe022bb18ec5ae8a184a8a198f147e72ba.jpeg)

 ![image](https://us1.discourse-cdn.com/flex025/uploads/athom/original/3X/0/b/0bffa64dde53fddc50ed0cd3901e58c6508ec7c1.jpeg)
