inventoresed
Version:
Z-Wave driver written entirely in JavaScript/TypeScript
119 lines (113 loc) • 2.31 kB
text/typescript
import { Interpreter, Machine, StateMachine } from "xstate";
import type { ZWaveNode } from "./Node";
import { NodeStatus } from "./_Types";
/* eslint-disable @typescript-eslint/ban-types */
export interface NodeStatusStateSchema {
states: {
unknown: {};
// non-sleeping nodes are either dead or alive
dead: {};
alive: {};
// sleeping nodes are asleep or awake
asleep: {};
awake: {};
};
}
/* eslint-enable @typescript-eslint/ban-types */
const statusDict = {
unknown: NodeStatus.Unknown,
dead: NodeStatus.Dead,
alive: NodeStatus.Alive,
asleep: NodeStatus.Asleep,
awake: NodeStatus.Awake,
} as const;
export function nodeStatusMachineStateToNodeStatus(
state: keyof NodeStatusStateSchema["states"],
): NodeStatus {
return statusDict[state] ?? NodeStatus.Unknown;
}
export type NodeStatusEvent =
| { type: "DEAD" }
| { type: "ALIVE" }
| { type: "ASLEEP" }
| { type: "AWAKE" };
export type NodeStatusMachine = StateMachine<
any,
NodeStatusStateSchema,
NodeStatusEvent,
any,
any,
any,
any
>;
export type NodeStatusInterpreter = Interpreter<
any,
NodeStatusStateSchema,
NodeStatusEvent
>;
export function createNodeStatusMachine(node: ZWaveNode): NodeStatusMachine {
return Machine<any, NodeStatusStateSchema, NodeStatusEvent>(
{
id: "nodeStatus",
initial: "unknown",
states: {
unknown: {
on: {
DEAD: {
target: "dead",
cond: "cannotSleep",
},
ALIVE: {
target: "alive",
cond: "cannotSleep",
},
ASLEEP: {
target: "asleep",
cond: "canSleep",
},
AWAKE: {
target: "awake",
cond: "canSleep",
},
},
},
dead: {
on: {
ALIVE: "alive",
},
},
alive: {
on: {
DEAD: "dead",
// GH#1054 we must have a way to send a node to sleep even if
// it was previously detected as a non-sleeping device
ASLEEP: {
target: "asleep",
cond: "canSleep",
},
AWAKE: {
target: "awake",
cond: "canSleep",
},
},
},
asleep: {
on: {
AWAKE: "awake",
},
},
awake: {
on: {
ASLEEP: "asleep",
},
},
},
},
{
guards: {
canSleep: () => !!node.canSleep,
cannotSleep: () => !node.canSleep,
},
},
);
}