@glasshome/sync-layer 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -89,6 +89,12 @@ export interface DemoStatisticBucket {
89
89
  max: number;
90
90
  /** Energy in Wh accumulated over the bucket (W-h integration). */
91
91
  sum: number;
92
+ /**
93
+ * Energy added during this bucket, in kWh, matching HA's `change` field for
94
+ * an energy (kWh) sensor. This is the per-bucket delta (not cumulative), the
95
+ * value daily-total consumers read.
96
+ */
97
+ change: number;
92
98
  }
93
99
  /**
94
100
  * Synthesize statistics buckets for one energy entity across a window.
@@ -160,6 +160,23 @@ function evChargerPower(lt) {
160
160
  const ramp = into < 2 ? into / 2 : 1;
161
161
  return 7200 * ramp;
162
162
  }
163
+ const HEAT_PUMP_PEAK_W = 3200;
164
+ /**
165
+ * A smooth heat-pump load: a slow morning/evening envelope carrying a
166
+ * few-minute shimmer. Its peaks push the home deficit past the battery's power
167
+ * cap, so grid import (and the running cost) visibly rise and fall on live
168
+ * ticks instead of sitting at zero. Gated out of the deep-night window so the
169
+ * quiet 02:00-03:00 baseline is unchanged.
170
+ */
171
+ function heatPumpPower(lt) {
172
+ const h = lt.hourFrac;
173
+ let envelope = 0;
174
+ if (h >= 6 && h <= 9) envelope = Math.sin((h - 6) / 3 * Math.PI);
175
+ else if (h >= 16 && h <= 23) envelope = Math.sin((h - 16) / 7 * Math.PI);
176
+ else return 0;
177
+ const shimmer = .7 + .3 * Math.sin(lt.minuteOfDay * Math.PI * 2);
178
+ return HEAT_PUMP_PEAK_W * envelope * shimmer;
179
+ }
163
180
  /** Smooth occupancy envelope: extra load mornings and evenings. */
164
181
  function occupancyEnvelope(lt) {
165
182
  const h = lt.hourFrac;
@@ -228,7 +245,7 @@ function batterySoc(lt, midnightMs) {
228
245
  return a + (b - a) * frac;
229
246
  }
230
247
  function homePower(lt) {
231
- const base = ALWAYS_ON_W + fridgePower(lt) + kettlePower(lt) + ovenPower(lt) + dishwasherPower(lt) + washerPower(lt) + evChargerPower(lt) + occupancyEnvelope(lt);
248
+ const base = ALWAYS_ON_W + fridgePower(lt) + kettlePower(lt) + ovenPower(lt) + dishwasherPower(lt) + washerPower(lt) + evChargerPower(lt) + heatPumpPower(lt) + occupancyEnvelope(lt);
232
249
  return base * homeNoise(lt);
233
250
  }
234
251
  /**
@@ -416,7 +433,8 @@ function synthesizeEnergyStatistics(entityId, startMs, endMs, period) {
416
433
  mean,
417
434
  min: min === Number.POSITIVE_INFINITY ? mean : min,
418
435
  max: max === Number.NEGATIVE_INFINITY ? mean : max,
419
- sum: cumulativeWh
436
+ sum: cumulativeWh,
437
+ change: energyWh / 1e3
420
438
  });
421
439
  }
422
440
  return buckets;
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { ENERGY_ENTITY_IDS, createDemoFixtures, demoEnergyPreferences, energyEntityValue, formatEnergyState, isEnergyEntity, isSunUp, resetStore, setState, simulateEnergy, state, sunEvents, synthesizeEnergyHistory, synthesizeEnergyStatistics } from "./demo-data-DiGSP4EH.js";
1
+ import { ENERGY_ENTITY_IDS, createDemoFixtures, demoEnergyPreferences, energyEntityValue, formatEnergyState, isEnergyEntity, isSunUp, resetStore, setState, simulateEnergy, state, sunEvents, synthesizeEnergyHistory, synthesizeEnergyStatistics } from "./demo-data-3LO-p1RV.js";
2
2
  import { runHaBridgeWorker } from "./worker-main-DTbzEKor.js";
3
3
  import { createConnection, createLongLivedTokenAuth, getAuth } from "home-assistant-js-websocket";
4
4
  import { produce, reconcile } from "solid-js/store";
@@ -2190,7 +2190,8 @@ const DEMO_HLS_STREAM = "https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8";
2190
2190
  * Returns a public demo HLS stream when not connected.
2191
2191
  */
2192
2192
  async function fetchStream(entityId, format = "hls") {
2193
- if (!state.conn) return format === "hls" ? DEMO_HLS_STREAM : null;
2193
+ if (isDemoMode()) return format === "hls" ? DEMO_HLS_STREAM : null;
2194
+ if (!state.conn) return null;
2194
2195
  const response = await sendCommand({
2195
2196
  type: "camera/stream",
2196
2197
  entity_id: entityId,
@@ -1,4 +1,4 @@
1
- import { createDemoFixtures, state } from "../demo-data-DiGSP4EH.js";
1
+ import { createDemoFixtures, state } from "../demo-data-3LO-p1RV.js";
2
2
 
3
3
  //#region src/testing/mock-behaviors/base.ts
4
4
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glasshome/sync-layer",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "Type-safe, reactive state synchronization layer for Home Assistant",
5
5
  "repository": {
6
6
  "type": "git",