about
The Scene module provides functionality for managing device scenes across multiple nodes in the ESP RainMaker system. It allows users to create, edit, trigger, and delete scenes that can control multiple devices simultaneously.
Scenes are implemented completely on the node side as a "service", with the cloud backend acting as a gateway between nodes and clients like phone apps.
Scenes
This guide explains how the Scene module works, focusing on the major operations and how CDF APIs are used throughout the system.
User Flow Overview
The Scene module has two main user flows:
- Create New Scene: Scenes → CreateScene → Select Device → Configure Device Parameters
- Edit Existing Scene: Scenes → CreateScene (with existing data) → Modify → Save
Architecture Overview
Components Structure
(scene)/
├── _layout.tsx # Navigation and context setup
├── Scenes.tsx # Main scene list screen
├── CreateScene.tsx # Create/edit scene screen
├── DeviceSelection.tsx # Choose devices for scene
└── DeviceParamsSelection.tsx # Configure device parameters
1. Scenes List (Scenes.tsx)
This is the main screen where users see all their scenes and can trigger them.
// Get CDF stores
const { store } = useCDF();
const { sceneStore, nodeStore, userStore } = store;
// Get scene list from CDF
const { sceneList } = sceneStore;
// Fetch and sync scenes data from all nodes in the currently active home
const fetchScenes = async () => {
const currentHome = groupStore?._groupsByID[groupStore?.currentHomeId];
await sceneStore.syncScenesFromNodes(currentHome.nodes || []);
};
Scene Operations
// Trigger a scene
const handleSceneAction = async (sceneId: string, action: string) => {
const selectedScene = sceneList.find((scene) => scene.id === sceneId);
switch (action) {
case "activate":
await selectedScene.activate(); // CDF handles communication
break;
case "edit":
setSceneInfo(selectedScene); // Load scene into context
router.push("/(scene)/CreateScene");
break;
case "delete":
await selectedScene.remove(); // CDF removes from all nodes
break;
}
};
What this does:
- Lists all scenes from CDF scene store
- Handles scene activation, editing, and deletion
- Uses CDF methods like
scene.activate(),scene.remove(),scene.edit()
2. Create New Scene Flow
Step 1: CreateScene.tsx (Empty State)
// Get CDF stores
const { store } = useCDF();
const { sceneStore } = store;
// Initialize empty scene
const [state, setState] = useState({
sceneName: "",
sceneId: generateRandomId(),
isEditing: false,
config: {},
nodes: [],
});
Step 2: DeviceSelection.tsx
// Get nodes from CDF store
const { store } = useCDF();
const nodeList = store?.nodeStore?.nodeList as ESPRMNode[];
// Filter nodes that support Scenes service
const sceneNodes = nodeList.filter((node) =>
node.nodeConfig?.services?.some(
(service) => service.type === ESPRM_SCENES_SERVICE
)
);
// Extract devices from each node
sceneNodes.forEach((node) => {
const devices = node.nodeConfig?.devices ?? [];
const scene = node.nodeConfig?.services?.find(
(service) => service.type === ESPRM_SCENES_SERVICE
)?.params[0] as any;
// Check if node has reached max scenes
const isMaxSceneReached =
scene && scene.bounds?.max && scene.bounds.max == scene.value.length;
devices.forEach((device) => {
allDevices.push({
node: deepClone(node),
device: deepClone(device),
isSelected: false, // New scene, no existing actions
isMaxSceneReached,
});
});
});