https://github.com/initialed85/stato
A simple state machine library written in Go
https://github.com/initialed85/stato
fsm fsm-library go golang
Last synced: about 2 months ago
JSON representation
A simple state machine library written in Go
- Host: GitHub
- URL: https://github.com/initialed85/stato
- Owner: initialed85
- License: mit
- Created: 2021-04-11T11:11:28.000Z (almost 5 years ago)
- Default Branch: master
- Last Pushed: 2024-05-25T14:11:26.000Z (almost 2 years ago)
- Last Synced: 2025-05-14T02:51:51.310Z (11 months ago)
- Topics: fsm, fsm-library, go, golang
- Language: Go
- Homepage:
- Size: 19.5 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# stato
# status: working and refreshed recently for use in an OCPP server
Named after the iconic Holden Statesman, `stato` tries to be a simple state machine library providing states and
transitions with one or more on-enter and on-exit callbacks for both.
## Usage
The example below builds a state machine that's intended to be used via the `ChangeState()` approach (i.e. try to find
a unique for the source state to the destination state) but you can also explicitly use the `Transition()` approach
(i.e. try to invoke a transition that calls for a specific source state and destination state).
```golang
package state_machines
import (
"fmt"
"github.com/initialed85/stato/pkg/fsm"
)
type ConnectorFSM struct {
Available *fsm.State
Preparing *fsm.State
Charging *fsm.State
SuspendedEV *fsm.State
SuspendedEVSE *fsm.State
Finishing *fsm.State
Reserved *fsm.State
Unavailable *fsm.State
Faulted *fsm.State
states []*fsm.State
transitions []*fsm.Transition
machine *fsm.Machine
}
func NewConnectorFSM() (*ConnectorFSM, error) {
f := ConnectorFSM{
Available: fsm.NewState(
"Available",
[]func() error{},
[]func() error{},
),
Preparing: fsm.NewState(
"Preparing",
[]func() error{},
[]func() error{},
),
Charging: fsm.NewState(
"Charging",
[]func() error{},
[]func() error{},
),
SuspendedEV: fsm.NewState(
"SuspendedEV",
[]func() error{},
[]func() error{},
),
SuspendedEVSE: fsm.NewState(
"SuspendedEVSE",
[]func() error{},
[]func() error{},
),
Finishing: fsm.NewState(
"Finishing",
[]func() error{},
[]func() error{},
),
Reserved: fsm.NewState(
"Reserved",
[]func() error{},
[]func() error{},
),
Unavailable: fsm.NewState(
"Unavailable",
[]func() error{},
[]func() error{},
),
Faulted: fsm.NewState(
"Faulted",
[]func() error{},
[]func() error{},
),
}
f.states = []*fsm.State{
f.Available,
f.Preparing,
f.Charging,
f.SuspendedEV,
f.SuspendedEVSE,
f.Finishing,
f.Reserved,
f.Unavailable,
f.Faulted,
}
alpha := map[string]*fsm.State{
"A": f.Available,
"B": f.Preparing,
"C": f.Charging,
"D": f.SuspendedEV,
"E": f.SuspendedEVSE,
"F": f.Finishing,
"G": f.Reserved,
"H": f.Unavailable,
"I": f.Faulted,
}
numeric := map[string]*fsm.State{
"1": f.Available,
"2": f.Preparing,
"3": f.Charging,
"4": f.SuspendedEV,
"5": f.SuspendedEVSE,
"6": f.Finishing,
"7": f.Reserved,
"8": f.Unavailable,
"9": f.Faulted,
}
// note: don't trust this matrix if you're implementing an OCPP server- it was hand-entered by a human
permutations := []string{
"__", "A2", "A3", "A4", "A5", "__", "A7", "A8", "A9",
"B1", "__", "B3", "B4", "B5", "__", "__", "__", "B9",
"C1", "__", "__", "C4", "C5", "C6", "__", "C8", "C9",
"D1", "__", "D3", "__", "D5", "D6", "__", "D8", "D9",
"E1", "__", "E3", "E4", "__", "E6", "__", "E8", "E9",
"F1", "F2", "__", "__", "__", "__", "__", "F8", "F9",
"G1", "G2", "__", "__", "__", "__", "__", "G8", "G9",
"H1", "H2", "H3", "H4", "H5", "__", "__", "__", "H9",
"I1", "I2", "I3", "I4", "I5", "I6", "I7", "I8", "_",
}
for _, permutation := range permutations {
source := permutation[0:1]
destination := permutation[1:2]
sourceState, alphaOk := alpha[source]
destinationState, numericOk := numeric[destination]
if !(alphaOk && numericOk) {
continue
}
f.transitions = append(
f.transitions,
fsm.NewTransition(
fmt.Sprintf("%vTo%v", source, destination),
[]func() error{},
[]func() error{},
sourceState,
destinationState,
),
)
}
machine, err := fsm.NewMachine(
"Connector",
f.states,
f.transitions,
f.Unavailable,
)
if err != nil {
return nil, err
}
f.machine = machine
return &f, nil
}
func (c *ConnectorFSM) ChangeState(destinationState *fsm.State) error {
return c.machine.ChangeState(destinationState)
}
```