Graph-IT

ControlPi-Plugin für Statemachines

Dieses Paket enthält ein Plugin für das ControlPi-System, mit dem Statemachines konfiguriert werden können, die auf Nachrichten des zentralen Nachrichten-Busses des ControlPi-Systems reagieren und bei Zustands-Wechseln Kommandos/Nachrichten an andere Komponenten des Systems schicken.

Installation

Eine ausführliche Dokumentation ist in der Dokumentation der ControlPi-Infrastruktur zu finden.

Der Code dieses Plugins kann mit git geclonet werden:

$ git clone git://git.graph-it.com/graphit/controlpi-statemachine.git

(Falls Zugang zu diesem Server per SSH besteht und Änderungen gepusht werden sollen, sollte stattdessen die SSH-URL benutzt werden.)

Dann kann es editierbar in ein virtuelles Environment installiert werden:

(venv)$ pip install --editable <Pfad zum Code-Repository>

Auf dem Raspberry Pi (oder wenn keine Code-Änderungen gewünscht sind) kann es auch direkt, ohne einen git-Clone installiert werden:

(venv)$ pip install git+git://git.graph-it.com/graphit/controlpi-statemachine.git

Benutzung

Eine minimale ControlPi-Konfiguration, die dieses Plugin benutzt, ist im git-Repository enthalten:

{
    "Debug": {
        "plugin": "WSServer",
        "port": 8080,
        "web": {
            "/": { "module": "controlpi_plugins.wsserver",
                   "location": "Debug" }
        }
    },
    "Engine Button": {
        "plugin": "Alias",
        "from": {
            "target": { "const": "Engine Button" },
            "command": { "const": "press" }
        },
        "to": {
            "event": "pressed"
        }
    },
    "Emergency Button": {
        "plugin": "Alias",
        "from": {
            "target": { "const": "Emergency Button" },
            "command": { "const": "press"}
        },
        "to": {
            "event": "pressed"
        }
    },
    "Engine": {
        "plugin": "State"
    },
    "Delay": {
        "plugin": "Wait",
        "seconds": 5
    },
    "Machine": {
        "plugin": "StateMachine",
        "init": "off",
        "states": {
            "emergency": {
                "commands": [
                    {
                        "target": "Engine",
                        "command": "set state",
                        "new state": false
                    }
                ],
                "transitions": [
                    {
                        "trigger": {
                            "sender": { "const": "Emergency Button" },
                            "event": { "const": "pressed" }
                        },
                        "to": "off"
                    }
                ]
            },
            "off": {
                "commands": [
                    {
                        "target": "Engine",
                        "command": "set state",
                        "new state": false
                    }
                ],
                "transitions": [
                    {
                        "trigger": {
                            "sender": { "const": "Emergency Button" },
                            "event": { "const": "pressed" }
                        },
                        "to": "emergency"
                    },
                    {
                        "trigger": {
                            "sender": { "const": "Engine Button" },
                            "event": { "const": "pressed" }
                        },
                        "to": "on"
                    }
                ]
            },
            "on": {
                "commands": [
                    {
                        "target": "Engine",
                        "command": "set state",
                        "new state": true
                    }
                ],
                "transitions": [
                    {
                        "trigger": {
                            "sender": { "const": "Emergency Button" },
                            "event": { "const": "pressed" }
                        },
                        "to": "emergency"
                    },
                    {
                        "trigger": {
                            "sender": { "const": "Engine Button" },
                            "event": { "const": "pressed" }
                        },
                        "to": "delay"
                    }
                ]
            },
            "delay": {
                "commands": [
                    {
                        "target": "Delay",
                        "command": "wait"
                    }
                ],
                "transitions": [
                    {
                        "trigger": {
                            "sender": { "const": "Emergency Button" },
                            "event": { "const": "pressed" }
                        },
                        "to": "emergency"
                    },
                    {
                        "trigger": {
                            "sender": { "const": "Delay" },
                            "event": { "const": "finished" }
                        },
                        "to": "off"
                    }
                ]
            }
        }
    }
}

Die Konfiguration einer StateMachine-Plugin-Instanz enthält ein Attribut init, das den initialen Zustand der Maschine benennt, und ein Attribut states, das ein Objekt enthält, dessen Schlüssel alle möglichen Zustände der Statemachine sind. Für jeden Zustand wird in commands eine Liste von Nachrichten angegeben, die beim Betreten des Zustands gesendet werden sollen, während in transitions eine Liste von Transitionen definiert wird, die jeweils ein Nachrichten-Schema als trigger und den Zustand, in den gewechselt werden soll, als to haben.

In der Debug-Oberfläche sieht das Beispiel folgendermaßen aus:

Debug-Oberfläche

Die beiden Alias-Instanzen simulieren Taster und die State-Instanz Engine einen Motor, der von der Statemachine gesteuert wird. Aus dem initialen Zustand off kann durch Drücken des Engine Button in den Zustand on gewechselt werden.

Nochmaliges Drücken des Engine Button schaltet die Maschine aber nicht sofort ab, sondern wechelt in einen fünf-sekündigen Nachlauf im Zustand delay. Dies wird dadurch erreicht, dass beim Betreten des Zustands dem Wait-Plugin Delay das Kommando wait geschickt wird und der Zustand dann durch eine Transition, die auf das finished-Event reagiert verlassen wird.

Außerdem kann die Maschine aus jedem Zustand heraus durch Drücken des Emergency Button sofort abgeschaltet werden, wobei in den Zustand emergency gewechselt wird. Dieser kann nur verlassen werden, wenn durch nochmaliges Drücken des Emergency Button bestätigt wird, dass die Gefahr vorüber ist.