[
{
"id": "tab-demo-traffic",
"type": "tab",
"label": "01 Traffic Light",
"disabled": false,
"info": "# 01 Traffic Light\n\n最基础的 SCXML 循环:red → green → yellow → red。\n\n- 点 **next** 推进一个状态;\n- 点 **reset** 从初始态 red 重建会话;\n- Hub 同时输出状态、变量和 topic;\n- 打开机器配置,可用三张表 / actions 弹窗编辑;\n- 打开右侧 **状态机** 侧栏看只读实时图。\n\n覆盖:基础状态转移、entry action、变量、reset、监控。"
},
{
"id": "demo-traffic-help",
"type": "comment",
"z": "tab-demo-traffic",
"name": "说明",
"info": "next 推进;reset 回到 red。状态/变量分别接 debug。",
"x": 80,
"y": 80,
"wires": []
},
{
"id": "demo-traffic-conf",
"type": "statechart-machine",
"z": "tab-demo-traffic",
"name": "Traffic Light",
"source": "\n\n \n \n \n \n \n \n \n",
"engine": "sandboxed",
"scriptTimeoutMs": 500,
"maxMicrosteps": 10000,
"monitorShowVars": false,
"persistVars": false,
"updateEvent": "update",
"x": 160,
"y": 160,
"wires": []
},
{
"id": "demo-traffic-next",
"type": "inject",
"z": "tab-demo-traffic",
"name": "next",
"props": [
{
"p": "topic",
"vt": "str",
"v": "next"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"payload": "",
"payloadType": "str",
"topic": "next",
"x": 100,
"y": 240,
"wires": [
[
"demo-traffic-out"
]
]
},
{
"id": "demo-traffic-reset",
"type": "inject",
"z": "tab-demo-traffic",
"name": "reset",
"props": [
{
"p": "payload",
"vt": "json",
"v": "{\"command\":\"reset\"}"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"payload": "{\"command\":\"reset\"}",
"payloadType": "json",
"topic": "",
"x": 100,
"y": 300,
"wires": [
[
"demo-traffic-out"
]
]
},
{
"id": "demo-traffic-out",
"type": "statechart-hub",
"z": "tab-demo-traffic",
"name": "traffic state",
"machine": "demo-traffic-conf",
"includeVars": true,
"emitInitial": true,
"includeInternalSends": false,
"stateTopic": "traffic/state",
"eventTopic": "traffic/{event}",
"x": 560,
"y": 220,
"wires": [
[
"demo-traffic-state",
"demo-traffic-vars"
],
[
"demo-traffic-events"
],
[]
]
},
{
"id": "demo-traffic-state",
"type": "debug",
"z": "tab-demo-traffic",
"name": "state (full)",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 820,
"y": 200,
"wires": []
},
{
"id": "demo-traffic-vars",
"type": "debug",
"z": "tab-demo-traffic",
"name": "vars",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "vars",
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
"x": 820,
"y": 260,
"wires": []
},
{
"id": "demo-traffic-events",
"type": "debug",
"z": "tab-demo-traffic",
"name": "events",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 820,
"y": 320,
"wires": []
},
{
"id": "tab-demo-commands",
"type": "tab",
"label": "02 Commands & Guards",
"disabled": false,
"info": "# 02 Commands & Guards\n\n演示 msg.command、变量、条件转移和 actions。\n\n- **start**(temp=20)→ cooling,并触发图内 send started;\n- **set temp=15** → 自动补 update → heating;\n- **set temp=25** → cooling;\n- **done** → 回 idle;\n- **reset** → 从初始态重建。\n\n覆盖:set / reset / event、updateEvent、cond、assign、send(data-expr)、stateTopic/eventTopic、变量调试。"
},
{
"id": "demo-cmd-help",
"type": "comment",
"z": "tab-demo-commands",
"name": "说明",
"info": "先点 start;再点 set temp=15 / 25;done 回 idle。",
"x": 80,
"y": 80,
"wires": []
},
{
"id": "demo-cmd-conf",
"type": "statechart-machine",
"z": "tab-demo-commands",
"name": "HVAC Guard",
"source": "\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n",
"engine": "sandboxed",
"scriptTimeoutMs": 500,
"maxMicrosteps": 10000,
"monitorShowVars": false,
"persistVars": false,
"updateEvent": "update",
"x": 180,
"y": 160,
"wires": []
},
{
"id": "demo-cmd-start",
"type": "inject",
"z": "tab-demo-commands",
"name": "start",
"props": [
{
"p": "topic",
"vt": "str",
"v": "start"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"payload": "",
"payloadType": "str",
"topic": "start",
"x": 100,
"y": 240,
"wires": [
[
"demo-cmd-out"
]
]
},
{
"id": "demo-cmd-temp15",
"type": "inject",
"z": "tab-demo-commands",
"name": "set temp=15",
"props": [
{
"p": "payload",
"vt": "json",
"v": "{\"command\":\"set\",\"payload\":{\"temp\":15}}"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"payload": "{\"command\":\"set\",\"payload\":{\"temp\":15}}",
"payloadType": "json",
"topic": "",
"x": 100,
"y": 300,
"wires": [
[
"demo-cmd-out"
]
]
},
{
"id": "demo-cmd-temp25",
"type": "inject",
"z": "tab-demo-commands",
"name": "set temp=25",
"props": [
{
"p": "payload",
"vt": "json",
"v": "{\"command\":\"set\",\"payload\":{\"temp\":25}}"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"payload": "{\"command\":\"set\",\"payload\":{\"temp\":25}}",
"payloadType": "json",
"topic": "",
"x": 100,
"y": 360,
"wires": [
[
"demo-cmd-out"
]
]
},
{
"id": "demo-cmd-done",
"type": "inject",
"z": "tab-demo-commands",
"name": "done",
"props": [
{
"p": "payload",
"vt": "json",
"v": "{\"command\":\"event\",\"event\":\"done\"}"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"payload": "{\"command\":\"event\",\"event\":\"done\"}",
"payloadType": "json",
"topic": "",
"x": 100,
"y": 420,
"wires": [
[
"demo-cmd-out"
]
]
},
{
"id": "demo-cmd-reset",
"type": "inject",
"z": "tab-demo-commands",
"name": "reset",
"props": [
{
"p": "payload",
"vt": "json",
"v": "{\"command\":\"reset\"}"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"payload": "{\"command\":\"reset\"}",
"payloadType": "json",
"topic": "",
"x": 100,
"y": 480,
"wires": [
[
"demo-cmd-out"
]
]
},
{
"id": "demo-cmd-out",
"type": "statechart-hub",
"z": "tab-demo-commands",
"name": "hvac state",
"machine": "demo-cmd-conf",
"includeVars": true,
"emitInitial": true,
"includeInternalSends": false,
"stateTopic": "hvac/state",
"eventTopic": "hvac/{event}",
"x": 590,
"y": 260,
"wires": [
[
"demo-cmd-state",
"demo-cmd-vars"
],
[
"demo-cmd-events"
],
[]
]
},
{
"id": "demo-cmd-state",
"type": "debug",
"z": "tab-demo-commands",
"name": "state (full)",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 860,
"y": 230,
"wires": []
},
{
"id": "demo-cmd-vars",
"type": "debug",
"z": "tab-demo-commands",
"name": "vars",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "vars",
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
"x": 860,
"y": 290,
"wires": []
},
{
"id": "demo-cmd-events",
"type": "debug",
"z": "tab-demo-commands",
"name": "started event",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 860,
"y": 350,
"wires": []
},
{
"id": "tab-demo-parallel",
"type": "tab",
"label": "03 Parallel & History",
"disabled": false,
"info": "# 03 Parallel & History\n\n两个独立机器:\n\n- **Parallel Plant**:power / network 两个并行区域,状态输出是数组;\n- **History Player**:open → details → pause → resume 恢复 details;back 回 home。\n\n覆盖:parallel、active state 数组、shallow history、两个 config node 独立会话。"
},
{
"id": "demo-par-help",
"type": "comment",
"z": "tab-demo-parallel",
"name": "说明",
"info": "Parallel 的 states 是数组;History 演示 pause/resume。",
"x": 80,
"y": 80,
"wires": []
},
{
"id": "demo-par-conf",
"type": "statechart-machine",
"z": "tab-demo-parallel",
"name": "Parallel Plant",
"source": "\n\n \n \n \n \n \n \n \n \n \n \n",
"engine": "sandboxed",
"scriptTimeoutMs": 500,
"maxMicrosteps": 10000,
"monitorShowVars": false,
"persistVars": false,
"updateEvent": "update",
"x": 160,
"y": 160,
"wires": []
},
{
"id": "demo-par-power",
"type": "inject",
"z": "tab-demo-parallel",
"name": "togglePower",
"props": [
{
"p": "topic",
"vt": "str",
"v": "togglePower"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"payload": "",
"payloadType": "str",
"topic": "togglePower",
"x": 100,
"y": 220,
"wires": [
[
"demo-par-out"
]
]
},
{
"id": "demo-par-connect",
"type": "inject",
"z": "tab-demo-parallel",
"name": "connect",
"props": [
{
"p": "topic",
"vt": "str",
"v": "connect"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"payload": "",
"payloadType": "str",
"topic": "connect",
"x": 100,
"y": 280,
"wires": [
[
"demo-par-out"
]
]
},
{
"id": "demo-par-disconnect",
"type": "inject",
"z": "tab-demo-parallel",
"name": "disconnect",
"props": [
{
"p": "topic",
"vt": "str",
"v": "disconnect"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"payload": "",
"payloadType": "str",
"topic": "disconnect",
"x": 100,
"y": 340,
"wires": [
[
"demo-par-out"
]
]
},
{
"id": "demo-par-out",
"type": "statechart-hub",
"z": "tab-demo-parallel",
"name": "parallel states",
"machine": "demo-par-conf",
"includeVars": false,
"emitInitial": true,
"includeInternalSends": false,
"stateTopic": "plant/state",
"eventTopic": "statechart/{machine}/evt/{event}",
"x": 580,
"y": 220,
"wires": [
[
"demo-par-debug"
],
[],
[]
]
},
{
"id": "demo-par-debug",
"type": "debug",
"z": "tab-demo-parallel",
"name": "states array",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 840,
"y": 220,
"wires": []
},
{
"id": "demo-hist-conf",
"type": "statechart-machine",
"z": "tab-demo-parallel",
"name": "History Player",
"source": "\n\n \n \n \n \n \n \n \n \n \n \n \n",
"engine": "sandboxed",
"scriptTimeoutMs": 500,
"maxMicrosteps": 10000,
"monitorShowVars": false,
"persistVars": false,
"updateEvent": "update",
"x": 160,
"y": 540,
"wires": []
},
{
"id": "demo-hist-open",
"type": "inject",
"z": "tab-demo-parallel",
"name": "open",
"props": [
{
"p": "topic",
"vt": "str",
"v": "open"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"payload": "",
"payloadType": "str",
"topic": "open",
"x": 100,
"y": 600,
"wires": [
[
"demo-hist-out"
]
]
},
{
"id": "demo-hist-pause",
"type": "inject",
"z": "tab-demo-parallel",
"name": "pause",
"props": [
{
"p": "topic",
"vt": "str",
"v": "pause"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"payload": "",
"payloadType": "str",
"topic": "pause",
"x": 100,
"y": 660,
"wires": [
[
"demo-hist-out"
]
]
},
{
"id": "demo-hist-resume",
"type": "inject",
"z": "tab-demo-parallel",
"name": "resume",
"props": [
{
"p": "topic",
"vt": "str",
"v": "resume"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"payload": "",
"payloadType": "str",
"topic": "resume",
"x": 100,
"y": 720,
"wires": [
[
"demo-hist-out"
]
]
},
{
"id": "demo-hist-stop",
"type": "inject",
"z": "tab-demo-parallel",
"name": "stop",
"props": [
{
"p": "topic",
"vt": "str",
"v": "stop"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"payload": "",
"payloadType": "str",
"topic": "stop",
"x": 100,
"y": 780,
"wires": [
[
"demo-hist-out"
]
]
},
{
"id": "demo-hist-back",
"type": "inject",
"z": "tab-demo-parallel",
"name": "back",
"props": [
{
"p": "topic",
"vt": "str",
"v": "back"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"payload": "",
"payloadType": "str",
"topic": "back",
"x": 100,
"y": 840,
"wires": [
[
"demo-hist-out"
]
]
},
{
"id": "demo-hist-out",
"type": "statechart-hub",
"z": "tab-demo-parallel",
"name": "history states",
"machine": "demo-hist-conf",
"includeVars": false,
"emitInitial": true,
"includeInternalSends": false,
"stateTopic": "player/state",
"eventTopic": "statechart/{machine}/evt/{event}",
"x": 580,
"y": 600,
"wires": [
[
"demo-hist-debug"
],
[],
[]
]
},
{
"id": "demo-hist-debug",
"type": "debug",
"z": "tab-demo-parallel",
"name": "states",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 840,
"y": 600,
"wires": []
},
{
"id": "tab-demo-delay",
"type": "tab",
"label": "04 Delay & Sends",
"disabled": false,
"info": "# 04 Delay & Sends\n\n1.2s / 0.8s 延时转移 + 图内 send:\n\n- **open** → opening →(1.2s)→ open;\n- **close** → closing →(0.8s)→ closed;\n- 输出 2 同时显示 door.notify 和内部 timer send(已勾选 include internal sends);\n- 状态 topic 为 door/state,事件 topic 为 door/{event}。\n\n覆盖:delay、send/id、内部/外部 send、eventTopic、定时器。"
},
{
"id": "demo-delay-help",
"type": "comment",
"z": "tab-demo-delay",
"name": "说明",
"info": "点 open/close,观察 1.2s/0.8s 后状态变化。",
"x": 80,
"y": 80,
"wires": []
},
{
"id": "demo-delay-conf",
"type": "statechart-machine",
"z": "tab-demo-delay",
"name": "Door with Delay",
"source": "\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n",
"engine": "sandboxed",
"scriptTimeoutMs": 500,
"maxMicrosteps": 10000,
"monitorShowVars": false,
"persistVars": false,
"updateEvent": "update",
"x": 160,
"y": 160,
"wires": []
},
{
"id": "demo-delay-open",
"type": "inject",
"z": "tab-demo-delay",
"name": "open",
"props": [
{
"p": "topic",
"vt": "str",
"v": "open"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"payload": "",
"payloadType": "str",
"topic": "open",
"x": 100,
"y": 240,
"wires": [
[
"demo-delay-out"
]
]
},
{
"id": "demo-delay-close",
"type": "inject",
"z": "tab-demo-delay",
"name": "close",
"props": [
{
"p": "topic",
"vt": "str",
"v": "close"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"payload": "",
"payloadType": "str",
"topic": "close",
"x": 100,
"y": 300,
"wires": [
[
"demo-delay-out"
]
]
},
{
"id": "demo-delay-reset",
"type": "inject",
"z": "tab-demo-delay",
"name": "reset",
"props": [
{
"p": "payload",
"vt": "json",
"v": "{\"command\":\"reset\"}"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"payload": "{\"command\":\"reset\"}",
"payloadType": "json",
"topic": "",
"x": 100,
"y": 360,
"wires": [
[
"demo-delay-out"
]
]
},
{
"id": "demo-delay-out",
"type": "statechart-hub",
"z": "tab-demo-delay",
"name": "door events",
"machine": "demo-delay-conf",
"includeVars": false,
"emitInitial": true,
"includeInternalSends": true,
"stateTopic": "door/state",
"eventTopic": "door/{event}",
"x": 580,
"y": 240,
"wires": [
[
"demo-delay-state"
],
[
"demo-delay-events"
],
[]
]
},
{
"id": "demo-delay-state",
"type": "debug",
"z": "tab-demo-delay",
"name": "door state",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 840,
"y": 220,
"wires": []
},
{
"id": "demo-delay-events",
"type": "debug",
"z": "tab-demo-delay",
"name": "send events",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 840,
"y": 300,
"wires": []
},
{
"id": "tab-demo-multi",
"type": "tab",
"label": "05 Multi-Machine",
"disabled": false,
"info": "# 05 Multi-Machine\n\n两个 config node 各自一个会话,用同名事件 \toggle 互不影响:\n\n- **Lamp**:off ↔ on;\n- **Fan**:low ↔ high;\n- 监控侧栏的机器选择器可切换两台;\n- 同一个 flow 里可以继续添加更多机器。\n\n覆盖:多 config node、独立 session、机器选择器。"
},
{
"id": "demo-multi-help",
"type": "comment",
"z": "tab-demo-multi",
"name": "说明",
"info": "两个机器都接 toggle,但状态独立。",
"x": 80,
"y": 80,
"wires": []
},
{
"id": "demo-lamp-conf",
"type": "statechart-machine",
"z": "tab-demo-multi",
"name": "Lamp",
"source": "\n\n \n \n",
"engine": "sandboxed",
"scriptTimeoutMs": 500,
"maxMicrosteps": 10000,
"monitorShowVars": false,
"persistVars": false,
"updateEvent": "update",
"x": 160,
"y": 160,
"wires": []
},
{
"id": "demo-fan-conf",
"type": "statechart-machine",
"z": "tab-demo-multi",
"name": "Fan",
"source": "\n\n \n \n",
"engine": "sandboxed",
"scriptTimeoutMs": 500,
"maxMicrosteps": 10000,
"monitorShowVars": false,
"persistVars": false,
"updateEvent": "update",
"x": 160,
"y": 440,
"wires": []
},
{
"id": "demo-lamp-toggle",
"type": "inject",
"z": "tab-demo-multi",
"name": "toggle lamp",
"props": [
{
"p": "topic",
"vt": "str",
"v": "toggle"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"payload": "",
"payloadType": "str",
"topic": "toggle",
"x": 100,
"y": 220,
"wires": [
[
"demo-lamp-out"
]
]
},
{
"id": "demo-fan-toggle",
"type": "inject",
"z": "tab-demo-multi",
"name": "toggle fan",
"props": [
{
"p": "topic",
"vt": "str",
"v": "toggle"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"payload": "",
"payloadType": "str",
"topic": "toggle",
"x": 100,
"y": 500,
"wires": [
[
"demo-fan-out"
]
]
},
{
"id": "demo-lamp-out",
"type": "statechart-hub",
"z": "tab-demo-multi",
"name": "lamp state",
"machine": "demo-lamp-conf",
"includeVars": false,
"emitInitial": true,
"includeInternalSends": false,
"stateTopic": "lamp/state",
"eventTopic": "statechart/{machine}/evt/{event}",
"x": 580,
"y": 220,
"wires": [
[
"demo-lamp-debug"
],
[],
[]
]
},
{
"id": "demo-fan-out",
"type": "statechart-hub",
"z": "tab-demo-multi",
"name": "fan state",
"machine": "demo-fan-conf",
"includeVars": false,
"emitInitial": true,
"includeInternalSends": false,
"stateTopic": "fan/state",
"eventTopic": "statechart/{machine}/evt/{event}",
"x": 580,
"y": 500,
"wires": [
[
"demo-fan-debug"
],
[],
[]
]
},
{
"id": "demo-lamp-debug",
"type": "debug",
"z": "tab-demo-multi",
"name": "lamp",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 840,
"y": 220,
"wires": []
},
{
"id": "demo-fan-debug",
"type": "debug",
"z": "tab-demo-multi",
"name": "fan",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 840,
"y": 500,
"wires": []
},
{
"id": "tab-demo-doc",
"type": "tab",
"label": "06 ProjectDoc & Persistence",
"disabled": false,
"info": "# 06 ProjectDoc & Persistence\n\n这台机器只存 **ProjectDoc JSON**(没有原始 SCXML),打开配置会直接看到三张表:\n\n- cart → paying → done(final);\n- entry action 更新 step 变量;\n- persistVars: true,变量写入 Node-RED context;\n- 点 **checkout / paid** 推进;**reset** 重建会话。\n\n覆盖:ProjectDoc、GUI 三张表、final 状态、persistVars、reset。"
},
{
"id": "demo-doc-help",
"type": "comment",
"z": "tab-demo-doc",
"name": "说明",
"info": "打开机器配置看 ProjectDoc 三张表;checkout → paid。",
"x": 80,
"y": 80,
"wires": []
},
{
"id": "demo-doc-conf",
"type": "statechart-machine",
"z": "tab-demo-doc",
"name": "Checkout (ProjectDoc)",
"source": "",
"doc": "{\"formatVersion\":1,\"name\":\"checkout\",\"initial\":\"u1\",\"datamodel\":[{\"id\":\"step\",\"expr\":\"'cart'\"}],\"states\":[{\"uid\":\"u1\",\"id\":\"cart\",\"label\":\"cart\",\"kind\":\"atomic\",\"parent\":null,\"initial\":null,\"entryActions\":[\"assign step = 'cart'\"],\"exitActions\":[]},{\"uid\":\"u2\",\"id\":\"paying\",\"label\":\"paying\",\"kind\":\"atomic\",\"parent\":null,\"initial\":null,\"entryActions\":[\"assign step = 'paying'\"],\"exitActions\":[]},{\"uid\":\"u3\",\"id\":\"done\",\"label\":\"done\",\"kind\":\"final\",\"parent\":null,\"initial\":null,\"entryActions\":[],\"exitActions\":[]}],\"transitions\":[{\"id\":\"t1\",\"source\":\"u1\",\"target\":\"u2\",\"event\":\"checkout\",\"cond\":\"\",\"actions\":[]},{\"id\":\"t2\",\"source\":\"u2\",\"target\":\"u3\",\"event\":\"paid\",\"cond\":\"\",\"actions\":[]}],\"layout\":{}}",
"engine": "sandboxed",
"scriptTimeoutMs": 500,
"maxMicrosteps": 10000,
"monitorShowVars": true,
"persistVars": true,
"updateEvent": "update",
"x": 160,
"y": 160,
"wires": []
},
{
"id": "demo-doc-checkout",
"type": "inject",
"z": "tab-demo-doc",
"name": "checkout",
"props": [
{
"p": "topic",
"vt": "str",
"v": "checkout"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"payload": "",
"payloadType": "str",
"topic": "checkout",
"x": 100,
"y": 240,
"wires": [
[
"demo-doc-out"
]
]
},
{
"id": "demo-doc-paid",
"type": "inject",
"z": "tab-demo-doc",
"name": "paid",
"props": [
{
"p": "topic",
"vt": "str",
"v": "paid"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"payload": "",
"payloadType": "str",
"topic": "paid",
"x": 100,
"y": 300,
"wires": [
[
"demo-doc-out"
]
]
},
{
"id": "demo-doc-reset",
"type": "inject",
"z": "tab-demo-doc",
"name": "reset",
"props": [
{
"p": "payload",
"vt": "json",
"v": "{\"command\":\"reset\"}"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"payload": "{\"command\":\"reset\"}",
"payloadType": "json",
"topic": "",
"x": 100,
"y": 360,
"wires": [
[
"demo-doc-out"
]
]
},
{
"id": "demo-doc-out",
"type": "statechart-hub",
"z": "tab-demo-doc",
"name": "checkout state",
"machine": "demo-doc-conf",
"includeVars": true,
"emitInitial": true,
"includeInternalSends": false,
"stateTopic": "checkout/state",
"eventTopic": "checkout/{event}",
"x": 620,
"y": 240,
"wires": [
[
"demo-doc-state",
"demo-doc-vars"
],
[],
[]
]
},
{
"id": "demo-doc-state",
"type": "debug",
"z": "tab-demo-doc",
"name": "state (full)",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 900,
"y": 220,
"wires": []
},
{
"id": "demo-doc-vars",
"type": "debug",
"z": "tab-demo-doc",
"name": "vars",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "vars",
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
"x": 900,
"y": 280,
"wires": []
},
{
"id": "tab-demo-internal",
"type": "tab",
"label": "07 Raise & Internal Events",
"disabled": false,
"info": "# Kit 0.13 · 内部事件 / raise\n\n演示 `statechart-kit@0.15.1` 的两个新能力:\n\n- **raise**:`arm` 转移执行 `raise ping`,在同一个宏步内产生图内内部事件;\n- **internalOnlyEvents**:`ping` 标记为「仅内部」,转移生成 SCXML guard\n `_event.type === 'internal'`;外部同名事件不会触发。\n\n推荐操作:\n\n1. 点「外部 ping(应被忽略)」:状态保持 idle,Hub 输出 2 没有 `ping`;\n2. 点「arm → raise ping」:idle → session/armed,raise ping 后进入 handling,visits +1;\n3. 点「ack」:回到 idle;\n4. 打开机器配置 → 完整编辑器,在事件面板把 ping 改成「双向」,再点外部 ping 就会触发。\n\n注意:`raise` 不是 ``,不会出现在 Hub 输出 2;这是刻意保留的 SCXML 语义。"
},
{
"id": "note-kit13-internal",
"type": "comment",
"z": "tab-demo-internal",
"name": "Kit 0.13 · raise + internal-only",
"info": "# Kit 0.13 · 内部事件 / raise\n\n演示 `statechart-kit@0.15.1` 的两个新能力:\n\n- **raise**:`arm` 转移执行 `raise ping`,在同一个宏步内产生图内内部事件;\n- **internalOnlyEvents**:`ping` 标记为「仅内部」,转移生成 SCXML guard\n `_event.type === 'internal'`;外部同名事件不会触发。\n\n推荐操作:\n\n1. 点「外部 ping(应被忽略)」:状态保持 idle,Hub 输出 2 没有 `ping`;\n2. 点「arm → raise ping」:idle → session/armed,raise ping 后进入 handling,visits +1;\n3. 点「ack」:回到 idle;\n4. 打开机器配置 → 完整编辑器,在事件面板把 ping 改成「双向」,再点外部 ping 就会触发。\n\n注意:`raise` 不是 ``,不会出现在 Hub 输出 2;这是刻意保留的 SCXML 语义。",
"x": 80,
"y": 60,
"w": 520,
"h": 120,
"wires": []
},
{
"id": "conf-internal-events",
"type": "statechart-machine",
"z": "tab-demo-internal",
"name": "Internal Events Demo",
"source": "\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n",
"doc": "{\"formatVersion\":1,\"name\":\"Internal Events Demo\",\"initial\":\"u-idle\",\"datamodel\":[{\"id\":\"visits\",\"expr\":\"0\"},{\"id\":\"lastEvent\",\"expr\":\"\\\"none\\\"\"}],\"states\":[{\"uid\":\"u-idle\",\"id\":\"idle\",\"label\":\"idle\",\"kind\":\"atomic\",\"parent\":null,\"initial\":null,\"entryActions\":[\"assign lastEvent = \\\"idle\\\"\"],\"exitActions\":[]},{\"uid\":\"u-session\",\"id\":\"session\",\"label\":\"session\",\"kind\":\"compound\",\"parent\":null,\"initial\":\"u-armed\",\"entryActions\":[],\"exitActions\":[]},{\"uid\":\"u-armed\",\"id\":\"armed\",\"label\":\"armed\",\"kind\":\"atomic\",\"parent\":\"u-session\",\"initial\":null,\"entryActions\":[],\"exitActions\":[]},{\"uid\":\"u-handling\",\"id\":\"handling\",\"label\":\"handling\",\"kind\":\"atomic\",\"parent\":\"u-session\",\"initial\":null,\"entryActions\":[\"assign visits = visits + 1\",\"assign lastEvent = \\\"handling\\\"\"],\"exitActions\":[]}],\"transitions\":[{\"id\":\"t-arm\",\"source\":\"u-idle\",\"target\":\"u-session\",\"event\":\"arm\",\"cond\":\"\",\"actions\":[\"assign lastEvent = \\\"arm\\\"\",\"raise ping\"]},{\"id\":\"t-ping\",\"source\":\"u-armed\",\"target\":\"u-handling\",\"event\":\"ping\",\"cond\":\"\",\"actions\":[]},{\"id\":\"t-ack\",\"source\":\"u-handling\",\"target\":\"u-idle\",\"event\":\"ack\",\"cond\":\"\",\"actions\":[]}],\"layout\":{\"u-idle\":{\"x\":80,\"y\":240},\"u-session\":{\"x\":340,\"y\":180},\"u-armed\":{\"x\":380,\"y\":300},\"u-handling\":{\"x\":580,\"y\":300}},\"internalOnlyEvents\":[\"ping\"]}",
"engine": "sandboxed",
"scriptTimeoutMs": 500,
"maxMicrosteps": 10000,
"monitorShowVars": true,
"persistVars": false,
"updateEvent": "update",
"x": 260,
"y": 230,
"wires": []
},
{
"id": "inject-external-ping",
"type": "inject",
"z": "tab-demo-internal",
"name": "外部 ping(应被忽略)",
"props": [
{
"p": "topic",
"vt": "str",
"v": "ping"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "ping",
"x": 120,
"y": 380,
"wires": [
[
"hub-internal"
]
]
},
{
"id": "inject-arm",
"type": "inject",
"z": "tab-demo-internal",
"name": "arm → raise ping",
"props": [
{
"p": "topic",
"vt": "str",
"v": "arm"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "arm",
"x": 120,
"y": 440,
"wires": [
[
"hub-internal"
]
]
},
{
"id": "inject-ack",
"type": "inject",
"z": "tab-demo-internal",
"name": "ack",
"props": [
{
"p": "topic",
"vt": "str",
"v": "ack"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "ack",
"x": 120,
"y": 500,
"wires": [
[
"hub-internal"
]
]
},
{
"id": "hub-internal",
"type": "statechart-hub",
"z": "tab-demo-internal",
"name": "Internal Events",
"machine": "conf-internal-events",
"includeVars": true,
"emitInitial": true,
"includeInternalSends": true,
"stateTopic": "",
"eventTopic": "statechart/{machine}/evt/{event}",
"x": 520,
"y": 420,
"wires": [
[
"kit13-debug-state"
],
[
"kit13-debug-events"
],
[
"kit13-debug-errors"
]
]
},
{
"id": "kit13-debug-state",
"type": "debug",
"z": "tab-demo-internal",
"name": "state / vars",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 820,
"y": 380,
"wires": []
},
{
"id": "kit13-debug-events",
"type": "debug",
"z": "tab-demo-internal",
"name": "chart send(raise 不出现)",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 820,
"y": 440,
"wires": []
},
{
"id": "kit13-debug-errors",
"type": "debug",
"z": "tab-demo-internal",
"name": "errors / done",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 820,
"y": 500,
"wires": []
}
]