@glasshome/sync-layer 0.9.1 → 0.10.0
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.
- package/dist/demo/ids.d.ts +5 -0
- package/dist/demo/ids.js +361 -0
- package/dist/index.d.ts +32 -52
- package/dist/index.js +101 -73
- package/dist/solid/index.js +1 -1
- package/dist/track-BAfgOjMk.js +4957 -0
- package/package.json +7 -1
- package/dist/track-IkwP6XmO.js +0 -2448
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as
|
|
1
|
+
import { $ as setPrivilegedConn, A as unloadDemoData, B as getAreaView, C as demoTimeMap, D as resetDemo, E as loadDemoHouse, F as MAX_HISTORY_POINTS, G as getEntityView, H as buildEntityView, I as appendHistoryPoint, J as forceResubscribe, K as getEntityViews, L as bulkAppendHistoryPoints, M as demoEnergyPreferences, N as isEnergyEntity, O as startDemoEnergyTicker, P as synthesizeEnergyHistory, Q as privilegedConn, R as buildAreaView, S as demoReplayModel, T as loadDemoData, U as entityViewEquals, V as getAreaViews, W as getAllEntityViews, X as setManagerConnection, Y as registerEntity, Z as setResubscribeHandler, _ as applyDemoServiceCall, a as fetchForecastData, b as demoCallLog, c as normalizeStatisticTime, d as callService, et as setState, f as sendCommand, g as updateEntity, h as turnOn, i as fetchForecast, j as demoAssetUrl, k as stopDemoEnergyTicker, l as batchEntityUpdates, m as turnOff, o as fetchForecasts, p as toggle, q as extractDomain, s as fetchStatisticsDuringPeriod, t as forceResubscribeCalendars, tt as state, u as batchServiceCalls, v as applyVisitorHolds, w as isDemoMode, x as demoModel, y as createDemoFixtures, z as buildDeviceView } from "./track-BAfgOjMk.js";
|
|
2
2
|
import { t as runHaBridgeWorker } from "./worker-main-B6eeHPDQ.js";
|
|
3
3
|
import { produce } from "solid-js/store";
|
|
4
4
|
//#region src/core/reducers.ts
|
|
@@ -995,6 +995,91 @@ function entityIdHistoryNeedsAttributes(entityId) {
|
|
|
995
995
|
return NEED_ATTRIBUTE_DOMAINS.includes(domain);
|
|
996
996
|
}
|
|
997
997
|
//#endregion
|
|
998
|
+
//#region src/demo/sim/history.ts
|
|
999
|
+
const DAY_MS = 864e5;
|
|
1000
|
+
const STEP_MS = 3e5;
|
|
1001
|
+
const TICK_WALL_MS = 1e3;
|
|
1002
|
+
/** Unix seconds, matching the energy branch's wire format (`synthesizeEnergyHistory`). */
|
|
1003
|
+
function toSeconds(ms) {
|
|
1004
|
+
return Math.round(ms / 1e3);
|
|
1005
|
+
}
|
|
1006
|
+
function pushPoint(track, point) {
|
|
1007
|
+
track.lastState = point.s;
|
|
1008
|
+
const last = track.points.at(-1);
|
|
1009
|
+
if (last && last.lu === point.lu) track.points[track.points.length - 1] = point;
|
|
1010
|
+
else track.points.push(point);
|
|
1011
|
+
}
|
|
1012
|
+
/**
|
|
1013
|
+
* Replays the demo house once from `startMs` to `endMs` (sim time) and reports each entity's state changes.
|
|
1014
|
+
* `toWallMs` stamps `lu` on the caller's clock.
|
|
1015
|
+
*/
|
|
1016
|
+
function demoHistory(entityIds, startMs, endMs, toWallMs = (ms) => ms) {
|
|
1017
|
+
const result = {};
|
|
1018
|
+
for (const id of entityIds) result[id] = [];
|
|
1019
|
+
const live = demoModel();
|
|
1020
|
+
if (!live) return result;
|
|
1021
|
+
const tracks = [];
|
|
1022
|
+
for (const entityId of new Set(entityIds)) {
|
|
1023
|
+
const device = live.deviceOf(entityId);
|
|
1024
|
+
if (device) tracks.push({
|
|
1025
|
+
entityId,
|
|
1026
|
+
deviceKey: device.key,
|
|
1027
|
+
points: [],
|
|
1028
|
+
lastState: void 0
|
|
1029
|
+
});
|
|
1030
|
+
}
|
|
1031
|
+
if (tracks.length === 0) return result;
|
|
1032
|
+
const liveNowMs = live.nowMs;
|
|
1033
|
+
const endC = toWallMs(liveNowMs) - toWallMs(endMs) <= TICK_WALL_MS ? liveNowMs : endMs;
|
|
1034
|
+
const startC = Math.max(startMs, endC - DAY_MS);
|
|
1035
|
+
if (startC >= endC) return result;
|
|
1036
|
+
const log = demoCallLog();
|
|
1037
|
+
const modelStartMs = log.length > 0 ? Math.min(startC, log[0].simMs) : startC;
|
|
1038
|
+
const replayModel = demoReplayModel(modelStartMs);
|
|
1039
|
+
if (!replayModel) return result;
|
|
1040
|
+
const replay = replayModel;
|
|
1041
|
+
function record(simMs) {
|
|
1042
|
+
if (simMs < startC) return;
|
|
1043
|
+
for (const track of tracks) {
|
|
1044
|
+
const p = replay.projectDevice(track.deviceKey)[track.entityId];
|
|
1045
|
+
if (!p || p.state === track.lastState) continue;
|
|
1046
|
+
pushPoint(track, {
|
|
1047
|
+
s: p.state,
|
|
1048
|
+
a: p.attributes,
|
|
1049
|
+
lu: toSeconds(toWallMs(simMs))
|
|
1050
|
+
});
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
record(replay.nowMs);
|
|
1054
|
+
let logIdx = 0;
|
|
1055
|
+
while (replay.nowMs < endC) {
|
|
1056
|
+
const nextLogMs = logIdx < log.length ? log[logIdx].simMs : Number.POSITIVE_INFINITY;
|
|
1057
|
+
const windowBoundary = replay.nowMs < startC ? startC : Number.POSITIVE_INFINITY;
|
|
1058
|
+
const targetMs = Math.min(replay.nowMs + STEP_MS, endC, nextLogMs, windowBoundary);
|
|
1059
|
+
replay.advanceTo(targetMs, STEP_MS);
|
|
1060
|
+
record(replay.nowMs);
|
|
1061
|
+
if (logIdx < log.length && log[logIdx].simMs === replay.nowMs) {
|
|
1062
|
+
const entry = log[logIdx];
|
|
1063
|
+
replay.dispatch(entry.call);
|
|
1064
|
+
applyVisitorHolds(replay, entry.call.entityIds);
|
|
1065
|
+
logIdx++;
|
|
1066
|
+
record(replay.nowMs);
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
for (const track of tracks) {
|
|
1070
|
+
if (endC === liveNowMs) {
|
|
1071
|
+
const p = live.projectDevice(track.deviceKey)[track.entityId];
|
|
1072
|
+
if (p && p.state !== track.lastState) pushPoint(track, {
|
|
1073
|
+
s: p.state,
|
|
1074
|
+
a: p.attributes,
|
|
1075
|
+
lu: toSeconds(toWallMs(endC))
|
|
1076
|
+
});
|
|
1077
|
+
}
|
|
1078
|
+
result[track.entityId] = track.points.length > 5760 ? track.points.slice(-MAX_HISTORY_POINTS) : track.points;
|
|
1079
|
+
}
|
|
1080
|
+
return result;
|
|
1081
|
+
}
|
|
1082
|
+
//#endregion
|
|
998
1083
|
//#region src/history/fetch.ts
|
|
999
1084
|
/**
|
|
1000
1085
|
* History Fetching
|
|
@@ -1006,18 +1091,19 @@ function entityIdHistoryNeedsAttributes(entityId) {
|
|
|
1006
1091
|
*/
|
|
1007
1092
|
async function fetchHistory(options) {
|
|
1008
1093
|
const { startTime, endTime, entityIds = [], includeStartTimeState = true, significantChangesOnly = true, minimalResponse = true, noAttributes: noAttributesOverride } = options;
|
|
1009
|
-
|
|
1010
|
-
|
|
1094
|
+
const timeMap = demoTimeMap();
|
|
1095
|
+
if (timeMap) {
|
|
1096
|
+
const startMs = timeMap.toSim(startTime.getTime());
|
|
1097
|
+
const endMs = timeMap.toSim((endTime ?? /* @__PURE__ */ new Date()).getTime());
|
|
1098
|
+
const energyStepMs = timeMap.toSim(6e4) - timeMap.toSim(0);
|
|
1099
|
+
const toWallSeconds = (simSeconds) => Math.round(timeMap.toWall(simSeconds * 1e3) / 1e3);
|
|
1100
|
+
const replayed = demoHistory(entityIds.filter((id) => !isEnergyEntity(id)), startMs, endMs, timeMap.toWall);
|
|
1011
1101
|
const result = {};
|
|
1012
|
-
for (const id of entityIds) {
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
a: {},
|
|
1018
|
-
lu: p.lu
|
|
1019
|
-
}));
|
|
1020
|
-
}
|
|
1102
|
+
for (const id of entityIds) result[id] = isEnergyEntity(id) ? synthesizeEnergyHistory(id, startMs, endMs, energyStepMs).map((p) => ({
|
|
1103
|
+
s: p.s,
|
|
1104
|
+
a: {},
|
|
1105
|
+
lu: toWallSeconds(p.lu)
|
|
1106
|
+
})) : replayed[id] ?? [];
|
|
1021
1107
|
return result;
|
|
1022
1108
|
}
|
|
1023
1109
|
const startTimeStr = startTime.toISOString();
|
|
@@ -1088,8 +1174,6 @@ function historyStateToTimeline(s) {
|
|
|
1088
1174
|
}
|
|
1089
1175
|
//#endregion
|
|
1090
1176
|
//#region src/history/query.ts
|
|
1091
|
-
/** Hard cap on retained points per entity timeline. */
|
|
1092
|
-
const MAX_HISTORY_POINTS = 5760;
|
|
1093
1177
|
/** Live tracker count per entity. Ref-counted because a timeline is shared: two
|
|
1094
1178
|
* widgets on the same entity must not let the first unmount delete the store
|
|
1095
1179
|
* data the second is still rendering (appendHistoryPoint would then silently
|
|
@@ -1120,64 +1204,6 @@ function untrackEntityHistory(entityId) {
|
|
|
1120
1204
|
delete s.history[entityId];
|
|
1121
1205
|
}));
|
|
1122
1206
|
}
|
|
1123
|
-
/**
|
|
1124
|
-
* Append a state change to an entity's history.
|
|
1125
|
-
* Called by the entity subscription handler when a tracked entity changes.
|
|
1126
|
-
*/
|
|
1127
|
-
function appendHistoryPoint(entityId, stateValue, attributes, lastUpdated, lastChanged) {
|
|
1128
|
-
setState(produce((s) => {
|
|
1129
|
-
const history = s.history[entityId];
|
|
1130
|
-
if (!history) return;
|
|
1131
|
-
const point = {
|
|
1132
|
-
s: stateValue,
|
|
1133
|
-
a: attributes,
|
|
1134
|
-
lu: lastUpdated,
|
|
1135
|
-
lc: lastChanged
|
|
1136
|
-
};
|
|
1137
|
-
history.entityHistory.push(point);
|
|
1138
|
-
history.timeline.push({
|
|
1139
|
-
timestamp: lastUpdated,
|
|
1140
|
-
state: stateValue,
|
|
1141
|
-
attributes,
|
|
1142
|
-
lastChanged,
|
|
1143
|
-
lastUpdated
|
|
1144
|
-
});
|
|
1145
|
-
}));
|
|
1146
|
-
}
|
|
1147
|
-
/**
|
|
1148
|
-
* Append multiple history points in a single setState(produce(...)).
|
|
1149
|
-
* Called by the rAF-batched subscription flush.
|
|
1150
|
-
*/
|
|
1151
|
-
function bulkAppendHistoryPoints(points) {
|
|
1152
|
-
if (points.length === 0) return;
|
|
1153
|
-
setState(produce((s) => {
|
|
1154
|
-
const touched = /* @__PURE__ */ new Set();
|
|
1155
|
-
for (const { entityId, stateValue, attributes, lastUpdated, lastChanged } of points) {
|
|
1156
|
-
const history = s.history[entityId];
|
|
1157
|
-
if (!history) continue;
|
|
1158
|
-
history.entityHistory.push({
|
|
1159
|
-
s: stateValue,
|
|
1160
|
-
a: attributes,
|
|
1161
|
-
lu: lastUpdated,
|
|
1162
|
-
lc: lastChanged
|
|
1163
|
-
});
|
|
1164
|
-
history.timeline.push({
|
|
1165
|
-
timestamp: lastUpdated,
|
|
1166
|
-
state: stateValue,
|
|
1167
|
-
attributes,
|
|
1168
|
-
lastChanged,
|
|
1169
|
-
lastUpdated
|
|
1170
|
-
});
|
|
1171
|
-
touched.add(entityId);
|
|
1172
|
-
}
|
|
1173
|
-
for (const entityId of touched) {
|
|
1174
|
-
const history = s.history[entityId];
|
|
1175
|
-
if (!history) continue;
|
|
1176
|
-
if (history.entityHistory.length > 5760) history.entityHistory.splice(0, history.entityHistory.length - MAX_HISTORY_POINTS);
|
|
1177
|
-
if (history.timeline.length > 5760) history.timeline.splice(0, history.timeline.length - MAX_HISTORY_POINTS);
|
|
1178
|
-
}
|
|
1179
|
-
}));
|
|
1180
|
-
}
|
|
1181
1207
|
//#endregion
|
|
1182
1208
|
//#region src/weather/query.ts
|
|
1183
1209
|
/**
|
|
@@ -1811,7 +1837,7 @@ function detachBridgeFromStore() {
|
|
|
1811
1837
|
* host's link with one the widget controls — every subsequent service call is
|
|
1812
1838
|
* intercepted and every entity the dashboard renders can be fabricated.
|
|
1813
1839
|
* - disconnect / detachBridgeFromStore: drop the household's connection.
|
|
1814
|
-
* - loadDemoData / unloadDemoData: overwrite live state with
|
|
1840
|
+
* - loadDemoData / loadDemoHouse / resetDemo / unloadDemoData: overwrite live state with the demo house.
|
|
1815
1841
|
*/
|
|
1816
1842
|
let unclaimed = {
|
|
1817
1843
|
attachBridgeToStore,
|
|
@@ -1821,6 +1847,8 @@ let unclaimed = {
|
|
|
1821
1847
|
createHaBridge,
|
|
1822
1848
|
disconnect,
|
|
1823
1849
|
loadDemoData,
|
|
1850
|
+
loadDemoHouse,
|
|
1851
|
+
resetDemo,
|
|
1824
1852
|
unloadDemoData
|
|
1825
1853
|
};
|
|
1826
1854
|
/**
|
package/dist/solid/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { G as getEntityView, Q as privilegedConn, R as buildAreaView, U as entityViewEquals, V as getAreaViews, Y as registerEntity, d as callService, et as setState, h as turnOn, m as turnOff, n as trackCalendarEvents, p as toggle, q as extractDomain, r as buildDemoForecast, s as fetchStatisticsDuringPeriod, tt as state, w as isDemoMode } from "../track-BAfgOjMk.js";
|
|
2
2
|
import { produce } from "solid-js/store";
|
|
3
3
|
import { createEffect, createMemo, createResource, onCleanup } from "solid-js";
|
|
4
4
|
//#region src/weather/track.ts
|