场景存储
SceneStore 是一种响应式存储,用于在应用中管理场景配置与场景操作。场景可以同时保存与恢复多个设备状态,从而通过一次操作快速控制多个设备。
概览
SceneStore 提供以下功能:
- 管理与同步场景列表
- 创建与更新场景
- 激活场景
- 查询节点配置并自动转换
- 合并多节点场景
- 自动同步
NodeStore - 响应式状态管理
场景在 CDF 中如何工作
查询节点配置并自动转换场景
在 CDF 中,场景会查询节点配置并进行自动转换。每个节点的 nodeConfig.services 包含一个场景服务,其中含有场景列表。SceneStore 会自动提取并合并这些场景。
无需手动转换 – 使用 CDF 时,场景会自动从以下路径转换:
node.nodeConfig.services[scenes].params[scenes].value
识别场景服务与参数
SceneStore 通过特定的服务类型与参数类型来识别场景:
-
服务类型:
esp.service.scenes(ESPRM_SERVICE_SCENES)- 标识节点服务数组中的场景服务。
- 位于
node.nodeConfig.services[],其中service.type === "esp.service.scenes"。
-
参数类型:
esp.param.scenes(ESPRM_PARAM_SCENES)- 标识场景服务中的场景参数。
- 位于
service.params[],其中param.type === "esp.param.scenes"。 - 实际的场景列表存放在
param.value[]中。
节点配置结构示例:
node.nodeConfig.services = [
{
type: "esp.service.scenes", // 服务类型标识符
params: [
{
type: "esp.param.scenes", // 参数类型标识符
value: [
// 场景数组
{
id: "scene1",
name: "Living Room Scene",
info: "Evening lighting",
action: { light: { power: true, brightness: 80 } },
},
{
id: "scene2",
name: "Bedroom Scene",
action: { fan: { power: false } },
},
],
},
],
},
];
多节点场景合并
多个节点上具有相同 ID 的场景会自动合并为一个场景,便于管理跨多个设备的场景。
示例:
- 节点 1 中存在 ID 为
scene1的场景 →{ id: 'scene1', nodes: ['node1'], actions: { node1: {...} } }。 - 节点 2 中存在 ID 为
scene1的场景 → 与节点 1 的场景合并。 - 节点 3 中存在 ID 为
scene1的场景 → 与节点 1 和节点 2 的场景合并。 - 结果:
{ id: 'scene1', nodes: ['node1', 'node2', 'node3'], actions: { node1: {...}, node2: {...}, node3: {...} } }。
当多个节点共享同一个场景 ID 时,这些节点会被合并为一个场景对象。可以通过查看场景的 nodes 数组属性来确认其涉及哪些节点:
const scene = sceneStore.getScene("scene1");
console.log("Scene spans nodes:", scene.nodes); // ['node1', 'node2', 'node3']
console.log("Actions per node:", scene.actions);
// {
// node1: { light: { power: true } },
// node2: { fan: { power: false } },
// node3: { switch: { power: true } }
// }
场景更新与节点定向
更新场景时,更改的应用方式取决于操作类型:
- 更新所有节点:如果更新跨多个节点的场景,则改动将应用至包含该场景的所有节点。
- 仅更新特定节点:如果仅更新某个设备/节点的场景,则改动将仅应用至该节点的场景配置。
SceneStore 会通过 updateNodeScene 函数自动处理节点更新,并在 NodeStore 中更新该节点的场景配置。
访问存储
通过 CDF 实例访问 SceneStore:
const sceneStore = espCDF.sceneStore;
属性
| 属性 | 类型 | 描述 |
|---|---|---|
| sceneList | Scene[](计算属性) | 存储中所有场景的计算数组。添加或移除场景时会自动更新。 |
| scenesByID | { [key: string]: Scene } | 按场景 ID 建立索引的字典,便于快速查找。 |
示例用法
// 获取所有场景
const scenes = sceneStore.sceneList;
console.log("Total scenes:", scenes.length);
scenes.forEach((scene) => {
console.log("Scene:", scene.name, scene.id);
});
// 按照 ID 获取场景
const scene = sceneStore.scenesByID["scene123"];
if (scene) {
console.log("Scene found:", scene.name);
}
SceneStore 方法
从节点同步场景
若要从指定节点同步场景,请使用 syncScenesFromNodes() 方法。该方法会:
- 从各节点的
nodeConfig.services[scenes]中提取场景配置。 - 将节点配置中的场景转换为场景实例。
- 将多个节点中 ID 相同的场景合并为一个场景。
- 用同步后的场景更新
SceneStore。
工作原理:
- 通过查找
type === "esp.service.scenes"(ESPRM_SERVICE_SCENES) 的服务来识别场景。 - 在该服务中,定位
type === "esp.param.scenes"(ESPRM_PARAM_SCENES)的参数。 - 从
param.value[]数组读取场景。 - 如果多个节点存在 ID 相同的场景,则进行合并:
nodes数组包含拥有该场景的所有节点 ID。actions对象按节点保存动作:{ node1: {...}, node2: {...} }。devicesCount为所有节点的设备总数。
/*
- nodeIds: 要同步场景的节点 ID 数组
*/
try {
// 从指定节点同步场景
await sceneStore.syncScenesFromNodes(["node1", "node2", "node3"]);
// 如果 node1、node2 和 node3 都有 ID 为 "scene1" 的场景,
// 则这些节点会合并为一个场景:
const scene = sceneStore.getScene("scene1");
console.log("Scene spans nodes:", scene.nodes); // ['node1', 'node2', 'node3']
console.log("Actions per node:", scene.actions);
} catch (error) {
console.error("Error syncing scenes:", error);
}
创建场景
要在存储中创建新场景,请使用 createScene() 方法。场景创建后会自动变成可观察对象,且系统会为其设置拦截器。
/*
- sceneData: 场景数据对象,包含:
- id(可选):场景 ID。如果未提供,会生成基于时间戳的 ID
- name: 场景名称
- info(可选):场景描述/信息
- nodes: 包含在场景中的节点 ID 数组
- actions: 每个节点的设备操作
*/
try {
const newScene = await sceneStore.createScene({
name: "Living Room Scene",
info: "Cozy evening lighting",
nodes: ["node1", "node2"],
actions: {
node1: {
light: {
power: true,
brightness: 80,
},
},
node2: {
fan: {
power: false,
},
},
},
});
console.log("Scene created:", newScene);
} catch (error) {
console.error("Error creating scene:", error);
}
获取场景
若想按 ID 获取场景,请使用 getScene() 方法。
/*
- sceneId: 要获取的场景 ID
*/
const scene = sceneStore.getScene("scene123");
if (scene) {
console.log("Scene details:", scene);
} else {
console.log("Scene not found");
}
设置场景列表
要替换现有的全部场景列表,请使用 setSceneList() 方法。每个场景都会自动变成可观察对象,且系统会为其设置拦截器。
/*
- scenes: 要设置的场景数组
*/
sceneStore.setSceneList(scenes);
添加场景
要向存储中添加单个场景并使其成为可观察对象,请使用 addScene() 方法。
/*
- scene: 要添加的场景
*/
const scene = new Scene(sceneData, espCDF);
const observableScene = sceneStore.addScene(scene);
按 ID 更新场景
要按 ID 更新场景且不将其转换为可观察对象,请使用 updateSceneByID() 方法。
/*
- id: 场景 ID
- scene: 要设置的场景对象
*/
sceneStore.updateSceneByID("scene123", updatedScene);
删除场景
要按 ID 从存储中移除多个场景,请使用 deleteScenes() 方法。
/*
- ids: 要删除的场景 ID 数组
*/
sceneStore.deleteScenes(["scene1", "scene2"]);