Entities
CDF entities are the stable, app-facing objects your UI calls. Each entity wraps SDK calls in operations, keeps the original SDK object in _raw, and emits operation events that drive store updates.
Use entity pages for task-oriented workflows (control a param, run a scene, share a group). Use domain stores for store maps, pagination, and session bootstrap.
Do not construct entities in UI code — adaptors create them and stores hold observable instances.
Common Workflows
Subscribe to operation events on an entity
import { initCDF } from "@espressif/rainmaker-base-cdf";
const espCDF = await initCDF({ sdkAdaptorRegistry });
const node = espCDF.nodeStore.getNodeById("node-id");
const unsubscribe = node?.subscribe((n, op, success, _, err) => {
if (!success) console.error({ nodeId: n.id, op, err });
});
// Clean up when the screen unmounts
unsubscribe?.();
Per-entity guides are in the catalog below.
Entity Catalog
CDF entity classes are the objects your UI and feature code call. Observable fields are updated after successful operations; methods delegate to injected operations and emit on the entity event bus.
| Entity | Role |
|---|---|
| ESPCDFUser | Authenticated user; groups, nodes, provisioning, Matter, and push helpers. |
| ESPCDFGroup | Room / home / fabric; nodes, scenes, schedules, automations, sharing. |
| ESPCDFNode | One backend node; connectivity, config tree, OTA, property-change sync. |
| ESPCDFNodeConfig | Node configuration snapshot (devices, version, info). |
| ESPCDFDevice | Device model under a node (Light, Fan, …). |
| ESPCDFDeviceParam | Single device parameter (read/write value). |
| ESPCDFService | Optional service slice on a node (params). |
| ESPCDFServiceParam | Parameter on a service. |
| ESPCDFScene | Scene definition and lifecycle. |
| ESPCDFSchedule | Schedule with triggers, action, enable flags, sync metadata. |
| ESPCDFAutomation | Automation (events → actions); uses operationsEvents for op bus. |
| ESPCDFGroupSharingRequest | Incoming/outgoing group share workflow. |
| ESPCDFProvisioningDevice | Ephemeral provisioned peer (no operation event emitter). |
Advanced Concepts
Unified entity wrapper
Every CDF entity (ESPCDFNode, ESPCDFGroup, ESPCDFUser, …) is a pure SDK wrapper:
An entity is constructed by an adaptor transformer with three injected pieces:
| Property | Who provides it | Purpose |
|---|---|---|
operations | Adaptor transformer | Object whose methods call the underlying SDK |
_raw | Adaptor transformer | Original SDK entity; excluded from MobX observation |
events | Entity constructor | OperationEventEmitter instance; used internally for event emission |
The critical rule: Entities delegate to operations and emit events. They never update their own observable properties. All observable mutations go through synchronizers. Exception: ESPCDFAutomation uses operationsEvents as the operation bus name (see ESPCDFAutomation).
Entity method pattern
Every entity method follows the runAndEmit pattern — delegate the SDK call, then emit success or failure:
// ESPCDFGroup.delete() — representative of all entity operations
async delete(): Promise<ESPCDFAPIResponse> {
return this.runAndEmit(
"delete", // operation name
() => this.operations.delete(), // SDK call
() => this, // data to include in success event
);
}
// runAndEmit is a shared helper on every entity:
private async runAndEmit<T>(
operation: OperationType,
execute: () => Promise<T>,
getData?: (result: T) => unknown,
): Promise<T> {
let succeeded = false;
let result!: T;
let error: unknown;
try {
result = await execute();
succeeded = true;
return result;
} catch (e) {
error = e;
throw e;
} finally {
this.emit(operation, succeeded, succeeded ? getData?.(result) : undefined, error);
}
}
On failure the error is re-thrown (so the caller can handle it), and the failure event is still emitted so synchronizers can log without applying partial state patches.
OperationEventEmitter
Every entity holds a typed OperationEventEmitter. The entity uses it internally; synchronizers subscribe to it.
// Type signature (illustrative)
class ESPCDFOperationEventEmitter<TEntity, TOperation extends string> {
subscribe(
listener: (
entity: TEntity,
operation: TOperation,
success: boolean,
data?: unknown,
error?: unknown,
) => void,
): () => void; // returns unsubscribe function
emit(
entity: TEntity,
operation: TOperation,
success: boolean,
data?: unknown,
error?: unknown,
): void;
dispose(): void; // removes all listeners
}
Related Resource
- Entity source (esp-rainmaker-app-cdf-ts)
- API Reference: