diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index e21a0ce8166960ab82cfa312a1cb6fc0d823fa3d..6034859aa70105ce7f465e2896e2367522ee534c 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,7 +1,7 @@
 # GitLab CI in conjunction with GitLab Runner can use Docker Engine to test and build any application.
 # Docker, when used with GitLab CI, runs each job in a separate and isolated container using the predefined image that is set up in .gitlab-ci.yml.
 # In this case we use the latest python docker image to build and test this project.
-image: nexus.engageska-portugal.pt/ska-docker/ska-python-buildenv:9.3.2
+image: nexus.engageska-portugal.pt/ska-docker/ska-python-buildenv:9.3.2.1
 
 include:
   - project: 'ska-telescope/templates-repository'
@@ -29,7 +29,7 @@ stages:
 clean shell runner:
   stage: .pre
   tags:
-    - docker-executor
+    - k8srunner
   script:
     # Gitlab CI badges creation
     - rm -rf build/*
@@ -37,7 +37,7 @@ clean shell runner:
 build wheel for publication: # Executed on a tag
   stage: build
   tags:
-    - docker-executor
+    - k8srunner
   script:
     - python3 setup.py egg_info -b+$CI_COMMIT_SHORT_SHA sdist bdist_wheel
   rules:
@@ -49,7 +49,7 @@ build wheel for publication: # Executed on a tag
 build wheel for development: # Executed on non-tagged commit
   stage: build
   tags:
-    - docker-executor
+    - k8srunner
   script:
     - python3 setup.py egg_info -b+dev.$CI_COMMIT_SHORT_SHA sdist bdist_wheel
   rules:
@@ -61,7 +61,7 @@ build wheel for development: # Executed on non-tagged commit
 unit tests:
   stage: test
   tags:
-    - docker-executor
+    - k8srunner
   script:
     - echo $(ls -d ./dist/*.whl | grep $CI_COMMIT_SHORT_SHA)
     - python3 -m pip install -U $(ls -d ./dist/*.whl | grep $CI_COMMIT_SHORT_SHA)
@@ -74,7 +74,7 @@ unit tests:
 linting:
   stage: linting
   tags:
-    - docker-executor
+    - k8srunner
   script:
     - echo $(ls -d ./dist/*.whl | grep $CI_COMMIT_SHORT_SHA)
     - python3 -m pip install -U $(ls -d ./dist/*.whl | grep $CI_COMMIT_SHORT_SHA)
@@ -86,7 +86,7 @@ linting:
 publish to nexus:
   stage: publish
   tags:
-    - docker-executor
+    - k8srunner
   variables:
     TWINE_USERNAME: $TWINE_USERNAME
     TWINE_PASSWORD: $TWINE_PASSWORD
@@ -105,7 +105,7 @@ release docker image:
   before_script:
   - docker login -u $DOCKER_REGISTRY_USERNAME -p $DOCKER_REGISTRY_PASSWORD $DOCKER_REGISTRY_HOST
   tags:
-    - docker-executor
+    - k8srunner
   script:
     - make build
     - make push
@@ -118,7 +118,7 @@ release docker image:
 pages:
   stage: pages
   tags:
-    - docker-executor
+    - k8srunner
   script:
     - cp -R build public
     - mv public/htmlcov/* public
diff --git a/.release b/.release
index c1c4389eb647922640cfdff017dba2f11f3f4857..87b75fde02ff38edc5a39741f2fed429127edd5a 100644
--- a/.release
+++ b/.release
@@ -1,2 +1,2 @@
-release=0.6.6
-tag=lmcbaseclasses-0.6.6
+release=0.7.0
+tag=lmcbaseclasses-0.7.0
diff --git a/Dockerfile b/Dockerfile
index 4dbff9ecae8071140a0d8803e91adfb15427b24f..aa0aa72623bb47b01a408da63681a9f5cc16f3f8 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,13 +1,10 @@
 # Use SKA python image as base image
-FROM nexus.engageska-portugal.pt/ska-docker/ska-python-buildenv:9.3.2 AS buildenv
-FROM nexus.engageska-portugal.pt/ska-docker/ska-python-runtime:9.3.2 AS runtime
+FROM nexus.engageska-portugal.pt/ska-docker/ska-python-buildenv:9.3.2.1 AS buildenv
+FROM nexus.engageska-portugal.pt/ska-docker/ska-python-runtime:9.3.2.1 AS runtime
 
 # create ipython profile to so that itango doesn't fail if ipython hasn't run yet
 RUN ipython profile create
 
-# TODO: move this dependency to ska-docker/docker/tango/ska-python-buildenv/requirements.txt
-RUN python3 -m pip install --user pytest-forked
-
 # Note: working dir is `/app` which will have a copy of our repo
 # The pip install will be a "user installation" so update path to access console scripts
 ENV PATH=/home/tango/.local/bin:$PATH
diff --git a/Makefile b/Makefile
index 9d111ec0cd7de5a588b8a09da922c53e163717d1..7989f1bb684584c22f5625e7532217f8e83dab7e 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@ SHELL = /bin/bash
 #
 DOCKER_REGISTRY_USER:=tango-example
 PROJECT = lmcbaseclasses
-
+IMAGE_FOR_DIAGRAMS = nexus.engageska-portugal.pt/ska-docker/ska-python-buildenv:9.3.2.1
 #
 # include makefile to pick up the standard Make targets, e.g., 'make build'
 # build, 'make push' docker push procedure, etc. The other Make targets
@@ -40,10 +40,21 @@ lint: ## lint lmcbaseclasses Python code
 	pylint --output-format=pylint2junit.JunitReporter src/ska > build/reports/linting.xml
 
 test-in-docker: build ## Build the docker image and run tests inside it.
-	@docker run $(IMAGE):$(VERSION) make test
+	@docker run --rm $(IMAGE):$(VERSION) make test
 
 lint-in-docker: build ## Build the docker image and run lint inside it.
-	@docker run $(IMAGE):$(VERSION) make lint
+	@docker run --rm $(IMAGE):$(VERSION) make lint
+
+generate-diagrams-in-docker: ## Build the docker image and generate state machine diagrams inside it.
+	@docker run --rm -v $(PWD):/diagrams $(IMAGE_FOR_DIAGRAMS) bash -c "cd /diagrams && make generate-diagrams-in-docker-internals"
+
+generate-diagrams-in-docker-internals:  ## Generate state machine diagrams (within a container!)
+	test -f /.dockerenv  # ensure running in docker container
+	apt-get update
+	apt-get install --yes graphviz graphviz-dev gsfonts pkg-config
+	python3 -m pip install pygraphviz
+	cd /diagrams/docs/source && python3 draw_state_machines.py
+	ls -lo /diagrams/docs/source/images/
 
 help:  ## show this help.
 	@grep -hE '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
diff --git a/README.md b/README.md
index 2311a8bd88e19fad7b7cd0418a1b302814e554e9..95a0c07f1265a09513214176bcaac2140e163d1b 100644
--- a/README.md
+++ b/README.md
@@ -25,6 +25,13 @@ The lmc-base-classe repository contains set of eight classes as mentioned in SKA
 
 ## Version History
 
+#### 0.7.0
+- Separate adminMode state machine from opState state machine
+- Add support for STANDBY opState
+- Add Standby() and Disable() commands to SKABaseDevice
+- Breaking behavioural changes to adminMode and opState state machines
+- Breaking change to `_straight_to_state` method signature
+
 #### 0.6.6
 - Documentation bugfix
 
@@ -36,7 +43,7 @@ The lmc-base-classe repository contains set of eight classes as mentioned in SKA
 - Refactor state machine to use pytransitions library.
 - Minor behavioural change: Off() command is accepted in every obsState, rather
 than only EMPTY obsState.
-- support `straight_to_state` shortcuts to simplify test setups
+- support `_straight_to_state` shortcuts to simplify test setups
 - Refactor of state machine testing to make it more portable
 
 #### 0.6.3
diff --git a/docs/source/SKABaseDevice.rst b/docs/source/SKABaseDevice.rst
index 9d41032725d5449356f3100f4035213ed5a81c07..49deb8eb9bdb6784bacef665d92e055d32bbf406 100644
--- a/docs/source/SKABaseDevice.rst
+++ b/docs/source/SKABaseDevice.rst
@@ -10,6 +10,11 @@ SKA BaseDevice
    :maxdepth: 2
 
 .. automodule:: ska.base.base_device
+
+.. autoclass:: ska.base.DeviceStateModel
+   :members:
+   :undoc-members:
+
 .. autoclass:: ska.base.SKABaseDevice
    :members:
    :undoc-members:
diff --git a/docs/source/State_Machine.rst b/docs/source/State_Machine.rst
index ff7d1687b8cdd628b351bff00989fe4544c8bdc7..dfb271032b77820ee02783bdee4655c38498a5c1 100644
--- a/docs/source/State_Machine.rst
+++ b/docs/source/State_Machine.rst
@@ -2,35 +2,125 @@
 State Machine
 =============
 
-The state machine modules implements SKA's two fundamental state machines: the
-base device state machine, and the observation state machine.
-
-Base device state machine
--------------------------
-The base device state machine provides basic state needed for all devices,
-covering initialisation, off and on states, and a fault state. This state
-machine is implemented by all SKA Tango devices that inherit from these LMC
-base classes, though some devices with standby power modes may need to
-implement further states.
-
-
-.. figure:: images/device_state_diagram.png
-  :width: 80%
-  :alt: Diagram of the device state machine, taken from SKA design
-        documentation, showing the state machine as designed
-
-  Diagram of the device state machine, taken from SKA design
-  documentation, showing the state machine as designed
-
-
-.. figure:: images/BaseDeviceStateMachine.png
+The state machine module implements three fundamental SKA state
+machines:
+
+* the admin mode state machine
+* the operational state (opState, represented in TANGO devices by TANGO
+  state) state machine
+* the observation state machine.
+
+Admin mode state machine
+------------------------
+The admin mode state machine allows for transitions between the five
+administrative modes:
+
+* NOT_FITTED: this is the lowest state of readiness, representing
+  devices that cannot be deployed without some external action, such as
+  plugging hardware in or updating network settings.)
+* RESERVED: the device is fitted but redundant to other devices. It is
+  ready to take over should other devices fail.
+* OFFLINE: the device has been declared by SKA operations not currently
+  to be used for operations (or whatever other function it provides)
+* MAINTENANCE: the device cannot be used for science purposes but can be
+  operationed for engineering / maintenance purposes, such as testing,
+  debugging, etc
+* ONLINE: the device can be used for science purposes.
+
+The admin mode state machine allows for
+
+* any transition between the modes NOT_FITTED, RESERVED and OFFLINE
+  (e.g. an unfitted device being fitted as a redundant or non-redundant
+  device, a redundant device taking over when another device fails, etc)
+* any transition between the modes OFFLINE, MAINTENANCE and ONLINE (e.g.
+  an online device being taken offline or put into maintenance mode to
+  diagnose a fault, a faulty device moving between maintenance and
+  offline mode as it undergoes sporadic periods of diagnosis.
+
+Diagrams of the admin mode state machine are shown below.
+
+.. figure:: images/AdminModeStateMachine.png
+  :alt: Diagram of the admin mode state machine, as designed
+
+  Diagram of the admin mode state machine, as designed
+
+.. figure:: images/AdminModeStateMachine_autogenerated.png
+  :alt: Diagram of the admin mode state machine, as implemented
+
+  Diagram of the admin mode state machine, automatically generated from
+  the implementation. The equivalence of this diagram to the diagram
+  above demonstrates that the machine has been implemented as designed.
+
+
+Operational state state machine
+-------------------------------
+The operational state (opState) machine represents the operational state
+of a SKA device. It is represented in TANGO devices using the TANGO
+"state", so the states used are a subset of the TANGO states: INIT,
+FAULT, DISABLE, STANDBY, OFF and ON.
+
+* INIT: the device is currently initialising
+* FAULT: the device has experienced an error from which it could not
+  recover.
+* DISABLE: the device is in its lowest state of readiness, from which
+  it may take some time to become fully operational. For example, if the
+  device manages hardware, that hardware may be switched off.
+* STANDBY: the device is unready, but can be made ready quickly. For
+  example, if the device manages hardware, that hardware may be in a
+  low-power standby mode.
+* OFF: the device is fully operational but is not currently in use
+* ON: the device is in use
+
+The operational state state machine allows for:
+
+* transition from INIT or FAULT into any of the three "readiness states"
+  DISABLE, STANDBY and OFF.
+* all transitions between these three "readiness states" DISABLE,
+  STANDBY and OFF.
+* transition between OFF and ON.
+
+.. figure:: images/OperationStateMachine_decoupled.png
+  :alt: Diagram of the operational state state machine, as designed,
+        ignoring coupling with admin mode
+
+  Diagram of the operational state (opState) state machine, as
+  designed, ignoring coupling with admin mode
+
+Unfortunately, operational state is inextricably coupled with admin
+mode: there are admin modes that imply disablement, and operational
+states such as ON should not be possible in such admin modes.
+
+To facilitate this, the entire operational state state machine is
+accessible only when the admin mode is ONLINE or MAINTENANCE. When in
+any other admin mode, the only permitted operational states are INIT,
+FAULT and DISABLE. This constraint is implemented into the operational
+state state machine by
+
+* three extra states: INIT_ADMIN, FAULT_ADMIN and DISABLED_ADMIN
+* two extra transition triggers: "admin_on" and "admin_off", which allow
+  for transition between INIT and INIT_ADMIN; FAULT and FAULT_ADMIN; and
+  DISABLE and DISABLE_ADMIN. 
+
+This implementation minimises the coupling between admin mode and
+operational state, allowing the two machines to be conceptualised almost
+separately.
+
+Diagrams of the operational state state machine are shown below.
+
+.. figure:: images/OperationStateMachine_coupled.png
+  :alt: Diagram of the operational state state machine, as designed,
+        showing coupling with admin mode
+
+  Diagram of the operational state (opState) state machine, as
+  designed, showing coupling with admin mode
+
+.. figure:: images/OperationStateMachine_autogenerated.png
   :width: 80%
-  :alt: Diagram of the device state machine, automatically generated
-        from the state machine as specified in code.
+  :alt: Diagram of the operational state state machine, as implemented
 
-  Diagram of the device state machine, automatically generated from the
-  state machine as specified in code. The equivalence of this diagram to
-  the diagram previous demonstrates that the machine has been
+  Diagram of the operational state state machine, automatically
+  generated from the implementation. The equivalence of this diagram
+  to the diagram above demonstrates that the machine has been
   implemented as designed.
 
 
@@ -39,31 +129,37 @@ Observation state machine
 The observation state machine is implemented by devices that manage
 observations (currently only subarray devices).
 
-.. figure:: images/ADR-8.png
+.. figure:: images/ObservationStateMachine_adr8.png
   :width: 80%
-  :alt: Diagram of the observation state machine, as decided and published in ADR-8.
+  :alt: Diagram of the observation state machine, as decided and
+        published in ADR-8.
   
-  Diagram of the observation state machine, as decided and published in ADR-8.
+  Diagram of the observation state machine, as decided and published in
+  ADR-8.
 
 
-.. figure:: images/ObservationStateMachine.png
+.. figure:: images/ObservationStateMachine_autogenerated.png
   :width: 80%
-  :alt: Diagram of the observation state machine, automatically generated from
-        the state machine as specified in code.
+  :alt: Diagram of the observation state machine, automatically
+        generated from the implementation
   
   Diagram of the observation state machine, automatically generated from
-  the state machine as specified in code. The equivalance of this
-  diagram to the diagram previous demonstrates that the machine has been
-  implemented in conformance with ADR-8.
+  the implementation. The equivalance of this diagram to the diagram
+  previous demonstrates that the machine has been implemented in
+  conformance with ADR-8.
 
 API
 ---
 
-.. toctree::
-   :maxdepth: 2
-
-
 .. automodule:: ska.base.state_machine
     :members:
     :undoc-members:
 
+.. autoclass:: OperationStateMachine
+    :members:
+
+.. autoclass:: AdminModeStateMachine
+    :members:
+
+.. autoclass:: ObservationStateMachine
+    :members:
diff --git a/docs/source/draw_state_machines.py b/docs/source/draw_state_machines.py
new file mode 100644
index 0000000000000000000000000000000000000000..4823b887cf2cd3839ac43099e7b65224c2fc2a63
--- /dev/null
+++ b/docs/source/draw_state_machines.py
@@ -0,0 +1,50 @@
+"""
+This module draws diagrams of the state machines.
+
+Usage:
+    ~/ska-src/lmc-base-classes$ docker run --rm -ti -v $PWD:/app continuumio/miniconda3 bash
+
+    (base) root@293f3b699c9b:/opt/project/src/ska/base# history
+    $ conda install --yes pygraphviz
+    $ pip install transitions
+    $ apt-get update && apt-get install gsfonts
+    $ cd /app/docs/source
+    $ python draw_state_machines.py
+
+(Or see the top level Makefile)
+
+"""
+import importlib
+import sys
+
+from unittest import mock
+from transitions.extensions import GraphMachine
+
+# local import, so we can run this without installing the whole package
+sys.path.append("../../src/ska/base")
+import state_machine
+
+
+def patch_in_graph_machine():
+    with mock.patch("transitions.Machine", GraphMachine):
+        mod = sys.modules["state_machine"]
+        importlib.reload(mod)
+
+
+def draw(machine_class):
+    machine_name = machine_class.__name__
+    graphing_options = {
+        "title": f"\n{machine_name}",
+        "show_conditions": True,
+        "show_state_attributes": True,
+        "show_auto_transitions": False,
+    }
+    machine = machine_class(None, **graphing_options)
+    machine.get_graph().draw(f"images/{machine_name}_autogenerated.png", prog='dot')
+
+
+if __name__ == "__main__":
+    patch_in_graph_machine()
+    draw(state_machine.OperationStateMachine)
+    draw(state_machine.AdminModeStateMachine)
+    draw(state_machine.ObservationStateMachine)
diff --git a/docs/source/images/AdminModeStateMachine.png b/docs/source/images/AdminModeStateMachine.png
new file mode 100644
index 0000000000000000000000000000000000000000..6351a89cf21b929414bfdaa2ca37028d77a32591
Binary files /dev/null and b/docs/source/images/AdminModeStateMachine.png differ
diff --git a/docs/source/images/AdminModeStateMachine_autogenerated.png b/docs/source/images/AdminModeStateMachine_autogenerated.png
new file mode 100644
index 0000000000000000000000000000000000000000..6c761f570cdbdeb0fa41b6a157ffea9736bf19ed
Binary files /dev/null and b/docs/source/images/AdminModeStateMachine_autogenerated.png differ
diff --git a/docs/source/images/BaseDeviceStateMachine.png b/docs/source/images/BaseDeviceStateMachine.png
deleted file mode 100644
index 805ed112bc4811383278bea4d00c88768580c7c1..0000000000000000000000000000000000000000
Binary files a/docs/source/images/BaseDeviceStateMachine.png and /dev/null differ
diff --git a/docs/source/images/ObservationStateMachine.png b/docs/source/images/ObservationStateMachine.png
deleted file mode 100644
index 8a06b18e1a03ac15f1664557b64f49c0f5a6fa65..0000000000000000000000000000000000000000
Binary files a/docs/source/images/ObservationStateMachine.png and /dev/null differ
diff --git a/docs/source/images/ADR-8.png b/docs/source/images/ObservationStateMachine_adr8.png
similarity index 100%
rename from docs/source/images/ADR-8.png
rename to docs/source/images/ObservationStateMachine_adr8.png
diff --git a/docs/source/images/ObservationStateMachine_autogenerated.png b/docs/source/images/ObservationStateMachine_autogenerated.png
new file mode 100644
index 0000000000000000000000000000000000000000..2299fbbe566219224e8f7b7179828c03298d6115
Binary files /dev/null and b/docs/source/images/ObservationStateMachine_autogenerated.png differ
diff --git a/docs/source/images/OperationStateMachine_autogenerated.png b/docs/source/images/OperationStateMachine_autogenerated.png
new file mode 100644
index 0000000000000000000000000000000000000000..a9845db4166b4727af342d486079e2453676e091
Binary files /dev/null and b/docs/source/images/OperationStateMachine_autogenerated.png differ
diff --git a/docs/source/images/OperationStateMachine_coupled.png b/docs/source/images/OperationStateMachine_coupled.png
new file mode 100644
index 0000000000000000000000000000000000000000..c2e4e248213dee574cf47f484873be631dc77734
Binary files /dev/null and b/docs/source/images/OperationStateMachine_coupled.png differ
diff --git a/docs/source/images/OperationStateMachine_decoupled.png b/docs/source/images/OperationStateMachine_decoupled.png
new file mode 100644
index 0000000000000000000000000000000000000000..057aef047390af60da94e7d574ad6c876b8b36cd
Binary files /dev/null and b/docs/source/images/OperationStateMachine_decoupled.png differ
diff --git a/docs/source/images/device_state_diagram.png b/docs/source/images/device_state_diagram.png
deleted file mode 100644
index 839caca46bad985fb1d6b59e5e6728e2d1ca5a35..0000000000000000000000000000000000000000
Binary files a/docs/source/images/device_state_diagram.png and /dev/null differ
diff --git a/src/ska/base/__init__.py b/src/ska/base/__init__.py
index 049a6be104bcccb29eab16282adf8888bfa8f600..5a718b4d8e64968cd6bf3e1034d877529f23a44a 100644
--- a/src/ska/base/__init__.py
+++ b/src/ska/base/__init__.py
@@ -3,19 +3,22 @@ __all__ = (
     "control_model",
     "state_machine",
     "SKAAlarmHandler",
-    "SKABaseDevice", "SKABaseDeviceStateModel",
+    "SKABaseDevice",
+    "DeviceStateModel",
     "SKACapability",
     "SKALogger",
     "SKAMaster",
     "SKAObsDevice",
-    "SKASubarray", "SKASubarrayStateModel", "SKASubarrayResourceManager",
+    "SKASubarray",
+    "SKASubarrayStateModel",
+    "SKASubarrayResourceManager",
     "SKATelState",
 )
 
 # Note: order of imports is important - start with lowest in the hierarchy
 
 # SKABaseDevice, and then classes that inherit from it
-from .base_device import SKABaseDevice, SKABaseDeviceStateModel
+from .base_device import SKABaseDevice, DeviceStateModel
 from .alarm_handler_device import SKAAlarmHandler
 from .logger_device import SKALogger
 from .master_device import SKAMaster
@@ -25,5 +28,7 @@ from .tel_state_device import SKATelState
 from .obs_device import SKAObsDevice
 from .capability_device import SKACapability
 from .subarray_device import (
-    SKASubarray, SKASubarrayStateModel, SKASubarrayResourceManager
+    SKASubarray,
+    SKASubarrayStateModel,
+    SKASubarrayResourceManager,
 )
diff --git a/src/ska/base/base_device.py b/src/ska/base/base_device.py
index 656922d2a75f48200be9f8b34e9a9b10f5af1881..2d8b824bad2e3141cd279271bcf8a9a8262668d9 100644
--- a/src/ska/base/base_device.py
+++ b/src/ska/base/base_device.py
@@ -38,12 +38,10 @@ from ska.base.control_model import (
     LoggingLevel
 )
 from ska.base.faults import StateModelError
-from ska.base.state_machine import BaseDeviceStateMachine
+from ska.base.state_machine import OperationStateMachine, AdminModeStateMachine
 
 from ska.base.utils import get_groups_from_json, for_testing_only
-from ska.base.faults import (GroupDefinitionsError,
-                             LoggingTargetError,
-                             LoggingLevelError)
+from ska.base.faults import GroupDefinitionsError, LoggingTargetError, LoggingLevelError
 
 LOG_FILE_SIZE = 1024 * 1024  # Log file size 1MB.
 
@@ -59,6 +57,7 @@ class _Log4TangoLoggingLevel(enum.IntEnum):
        https://github.com/tango-controls/cppTango/blob/
        4feffd7c8e24b51c9597a40b9ef9982dd6e99cdf/log4tango/include/log4tango/Level.hh#L86-L93
     """
+
     OFF = 100
     FATAL = 200
     ERROR = 300
@@ -136,7 +135,7 @@ class LoggingUtils:
     def sanitise_logging_targets(targets, device_name):
         """Validate and return logging targets '<type>::<name>' strings.
 
-        :param target:
+        :param targets: 
             List of candidate logging target strings, like '<type>[::<name>]'
             Empty and whitespace-only strings are ignored.  Can also be None.
 
@@ -146,7 +145,7 @@ class LoggingUtils:
 
         :return: list of '<type>::<name>' strings, with default name, if applicable
 
-        :raises: LoggingTargetError for invalid target string that cannot be corrected
+        :raises LoggingTargetError: for invalid target string that cannot be corrected
         """
         default_target_names = {
             "console": "cout",
@@ -205,7 +204,7 @@ class LoggingUtils:
             - address is tuple of (hostname, port), with hostname a string, and port an integer.
             - socktype is socket.SOCK_DGRAM for UDP, or socket.SOCK_STREAM for TCP.
 
-        :raises: LoggingTargetError for invalid url string
+        :raises LoggingTargetError: for invalid url string
         """
         address = None
         socktype = None
@@ -257,7 +256,7 @@ class LoggingUtils:
 
         :return: StreamHandler, RotatingFileHandler, SysLogHandler, or TangoLoggingServiceHandler
 
-        :raises: LoggingTargetError for invalid target string
+        :raises LoggingTargetError: for invalid target string
         """
         if "::" in target:
             target_type, target_name = target.split("::", 1)
@@ -309,12 +308,20 @@ class LoggingUtils:
 # PROTECTED REGION END #    //  SKABaseDevice.additionnal_import
 
 
-__all__ = ["SKABaseDevice", "main"]
+__all__ = ["DeviceStateModel", "SKABaseDevice", "main"]
 
 
-class SKABaseDeviceStateModel:
+class DeviceStateModel:
     """
-    Implements the state model for the SKABaseDevice
+    Implements the state model for the SKABaseDevice.
+
+    This implementation contains separate state machines for adminMode
+    and opState. Since the two are slightly but inextricably coupled,
+    the opState machine includes "ADMIN" flavours for the "INIT",
+    "FAULT" and "DISABLED" states, to represent states where the device
+    has been administratively disabled via the adminModes "RESERVED",
+    "NOT_FITTED" and "OFFLINE". This model drives the two state machines
+    to ensure they remain coherent.
     """
 
     def __init__(self, logger, op_state_callback=None, admin_mode_callback=None):
@@ -324,11 +331,11 @@ class SKABaseDeviceStateModel:
         :param logger: the logger to be used by this state model.
         :type logger: a logger that implements the standard library
             logger interface
-        :param op_state_callback: A callback to be called when a
-            transition implies a change to op state
+        :param op_state_callback: A callback to be called when the state
+            machine for op_state reports a change of state
         :type op_state_callback: callable
-        :param admin_mode_callback: A callback to be called when a
-            transition causes a change to device admin_mode
+        :param admin_mode_callback: A callback to be called when the
+            state machine for admin_mode reports a change of state
         :type admin_mode_callback: callable
         """
         self.logger = logger
@@ -339,9 +346,9 @@ class SKABaseDeviceStateModel:
         self._op_state_callback = op_state_callback
         self._admin_mode_callback = admin_mode_callback
 
-        self._state_machine = BaseDeviceStateMachine(
-            op_state_callback=self._update_op_state,
-            admin_mode_callback=self._update_admin_mode
+        self._op_state_machine = OperationStateMachine(callback=self._update_op_state)
+        self._admin_mode_state_machine = AdminModeStateMachine(
+            callback=self._update_admin_mode
         )
 
     @property
@@ -354,14 +361,17 @@ class SKABaseDeviceStateModel:
         """
         return self._admin_mode
 
-    def _update_admin_mode(self, admin_mode):
+    def _update_admin_mode(self, machine_state):
         """
-        Helper method that updates admin_mode, ensuring that the callback is
-        called if one exists.
+        Helper method that updates admin_mode whenever the admin_mode
+        state machine reports a change of state, ensuring that the
+        callback is called if one exists.
 
-        :param admin_mode: the new adminMode attribute value
-        :type admin_mode: AdminMode
+        :param machine_state: the new state of the adminMode state
+            machine
+        :type machine_state: str
         """
+        admin_mode = AdminMode[machine_state]
         if self._admin_mode != admin_mode:
             self._admin_mode = admin_mode
             if self._admin_mode_callback is not None:
@@ -370,34 +380,98 @@ class SKABaseDeviceStateModel:
     @property
     def op_state(self):
         """
-        Returns the op_state
+        Returns the op_state of this state model
 
         :returns: op_state of this state model
         :rtype: tango.DevState
         """
         return self._op_state
 
-    def _update_op_state(self, op_state):
-        """
-        Helper method that updates op_state, ensuring that the callback is
-        called if one exists.
-
-        :param op_state: the new opState attribute value
-        :type op_state: tango.DevState
-        """
+    _op_state_mapping = {
+        "INIT": DevState.INIT,
+        "INIT_ADMIN": DevState.INIT,
+        "FAULT": DevState.FAULT,
+        "FAULT_ADMIN": DevState.FAULT,
+        "DISABLE": DevState.DISABLE,
+        "DISABLE_ADMIN": DevState.DISABLE,
+        "STANDBY": DevState.STANDBY,
+        "OFF": DevState.OFF,
+        "ON": DevState.ON,
+    }
+
+    def _update_op_state(self, machine_state):
+        """
+        Helper method that updates op_state whenever the operation
+        state machine reports a change of state, ensuring that the
+        callback is called if one exists.
+
+        :param machine_state: the new state of the operation state
+            machine
+        :type machine_state: str
+        """
+        op_state = self._op_state_mapping[machine_state]
         if self._op_state != op_state:
             self._op_state = op_state
             if self._op_state_callback is not None:
                 self._op_state_callback(op_state)
 
+    __action_breakdown = {
+        # "action": ("action_on_op_machine", "action_on_admin_mode_machine"),
+        "to_reserved": ("admin_on", "to_reserved"),
+        "to_notfitted": ("admin_on", "to_notfitted"),
+        "to_offline": ("admin_on", "to_offline"),
+        "to_maintenance": ("admin_off", "to_maintenance"),
+        "to_online": ("admin_off", "to_online"),
+        "init_started": ("init_started", None),
+        "init_succeeded_disable": ("init_succeeded_disable", None),
+        "init_succeeded_standby": ("init_succeeded_standby", None),
+        "init_succeeded_off": ("init_succeeded_off", None),
+        "init_failed": ("init_failed", None),
+        "reset_started": ("reset_started", None),
+        "reset_succeeded_disable": ("reset_succeeded_disable", None),
+        "reset_succeeded_standby": ("reset_succeeded_standby", None),
+        "reset_succeeded_off": ("reset_succeeded_off", None),
+        "reset_failed": ("reset_failed", None),
+        "disable_succeeded": ("disable_succeeded", None),
+        "disable_failed": ("disable_failed", None),
+        "standby_succeeded": ("standby_succeeded", None),
+        "standby_failed": ("standby_failed", None),
+        "off_succeeded": ("off_succeeded", None),
+        "off_failed": ("off_failed", None),
+        "on_succeeded": ("on_succeeded", None),
+        "on_failed": ("on_failed", None),
+        "fatal_error": ("fatal_error", None),
+    }
+
     def is_action_allowed(self, action):
         """
         Whether a given action is allowed in the current state.
 
         :param action: an action, as given in the transitions table
-        :type action: ANY
+        :type action: str
+
+        :raises StateModelError: if the action is unknown to the state
+            machine
+
+        :return: whether the action is allowed in the current state
+        :rtype: bool
         """
-        return action in self._state_machine.get_triggers(self._state_machine.state)
+        try:
+            (op_action, admin_action) = self.__action_breakdown[action]
+        except KeyError as key_error:
+            raise StateModelError(key_error)
+
+        if (
+            admin_action is not None
+            and admin_action
+            not in self._admin_mode_state_machine.get_triggers(
+                self._admin_mode_state_machine.state
+            )
+        ):
+            return False
+        return op_action in self._op_state_machine.get_triggers(
+            self._op_state_machine.state
+        )
 
     def try_action(self, action):
         """
@@ -405,7 +479,7 @@ class SKABaseDeviceStateModel:
         and raises a StateModelError if it is not.
 
         :param action: an action, as given in the transitions table
-        :type action: ANY
+        :type action: str
 
         :raises StateModelError: if the action is not allowed in the
             current state
@@ -415,7 +489,8 @@ class SKABaseDeviceStateModel:
         """
         if not self.is_action_allowed(action):
             raise StateModelError(
-                f"Action '{action}' not allowed in current state ({self._state_machine.state})."
+                f"Action {action} is not allowed in operational state "
+                f"{self.op_state}, admin mode {self.admin_mode}."
             )
         return True
 
@@ -429,59 +504,62 @@ class SKABaseDeviceStateModel:
             current state
 
         """
-        try:
-            self._state_machine.trigger(action)
-        except MachineError as error:
-            raise StateModelError(error)
+        self.try_action(action)
+
+        (op_action, admin_action) = self.__action_breakdown[action]
+
+        if op_action is not None:
+            self._op_state_machine.trigger(op_action)
+        if admin_action is not None:
+            self._admin_mode_state_machine.trigger(action)
 
     @for_testing_only
-    def _straight_to_state(self, state):
+    def _straight_to_state(self, op_state=None, admin_mode=None):
         """
-        Takes the DeviceStateModel straight to the specified state. This method
-        exists to simplify testing; for example, if testing that a command may
-        be run in a given state, one can push the state model straight to that
+        Takes the DeviceStateModel straight to the specified state / mode. This
+        method exists to simplify testing; for example, if testing that a command
+        may be run in a given state, one can push the state model straight to that
         state, rather than having to drive it to that state through a sequence
         of actions. It is not intended that this method would be called outside
         of test setups. A warning will be raised if it is.
 
-        Note that states are non-deterministic with respect to adminMode. For
-        example, in state "FAULT-DISABLED", the adminMode could be OFFLINE or
-        NOT_FITTED. When you drive the state machine through its transitions,
-        the adminMode will be set accordingly. When using this method, the
-        adminMode will simply be set to something sensible.
+        Note that this method will allow you to put the device into an incoherent
+        combination of admin_mode and op_state (e.g. OFFLINE and ON).
 
-        :param state: the target state
-        :type state: string
+        :param op_state: the target operational state (optional)
+        :type op_state: :py:class:`tango.DevState`
+        :param admin_mode: the target admin mode (optional)
+        :type admin_mode: :py:class:`~ska.base.control_model.AdminMode`
         """
-        if state == "UNINITIALISED":
-            pass
-        elif "DISABLED" in state:
-            if self._admin_mode not in [AdminMode.OFFLINE, AdminMode.NOT_FITTED]:
-                self._state_machine._update_admin_mode(AdminMode.OFFLINE)
+        if admin_mode is None:
+            admin_mode = self._admin_mode_state_machine.state
         else:
-            if self._admin_mode not in [AdminMode.ONLINE, AdminMode.MAINTENANCE]:
-                self._state_machine._update_admin_mode(AdminMode.ONLINE)
+            admin_mode = admin_mode.name
 
-        getattr(self._state_machine, f"to_{state}")()
+        if op_state is None:
+            op_state = self._op_state_machine.state
+        else:
+            op_state = op_state.name
 
-    @property
-    def _state(self):
-        """
-        Returns the state of the underlying state machine. This would normally
-        be a hidden implementation detail, but is exposed here for testing
-        purposes.
-        """
-        return self._state_machine.state
+        if op_state.endswith("_ADMIN"):
+            op_state = op_state[:-6]
+        if admin_mode in ["RESERVED", "NOT_FITTED", "OFFLINE"]:
+            op_state = f"{op_state}_ADMIN"
+
+        getattr(self._admin_mode_state_machine, f"to_{admin_mode}")()
+        getattr(self._op_state_machine, f"to_{op_state}")()
 
 
 class SKABaseDevice(Device):
     """
     A generic base device for SKA.
     """
+
     class InitCommand(ActionCommand):
         """
         A class for the SKABaseDevice's init_device() "command".
         """
+
         def __init__(self, target, state_model, logger=None):
             """
             Create a new InitCommand
@@ -493,7 +571,7 @@ class SKABaseDevice(Device):
             :param state_model: the state model that this command uses
                  to check that it is allowed to run, and that it drives
                  with actions.
-            :type state_model: SKABaseDeviceStateModel
+            :type state_model: :py:class:`DeviceStateModel`
             :param logger: the logger to be used by this Command. If not
                 provided, then a default module logger will be used.
             :type logger: a logger that implements the standard library
@@ -557,6 +635,9 @@ class SKABaseDevice(Device):
             self.logger.info(message)
             return (ResultCode.OK, message)
 
+        def succeeded(self):
+            self.state_model.perform_action("init_succeeded_off")
+
     _logging_config_lock = threading.Lock()
     _logging_configured = False
 
@@ -723,7 +804,7 @@ class SKABaseDevice(Device):
         callback
 
         :param admin_mode: the new admin_mode value
-        :type admin_mode: AdminMode
+        :type admin_mode: :py:class:`~ska.base.control_model.AdminMode`
         """
         self.push_change_event("adminMode", admin_mode)
         self.push_archive_event("adminMode", admin_mode)
@@ -734,12 +815,10 @@ class SKABaseDevice(Device):
         callback
 
         :param state: the new state value
-        :type state: DevState
+        :type state: :py:class:`tango.DevState`
         """
         if state != self.get_state():
-            self.logger.info(
-                f"Device state changed from {self.get_state()} to {state}"
-            )
+            self.logger.info(f"Device state changed from {self.get_state()} to {state}")
             self.set_state(state)
             self.set_status(f"The device is in {state} state.")
 
@@ -749,11 +828,11 @@ class SKABaseDevice(Device):
         events are pushed.
 
         :param state: the new state
-        :type state: tango.DevState
+        :type state: :py:class:`tango.DevState`
         """
         super().set_state(state)
-        self.push_change_event('state')
-        self.push_archive_event('state')
+        self.push_change_event("state")
+        self.push_archive_event("state")
 
     def set_status(self, status):
         """
@@ -764,8 +843,8 @@ class SKABaseDevice(Device):
         :type status: str
         """
         super().set_status(status)
-        self.push_change_event('status')
-        self.push_archive_event('status')
+        self.push_change_event("status")
+        self.push_archive_event("status")
 
     def init_device(self):
         """
@@ -775,8 +854,6 @@ class SKABaseDevice(Device):
         default implementation of state management may leave
         ``init_device()`` alone.  Override the ``do()`` method
         on the nested class ``InitCommand`` instead.
-
-        :return: None
         """
         try:
             super().init_device()
@@ -801,10 +878,10 @@ class SKABaseDevice(Device):
         """
         Creates the state model for the device
         """
-        self.state_model = SKABaseDeviceStateModel(
+        self.state_model = DeviceStateModel(
             logger=self.logger,
             op_state_callback=self._update_state,
-            admin_mode_callback=self._update_admin_mode
+            admin_mode_callback=self._update_admin_mode,
         )
 
     def register_command_object(self, command_name, command_object):
@@ -841,20 +918,19 @@ class SKABaseDevice(Device):
         """
         device_args = (self, self.state_model, self.logger)
 
-        self.register_command_object("On", self.OnCommand(*device_args))
+        self.register_command_object("Disable", self.DisableCommand(*device_args))
+        self.register_command_object("Standby", self.StandbyCommand(*device_args))
         self.register_command_object("Off", self.OffCommand(*device_args))
+        self.register_command_object("On", self.OnCommand(*device_args))
         self.register_command_object("Reset", self.ResetCommand(*device_args))
         self.register_command_object(
-            "GetVersionInfo",
-            self.GetVersionInfoCommand(*device_args)
+            "GetVersionInfo", self.GetVersionInfoCommand(*device_args)
         )
 
     def always_executed_hook(self):
         # PROTECTED REGION ID(SKABaseDevice.always_executed_hook) ENABLED START #
         """
         Method that is always executed before any device command gets executed.
-
-        :return: None
         """
         # PROTECTED REGION END #    //  SKABaseDevice.always_executed_hook
 
@@ -862,8 +938,6 @@ class SKABaseDevice(Device):
         # PROTECTED REGION ID(SKABaseDevice.delete_device) ENABLED START #
         """
         Method to cleanup when device is stopped.
-
-        :return: None
         """
         # PROTECTED REGION END #    //  SKABaseDevice.delete_device
 
@@ -876,7 +950,7 @@ class SKABaseDevice(Device):
         """
         Reads the Build State of the device.
 
-        :return: None
+        :return: the build state of the device
         """
         return self._build_state
         # PROTECTED REGION END #    //  SKABaseDevice.buildState_read
@@ -886,7 +960,7 @@ class SKABaseDevice(Device):
         """
         Reads the Version Id of the device.
 
-        :return: None
+        :return: the version id of the device
         """
         return self._version_id
         # PROTECTED REGION END #    //  SKABaseDevice.versionId_read
@@ -909,7 +983,7 @@ class SKABaseDevice(Device):
 
         :param value: Logging level for logger
 
-        :return: None.
+        :raises LoggingLevelError: for invalid value
         """
         try:
             lmc_logging_level = LoggingLevel(value)
@@ -949,8 +1023,6 @@ class SKABaseDevice(Device):
         library defaults.
 
         :param value: Logging targets for logger
-
-        :return: None.
         """
         device_name = self.get_name()
         valid_targets = LoggingUtils.sanitise_logging_targets(value,
@@ -985,9 +1057,9 @@ class SKABaseDevice(Device):
         Sets Admin Mode of the device.
 
         :param value: Admin Mode of the device.
-        :type value: AdminMode
+        :type value: :py:class:`~ska.base.control_model.AdminMode`
 
-        :return: None
+        :raises ValueError: for unknown adminMode
         """
         if value == AdminMode.NOT_FITTED:
             self.state_model.perform_action("to_notfitted")
@@ -997,6 +1069,8 @@ class SKABaseDevice(Device):
             self.state_model.perform_action("to_maintenance")
         elif value == AdminMode.ONLINE:
             self.state_model.perform_action("to_online")
+        elif value == AdminMode.RESERVED:
+            self.state_model.perform_action("to_reserved")
         else:
             raise ValueError(f"Unknown adminMode {value}")
         # PROTECTED REGION END #    //  SKABaseDevice.adminMode_write
@@ -1017,8 +1091,6 @@ class SKABaseDevice(Device):
         Sets Control Mode of the device.
 
         :param value: Control mode value
-
-        :return: None
         """
         self._control_mode = value
         # PROTECTED REGION END #    //  SKABaseDevice.controlMode_write
@@ -1039,8 +1111,6 @@ class SKABaseDevice(Device):
         Sets Simulation Mode of the device
 
         :param value: SimulationMode
-
-        :return: None
         """
         self._simulation_mode = value
         # PROTECTED REGION END #    //  SKABaseDevice.simulationMode_write
@@ -1061,8 +1131,6 @@ class SKABaseDevice(Device):
         Sets Test Mode of the device.
 
         :param value: Test Mode
-
-        :return: None
         """
         self._test_mode = value
         # PROTECTED REGION END #    //  SKABaseDevice.testMode_write
@@ -1118,7 +1186,7 @@ class SKABaseDevice(Device):
             :param state_model: the state model that this command uses
                  to check that it is allowed to run, and that it drives
                  with actions.
-            :type state_model: SKABaseDeviceStateModel
+            :type state_model: :py:class:`DeviceStateModel`
             :param logger: the logger to be used by this Command. If not
                 provided, then a default module logger will be used.
             :type logger: a logger that implements the standard library
@@ -1169,19 +1237,23 @@ class SKABaseDevice(Device):
         To modify behaviour for this command, modify the do() method of
         the command class.
 
-        :return: None
+        :return: A tuple containing a return code and a string
+            message indicating status. The message is for
+            information purpose only.
+        :rtype: (ResultCode, str)
         """
         command = self.get_command_object("Reset")
         (return_code, message) = command()
         return [[return_code], [message]]
 
-    class OnCommand(ActionCommand):
+    class DisableCommand(ActionCommand):
         """
-        A class for the SKABaseDevice's On() command.
+        A class for the SKABaseDevice's Disable() command.
         """
+
         def __init__(self, target, state_model, logger=None):
             """
-            Constructor for OnCommand
+            Constructor for DisableCommand
 
             :param target: the object that this command acts upon; for
                 example, the SKABaseDevice for which this class
@@ -1190,37 +1262,107 @@ class SKABaseDevice(Device):
             :param state_model: the state model that this command uses
                  to check that it is allowed to run, and that it drives
                  with actions.
-            :type state_model: SKABaseDeviceStateModel
+            :type state_model: :py:class:`DeviceStateModel`
             :param logger: the logger to be used by this Command. If not
                 provided, then a default module logger will be used.
             :type logger: a logger that implements the standard library
                 logger interface
             """
-            super().__init__(target, state_model, "on", logger=logger)
+            super().__init__(target, state_model, "disable", logger=logger)
 
         def do(self):
             """
-            Stateless hook for On() command functionality.
+            Stateless hook for Disable() command functionality.
 
             :return: A tuple containing a return code and a string
                 message indicating status. The message is for
                 information purpose only.
             :rtype: (ResultCode, str)
             """
-            message = "On command completed OK"
+            message = "Disable command completed OK"
             self.logger.info(message)
             return (ResultCode.OK, message)
 
-    def is_On_allowed(self):
+    def is_Disable_allowed(self):
         """
-        Check if command `On` is allowed in the current device state.
+        Check if command Disable is allowed in the current device state.
 
         :raises ``tango.DevFailed``: if the command is not allowed
 
         :return: ``True`` if the command is allowed
         :rtype: boolean
         """
-        command = self.get_command_object("On")
+        command = self.get_command_object("Disable")
+        return command.check_allowed()
+
+    @command(
+        dtype_out="DevVarLongStringArray",
+        doc_out="(ReturnType, 'informational message')",
+    )
+    @DebugIt()
+    def Disable(self):
+        """
+        Put the device into disabled mode
+
+        To modify behaviour for this command, modify the do() method of
+        the command class.
+
+        :return: A tuple containing a return code and a string
+            message indicating status. The message is for
+            information purpose only.
+        :rtype: (ResultCode, str)
+        """
+        command = self.get_command_object("Disable")
+        (return_code, message) = command()
+        return [[return_code], [message]]
+
+    class StandbyCommand(ActionCommand):
+        """
+        A class for the SKABaseDevice's Standby() command.
+        """
+
+        def __init__(self, target, state_model, logger=None):
+            """
+            Constructor for StandbyCommand
+
+            :param target: the object that this command acts upon; for
+                example, the SKABaseDevice for which this class
+                implements the command
+            :type target: object
+            :param state_model: the state model that this command uses
+                 to check that it is allowed to run, and that it drives
+                 with actions.
+            :type state_model: :py:class:`DeviceStateModel`
+            :param logger: the logger to be used by this Command. If not
+                provided, then a default module logger will be used.
+            :type logger: a logger that implements the standard library
+                logger interface
+            """
+            super().__init__(target, state_model, "standby", logger=logger)
+
+        def do(self):
+            """
+            Stateless hook for Standby() command functionality.
+
+            :return: A tuple containing a return code and a string
+                message indicating status. The message is for
+                information purpose only.
+            :rtype: (ResultCode, str)
+            """
+            message = "Standby command completed OK"
+            self.logger.info(message)
+            return (ResultCode.OK, message)
+
+    def is_Standby_allowed(self):
+        """
+        Check if command Standby is allowed in the current device state.
+
+        :raises ``tango.DevFailed``: if the command is not allowed
+
+        :return: ``True`` if the command is allowed
+        :rtype: boolean
+        """
+        command = self.get_command_object("Standby")
         return command.check_allowed()
 
     @command(
@@ -1228,14 +1370,19 @@ class SKABaseDevice(Device):
         doc_out="(ReturnType, 'informational message')",
     )
     @DebugIt()
-    def On(self):
+    def Standby(self):
         """
-        Turn device on
+        Put the device into standby mode
 
         To modify behaviour for this command, modify the do() method of
         the command class.
+
+        :return: A tuple containing a return code and a string
+            message indicating status. The message is for
+            information purpose only.
+        :rtype: (ResultCode, str)
         """
-        command = self.get_command_object("On")
+        command = self.get_command_object("Standby")
         (return_code, message) = command()
         return [[return_code], [message]]
 
@@ -1243,6 +1390,7 @@ class SKABaseDevice(Device):
         """
         A class for the SKABaseDevice's Off() command.
         """
+
         def __init__(self, target, state_model, logger=None):
             """
             Constructor for OffCommand
@@ -1254,7 +1402,7 @@ class SKABaseDevice(Device):
             :param state_model: the state model that this command uses
                  to check that it is allowed to run, and that it drives
                  with actions.
-            :type state_model: SKABaseDeviceStateModel
+            :type state_model: :py:class:`DeviceStateModel`
             :param logger: the logger to be used by this Command. If not
                 provided, then a default module logger will be used.
             :type logger: a logger that implements the standard library
@@ -1298,11 +1446,86 @@ class SKABaseDevice(Device):
 
         To modify behaviour for this command, modify the do() method of
         the command class.
+
+        :return: A tuple containing a return code and a string
+            message indicating status. The message is for
+            information purpose only.
+        :rtype: (ResultCode, str)
         """
         command = self.get_command_object("Off")
         (return_code, message) = command()
         return [[return_code], [message]]
 
+    class OnCommand(ActionCommand):
+        """
+        A class for the SKABaseDevice's On() command.
+        """
+
+        def __init__(self, target, state_model, logger=None):
+            """
+            Constructor for OnCommand
+
+            :param target: the object that this command acts upon; for
+                example, the SKABaseDevice for which this class
+                implements the command
+            :type target: object
+            :param state_model: the state model that this command uses
+                 to check that it is allowed to run, and that it drives
+                 with actions.
+            :type state_model: :py:class:`DeviceStateModel`
+            :param logger: the logger to be used by this Command. If not
+                provided, then a default module logger will be used.
+            :type logger: a logger that implements the standard library
+                logger interface
+            """
+            super().__init__(target, state_model, "on", logger=logger)
+
+        def do(self):
+            """
+            Stateless hook for On() command functionality.
+
+            :return: A tuple containing a return code and a string
+                message indicating status. The message is for
+                information purpose only.
+            :rtype: (ResultCode, str)
+            """
+            message = "On command completed OK"
+            self.logger.info(message)
+            return (ResultCode.OK, message)
+
+    def is_On_allowed(self):
+        """
+        Check if command `On` is allowed in the current device state.
+
+        :raises ``tango.DevFailed``: if the command is not allowed
+
+        :return: ``True`` if the command is allowed
+        :rtype: boolean
+        """
+        command = self.get_command_object("On")
+        return command.check_allowed()
+
+    @command(
+        dtype_out="DevVarLongStringArray",
+        doc_out="(ReturnType, 'informational message')",
+    )
+    @DebugIt()
+    def On(self):
+        """
+        Turn device on
+
+        To modify behaviour for this command, modify the do() method of
+        the command class.
+
+        :return: A tuple containing a return code and a string
+            message indicating status. The message is for
+            information purpose only.
+        :rtype: (ResultCode, str)
+        """
+        command = self.get_command_object("On")
+        (return_code, message) = command()
+        return [[return_code], [message]]
+
 
 # ----------
 # Run server
@@ -1314,8 +1537,8 @@ def main(args=None, **kwargs):
     """
     Main function of the SKABaseDevice module.
 
-    :param args: None
-    :param kwargs:
+    :param args: positional args to tango.server.run
+    :param kwargs: named args to tango.server.run
     """
     return run((SKABaseDevice,), args=args, **kwargs)
     # PROTECTED REGION END #    //  SKABaseDevice.main
diff --git a/src/ska/base/commands.py b/src/ska/base/commands.py
index b8d70baa16f4d10d9fe57dfd7f0fdc9649efe2c7..e326c62c2373171c6b6b1e89b057475694e187c2 100644
--- a/src/ska/base/commands.py
+++ b/src/ska/base/commands.py
@@ -146,7 +146,7 @@ class BaseCommand:
 
         :param action: the action to perform on the state model
         :type action: string
-        :raises: CommandError if the action is not allowed in current state
+        :raises CommandError: if the action is not allowed in current state
         :returns: True is the action is allowed
         """
         try:
@@ -288,7 +288,7 @@ class ActionCommand(ResponseCommand):
 
         :param return_code: The return_code returned by the ``do()``
             method
-        :type return_code: ResultCode
+        :type return_code: :py:class:`ResultCode`
         """
         if return_code == ResultCode.OK:
             self.succeeded()
diff --git a/src/ska/base/logger_device.py b/src/ska/base/logger_device.py
index 72f03d2cf291bd62b2135e94257cbbe432d5a793..39a5704819d31f860c199204d20aeff89d6e9b86 100644
--- a/src/ska/base/logger_device.py
+++ b/src/ska/base/logger_device.py
@@ -139,7 +139,7 @@ class SKALogger(SKABaseDevice):
             * argin[0]: list of DevLong. Desired logging level.
             * argin[1]: list of DevString. Desired tango device.
 
-        :type argin: DevVarLongStringArray
+        :type argin: :py:class:`tango.DevVarLongStringArray`
 
         :returns: None.
         """
diff --git a/src/ska/base/master_device.py b/src/ska/base/master_device.py
index bc5038198b293844d4717febb1fbd06811c91be2..a8e0c93a3c01690b7797e71c885628803fa5abd7 100644
--- a/src/ska/base/master_device.py
+++ b/src/ska/base/master_device.py
@@ -231,7 +231,7 @@ class SKAMaster(SKABaseDevice):
             * [nrInstances]: DevLong. Number of instances of the capability.
             * [Capability types]: DevString. Type of capability.
 
-        :type argin: DevVarLongStringArray.
+        :type argin: :py:class:`tango.DevVarLongStringArray`.
 
         :return: True if capability can be achieved, False if cannot
         :rtype: DevBoolean
diff --git a/src/ska/base/obs_device.py b/src/ska/base/obs_device.py
index 9119cc0aeb2ebc65546f8aa74325809a31db3795..b92b31c23329be84a30f58e85d205cb91953270c 100644
--- a/src/ska/base/obs_device.py
+++ b/src/ska/base/obs_device.py
@@ -102,7 +102,7 @@ class SKAObsDevice(SKABaseDevice):
         callback
 
         :param obs_state: the new obs_state value
-        :type obs_state: ObsState
+        :type admin_mode: :py:class:`~ska.base.control_model.ObsState`
         """
         self._obs_state = obs_state
         self.push_change_event("obsState", obs_state)
diff --git a/src/ska/base/release.py b/src/ska/base/release.py
index 894fa0ecafcc8232914a3baad0729f799e6aa572..a983abcd3064aead4090cba2d4f7d79cfadaac3a 100644
--- a/src/ska/base/release.py
+++ b/src/ska/base/release.py
@@ -7,7 +7,7 @@
 """Release information for lmc-base-classes Python Package"""
 
 name = """lmcbaseclasses"""
-version = "0.6.6"
+version = "0.7.0"
 version_info = version.split(".")
 description = """A set of generic base devices for SKA Telescope."""
 author = "SKA India and SARAO and CSIRO"
diff --git a/src/ska/base/state_machine.py b/src/ska/base/state_machine.py
index 8ecbfa56912a4284c7bc686bba802d4860642458..0dc1f325762e29d9da711c10346197263adeb73c 100644
--- a/src/ska/base/state_machine.py
+++ b/src/ska/base/state_machine.py
@@ -2,212 +2,204 @@
 This module contains specifications of SKA state machines.
 """
 from transitions import Machine, State
-from tango import DevState
 
-from ska.base.control_model import AdminMode, ObsState
 
+__all__ = ["OperationStateMachine", "AdminModeStateMachine", "ObservationStateMachine"]
 
-class BaseDeviceStateMachine(Machine):
+
+class OperationStateMachine(Machine):
     """
-    State machine for an SKA base device. Supports ON and OFF states,
-    states, plus initialisation and fault states, and
-    also the basic admin modes.
+    State machine for operational state ("opState").
+
+    The states supported are "UNINITIALISED", "INIT", "FAULT",
+    "DISABLE", "STANDBY", "OFF" and "ON".
+
+    The states "INIT", "FAULT" and "DISABLE" also have "INIT_ADMIN",
+    "FAULT_ADMIN" and "DISABLE_ADMIN" flavours to represent these states
+    in situations where the device being modelled has been
+    administratively disabled.
     """
 
-    def __init__(self, op_state_callback=None, admin_mode_callback=None):
+    def __init__(self, callback=None, **extra_kwargs):
         """
         Initialises the state model.
 
-        :param op_state_callback: A callback to be called when a
-            transition implies a change to op state
-        :type op_state_callback: callable
-        :param admin_mode_callback: A callback to be called when a
-            transition causes a change to device admin_mode
-        :type admin_mode_callback: callable
+        :param callback: A callback to be called when a transition
+            implies a change to op state
+        :type callback: callable
+        :param extra_kwargs: Additional keywords arguments to pass to super class
+            initialiser (useful for graphing)
         """
-        self._admin_mode = None
-        self._admin_mode_callback = admin_mode_callback
-        self._op_state = None
-        self._op_state_callback = op_state_callback
+        self._callback = callback
 
         states = [
-            State("UNINITIALISED"),
-            State("INIT_ENABLED", on_enter="_init_entered"),
-            State("INIT_DISABLED", on_enter="_init_entered"),
-            State("FAULT_ENABLED", on_enter="_fault_entered"),
-            State("FAULT_DISABLED", on_enter="_fault_entered"),
-            State("DISABLED", on_enter="_disabled_entered"),
-            State("OFF", on_enter="_off_entered"),
-            State("ON", on_enter="_on_entered"),
+            "UNINITIALISED",
+            "INIT",
+            "INIT_ADMIN",
+            "FAULT",
+            "FAULT_ADMIN",
+            "DISABLE",
+            "DISABLE_ADMIN",
+            "STANDBY",
+            "OFF",
+            "ON",
         ]
 
         transitions = [
             {
                 "source": "UNINITIALISED",
                 "trigger": "init_started",
-                "dest": "INIT_ENABLED",
-                "after": self._maintenance_callback,
+                "dest": "INIT",
             },
             {
-                "source": ["INIT_ENABLED", "OFF", "FAULT_ENABLED", "ON"],
+                "source": ["INIT", "FAULT", "DISABLE", "STANDBY", "OFF", "ON"],
                 "trigger": "fatal_error",
-                "dest": "FAULT_ENABLED",
+                "dest": "FAULT",
             },
             {
-                "source": ["INIT_DISABLED", "DISABLED", "FAULT_DISABLED"],
+                "source": ["INIT_ADMIN", "FAULT_ADMIN", "DISABLE_ADMIN"],
                 "trigger": "fatal_error",
-                "dest": "FAULT_DISABLED",
+                "dest": "FAULT_ADMIN",
             },
             {
-                "source": "INIT_ENABLED",
-                "trigger": "init_succeeded",
-                "dest": "OFF",
+                "source": "INIT",
+                "trigger": "init_succeeded_disable",
+                "dest": "DISABLE",
+            },
+            {
+                "source": "INIT_ADMIN",
+                "trigger": "init_succeeded_disable",
+                "dest": "DISABLE_ADMIN",
             },
             {
-                "source": "INIT_DISABLED",
-                "trigger": "init_succeeded",
-                "dest": "DISABLED",
+                "source": "INIT",
+                "trigger": "init_succeeded_standby",
+                "dest": "STANDBY",
             },
             {
-                "source": "INIT_ENABLED",
+                "source": "INIT",
+                "trigger": "init_succeeded_off",
+                "dest": "OFF",
+            },
+            {
+                "source": "INIT",
                 "trigger": "init_failed",
-                "dest": "FAULT_ENABLED",
+                "dest": "FAULT",
             },
             {
-                "source": "INIT_DISABLED",
+                "source": "INIT_ADMIN",
                 "trigger": "init_failed",
-                "dest": "FAULT_DISABLED",
+                "dest": "FAULT_ADMIN",
             },
             {
-                "source": ["INIT_ENABLED", "INIT_DISABLED"],
-                "trigger": "to_notfitted",
-                "dest": "INIT_DISABLED",
-                "after": self._not_fitted_callback
+                "source": ["INIT", "INIT_ADMIN"],
+                "trigger": "admin_on",
+                "dest": "INIT_ADMIN",
             },
             {
-                "source": ["INIT_ENABLED", "INIT_DISABLED"],
-                "trigger": "to_offline",
-                "dest": "INIT_DISABLED",
-                "after": self._offline_callback
+                "source": ["INIT", "INIT_ADMIN"],
+                "trigger": "admin_off",
+                "dest": "INIT",
             },
             {
-                "source": ["INIT_ENABLED", "INIT_DISABLED"],
-                "trigger": "to_maintenance",
-                "dest": "INIT_ENABLED",
-                "after": self._maintenance_callback
+                "source": "FAULT",
+                "trigger": "reset_succeeded_disable",
+                "dest": "DISABLE",
             },
             {
-                "source": ["INIT_ENABLED", "INIT_DISABLED"],
-                "trigger": "to_online",
-                "dest": "INIT_ENABLED",
-                "after": self._online_callback
+                "source": "FAULT_ADMIN",
+                "trigger": "reset_succeeded_disable",
+                "dest": "DISABLE_ADMIN",
             },
             {
-                "source": "FAULT_DISABLED",
-                "trigger": "reset_succeeded",
-                "dest": "DISABLED",
+                "source": "FAULT",
+                "trigger": "reset_succeeded_standby",
+                "dest": "STANDBY",
             },
             {
-                "source": "FAULT_ENABLED",
-                "trigger": "reset_succeeded",
+                "source": "FAULT",
+                "trigger": "reset_succeeded_off",
                 "dest": "OFF",
             },
             {
-                "source": ["FAULT_DISABLED", "FAULT_ENABLED"],
+                "source": "FAULT",
                 "trigger": "reset_failed",
-                "dest": None,
+                "dest": "FAULT",
             },
             {
-                "source": ["FAULT_DISABLED", "FAULT_ENABLED"],
-                "trigger": "to_notfitted",
-                "dest": "FAULT_DISABLED",
-                "after": self._not_fitted_callback
+                "source": "FAULT_ADMIN",
+                "trigger": "reset_failed",
+                "dest": "FAULT_ADMIN",
             },
             {
-                "source": ["FAULT_DISABLED", "FAULT_ENABLED"],
-                "trigger": "to_offline",
-                "dest": "FAULT_DISABLED",
-                "after": self._offline_callback
+                "source": ["FAULT", "FAULT_ADMIN"],
+                "trigger": "admin_on",
+                "dest": "FAULT_ADMIN",
             },
             {
-                "source": ["FAULT_DISABLED", "FAULT_ENABLED"],
-                "trigger": "to_maintenance",
-                "dest": "FAULT_ENABLED",
-                "after": self._maintenance_callback
+                "source": ["FAULT", "FAULT_ADMIN"],
+                "trigger": "admin_off",
+                "dest": "FAULT",
             },
             {
-                "source": ["FAULT_DISABLED", "FAULT_ENABLED"],
-                "trigger": "to_online",
-                "dest": "FAULT_ENABLED",
-                "after": self._online_callback
+                "source": ["DISABLE", "DISABLE_ADMIN"],
+                "trigger": "admin_on",
+                "dest": "DISABLE_ADMIN",
             },
             {
-                "source": "DISABLED",
-                "trigger": "to_notfitted",
-                "dest": "DISABLED",
-                "after": self._not_fitted_callback
+                "source": ["DISABLE", "DISABLE_ADMIN"],
+                "trigger": "admin_off",
+                "dest": "DISABLE",
             },
             {
-                "source": "DISABLED",
-                "trigger": "to_offline",
-                "dest": "DISABLED",
-                "after": self._offline_callback
+                "source": "DISABLE_ADMIN",
+                "trigger": "disable_succeeded",
+                "dest": "DISABLE_ADMIN",
             },
             {
-                "source": "DISABLED",
-                "trigger": "to_maintenance",
-                "dest": "OFF",
-                "after": self._maintenance_callback
+                "source": "DISABLE_ADMIN",
+                "trigger": "disable_failed",
+                "dest": "FAULT_ADMIN",
             },
             {
-                "source": "DISABLED",
-                "trigger": "to_online",
-                "dest": "OFF",
-                "after": self._online_callback
+                "source": ["DISABLE", "STANDBY", "OFF"],
+                "trigger": "disable_succeeded",
+                "dest": "DISABLE",
             },
             {
-                "source": "OFF",
-                "trigger": "to_notfitted",
-                "dest": "DISABLED",
-                "after": self._not_fitted_callback
+                "source": ["DISABLE", "STANDBY", "OFF"],
+                "trigger": "disable_failed",
+                "dest": "FAULT",
             },
             {
-                "source": "OFF",
-                "trigger": "to_offline",
-                "dest": "DISABLED",
-                "after": self._offline_callback
+                "source": ["DISABLE", "STANDBY", "OFF"],
+                "trigger": "standby_succeeded",
+                "dest": "STANDBY",
             },
             {
-                "source": "OFF",
-                "trigger": "to_maintenance",
-                "dest": "OFF",
-                "after": self._maintenance_callback
+                "source": ["DISABLE", "STANDBY", "OFF"],
+                "trigger": "standby_failed",
+                "dest": "FAULT",
             },
             {
-                "source": "OFF",
-                "trigger": "to_online",
+                "source": ["DISABLE", "STANDBY", "OFF", "ON"],
+                "trigger": "off_succeeded",
                 "dest": "OFF",
-                "after": self._online_callback
             },
             {
-                "source": "OFF",
+                "source": ["DISABLE", "STANDBY", "OFF", "ON"],
+                "trigger": "off_failed",
+                "dest": "FAULT",
+            },
+            {
+                "source": ["OFF", "ON"],
                 "trigger": "on_succeeded",
                 "dest": "ON",
             },
             {
-                "source": "OFF",
+                "source": ["OFF", "ON"],
                 "trigger": "on_failed",
-                "dest": "FAULT_ENABLED",
-            },
-            {
-                "source": "ON",
-                "trigger": "off_succeeded",
-                "dest": "OFF",
-            },
-            {
-                "source": "ON",
-                "trigger": "off_failed",
-                "dest": "FAULT_ENABLED",
+                "dest": "FAULT",
             },
         ]
 
@@ -215,90 +207,81 @@ class BaseDeviceStateMachine(Machine):
             states=states,
             initial="UNINITIALISED",
             transitions=transitions,
+            after_state_change=self._state_changed,
+            **extra_kwargs,
         )
 
-    def _init_entered(self):
-        """
-        called when the state machine enters the "" state.
-        """
-        self._update_op_state(DevState.INIT)
-
-    def _fault_entered(self):
-        """
-        called when the state machine enters the "" state.
+    def _state_changed(self):
         """
-        self._update_op_state(DevState.FAULT)
-
-    def _disabled_entered(self):
-        """
-        called when the state machine enters the "" state.
-        """
-        self._update_op_state(DevState.DISABLE)
-
-    def _off_entered(self):
-        """
-        called when the state machine enters the "" state.
-        """
-        self._update_op_state(DevState.OFF)
-
-    def _on_entered(self):
-        """
-        called when the state machine enters the "" state.
+        State machine callback that is called every time the op_state
+        changes. Responsible for ensuring that callbacks are called.
         """
-        self._update_op_state(DevState.ON)
+        if self._callback is not None:
+            self._callback(self.state)
 
-    def _not_fitted_callback(self):
-        """
-        callback called when the state machine is set to admin mode
-        NOT FITTED
-        """
-        self._update_admin_mode(AdminMode.NOT_FITTED)
 
-    def _offline_callback(self):
-        """
-        callback called when the state machine is set to admin mode
-        OFFLINE
-        """
-        self._update_admin_mode(AdminMode.OFFLINE)
+class AdminModeStateMachine(Machine):
+    """
+    The state machine governing admin modes
+    """
 
-    def _maintenance_callback(self):
+    def __init__(self, callback=None, **extra_kwargs):
         """
-        callback called when the state machine is set to admin mode
-        MAINTENANCE
-        """
-        self._update_admin_mode(AdminMode.MAINTENANCE)
+        Initialises the admin mode state machine model.
 
-    def _online_callback(self):
-        """
-        callback called when the state machine is set to admin mode
-        online
+        :param callback: A callback to be called whenever there is a transition
+            to a new admin mode value
+        :type callback: callable
+        :param extra_kwargs: Additional keywords arguments to pass to super class
+            initialiser (useful for graphing)
         """
-        self._update_admin_mode(AdminMode.ONLINE)
+        self._callback = callback
 
-    def _update_admin_mode(self, admin_mode):
-        """
-        Helper method: calls the admin_mode callback if one exists
+        states = ["RESERVED", "NOT_FITTED", "OFFLINE", "MAINTENANCE", "ONLINE"]
+        transitions = [
+            {
+                "source": ["NOT_FITTED", "RESERVED", "OFFLINE"],
+                "trigger": "to_reserved",
+                "dest": "RESERVED",
+            },
+            {
+                "source": ["RESERVED", "NOT_FITTED", "OFFLINE"],
+                "trigger": "to_notfitted",
+                "dest": "NOT_FITTED",
+            },
+            {
+                "source": ["RESERVED", "NOT_FITTED", "OFFLINE", "MAINTENANCE", "ONLINE"],
+                "trigger": "to_offline",
+                "dest": "OFFLINE",
+            },
+            {
+                "source": ["OFFLINE", "MAINTENANCE", "ONLINE"],
+                "trigger": "to_maintenance",
+                "dest": "MAINTENANCE",
+            },
+            {
+                "source": ["OFFLINE", "MAINTENANCE", "ONLINE"],
+                "trigger": "to_online",
+                "dest": "ONLINE",
+            },
+        ]
 
-        :param admin_mode: the new admin_mode value
-        :type admin_mode: AdminMode
-        """
-        if self._admin_mode != admin_mode:
-            self._admin_mode = admin_mode
-            if self._admin_mode_callback is not None:
-                self._admin_mode_callback(self._admin_mode)
+        super().__init__(
+            states=states,
+            initial="MAINTENANCE",
+            transitions=transitions,
+            after_state_change=self._state_changed,
+            **extra_kwargs,
+        )
+        self._state_changed()
 
-    def _update_op_state(self, op_state):
+    def _state_changed(self):
         """
-        Helper method: sets this state models op_state, and calls the
-        op_state callback if one exists
-
-        :param op_state: the new op state value
-        :type op_state: DevState
+        State machine callback that is called every time the admin mode
+        changes. Responsible for ensuring that callbacks are called.
         """
-        if self._op_state != op_state:
-            self._op_state = op_state
-            if self._op_state_callback is not None:
-                self._op_state_callback(self._op_state)
+        if self._callback is not None:
+            self._callback(self.state)
 
 
 class ObservationStateMachine(Machine):
@@ -307,164 +290,177 @@ class ObservationStateMachine(Machine):
     ADR-8.
     """
 
-    def __init__(self, obs_state_callback=None):
+    def __init__(self, callback=None, **extra_kwargs):
         """
         Initialises the model.
 
-        :param obs_state_callback: A callback to be called when a
-            transition causes a change to device obs_state
-        :type obs_state_callback: callable
+        :param callback: A callback to be called when the state changes
+        :type callback: callable
+        :param extra_kwargs: Additional keywords arguments to pass to super class
+            initialiser (useful for graphing)
         """
-        self._obs_state = ObsState.EMPTY
-        self._obs_state_callback = obs_state_callback
+        self._callback = callback
 
-        states = [obs_state.name for obs_state in ObsState]
+        states = [
+            "EMPTY",
+            "RESOURCING",
+            "IDLE",
+            "CONFIGURING",
+            "READY",
+            "SCANNING",
+            "ABORTING",
+            "ABORTED",
+            "RESETTING",
+            "RESTARTING",
+            "FAULT",
+        ]
         transitions = [
             {
                 "source": "*",
                 "trigger": "fatal_error",
-                "dest": ObsState.FAULT.name,
+                "dest": "FAULT",
             },
             {
-                "source": [ObsState.EMPTY.name, ObsState.IDLE.name],
+                "source": ["EMPTY", "IDLE"],
                 "trigger": "assign_started",
-                "dest": ObsState.RESOURCING.name,
+                "dest": "RESOURCING",
             },
             {
-                "source": ObsState.IDLE.name,
+                "source": "IDLE",
                 "trigger": "release_started",
-                "dest": ObsState.RESOURCING.name,
+                "dest": "RESOURCING",
             },
             {
-                "source": ObsState.RESOURCING.name,
+                "source": "RESOURCING",
                 "trigger": "resourcing_succeeded_some_resources",
-                "dest": ObsState.IDLE.name,
+                "dest": "IDLE",
             },
             {
-                "source": ObsState.RESOURCING.name,
+                "source": "RESOURCING",
                 "trigger": "resourcing_succeeded_no_resources",
-                "dest": ObsState.EMPTY.name,
+                "dest": "EMPTY",
             },
             {
-                "source": ObsState.RESOURCING.name,
+                "source": "RESOURCING",
                 "trigger": "resourcing_failed",
-                "dest": ObsState.FAULT.name,
+                "dest": "FAULT",
             },
             {
-                "source": [ObsState.IDLE.name, ObsState.READY.name],
+                "source": ["IDLE", "READY"],
                 "trigger": "configure_started",
-                "dest": ObsState.CONFIGURING.name,
+                "dest": "CONFIGURING",
             },
             {
-                "source": ObsState.CONFIGURING.name,
+                "source": "CONFIGURING",
                 "trigger": "configure_succeeded",
-                "dest": ObsState.READY.name,
+                "dest": "READY",
             },
             {
-                "source": ObsState.CONFIGURING.name,
+                "source": "CONFIGURING",
                 "trigger": "configure_failed",
-                "dest": ObsState.FAULT.name,
+                "dest": "FAULT",
             },
             {
-                "source": ObsState.READY.name,
+                "source": "READY",
                 "trigger": "end_succeeded",
-                "dest": ObsState.IDLE.name,
+                "dest": "IDLE",
             },
             {
-                "source": ObsState.READY.name,
+                "source": "READY",
                 "trigger": "end_failed",
-                "dest": ObsState.FAULT.name,
+                "dest": "FAULT",
             },
             {
-                "source": ObsState.READY.name,
+                "source": "READY",
                 "trigger": "scan_started",
-                "dest": ObsState.SCANNING.name,
+                "dest": "SCANNING",
             },
             {
-                "source": ObsState.SCANNING.name,
+                "source": "SCANNING",
                 "trigger": "scan_succeeded",
-                "dest": ObsState.READY.name,
+                "dest": "READY",
             },
             {
-                "source": ObsState.SCANNING.name,
+                "source": "SCANNING",
                 "trigger": "scan_failed",
-                "dest": ObsState.FAULT.name,
+                "dest": "FAULT",
             },
             {
-                "source": ObsState.SCANNING.name,
+                "source": "SCANNING",
                 "trigger": "end_scan_succeeded",
-                "dest": ObsState.READY.name,
+                "dest": "READY",
             },
             {
-                "source": ObsState.SCANNING.name,
+                "source": "SCANNING",
                 "trigger": "end_scan_failed",
-                "dest": ObsState.FAULT.name,
+                "dest": "FAULT",
             },
             {
                 "source": [
-                    ObsState.IDLE.name, ObsState.CONFIGURING.name,
-                    ObsState.READY.name, ObsState.SCANNING.name,
-                    ObsState.RESETTING.name,
+                    "IDLE",
+                    "CONFIGURING",
+                    "READY",
+                    "SCANNING",
+                    "RESETTING",
                 ],
                 "trigger": "abort_started",
-                "dest": ObsState.ABORTING.name,
+                "dest": "ABORTING",
             },
             {
-                "source": ObsState.ABORTING.name,
+                "source": "ABORTING",
                 "trigger": "abort_succeeded",
-                "dest": ObsState.ABORTED.name,
+                "dest": "ABORTED",
             },
             {
-                "source": ObsState.ABORTING.name,
+                "source": "ABORTING",
                 "trigger": "abort_failed",
-                "dest": ObsState.FAULT.name,
+                "dest": "FAULT",
             },
             {
-                "source": [ObsState.ABORTED.name, ObsState.FAULT.name],
-                "trigger": "obs_reset_started",
-                "dest": ObsState.RESETTING.name,
+                "source": ["ABORTED", "FAULT"],
+                "trigger": "reset_started",
+                "dest": "RESETTING",
             },
             {
-                "source": ObsState.RESETTING.name,
-                "trigger": "obs_reset_succeeded",
-                "dest": ObsState.IDLE.name,
+                "source": "RESETTING",
+                "trigger": "reset_succeeded",
+                "dest": "IDLE",
             },
             {
-                "source": ObsState.RESETTING.name,
-                "trigger": "obs_reset_failed",
-                "dest": ObsState.FAULT.name,
+                "source": "RESETTING",
+                "trigger": "reset_failed",
+                "dest": "FAULT",
             },
             {
-                "source": [ObsState.ABORTED.name, ObsState.FAULT.name],
+                "source": ["ABORTED", "FAULT"],
                 "trigger": "restart_started",
-                "dest": ObsState.RESTARTING.name,
+                "dest": "RESTARTING",
             },
             {
-                "source": ObsState.RESTARTING.name,
+                "source": "RESTARTING",
                 "trigger": "restart_succeeded",
-                "dest": ObsState.EMPTY.name,
+                "dest": "EMPTY",
             },
             {
-                "source": ObsState.RESTARTING.name,
+                "source": "RESTARTING",
                 "trigger": "restart_failed",
-                "dest": ObsState.FAULT.name,
+                "dest": "FAULT",
             },
         ]
 
         super().__init__(
             states=states,
-            initial=ObsState.EMPTY.name,
+            initial="EMPTY",
             transitions=transitions,
-            after_state_change=self._obs_state_changed
+            after_state_change=self._state_changed,
+            **extra_kwargs,
         )
+        self._state_changed()
 
-    def _obs_state_changed(self):
+    def _state_changed(self):
         """
         State machine callback that is called every time the obs_state
         changes. Responsible for ensuring that callbacks are called.
         """
-        obs_state = ObsState[self.state]
-        if self._obs_state != obs_state:
-            self._obs_state = obs_state
-            if self._obs_state_callback is not None:
-                self._obs_state_callback(self._obs_state)
+        if self._callback is not None:
+            self._callback(self.state)
diff --git a/src/ska/base/subarray_device.py b/src/ska/base/subarray_device.py
index 9a0fe49319e1973b121e67b3f3517b9bd8a557d1..b66b16c045d7e92ef7b3be2e1bc120229b488b3e 100644
--- a/src/ska/base/subarray_device.py
+++ b/src/ska/base/subarray_device.py
@@ -14,12 +14,12 @@ information like assigned resources, configured capabilities, etc.
 import json
 import warnings
 
-from tango import DebugIt
+from tango import DebugIt, DevState
 from tango.server import run, attribute, command
 from tango.server import device_property
 
 # SKA specific imports
-from ska.base import SKAObsDevice, SKABaseDeviceStateModel
+from ska.base import SKAObsDevice, DeviceStateModel
 from ska.base.commands import ActionCommand, ResultCode
 from ska.base.control_model import AdminMode, ObsState
 from ska.base.faults import CapabilityValidationError, StateModelError
@@ -28,10 +28,10 @@ from ska.base.utils import for_testing_only
 
 # PROTECTED REGION END #    //  SKASubarray.additionnal_imports
 
-__all__ = ["SKASubarray", "main"]
+__all__ = ["SKASubarray", "SKASubarrayStateModel", "main"]
 
 
-class SKASubarrayStateModel(SKABaseDeviceStateModel):
+class SKASubarrayStateModel(DeviceStateModel):
     """
     Implements the state model for the SKASubarray
     """
@@ -41,7 +41,7 @@ class SKASubarrayStateModel(SKABaseDeviceStateModel):
         logger,
         op_state_callback=None,
         admin_mode_callback=None,
-        obs_state_callback=None
+        obs_state_callback=None,
     ):
         """
         Initialises the model. Note that this does not imply moving to
@@ -66,7 +66,7 @@ class SKASubarrayStateModel(SKABaseDeviceStateModel):
             admin_mode_callback=admin_mode_callback,
         )
 
-        self._obs_state = ObsState.EMPTY
+        self._obs_state = None
         self._obs_state_callback = obs_state_callback
 
         self._observation_state_machine = ObservationStateMachine(
@@ -83,33 +83,119 @@ class SKASubarrayStateModel(SKABaseDeviceStateModel):
         """
         return self._obs_state
 
-    def _update_obs_state(self, obs_state):
+    def _update_obs_state(self, machine_state):
         """
-        Helper method that updates obs_state, ensuring that the callback
-        is called if one exists.
+        Helper method that updates obs_state whenever the observation
+        state machine reports a change of state, ensuring that the
+        callback is called if one exists.
 
-        :param obs_state: the new obsState attribute value
-        :type obs_state: ObsState
+        :param machine_state: the new state of the observation state
+            machine
+        :type machine_state: str
         """
+        obs_state = ObsState[machine_state]
         if self._obs_state != obs_state:
             self._obs_state = obs_state
             if self._obs_state_callback is not None:
                 self._obs_state_callback(obs_state)
 
+    __action_breakdown = {
+        # "action": ("action_on_obs_machine", "action_on_superclass"),
+        "off_succeeded": ("to_EMPTY", "off_succeeded"),
+        "off_failed": ("to_EMPTY", "off_failed"),
+        "on_succeeded": (None, "on_succeeded"),
+        "on_failed": ("to_EMPTY", "on_failed"),
+        "assign_started": ("assign_started", None),
+        "release_started": ("release_started", None),
+        "resourcing_succeeded_some_resources": (
+            "resourcing_succeeded_some_resources",
+            None,
+        ),
+        "resourcing_succeeded_no_resources": (
+            "resourcing_succeeded_no_resources",
+            None,
+        ),
+        "resourcing_failed": ("resourcing_failed", None),
+        "configure_started": ("configure_started", None),
+        "configure_succeeded": ("configure_succeeded", None),
+        "configure_failed": ("configure_failed", None),
+        "scan_started": ("scan_started", None),
+        "scan_succeeded": ("scan_succeeded", None),
+        "scan_failed": ("scan_failed", None),
+        "end_scan_succeeded": ("end_scan_succeeded", None),
+        "end_scan_failed": ("end_scan_failed", None),
+        "end_succeeded": ("end_succeeded", None),
+        "end_failed": ("end_failed", None),
+        "abort_started": ("abort_started", None),
+        "abort_succeeded": ("abort_succeeded", None),
+        "abort_failed": ("abort_failed", None),
+        "obs_reset_started": ("reset_started", None),
+        "obs_reset_succeeded": ("reset_succeeded", None),
+        "obs_reset_failed": ("reset_failed", None),
+        "restart_started": ("restart_started", None),
+        "restart_succeeded": ("restart_succeeded", None),
+        "restart_failed": ("restart_failed", None),
+        "fatal_error": ("fatal_error", None),
+    }
+
+    def _is_obs_action_allowed(self, action):
+        if action not in self.__action_breakdown:
+            return None
+
+        if self.op_state != DevState.ON:
+            return False
+
+        (obs_action, super_action) = self.__action_breakdown[action]
+
+        if obs_action not in self._observation_state_machine.get_triggers(
+            self._observation_state_machine.state
+        ):
+            return False
+        return super_action is None or super().is_action_allowed(super_action)
+
     def is_action_allowed(self, action):
         """
         Whether a given action is allowed in the current state.
 
         :param action: an action, as given in the transitions table
         :type action: ANY
+
+        :returns: where the action is allowed in the current state:
+        :rtype: bool: True if the action is allowed, False if it is
+            not allowed
+        :raises StateModelError: for an unrecognised action
+        """
+        obs_allowed = self._is_obs_action_allowed(action)
+        if obs_allowed is None:
+            return super().is_action_allowed(action)
+        if obs_allowed:
+            return True
+        try:
+            return super().is_action_allowed(action)
+        except StateModelError:
+            return False
+
+    def try_action(self, action):
         """
-        if self._state_machine.state == "ON":
-            if action in self._observation_state_machine.get_triggers(
-                self._observation_state_machine.state
-            ):
-                return True
+        Checks whether a given action is allowed in the current state,
+        and raises a StateModelError if it is not.
 
-        return action in self._state_machine.get_triggers(self._state_machine.state)
+        :param action: an action, as given in the transitions table
+        :type action: str
+
+        :raises StateModelError: if the action is not allowed in the
+            current state
+
+        :returns: True if the action is allowed
+        :rtype: boolean
+        """
+        if not self.is_action_allowed(action):
+            raise StateModelError(
+                f"Action {action} is not allowed in operational state "
+                f"{self.op_state}, admin mode {self.admin_mode}, "
+                f"observation state {self.obs_state}."
+            )
+        return True
 
     def perform_action(self, action):
         """
@@ -122,17 +208,12 @@ class SKASubarrayStateModel(SKABaseDeviceStateModel):
             current state
 
         """
-        if self._state_machine.state == "ON":
-            if action in self._observation_state_machine.get_triggers(
-                self._observation_state_machine.state
-            ):
-                self._observation_state_machine.trigger(action)
-                return
+        self.try_action(action)
 
-        if action in self._state_machine.get_triggers(
-            self._state_machine.state
-        ):
-            if self._observation_state_machine.state != "EMPTY":
+        if self._is_obs_action_allowed(action):
+            (obs_action, super_action) = self.__action_breakdown[action]
+
+            if obs_action == "to_EMPTY":
                 message = (
                     "Changing device state of a non-EMPTY observing device "
                     "should only be done as an emergency measure and may be "
@@ -140,74 +221,46 @@ class SKASubarrayStateModel(SKABaseDeviceStateModel):
                 )
                 self.logger.warning(message)
                 warnings.warn(message, PendingDeprecationWarning)
-                self._observation_state_machine.to_EMPTY()
-            self._state_machine.trigger(action)
-            return
-
-        raise StateModelError(
-            f"Action {action} is not allowed in device state "
-            "{self._state_machine.state}, observation_state "
-            "{self._observation_state_machine.state}."
-        )
 
-    @for_testing_only
-    def _straight_to_state(self, state):
-        """
-        Takes the DeviceStateModel straight to the specified state. This method
-        exists to simplify testing; for example, if testing that a command may
-        be run in a given state, one can push the state model straight to that
-        state, rather than having to drive it to that state through a sequence
-        of actions. It is not intended that this method would be called outside
-        of test setups. A warning is raised if it is.
-
-        Note that states are non-deterministics with respect to adminMode. For
-        example, in state "FAULT-DISABLED", the adminMode could be OFFLINE or
-        NOT_FITTED. When you drive the state machine through its transitions,
-        the adminMode will be set accordingly. When using this method, the
-        adminMode will simply be set to something sensible.
-
-        :param state: the target state
-        :type state: string
-        """
-        if state == "UNINITIALISED":
-            pass
-        elif "DISABLED" in state:
-            if self._admin_mode not in [AdminMode.OFFLINE, AdminMode.NOT_FITTED]:
-                self._state_machine._update_admin_mode(AdminMode.OFFLINE)
+            self._observation_state_machine.trigger(obs_action)
+            if super_action is not None:
+                super().perform_action(super_action)
         else:
-            if self._admin_mode not in [AdminMode.ONLINE, AdminMode.MAINTENANCE]:
-                self._state_machine._update_admin_mode(AdminMode.ONLINE)
+            super().perform_action(action)
 
-        to_state = getattr(self._observation_state_machine, f"to_{state}", None)
-        if to_state is not None:
-            self._state_machine.to_ON()
-            to_state()
-            return
-
-        to_state = getattr(self._state_machine, f"to_{state}", None)
-        if to_state is not None:
-            self._observation_state_machine.to_EMPTY()
-            to_state()
-            return
+    @for_testing_only
+    def _straight_to_state(self, op_state=None, admin_mode=None, obs_state=None):
+        """
+        Takes the SKASubarrayStateModel straight to the specified states.
+        This method exists to simplify testing; for example, if testing
+        that a command may be run in a given state, one can push the
+        state model straight to that state, rather than having to drive
+        it to that state through a sequence of actions. It is not
+        intended that this method would be called outside of test
+        setups. A warning will be raised if it is.
 
-        raise StateModelError(f"No such state {state}")
+        Note that this method will allow you to put the device into an
+        incoherent combination of states and modes (e.g. adminMode
+        OFFLINE, opState STANDBY, and obsState SCANNING).
 
-    @property
-    def _state(self):
+        :param op_state: the target operational state (optional)
+        :type op_state: :py:class:`tango.DevState`
+        :param admin_mode: the target admin mode (optional)
+        :type admin_mode: :py:class:`~ska.base.control_model.AdminMode`
+        :param obs_state: the target observation state (optional)
+        :type obs_state: :py:class:`~ska.base.control_model.ObsState`
         """
-        Returns the state of the underlying state machine. This would normally
-        be a hidden implementation detail, but is exposed here for testing
-        purposes.
-        """
-        if self._state_machine.state == "ON":
-            return self._observation_state_machine.state
-        return self._state_machine.state
+        if obs_state is not None:
+            getattr(self._observation_state_machine, f"to_{obs_state.name}")()
+        super()._straight_to_state(op_state=op_state, admin_mode=admin_mode)
+
 
 
 class SKASubarrayResourceManager:
     """
     A simple class for managing subarray resources
     """
+
     def __init__(self):
         """
         Constructor for SKASubarrayResourceManager
@@ -277,10 +330,12 @@ class SKASubarray(SKAObsDevice):
     """
     Implements the SKA SubArray device
     """
+
     class InitCommand(SKAObsDevice.InitCommand):
         """
         A class for the SKASubarray's init_device() "command".
         """
+
         def do(self):
             """
             Stateless hook for device initialisation.
@@ -317,6 +372,7 @@ class SKASubarray(SKAObsDevice):
         """
         An abstract base class for SKASubarray's resourcing commands.
         """
+
         def __init__(self, target, state_model, action_hook, logger=None):
             """
             Constructor for _ResourcingCommand
@@ -328,7 +384,7 @@ class SKASubarray(SKAObsDevice):
             :param state_model: the state model that this command uses
                  to check that it is allowed to run, and that it drives
                  with actions.
-            :type state_model: SKASubarrayStateModel instance
+            :type state_model: :py:class:`SKASubarrayStateModel`
             :param action_hook: a hook for the command, used to build
                 actions that will be sent to the state model; for example,
                 if the hook is "scan", then success of the command will
@@ -365,6 +421,7 @@ class SKASubarray(SKAObsDevice):
         """
         A class for SKASubarray's AssignResources() command.
         """
+
         def __init__(self, target, state_model, logger=None):
             """
             Constructor for AssignResourcesCommand
@@ -376,7 +433,7 @@ class SKASubarray(SKAObsDevice):
             :param state_model: the state model that this command uses
                  to check that it is allowed to run, and that it drives
                  with actions.
-            :type state_model: SKASubarrayStateModel instance
+            :type state_model: :py:class:`SKASubarrayStateModel`
             :param logger: the logger to be used by this Command. If not
                 provided, then a default module logger will be used.
             :type logger: a logger that implements the standard library
@@ -407,6 +464,7 @@ class SKASubarray(SKAObsDevice):
         """
         A class for SKASubarray's ReleaseResources() command.
         """
+
         def __init__(self, target, state_model, logger=None):
             """
             Constructor for OnCommand()
@@ -418,7 +476,7 @@ class SKASubarray(SKAObsDevice):
             :param state_model: the state model that this command uses
                  to check that it is allowed to run, and that it drives
                  with actions.
-            :type state_model: SKASubarrayStateModel instance
+            :type state_model: :py:class:`SKASubarrayStateModel`
             :param logger: the logger to be used by this Command. If not
                 provided, then a default module logger will be used.
             :type logger: a logger that implements the standard library
@@ -449,6 +507,7 @@ class SKASubarray(SKAObsDevice):
         """
         A class for SKASubarray's ReleaseAllResources() command.
         """
+
         def do(self):
             """
             Stateless hook for ReleaseAllResources() command functionality.
@@ -474,6 +533,7 @@ class SKASubarray(SKAObsDevice):
         """
         A class for SKASubarray's Configure() command.
         """
+
         def __init__(self, target, state_model, logger=None):
             """
             Constructor for ConfigureCommand
@@ -485,7 +545,7 @@ class SKASubarray(SKAObsDevice):
             :param state_model: the state model that this command uses
                  to check that it is allowed to run, and that it drives
                  with actions.
-            :type state_model: SKASubarrayStateModel instance
+            :type state_model: :py:class:`SKASubarrayStateModel`
             :param logger: the logger to be used by this Command. If not
                 provided, then a default module logger will be used.
             :type logger: a logger that implements the standard library
@@ -529,6 +589,7 @@ class SKASubarray(SKAObsDevice):
         """
         A class for SKASubarray's Scan() command.
         """
+
         def __init__(self, target, state_model, logger=None):
             """
             Constructor for ScanCommand
@@ -540,7 +601,7 @@ class SKASubarray(SKAObsDevice):
             :param state_model: the state model that this command uses
                  to check that it is allowed to run, and that it drives
                  with actions.
-            :type state_model: SKASubarrayStateModel
+            :type state_model: :py:class:`SKASubarrayStateModel`
             :param logger: the logger to be used by this Command. If not
                 provided, then a default module logger will be used.
             :type logger: a logger that implements the standard library
@@ -571,6 +632,7 @@ class SKASubarray(SKAObsDevice):
         """
         A class for SKASubarray's EndScan() command.
         """
+
         def __init__(self, target, state_model, logger=None):
             """
             Constructor for EndScanCommand
@@ -582,7 +644,7 @@ class SKASubarray(SKAObsDevice):
             :param state_model: the state model that this command uses
                  to check that it is allowed to run, and that it drives
                  with actions.
-            :type state_model: SKASubarrayStateModel
+            :type state_model: :py:class:`SKASubarrayStateModel`
             :param logger: the logger to be used by this Command. If not
                 provided, then a default module logger will be used.
             :type logger: a logger that implements the standard library
@@ -607,6 +669,7 @@ class SKASubarray(SKAObsDevice):
         """
         A class for SKASubarray's End() command.
         """
+
         def __init__(self, target, state_model, logger=None):
             """
             Constructor for EndCommand
@@ -618,7 +681,7 @@ class SKASubarray(SKAObsDevice):
             :param state_model: the state model that this command uses
                  to check that it is allowed to run, and that it drives
                  with actions.
-            :type state_model: SKASubarrayStateModel
+            :type state_model: :py:class:`SKASubarrayStateModel`
             :param logger: the logger to be used by this Command. If not
                 provided, then a default module logger will be used.
             :type logger: a logger that implements the standard library
@@ -646,6 +709,7 @@ class SKASubarray(SKAObsDevice):
         """
         A class for SKASubarray's Abort() command.
         """
+
         def __init__(self, target, state_model, logger=None):
             """
             Constructor for AbortCommand
@@ -657,7 +721,7 @@ class SKASubarray(SKAObsDevice):
             :param state_model: the state model that this command uses
                  to check that it is allowed to run, and that it drives
                  with actions.
-            :type state_model: SKASubarrayStateModel
+            :type state_model: :py:class:`SKASubarrayStateModel`
             :param logger: the logger to be used by this Command. If not
                 provided, then a default module logger will be used.
             :type logger: a logger that implements the standard library
@@ -684,6 +748,7 @@ class SKASubarray(SKAObsDevice):
         """
         A class for SKASubarray's ObsReset() command.
         """
+
         def __init__(self, target, state_model, logger=None):
             """
             Constructor for ObsResetCommand
@@ -695,7 +760,7 @@ class SKASubarray(SKAObsDevice):
             :param state_model: the state model that this command uses
                  to check that it is allowed to run, and that it drives
                  with actions.
-            :type state_model: SKASubarrayStateModel
+            :type state_model: :py:class:`SKASubarrayStateModel`
             :param logger: the logger to be used by this Command. If not
                 provided, then a default module logger will be used.
             :type logger: a logger that implements the standard library
@@ -730,6 +795,7 @@ class SKASubarray(SKAObsDevice):
         """
         A class for SKASubarray's Restart() command.
         """
+
         def __init__(self, target, state_model, logger=None):
             """
             Constructor for RestartCommand
@@ -741,7 +807,7 @@ class SKASubarray(SKAObsDevice):
             :param state_model: the state model that this command uses
                  to check that it is allowed to run, and that it drives
                  with actions.
-            :type state_model: SKASubarrayStateModel
+            :type state_model: :py:class:`SKASubarrayStateModel`
             :param logger: the logger to be used by this Command. If not
                 provided, then a default module logger will be used.
             :type logger: a logger that implements the standard library
@@ -784,7 +850,7 @@ class SKASubarray(SKAObsDevice):
             logger=self.logger,
             op_state_callback=self._update_state,
             admin_mode_callback=self._update_admin_mode,
-            obs_state_callback=self._update_obs_state
+            obs_state_callback=self._update_obs_state,
         )
 
     def init_command_objects(self):
@@ -797,36 +863,21 @@ class SKASubarray(SKAObsDevice):
         resource_args = (self.resource_manager, self.state_model, self.logger)
 
         self.register_command_object(
-            "AssignResources",
-            self.AssignResourcesCommand(*resource_args)
+            "AssignResources", self.AssignResourcesCommand(*resource_args)
         )
         self.register_command_object(
-            "ReleaseResources",
-            self.ReleaseResourcesCommand(*resource_args)
+            "ReleaseResources", self.ReleaseResourcesCommand(*resource_args)
         )
         self.register_command_object(
-            "ReleaseAllResources",
-            self.ReleaseAllResourcesCommand(*resource_args)
-        )
-        self.register_command_object(
-            "Configure",
-            self.ConfigureCommand(*device_args)
+            "ReleaseAllResources", self.ReleaseAllResourcesCommand(*resource_args)
         )
+        self.register_command_object("Configure", self.ConfigureCommand(*device_args))
         self.register_command_object("Scan", self.ScanCommand(*device_args))
-        self.register_command_object(
-            "EndScan",
-            self.EndScanCommand(*device_args)
-        )
+        self.register_command_object("EndScan", self.EndScanCommand(*device_args))
         self.register_command_object("End", self.EndCommand(*device_args))
         self.register_command_object("Abort", self.AbortCommand(*device_args))
-        self.register_command_object(
-            "ObsReset",
-            self.ObsResetCommand(*device_args)
-        )
-        self.register_command_object(
-            "Restart",
-            self.RestartCommand(*device_args)
-        )
+        self.register_command_object("ObsReset", self.ObsResetCommand(*device_args))
+        self.register_command_object("Restart", self.RestartCommand(*device_args))
 
     def _validate_capability_types(self, capability_types):
         """
@@ -835,13 +886,13 @@ class SKASubarray(SKAObsDevice):
 
         :param device: the device for which this class implements
             the configure command
-        :type device: SKASubarray
+        :type device: :py:class:`SKASubarray`
         :param capability_types: a list strings representing
             capability types.
         :type capability_types: list
 
-        :raises ValueError: If any of the capabilities requested are
-            not valid.
+        :raises CapabilityValidationError: If any of the capabilities
+            requested are not valid.
         """
         invalid_capabilities = list(
             set(capability_types) - set(self._configured_capabilities))
@@ -903,8 +954,6 @@ class SKASubarray(SKAObsDevice):
         # PROTECTED REGION ID(SKASubarray.always_executed_hook) ENABLED START #
         """
         Method that is always executed before any device command gets executed.
-
-        :return: None
         """
         pass
         # PROTECTED REGION END #    //  SKASubarray.always_executed_hook
@@ -913,8 +962,6 @@ class SKASubarray(SKAObsDevice):
         # PROTECTED REGION ID(SKASubarray.delete_device) ENABLED START #
         """
         Method to cleanup when device is stopped.
-
-        :return: None
         """
         pass
         # PROTECTED REGION END #    //  SKASubarray.delete_device
@@ -951,8 +998,9 @@ class SKASubarray(SKAObsDevice):
             in the Subarray
         """
         configured_capabilities = []
-        for capability_type, capability_instances in (
-                list(self._configured_capabilities.items())):
+        for capability_type, capability_instances in list(
+            self._configured_capabilities.items()
+        ):
             configured_capabilities.append(
                 "{}:{}".format(capability_type, capability_instances))
         return sorted(configured_capabilities)
@@ -991,6 +1039,11 @@ class SKASubarray(SKAObsDevice):
 
         :param argin: the resources to be assigned
         :type argin: list of str
+
+        :return: A tuple containing a return code and a string
+            message indicating status. The message is for
+            information purpose only.
+        :rtype: (ResultCode, str)
         """
         command = self.get_command_object("AssignResources")
         (return_code, message) = command(argin)
@@ -1025,6 +1078,11 @@ class SKASubarray(SKAObsDevice):
 
         :param argin: the resources to be released
         :type argin: list of str
+
+        :return: A tuple containing a return code and a string
+            message indicating status. The message is for
+            information purpose only.
+        :rtype: (ResultCode, str)
         """
         command = self.get_command_object("ReleaseResources")
         (return_code, message) = command(argin)
@@ -1055,8 +1113,10 @@ class SKASubarray(SKAObsDevice):
         To modify behaviour for this command, modify the do() method of
         the command class.
 
-        :return: list of resources removed
-        :rtype: list of string
+        :return: A tuple containing a return code and a string
+            message indicating status. The message is for
+            information purpose only.
+        :rtype: (ResultCode, str)
         """
         command = self.get_command_object("ReleaseAllResources")
         (return_code, message) = command()
@@ -1091,6 +1151,11 @@ class SKASubarray(SKAObsDevice):
 
         :param argin: configuration specification
         :type argin: string
+
+        :return: A tuple containing a return code and a string
+            message indicating status. The message is for
+            information purpose only.
+        :rtype: (ResultCode, str)
         """
         command = self.get_command_object("Configure")
         (return_code, message) = command(argin)
@@ -1124,6 +1189,11 @@ class SKASubarray(SKAObsDevice):
 
         :param argin: Information about the scan
         :type argin: Array of str
+
+        :return: A tuple containing a return code and a string
+            message indicating status. The message is for
+            information purpose only.
+        :rtype: (ResultCode, str)
         """
         command = self.get_command_object("Scan")
         (return_code, message) = command(argin)
@@ -1152,6 +1222,11 @@ class SKASubarray(SKAObsDevice):
 
         To modify behaviour for this command, modify the do() method of
         the command class.
+
+        :return: A tuple containing a return code and a string
+            message indicating status. The message is for
+            information purpose only.
+        :rtype: (ResultCode, str)
         """
         command = self.get_command_object("EndScan")
         (return_code, message) = command()
@@ -1181,6 +1256,11 @@ class SKASubarray(SKAObsDevice):
 
         To modify behaviour for this command, modify the do() method of
         the command class.
+
+        :return: A tuple containing a return code and a string
+            message indicating status. The message is for
+            information purpose only.
+        :rtype: (ResultCode, str)
         """
         command = self.get_command_object("End")
         (return_code, message) = command()
@@ -1210,6 +1290,11 @@ class SKASubarray(SKAObsDevice):
 
         To modify behaviour for this command, modify the do() method of
         the command class.
+
+        :return: A tuple containing a return code and a string
+            message indicating status. The message is for
+            information purpose only.
+        :rtype: (ResultCode, str)
         """
         command = self.get_command_object("Abort")
         (return_code, message) = command()
@@ -1239,6 +1324,11 @@ class SKASubarray(SKAObsDevice):
 
         To modify behaviour for this command, modify the do() method of
         the command class.
+
+        :return: A tuple containing a return code and a string
+            message indicating status. The message is for
+            information purpose only.
+        :rtype: (ResultCode, str)
         """
         command = self.get_command_object("ObsReset")
         (return_code, message) = command()
@@ -1269,6 +1359,11 @@ class SKASubarray(SKAObsDevice):
 
         To modify behaviour for this command, modify the do() method of
         the command class.
+
+        :return: A tuple containing a return code and a string
+            message indicating status. The message is for
+            information purpose only.
+        :rtype: (ResultCode, str)
         """
         command = self.get_command_object("Restart")
         (return_code, message) = command()
@@ -1282,6 +1377,11 @@ def main(args=None, **kwargs):
     # PROTECTED REGION ID(SKASubarray.main) ENABLED START #
     """
     Main entry point of the module.
+
+    :param args: positional args to tango.server.run
+    :param kwargs: named args to tango.server.run
+
+    :return: exit code
     """
     return run((SKASubarray,), args=args, **kwargs)
     # PROTECTED REGION END #    //  SKASubarray.main
diff --git a/tests/conftest.py b/tests/conftest.py
index f3299213d1964c75f26dcd1fad3b324c8f712605..0c6cc46d34d701d2bbb8b68239c3356b928ad314 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,6 +1,7 @@
 """
 A module defining a list of fixtures that are shared across all ska.base tests.
 """
+from collections import defaultdict
 import importlib
 import itertools
 import json
@@ -8,9 +9,11 @@ import pytest
 from queue import Empty, Queue
 from transitions import MachineError
 
-from tango import EventType
+from tango import DevState, EventType
 from tango.test_context import DeviceTestContext
 
+from ska.base.control_model import AdminMode, ObsState
+
 
 def pytest_configure(config):
     """
@@ -31,32 +34,30 @@ def pytest_generate_tests(metafunc):
     will have its tests parameterised by the states and actions in the
     specification provided by that mark
     """
-    # called once per each test function
     mark = metafunc.definition.get_closest_marker("state_machine_tester")
     if mark:
         spec = mark.args[0]
-        states = set()
-        triggers = set()
-        expected = {}
 
-        for (from_state, trigger, to_state) in spec:
-            states.add(from_state)
-            states.add(to_state)
-            triggers.add(trigger)
-            expected[(from_state, trigger)] = to_state
+        states = {state: spec["states"][state] or state for state in spec["states"]}
 
-        states = sorted(states)
-        triggers = sorted(triggers)
+        triggers = set()
+        expected = defaultdict(lambda: None)
+        for transition in spec["transitions"]:
+            triggers.add(transition["trigger"])
+            expected[(transition["from"], transition["trigger"])] = states[transition["to"]]
+        test_cases = list(itertools.product(sorted(states), sorted(triggers)))
+        test_ids = [f"{state}-{trigger}" for (state, trigger) in test_cases]
 
         metafunc.parametrize(
             "state_under_test, action_under_test, expected_state",
             [
                 (
-                    state,
+                    states[state],
                     trigger,
-                    expected[(state, trigger)] if (state, trigger) in expected else None
-                ) for (state, trigger) in itertools.product(states, triggers)
-            ]
+                    expected[(state, trigger)]
+                ) for (state, trigger) in test_cases
+            ],
+            ids=test_ids
         )
 
 
@@ -102,10 +103,12 @@ class StateMachineTester:
         # Test that the action under test does what we expect it to
         if expected_state is None:
             # Action should fail and the state should not change
-            self.check_action_disallowed(machine, action_under_test)
+            assert not self.is_action_allowed(machine, action_under_test)
+            self.check_action_fails(machine, action_under_test)
             self.assert_state(machine, state_under_test)
         else:
             # Action should succeed
+            assert self.is_action_allowed(machine, action_under_test)
             self.perform_action(machine, action_under_test)
             self.assert_state(machine, expected_state)
 
@@ -122,6 +125,18 @@ class StateMachineTester:
         """
         raise NotImplementedError()
 
+    def is_action_allowed(self, machine, action):
+        """
+        Abstract method for checking whether the action under test is
+        allowed from the current state.
+
+        :param machine: the state machine under test
+        :type machine: state machine object instance
+        :param action: action to be performed on the state machine
+        :type action: str
+        """
+        raise NotImplementedError()
+
     def perform_action(self, machine, action):
         """
         Abstract method for performing an action on the state machine
@@ -133,7 +148,7 @@ class StateMachineTester:
         """
         raise NotImplementedError()
 
-    def check_action_disallowed(self, machine, action):
+    def check_action_fails(self, machine, action):
         """
         Abstract method for asserting that an action fails if performed
         on the state machine under test in its current state.
@@ -179,6 +194,18 @@ class TransitionsStateMachineTester(StateMachineTester):
         """
         assert machine.state == state
 
+    def is_action_allowed(self, machine, action):
+        """
+        Check whether the action under test is allowed from the current
+        state.
+
+        :param machine: the state machine under test
+        :type machine: state machine object instance
+        :param action: action to be performed on the state machine
+        :type action: str
+        """
+        return action in machine.get_triggers(machine.state)
+
     def perform_action(self, machine, action):
         """
         Perform a given action on the state machine under test.
@@ -190,9 +217,9 @@ class TransitionsStateMachineTester(StateMachineTester):
         """
         machine.trigger(action)
 
-    def check_action_disallowed(self, machine, action):
+    def check_action_fails(self, machine, action):
         """
-        Assert that performing a given action on the state maching under
+        Check that attempting a given action on the state machine under
         test fails in its current state.
 
         :param machine: the state machine under test
@@ -233,6 +260,25 @@ def load_data(name):
     with open(f"tests/data/{name}.json", "r") as json_file:
         return json.load(json_file)
 
+def load_state_machine_spec(name):
+    """
+    Loads a state machine specification by name.
+
+    :param name: name of the dataset to be loaded; this implementation
+        uses the name to find a JSON file containing the data to be
+        loaded.
+    :type name: string
+    """
+    machine_spec = load_data(name)
+    for state in machine_spec["states"]:
+        state_spec = machine_spec["states"][state]
+        if "admin_mode" in state_spec:
+            state_spec["admin_mode"] = AdminMode[state_spec["admin_mode"]]
+        if "op_state" in state_spec:
+            state_spec["op_state"] = getattr(DevState, state_spec["op_state"])
+        if "obs_state" in state_spec:
+            state_spec["obs_state"] = ObsState[state_spec["obs_state"]]
+    return machine_spec
 
 @pytest.fixture(scope="class")
 def tango_context(request):
@@ -251,8 +297,7 @@ def tango_context(request):
             'NrSubarrays': '16',
             'CapabilityTypes': '',
             'MaxCapabilities': ['BAND1:1', 'BAND2:1']
-            },
-
+        },
         'SKASubarray': {
             "CapabilityTypes": ["BAND1", "BAND2"],
             'LoggingTargetsDefault': '',
@@ -319,12 +364,14 @@ def tango_change_event_helper(tango_context):
         state_callback.assert_calls([DevState.OFF, DevState.ON])
 
     """
+
     class _Callback:
         """
         Private callback handler class, an instance of which is returned
         by the tango_change_event_helper each time it is used to
         subscribe to a change event.
         """
+
         @staticmethod
         def subscribe(attribute_name):
             """
@@ -371,7 +418,7 @@ def tango_change_event_helper(tango_context):
             Event subscription callback
 
             :param event_data: data about the change events
-            :type event_data: tango.EventData
+            :type event_data: :py:class:`tango.EventData`
             """
             if event_data.err:
                 error = event_data.errors[0]
diff --git a/tests/data/admin_mode_state_machine.json b/tests/data/admin_mode_state_machine.json
new file mode 100644
index 0000000000000000000000000000000000000000..3d7e303f13fa00bf50172a1f8856459f772ab4ad
--- /dev/null
+++ b/tests/data/admin_mode_state_machine.json
@@ -0,0 +1,96 @@
+{
+    "states": {
+        "RESERVED": {},
+        "NOT_FITTED": {},
+        "OFFLINE": {},
+        "MAINTENANCE": {},
+        "ONLINE": {}
+    },
+    "transitions": [
+        {
+            "from": "NOT_FITTED",
+            "to": "NOT_FITTED",
+            "trigger": "to_notfitted"
+        },
+        {
+            "from": "NOT_FITTED",
+            "to": "RESERVED",
+            "trigger": "to_reserved"
+        },
+        {
+            "from": "NOT_FITTED",
+            "to": "OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "RESERVED",
+            "to": "NOT_FITTED",
+            "trigger": "to_notfitted"
+        },
+        {
+            "from": "RESERVED",
+            "to": "RESERVED",
+            "trigger": "to_reserved"
+        },
+        {
+            "from": "RESERVED",
+            "to": "OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "OFFLINE",
+            "to": "RESERVED",
+            "trigger": "to_reserved"
+        },
+        {
+            "from": "OFFLINE",
+            "to": "NOT_FITTED",
+            "trigger": "to_notfitted"
+        },
+        {
+            "from": "OFFLINE",
+            "to": "OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "OFFLINE",
+            "to": "MAINTENANCE",
+            "trigger": "to_maintenance"
+        },
+        {
+            "from": "OFFLINE",
+            "to": "ONLINE",
+            "trigger": "to_online"
+        },
+        {
+            "from": "MAINTENANCE",
+            "to": "OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "MAINTENANCE",
+            "to": "MAINTENANCE",
+            "trigger": "to_maintenance"
+        },
+        {
+            "from": "MAINTENANCE",
+            "to": "ONLINE",
+            "trigger": "to_online"
+        },
+        {
+            "from": "ONLINE",
+            "to": "OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "ONLINE",
+            "to": "MAINTENANCE",
+            "trigger": "to_maintenance"
+        },
+        {
+            "from": "ONLINE",
+            "to": "ONLINE",
+            "trigger": "to_online"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/tests/data/base_device_state_machine.json b/tests/data/base_device_state_machine.json
deleted file mode 100644
index a9891a842b798cb6c0ceff7fbd0c129ba9e42dd5..0000000000000000000000000000000000000000
--- a/tests/data/base_device_state_machine.json
+++ /dev/null
@@ -1,222 +0,0 @@
-[
-    [
-        "UNINITIALISED",
-        "init_started",
-        "INIT_ENABLED"
-    ],
-    [
-        "INIT_ENABLED",
-        "to_notfitted",
-        "INIT_DISABLED"
-    ],
-    [
-        "INIT_ENABLED",
-        "to_offline",
-        "INIT_DISABLED"
-    ],
-    [
-        "INIT_ENABLED",
-        "to_online",
-        "INIT_ENABLED"
-    ],
-    [
-        "INIT_ENABLED",
-        "to_maintenance",
-        "INIT_ENABLED"
-    ],
-    [
-        "INIT_ENABLED",
-        "init_succeeded",
-        "OFF"
-    ],
-    [
-        "INIT_ENABLED",
-        "init_failed",
-        "FAULT_ENABLED"
-    ],
-    [
-        "INIT_ENABLED",
-        "fatal_error",
-        "FAULT_ENABLED"
-    ],
-    [
-        "INIT_DISABLED",
-        "to_notfitted",
-        "INIT_DISABLED"
-    ],
-    [
-        "INIT_DISABLED",
-        "to_offline",
-        "INIT_DISABLED"
-    ],
-    [
-        "INIT_DISABLED",
-        "to_online",
-        "INIT_ENABLED"
-    ],
-    [
-        "INIT_DISABLED",
-        "to_maintenance",
-        "INIT_ENABLED"
-    ],
-    [
-        "INIT_DISABLED",
-        "init_succeeded",
-        "DISABLED"
-    ],
-    [
-        "INIT_DISABLED",
-        "init_failed",
-        "FAULT_DISABLED"
-    ],
-    [
-        "INIT_DISABLED",
-        "fatal_error",
-        "FAULT_DISABLED"
-    ],
-    [
-        "FAULT_DISABLED",
-        "to_notfitted",
-        "FAULT_DISABLED"
-    ],
-    [
-        "FAULT_DISABLED",
-        "to_offline",
-        "FAULT_DISABLED"
-    ],
-    [
-        "FAULT_DISABLED",
-        "to_online",
-        "FAULT_ENABLED"
-    ],
-    [
-        "FAULT_DISABLED",
-        "to_maintenance",
-        "FAULT_ENABLED"
-    ],
-    [
-        "FAULT_DISABLED",
-        "reset_succeeded",
-        "DISABLED"
-    ],
-    [
-        "FAULT_DISABLED",
-        "reset_failed",
-        "FAULT_DISABLED"
-    ],
-    [
-        "FAULT_DISABLED",
-        "fatal_error",
-        "FAULT_DISABLED"
-    ],
-    [
-        "FAULT_ENABLED",
-        "to_notfitted",
-        "FAULT_DISABLED"
-    ],
-    [
-        "FAULT_ENABLED",
-        "to_offline",
-        "FAULT_DISABLED"
-    ],
-    [
-        "FAULT_ENABLED",
-        "to_online",
-        "FAULT_ENABLED"
-    ],
-    [
-        "FAULT_ENABLED",
-        "to_maintenance",
-        "FAULT_ENABLED"
-    ],
-    [
-        "FAULT_ENABLED",
-        "reset_succeeded",
-        "OFF"
-    ],
-    [
-        "FAULT_ENABLED",
-        "reset_failed",
-        "FAULT_ENABLED"
-    ],
-    [
-        "FAULT_ENABLED",
-        "fatal_error",
-        "FAULT_ENABLED"
-    ],
-    [
-        "DISABLED",
-        "to_notfitted",
-        "DISABLED"
-    ],
-    [
-        "DISABLED",
-        "to_offline",
-        "DISABLED"
-    ],
-    [
-        "DISABLED",
-        "to_online",
-        "OFF"
-    ],
-    [
-        "DISABLED",
-        "to_maintenance",
-        "OFF"
-    ],
-    [
-        "DISABLED",
-        "fatal_error",
-        "FAULT_DISABLED"
-    ],
-    [
-        "OFF",
-        "to_notfitted",
-        "DISABLED"
-    ],
-    [
-        "OFF",
-        "to_offline",
-        "DISABLED"
-    ],
-    [
-        "OFF",
-        "to_online",
-        "OFF"
-    ],
-    [
-        "OFF",
-        "to_maintenance",
-        "OFF"
-    ],
-    [
-        "OFF",
-        "on_succeeded",
-        "ON"
-    ],
-    [
-        "OFF",
-        "on_failed",
-        "FAULT_ENABLED"
-    ],
-    [
-        "OFF",
-        "fatal_error",
-        "FAULT_ENABLED"
-    ],
-    [
-        "ON",
-        "off_succeeded",
-        "OFF"
-    ],
-    [
-        "ON",
-        "off_failed",
-        "FAULT_ENABLED"
-    ],
-    [
-        "ON",
-        "fatal_error",
-        "FAULT_ENABLED"
-    ]
-]
\ No newline at end of file
diff --git a/tests/data/device_state_machine.json b/tests/data/device_state_machine.json
new file mode 100644
index 0000000000000000000000000000000000000000..544064bcc27c287d0574895a5777d7d06cf72481
--- /dev/null
+++ b/tests/data/device_state_machine.json
@@ -0,0 +1,860 @@
+{
+    "states": {
+        "INIT_MAINTENANCE": {
+            "admin_mode": "MAINTENANCE",
+            "op_state": "INIT"
+        },
+        "INIT_ONLINE": {
+            "admin_mode": "ONLINE",
+            "op_state": "INIT"
+        },
+        "INIT_OFFLINE": {
+            "admin_mode": "OFFLINE",
+            "op_state": "INIT"
+        },
+        "INIT_NOTFITTED": {
+            "admin_mode": "NOT_FITTED",
+            "op_state": "INIT"
+        },
+        "INIT_RESERVED": {
+            "admin_mode": "RESERVED",
+            "op_state": "INIT"
+        },
+        "FAULT_MAINTENANCE": {
+            "admin_mode": "MAINTENANCE",
+            "op_state": "FAULT"
+        },
+        "FAULT_ONLINE": {
+            "admin_mode": "ONLINE",
+            "op_state": "FAULT"
+        },
+        "FAULT_OFFLINE": {
+            "admin_mode": "OFFLINE",
+            "op_state": "FAULT"
+        },
+        "FAULT_NOTFITTED": {
+            "admin_mode": "NOT_FITTED",
+            "op_state": "FAULT"
+        },
+        "FAULT_RESERVED": {
+            "admin_mode": "RESERVED",
+            "op_state": "FAULT"
+        },
+        "DISABLE_MAINTENANCE": {
+            "admin_mode": "MAINTENANCE",
+            "op_state": "DISABLE"
+        },
+        "DISABLE_ONLINE": {
+            "admin_mode": "ONLINE",
+            "op_state": "DISABLE"
+        },
+        "DISABLE_OFFLINE": {
+            "admin_mode": "OFFLINE",
+            "op_state": "DISABLE"
+        },
+        "DISABLE_NOTFITTED": {
+            "admin_mode": "NOT_FITTED",
+            "op_state": "DISABLE"
+        },
+        "DISABLE_RESERVED": {
+            "admin_mode": "RESERVED",
+            "op_state": "DISABLE"
+        },
+        "STANDBY_MAINTENANCE": {
+            "admin_mode": "MAINTENANCE",
+            "op_state": "STANDBY"
+        },
+        "STANDBY_ONLINE": {
+            "admin_mode": "ONLINE",
+            "op_state": "STANDBY"
+        },
+        "OFF_MAINTENANCE": {
+            "admin_mode": "MAINTENANCE",
+            "op_state": "OFF"
+        },
+        "OFF_ONLINE": {
+            "admin_mode": "ONLINE",
+            "op_state": "OFF"
+        },
+        "ON_MAINTENANCE": {
+            "admin_mode": "MAINTENANCE",
+            "op_state": "ON"
+        },
+        "ON_ONLINE": {
+            "admin_mode": "ONLINE",
+            "op_state": "ON"
+        }
+    },
+    "transitions": [
+        {
+            "from": "INIT_MAINTENANCE",
+            "to": "INIT_OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "INIT_MAINTENANCE",
+            "to": "INIT_MAINTENANCE",
+            "trigger": "to_maintenance"
+        },
+        {
+            "from": "INIT_MAINTENANCE",
+            "to": "INIT_ONLINE",
+            "trigger": "to_online"
+        },
+        {
+            "from": "INIT_MAINTENANCE",
+            "to": "DISABLE_MAINTENANCE",
+            "trigger": "init_succeeded_disable"
+        },
+        {
+            "from": "INIT_MAINTENANCE",
+            "to": "STANDBY_MAINTENANCE",
+            "trigger": "init_succeeded_standby"
+        },
+        {
+            "from": "INIT_MAINTENANCE",
+            "to": "OFF_MAINTENANCE",
+            "trigger": "init_succeeded_off"
+        },
+        {
+            "from": "INIT_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "init_failed"
+        },
+        {
+            "from": "INIT_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "INIT_ONLINE",
+            "to": "INIT_MAINTENANCE",
+            "trigger": "to_maintenance"
+        },
+        {
+            "from": "INIT_ONLINE",
+            "to": "INIT_ONLINE",
+            "trigger": "to_online"
+        },
+        {
+            "from": "INIT_ONLINE",
+            "to": "INIT_OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "INIT_ONLINE",
+            "to": "DISABLE_ONLINE",
+            "trigger": "init_succeeded_disable"
+        },
+        {
+            "from": "INIT_ONLINE",
+            "to": "STANDBY_ONLINE",
+            "trigger": "init_succeeded_standby"
+        },
+        {
+            "from": "INIT_ONLINE",
+            "to": "OFF_ONLINE",
+            "trigger": "init_succeeded_off"
+        },
+        {
+            "from": "INIT_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "init_failed"
+        },
+        {
+            "from": "INIT_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "INIT_OFFLINE",
+            "to": "INIT_ONLINE",
+            "trigger": "to_online"
+        },
+        {
+            "from": "INIT_OFFLINE",
+            "to": "INIT_MAINTENANCE",
+            "trigger": "to_maintenance"
+        },
+        {
+            "from": "INIT_OFFLINE",
+            "to": "INIT_OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "INIT_OFFLINE",
+            "to": "INIT_RESERVED",
+            "trigger": "to_reserved"
+        },
+        {
+            "from": "INIT_OFFLINE",
+            "to": "INIT_NOTFITTED",
+            "trigger": "to_notfitted"
+        },
+        {
+            "from": "INIT_OFFLINE",
+            "to": "DISABLE_OFFLINE",
+            "trigger": "init_succeeded_disable"
+        },
+        {
+            "from": "INIT_OFFLINE",
+            "to": "FAULT_OFFLINE",
+            "trigger": "init_failed"
+        },
+        {
+            "from": "INIT_OFFLINE",
+            "to": "FAULT_OFFLINE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "INIT_NOTFITTED",
+            "to": "INIT_OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "INIT_NOTFITTED",
+            "to": "INIT_RESERVED",
+            "trigger": "to_reserved"
+        },
+        {
+            "from": "INIT_NOTFITTED",
+            "to": "INIT_NOTFITTED",
+            "trigger": "to_notfitted"
+        },
+        {
+            "from": "INIT_NOTFITTED",
+            "to": "DISABLE_NOTFITTED",
+            "trigger": "init_succeeded_disable"
+        },
+        {
+            "from": "INIT_NOTFITTED",
+            "to": "FAULT_NOTFITTED",
+            "trigger": "init_failed"
+        },
+        {
+            "from": "INIT_NOTFITTED",
+            "to": "FAULT_NOTFITTED",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "INIT_RESERVED",
+            "to": "INIT_NOTFITTED",
+            "trigger": "to_notfitted"
+        },
+        {
+            "from": "INIT_RESERVED",
+            "to": "INIT_OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "INIT_RESERVED",
+            "to": "INIT_RESERVED",
+            "trigger": "to_reserved"
+        },
+        {
+            "from": "INIT_RESERVED",
+            "to": "DISABLE_RESERVED",
+            "trigger": "init_succeeded_disable"
+        },
+        {
+            "from": "INIT_RESERVED",
+            "to": "FAULT_RESERVED",
+            "trigger": "init_failed"
+        },
+        {
+            "from": "INIT_RESERVED",
+            "to": "FAULT_RESERVED",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "FAULT_MAINTENANCE",
+            "to": "FAULT_OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "FAULT_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "to_maintenance"
+        },
+        {
+            "from": "FAULT_MAINTENANCE",
+            "to": "FAULT_ONLINE",
+            "trigger": "to_online"
+        },
+        {
+            "from": "FAULT_MAINTENANCE",
+            "to": "DISABLE_MAINTENANCE",
+            "trigger": "reset_succeeded_disable"
+        },
+        {
+            "from": "FAULT_MAINTENANCE",
+            "to": "STANDBY_MAINTENANCE",
+            "trigger": "reset_succeeded_standby"
+        },
+        {
+            "from": "FAULT_MAINTENANCE",
+            "to": "OFF_MAINTENANCE",
+            "trigger": "reset_succeeded_off"
+        },
+        {
+            "from": "FAULT_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "reset_failed"
+        },
+        {
+            "from": "FAULT_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "FAULT_ONLINE",
+            "to": "FAULT_OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "FAULT_ONLINE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "to_maintenance"
+        },
+        {
+            "from": "FAULT_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "to_online"
+        },
+        {
+            "from": "FAULT_ONLINE",
+            "to": "DISABLE_ONLINE",
+            "trigger": "reset_succeeded_disable"
+        },
+        {
+            "from": "FAULT_ONLINE",
+            "to": "STANDBY_ONLINE",
+            "trigger": "reset_succeeded_standby"
+        },
+        {
+            "from": "FAULT_ONLINE",
+            "to": "OFF_ONLINE",
+            "trigger": "reset_succeeded_off"
+        },
+        {
+            "from": "FAULT_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "reset_failed"
+        },
+        {
+            "from": "FAULT_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "FAULT_OFFLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "to_online"
+        },
+        {
+            "from": "FAULT_OFFLINE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "to_maintenance"
+        },
+        {
+            "from": "FAULT_OFFLINE",
+            "to": "FAULT_OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "FAULT_OFFLINE",
+            "to": "FAULT_RESERVED",
+            "trigger": "to_reserved"
+        },
+        {
+            "from": "FAULT_OFFLINE",
+            "to": "FAULT_NOTFITTED",
+            "trigger": "to_notfitted"
+        },
+        {
+            "from": "FAULT_OFFLINE",
+            "to": "DISABLE_OFFLINE",
+            "trigger": "reset_succeeded_disable"
+        },
+        {
+            "from": "FAULT_OFFLINE",
+            "to": "FAULT_OFFLINE",
+            "trigger": "reset_failed"
+        },
+        {
+            "from": "FAULT_OFFLINE",
+            "to": "FAULT_OFFLINE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "FAULT_NOTFITTED",
+            "to": "FAULT_OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "FAULT_NOTFITTED",
+            "to": "FAULT_NOTFITTED",
+            "trigger": "to_notfitted"
+        },
+        {
+            "from": "FAULT_NOTFITTED",
+            "to": "FAULT_RESERVED",
+            "trigger": "to_reserved"
+        },
+        {
+            "from": "FAULT_NOTFITTED",
+            "to": "DISABLE_NOTFITTED",
+            "trigger": "reset_succeeded_disable"
+        },
+        {
+            "from": "FAULT_NOTFITTED",
+            "to": "FAULT_NOTFITTED",
+            "trigger": "reset_failed"
+        },
+        {
+            "from": "FAULT_NOTFITTED",
+            "to": "FAULT_NOTFITTED",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "FAULT_RESERVED",
+            "to": "FAULT_NOTFITTED",
+            "trigger": "to_notfitted"
+        },
+        {
+            "from": "FAULT_RESERVED",
+            "to": "FAULT_RESERVED",
+            "trigger": "to_reserved"
+        },
+        {
+            "from": "FAULT_RESERVED",
+            "to": "FAULT_OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "FAULT_RESERVED",
+            "to": "DISABLE_RESERVED",
+            "trigger": "reset_succeeded_disable"
+        },
+        {
+            "from": "FAULT_RESERVED",
+            "to": "FAULT_RESERVED",
+            "trigger": "reset_failed"
+        },
+        {
+            "from": "FAULT_RESERVED",
+            "to": "FAULT_RESERVED",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "DISABLE_MAINTENANCE",
+            "to": "DISABLE_OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "DISABLE_MAINTENANCE",
+            "to": "DISABLE_MAINTENANCE",
+            "trigger": "to_maintenance"
+        },
+        {
+            "from": "DISABLE_MAINTENANCE",
+            "to": "DISABLE_ONLINE",
+            "trigger": "to_online"
+        },
+        {
+            "from": "DISABLE_MAINTENANCE",
+            "to": "DISABLE_MAINTENANCE",
+            "trigger": "disable_succeeded"
+        },
+        {
+            "from": "DISABLE_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "disable_failed"
+        },
+        {
+            "from": "DISABLE_MAINTENANCE",
+            "to": "STANDBY_MAINTENANCE",
+            "trigger": "standby_succeeded"
+        },
+        {
+            "from": "DISABLE_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "standby_failed"
+        },
+        {
+            "from": "DISABLE_MAINTENANCE",
+            "to": "OFF_MAINTENANCE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "DISABLE_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "DISABLE_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "DISABLE_ONLINE",
+            "to": "DISABLE_OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "DISABLE_ONLINE",
+            "to": "DISABLE_MAINTENANCE",
+            "trigger": "to_maintenance"
+        },
+        {
+            "from": "DISABLE_ONLINE",
+            "to": "DISABLE_ONLINE",
+            "trigger": "to_online"
+        },
+        {
+            "from": "DISABLE_ONLINE",
+            "to": "DISABLE_ONLINE",
+            "trigger": "disable_succeeded"
+        },
+        {
+            "from": "DISABLE_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "disable_failed"
+        },
+        {
+            "from": "DISABLE_ONLINE",
+            "to": "STANDBY_ONLINE",
+            "trigger": "standby_succeeded"
+        },
+        {
+            "from": "DISABLE_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "standby_failed"
+        },
+        {
+            "from": "DISABLE_ONLINE",
+            "to": "OFF_ONLINE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "DISABLE_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "DISABLE_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "DISABLE_OFFLINE",
+            "to": "DISABLE_OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "DISABLE_OFFLINE",
+            "to": "DISABLE_MAINTENANCE",
+            "trigger": "to_maintenance"
+        },
+        {
+            "from": "DISABLE_OFFLINE",
+            "to": "DISABLE_ONLINE",
+            "trigger": "to_online"
+        },
+        {
+            "from": "DISABLE_OFFLINE",
+            "to": "DISABLE_NOTFITTED",
+            "trigger": "to_notfitted"
+        },
+        {
+            "from": "DISABLE_OFFLINE",
+            "to": "DISABLE_RESERVED",
+            "trigger": "to_reserved"
+        },
+        {
+            "from": "DISABLE_OFFLINE",
+            "to": "DISABLE_OFFLINE",
+            "trigger": "disable_succeeded"
+        },
+        {
+            "from": "DISABLE_OFFLINE",
+            "to": "FAULT_OFFLINE",
+            "trigger": "disable_failed"
+        },
+        {
+            "from": "DISABLE_OFFLINE",
+            "to": "FAULT_OFFLINE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "DISABLE_NOTFITTED",
+            "to": "DISABLE_NOTFITTED",
+            "trigger": "to_notfitted"
+        },
+        {
+            "from": "DISABLE_NOTFITTED",
+            "to": "DISABLE_OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "DISABLE_NOTFITTED",
+            "to": "DISABLE_RESERVED",
+            "trigger": "to_reserved"
+        },
+        {
+            "from": "DISABLE_NOTFITTED",
+            "to": "DISABLE_NOTFITTED",
+            "trigger": "disable_succeeded"
+        },
+        {
+            "from": "DISABLE_NOTFITTED",
+            "to": "FAULT_NOTFITTED",
+            "trigger": "disable_failed"
+        },
+        {
+            "from": "DISABLE_NOTFITTED",
+            "to": "FAULT_NOTFITTED",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "DISABLE_RESERVED",
+            "to": "DISABLE_RESERVED",
+            "trigger": "to_reserved"
+        },
+        {
+            "from": "DISABLE_RESERVED",
+            "to": "DISABLE_NOTFITTED",
+            "trigger": "to_notfitted"
+        },
+        {
+            "from": "DISABLE_RESERVED",
+            "to": "DISABLE_OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "DISABLE_RESERVED",
+            "to": "DISABLE_RESERVED",
+            "trigger": "disable_succeeded"
+        },
+        {
+            "from": "DISABLE_RESERVED",
+            "to": "FAULT_RESERVED",
+            "trigger": "disable_failed"
+        },
+        {
+            "from": "DISABLE_RESERVED",
+            "to": "FAULT_RESERVED",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "STANDBY_MAINTENANCE",
+            "to": "DISABLE_MAINTENANCE",
+            "trigger": "disable_succeeded"
+        },
+        {
+            "from": "STANDBY_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "disable_failed"
+        },
+        {
+            "from": "STANDBY_MAINTENANCE",
+            "to": "STANDBY_MAINTENANCE",
+            "trigger": "standby_succeeded"
+        },
+        {
+            "from": "STANDBY_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "standby_failed"
+        },
+        {
+            "from": "STANDBY_MAINTENANCE",
+            "to": "OFF_MAINTENANCE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "STANDBY_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "STANDBY_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "STANDBY_ONLINE",
+            "to": "DISABLE_ONLINE",
+            "trigger": "disable_succeeded"
+        },
+        {
+            "from": "STANDBY_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "disable_failed"
+        },
+        {
+            "from": "STANDBY_ONLINE",
+            "to": "STANDBY_ONLINE",
+            "trigger": "standby_succeeded"
+        },
+        {
+            "from": "STANDBY_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "standby_failed"
+        },
+        {
+            "from": "STANDBY_ONLINE",
+            "to": "OFF_ONLINE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "STANDBY_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "STANDBY_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "OFF_MAINTENANCE",
+            "to": "DISABLE_MAINTENANCE",
+            "trigger": "disable_succeeded"
+        },
+        {
+            "from": "OFF_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "disable_failed"
+        },
+        {
+            "from": "OFF_MAINTENANCE",
+            "to": "STANDBY_MAINTENANCE",
+            "trigger": "standby_succeeded"
+        },
+        {
+            "from": "OFF_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "standby_failed"
+        },
+        {
+            "from": "OFF_MAINTENANCE",
+            "to": "OFF_MAINTENANCE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "OFF_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "OFF_MAINTENANCE",
+            "to": "ON_MAINTENANCE",
+            "trigger": "on_succeeded"
+        },
+        {
+            "from": "OFF_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "on_failed"
+        },
+        {
+            "from": "OFF_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "OFF_ONLINE",
+            "to": "DISABLE_ONLINE",
+            "trigger": "disable_succeeded"
+        },
+        {
+            "from": "OFF_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "disable_failed"
+        },
+        {
+            "from": "OFF_ONLINE",
+            "to": "STANDBY_ONLINE",
+            "trigger": "standby_succeeded"
+        },
+        {
+            "from": "OFF_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "standby_failed"
+        },
+        {
+            "from": "OFF_ONLINE",
+            "to": "OFF_ONLINE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "OFF_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "OFF_ONLINE",
+            "to": "ON_ONLINE",
+            "trigger": "on_succeeded"
+        },
+        {
+            "from": "OFF_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "on_failed"
+        },
+        {
+            "from": "OFF_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "ON_MAINTENANCE",
+            "to": "OFF_MAINTENANCE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "ON_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "ON_MAINTENANCE",
+            "to": "ON_MAINTENANCE",
+            "trigger": "on_succeeded"
+        },
+        {
+            "from": "ON_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "on_failed"
+        },
+        {
+            "from": "ON_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "ON_ONLINE",
+            "to": "OFF_ONLINE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "ON_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "ON_ONLINE",
+            "to": "ON_ONLINE",
+            "trigger": "on_succeeded"
+        },
+        {
+            "from": "ON_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "on_failed"
+        },
+        {
+            "from": "ON_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "fatal_error"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/tests/data/observation_state_machine.json b/tests/data/observation_state_machine.json
index 8aa6c51d39dc432157a142cba0b1191b645064b4..5315193a1a9bf9e96024cc78b683cfb7c94c33fd 100644
--- a/tests/data/observation_state_machine.json
+++ b/tests/data/observation_state_machine.json
@@ -1,217 +1,232 @@
-[
-    [
-        "EMPTY",
-        "assign_started",
-        "RESOURCING"
-    ],
-    [
-        "EMPTY",
-        "fatal_error",
-        "FAULT"
-    ],
-    [
-        "RESOURCING",
-        "resourcing_succeeded_some_resources",
-        "IDLE"
-    ],
-    [
-        "RESOURCING",
-        "resourcing_succeeded_no_resources",
-        "EMPTY"
-    ],
-    [
-        "RESOURCING",
-        "resourcing_failed",
-        "FAULT"
-    ],
-    [
-        "RESOURCING",
-        "fatal_error",
-        "FAULT"
-    ],
-    [
-        "IDLE",
-        "assign_started",
-        "RESOURCING"
-    ],
-    [
-        "IDLE",
-        "release_started",
-        "RESOURCING"
-    ],
-    [
-        "IDLE",
-        "configure_started",
-        "CONFIGURING"
-    ],
-    [
-        "IDLE",
-        "abort_started",
-        "ABORTING"
-    ],
-    [
-        "IDLE",
-        "fatal_error",
-        "FAULT"
-    ],
-    [
-        "CONFIGURING",
-        "configure_succeeded",
-        "READY"
-    ],
-    [
-        "CONFIGURING",
-        "configure_failed",
-        "FAULT"
-    ],
-    [
-        "CONFIGURING",
-        "abort_started",
-        "ABORTING"
-    ],
-    [
-        "CONFIGURING",
-        "fatal_error",
-        "FAULT"
-    ],
-    [
-        "READY",
-        "end_succeeded",
-        "IDLE"
-    ],
-    [
-        "READY",
-        "end_failed",
-        "FAULT"
-    ],
-    [
-        "READY",
-        "configure_started",
-        "CONFIGURING"
-    ],
-    [
-        "READY",
-        "abort_started",
-        "ABORTING"
-    ],
-    [
-        "READY",
-        "scan_started",
-        "SCANNING"
-    ],
-    [
-        "READY",
-        "fatal_error",
-        "FAULT"
-    ],
-    [
-        "SCANNING",
-        "scan_succeeded",
-        "READY"
-    ],
-    [
-        "SCANNING",
-        "scan_failed",
-        "FAULT"
-    ],
-    [
-        "SCANNING",
-        "end_scan_succeeded",
-        "READY"
-    ],
-    [
-        "SCANNING",
-        "end_scan_failed",
-        "FAULT"
-    ],
-    [
-        "SCANNING",
-        "abort_started",
-        "ABORTING"
-    ],
-    [
-        "SCANNING",
-        "fatal_error",
-        "FAULT"
-    ],
-    [
-        "ABORTING",
-        "abort_succeeded",
-        "ABORTED"
-    ],
-    [
-        "ABORTING",
-        "abort_failed",
-        "FAULT"
-    ],
-    [
-        "ABORTING",
-        "fatal_error",
-        "FAULT"
-    ],
-    [
-        "ABORTED",
-        "obs_reset_started",
-        "RESETTING"
-    ],
-    [
-        "ABORTED",
-        "restart_started",
-        "RESTARTING"
-    ],
-    [
-        "ABORTED",
-        "fatal_error",
-        "FAULT"
-    ],
-    [
-        "FAULT",
-        "obs_reset_started",
-        "RESETTING"
-    ],
-    [
-        "FAULT",
-        "restart_started",
-        "RESTARTING"
-    ],
-    [
-        "FAULT",
-        "fatal_error",
-        "FAULT"
-    ],
-    [
-        "RESETTING",
-        "obs_reset_succeeded",
-        "IDLE"
-    ],
-    [
-        "RESETTING",
-        "obs_reset_failed",
-        "FAULT"
-    ],
-    [
-        "RESETTING",
-        "abort_started",
-        "ABORTING"
-    ],
-    [
-        "RESETTING",
-        "fatal_error",
-        "FAULT"
-    ],
-    [
-        "RESTARTING",
-        "restart_succeeded",
-        "EMPTY"
-    ],
-    [
-        "RESTARTING",
-        "restart_failed",
-        "FAULT"
-    ],
-    [
-        "RESTARTING",
-        "fatal_error",
-        "FAULT"
+{
+    "states": {
+        "EMPTY": {},
+        "RESOURCING": {},
+        "FAULT": {},
+        "IDLE": {},
+        "CONFIGURING": {},
+        "ABORTING": {},
+        "READY": {},
+        "SCANNING": {},
+        "ABORTED": {},
+        "RESETTING": {},
+        "RESTARTING": {}
+    },
+    "transitions": [
+        {
+            "from": "EMPTY",
+            "to": "RESOURCING",
+            "trigger": "assign_started"
+        },
+        {
+            "from": "EMPTY",
+            "to": "FAULT",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "RESOURCING",
+            "to": "IDLE",
+            "trigger": "resourcing_succeeded_some_resources"
+        },
+        {
+            "from": "RESOURCING",
+            "to": "EMPTY",
+            "trigger": "resourcing_succeeded_no_resources"
+        },
+        {
+            "from": "RESOURCING",
+            "to": "FAULT",
+            "trigger": "resourcing_failed"
+        },
+        {
+            "from": "RESOURCING",
+            "to": "FAULT",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "IDLE",
+            "to": "RESOURCING",
+            "trigger": "assign_started"
+        },
+        {
+            "from": "IDLE",
+            "to": "RESOURCING",
+            "trigger": "release_started"
+        },
+        {
+            "from": "IDLE",
+            "to": "CONFIGURING",
+            "trigger": "configure_started"
+        },
+        {
+            "from": "IDLE",
+            "to": "ABORTING",
+            "trigger": "abort_started"
+        },
+        {
+            "from": "IDLE",
+            "to": "FAULT",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "CONFIGURING",
+            "to": "READY",
+            "trigger": "configure_succeeded"
+        },
+        {
+            "from": "CONFIGURING",
+            "to": "FAULT",
+            "trigger": "configure_failed"
+        },
+        {
+            "from": "CONFIGURING",
+            "to": "ABORTING",
+            "trigger": "abort_started"
+        },
+        {
+            "from": "CONFIGURING",
+            "to": "FAULT",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "READY",
+            "to": "IDLE",
+            "trigger": "end_succeeded"
+        },
+        {
+            "from": "READY",
+            "to": "FAULT",
+            "trigger": "end_failed"
+        },
+        {
+            "from": "READY",
+            "to": "CONFIGURING",
+            "trigger": "configure_started"
+        },
+        {
+            "from": "READY",
+            "to": "ABORTING",
+            "trigger": "abort_started"
+        },
+        {
+            "from": "READY",
+            "to": "SCANNING",
+            "trigger": "scan_started"
+        },
+        {
+            "from": "READY",
+            "to": "FAULT",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "SCANNING",
+            "to": "READY",
+            "trigger": "scan_succeeded"
+        },
+        {
+            "from": "SCANNING",
+            "to": "FAULT",
+            "trigger": "scan_failed"
+        },
+        {
+            "from": "SCANNING",
+            "to": "READY",
+            "trigger": "end_scan_succeeded"
+        },
+        {
+            "from": "SCANNING",
+            "to": "FAULT",
+            "trigger": "end_scan_failed"
+        },
+        {
+            "from": "SCANNING",
+            "to": "ABORTING",
+            "trigger": "abort_started"
+        },
+        {
+            "from": "SCANNING",
+            "to": "FAULT",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "ABORTING",
+            "to": "ABORTED",
+            "trigger": "abort_succeeded"
+        },
+        {
+            "from": "ABORTING",
+            "to": "FAULT",
+            "trigger": "abort_failed"
+        },
+        {
+            "from": "ABORTING",
+            "to": "FAULT",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "ABORTED",
+            "to": "RESETTING",
+            "trigger": "reset_started"
+        },
+        {
+            "from": "ABORTED",
+            "to": "RESTARTING",
+            "trigger": "restart_started"
+        },
+        {
+            "from": "ABORTED",
+            "to": "FAULT",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "FAULT",
+            "to": "RESETTING",
+            "trigger": "reset_started"
+        },
+        {
+            "from": "FAULT",
+            "to": "RESTARTING",
+            "trigger": "restart_started"
+        },
+        {
+            "from": "FAULT",
+            "to": "FAULT",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "RESETTING",
+            "to": "IDLE",
+            "trigger": "reset_succeeded"
+        },
+        {
+            "from": "RESETTING",
+            "to": "FAULT",
+            "trigger": "reset_failed"
+        },
+        {
+            "from": "RESETTING",
+            "to": "ABORTING",
+            "trigger": "abort_started"
+        },
+        {
+            "from": "RESETTING",
+            "to": "FAULT",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "RESTARTING",
+            "to": "EMPTY",
+            "trigger": "restart_succeeded"
+        },
+        {
+            "from": "RESTARTING",
+            "to": "FAULT",
+            "trigger": "restart_failed"
+        },
+        {
+            "from": "RESTARTING",
+            "to": "FAULT",
+            "trigger": "fatal_error"
+        }
     ]
-]
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/tests/data/operation_state_machine.json b/tests/data/operation_state_machine.json
new file mode 100644
index 0000000000000000000000000000000000000000..86774be77bf13c6c47e4ba4deb90401316c4d207
--- /dev/null
+++ b/tests/data/operation_state_machine.json
@@ -0,0 +1,316 @@
+{
+    "states": {
+        "UNINITIALISED": {},
+        "INIT": {},
+        "DISABLE": {},
+        "INIT_ADMIN": {},
+        "DISABLE_ADMIN": {},
+        "STANDBY": {},
+        "OFF": {},
+        "FAULT": {},
+        "FAULT_ADMIN": {},
+        "ON": {}
+    },
+    "transitions": [
+        {
+            "from": "UNINITIALISED",
+            "to": "INIT",
+            "trigger": "init_started"
+        },
+        {
+            "from": "INIT",
+            "to": "DISABLE",
+            "trigger": "init_succeeded_disable"
+        },
+        {
+            "from": "INIT_ADMIN",
+            "to": "DISABLE_ADMIN",
+            "trigger": "init_succeeded_disable"
+        },
+        {
+            "from": "INIT",
+            "to": "STANDBY",
+            "trigger": "init_succeeded_standby"
+        },
+        {
+            "from": "INIT",
+            "to": "OFF",
+            "trigger": "init_succeeded_off"
+        },
+        {
+            "from": "INIT",
+            "to": "FAULT",
+            "trigger": "init_failed"
+        },
+        {
+            "from": "INIT_ADMIN",
+            "to": "FAULT_ADMIN",
+            "trigger": "init_failed"
+        },
+        {
+            "from": "INIT",
+            "to": "FAULT",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "INIT",
+            "to": "INIT_ADMIN",
+            "trigger": "admin_on"
+        },
+        {
+            "from": "INIT",
+            "to": "INIT",
+            "trigger": "admin_off"
+        },
+        {
+            "from": "INIT_ADMIN",
+            "to": "INIT_ADMIN",
+            "trigger": "admin_on"
+        },
+        {
+            "from": "INIT_ADMIN",
+            "to": "INIT",
+            "trigger": "admin_off"
+        },
+        {
+            "from": "INIT_ADMIN",
+            "to": "FAULT_ADMIN",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "FAULT",
+            "to": "DISABLE",
+            "trigger": "reset_succeeded_disable"
+        },
+        {
+            "from": "FAULT_ADMIN",
+            "to": "DISABLE_ADMIN",
+            "trigger": "reset_succeeded_disable"
+        },
+        {
+            "from": "FAULT",
+            "to": "STANDBY",
+            "trigger": "reset_succeeded_standby"
+        },
+        {
+            "from": "FAULT",
+            "to": "OFF",
+            "trigger": "reset_succeeded_off"
+        },
+        {
+            "from": "FAULT",
+            "to": "FAULT",
+            "trigger": "reset_failed"
+        },
+        {
+            "from": "FAULT_ADMIN",
+            "to": "FAULT_ADMIN",
+            "trigger": "reset_failed"
+        },
+        {
+            "from": "FAULT",
+            "to": "FAULT",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "FAULT_ADMIN",
+            "to": "FAULT_ADMIN",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "FAULT",
+            "to": "FAULT_ADMIN",
+            "trigger": "admin_on"
+        },
+        {
+            "from": "FAULT",
+            "to": "FAULT",
+            "trigger": "admin_off"
+        },
+        {
+            "from": "FAULT_ADMIN",
+            "to": "FAULT_ADMIN",
+            "trigger": "admin_on"
+        },
+        {
+            "from": "FAULT_ADMIN",
+            "to": "FAULT",
+            "trigger": "admin_off"
+        },
+        {
+            "from": "DISABLE",
+            "to": "DISABLE",
+            "trigger": "disable_succeeded"
+        },
+        {
+            "from": "DISABLE",
+            "to": "FAULT",
+            "trigger": "disable_failed"
+        },
+        {
+            "from": "DISABLE",
+            "to": "STANDBY",
+            "trigger": "standby_succeeded"
+        },
+        {
+            "from": "DISABLE",
+            "to": "FAULT",
+            "trigger": "standby_failed"
+        },
+        {
+            "from": "DISABLE",
+            "to": "OFF",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "DISABLE",
+            "to": "FAULT",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "DISABLE",
+            "to": "FAULT",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "DISABLE_ADMIN",
+            "to": "FAULT_ADMIN",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "DISABLE",
+            "to": "DISABLE_ADMIN",
+            "trigger": "admin_on"
+        },
+        {
+            "from": "DISABLE",
+            "to": "DISABLE",
+            "trigger": "admin_off"
+        },
+        {
+            "from": "DISABLE_ADMIN",
+            "to": "DISABLE_ADMIN",
+            "trigger": "admin_on"
+        },
+        {
+            "from": "DISABLE_ADMIN",
+            "to": "DISABLE",
+            "trigger": "admin_off"
+        },
+        {
+            "from": "DISABLE_ADMIN",
+            "to": "DISABLE_ADMIN",
+            "trigger": "disable_succeeded"
+        },
+        {
+            "from": "DISABLE_ADMIN",
+            "to": "FAULT_ADMIN",
+            "trigger": "disable_failed"
+        },
+        {
+            "from": "STANDBY",
+            "to": "DISABLE",
+            "trigger": "disable_succeeded"
+        },
+        {
+            "from": "STANDBY",
+            "to": "FAULT",
+            "trigger": "disable_failed"
+        },
+        {
+            "from": "STANDBY",
+            "to": "STANDBY",
+            "trigger": "standby_succeeded"
+        },
+        {
+            "from": "STANDBY",
+            "to": "FAULT",
+            "trigger": "standby_failed"
+        },
+        {
+            "from": "STANDBY",
+            "to": "OFF",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "STANDBY",
+            "to": "FAULT",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "STANDBY",
+            "to": "FAULT",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "OFF",
+            "to": "DISABLE",
+            "trigger": "disable_succeeded"
+        },
+        {
+            "from": "OFF",
+            "to": "FAULT",
+            "trigger": "disable_failed"
+        },
+        {
+            "from": "OFF",
+            "to": "STANDBY",
+            "trigger": "standby_succeeded"
+        },
+        {
+            "from": "OFF",
+            "to": "FAULT",
+            "trigger": "standby_failed"
+        },
+        {
+            "from": "OFF",
+            "to": "OFF",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "OFF",
+            "to": "FAULT",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "OFF",
+            "to": "ON",
+            "trigger": "on_succeeded"
+        },
+        {
+            "from": "OFF",
+            "to": "FAULT",
+            "trigger": "on_failed"
+        },
+        {
+            "from": "OFF",
+            "to": "FAULT",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "ON",
+            "to": "OFF",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "ON",
+            "to": "FAULT",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "ON",
+            "to": "ON",
+            "trigger": "on_succeeded"
+        },
+        {
+            "from": "ON",
+            "to": "FAULT",
+            "trigger": "on_failed"
+        },
+        {
+            "from": "ON",
+            "to": "FAULT",
+            "trigger": "fatal_error"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/tests/data/subarray_state_machine.json b/tests/data/subarray_state_machine.json
index 807358c8280494602ba7c2d28ccd17c90de2f1f6..57e33c3fee357176780044d46c487cfd3f7202a9 100644
--- a/tests/data/subarray_state_machine.json
+++ b/tests/data/subarray_state_machine.json
@@ -1,532 +1,1801 @@
-[
-    [
-        "UNINITIALISED",
-        "init_started",
-        "INIT_ENABLED"
-    ],
-    [
-        "INIT_ENABLED",
-        "to_notfitted",
-        "INIT_DISABLED"
-    ],
-    [
-        "INIT_ENABLED",
-        "to_offline",
-        "INIT_DISABLED"
-    ],
-    [
-        "INIT_ENABLED",
-        "to_online",
-        "INIT_ENABLED"
-    ],
-    [
-        "INIT_ENABLED",
-        "to_maintenance",
-        "INIT_ENABLED"
-    ],
-    [
-        "INIT_ENABLED",
-        "init_succeeded",
-        "OFF"
-    ],
-    [
-        "INIT_ENABLED",
-        "init_failed",
-        "FAULT_ENABLED"
-    ],
-    [
-        "INIT_ENABLED",
-        "fatal_error",
-        "FAULT_ENABLED"
-    ],
-    [
-        "INIT_DISABLED",
-        "to_notfitted",
-        "INIT_DISABLED"
-    ],
-    [
-        "INIT_DISABLED",
-        "to_offline",
-        "INIT_DISABLED"
-    ],
-    [
-        "INIT_DISABLED",
-        "to_online",
-        "INIT_ENABLED"
-    ],
-    [
-        "INIT_DISABLED",
-        "to_maintenance",
-        "INIT_ENABLED"
-    ],
-    [
-        "INIT_DISABLED",
-        "init_succeeded",
-        "DISABLED"
-    ],
-    [
-        "INIT_DISABLED",
-        "init_failed",
-        "FAULT_DISABLED"
-    ],
-    [
-        "INIT_DISABLED",
-        "fatal_error",
-        "FAULT_DISABLED"
-    ],
-    [
-        "FAULT_DISABLED",
-        "to_notfitted",
-        "FAULT_DISABLED"
-    ],
-    [
-        "FAULT_DISABLED",
-        "to_offline",
-        "FAULT_DISABLED"
-    ],
-    [
-        "FAULT_DISABLED",
-        "to_online",
-        "FAULT_ENABLED"
-    ],
-    [
-        "FAULT_DISABLED",
-        "to_maintenance",
-        "FAULT_ENABLED"
-    ],
-    [
-        "FAULT_DISABLED",
-        "reset_succeeded",
-        "DISABLED"
-    ],
-    [
-        "FAULT_DISABLED",
-        "reset_failed",
-        "FAULT_DISABLED"
-    ],
-    [
-        "FAULT_DISABLED",
-        "fatal_error",
-        "FAULT_DISABLED"
-    ],
-    [
-        "FAULT_ENABLED",
-        "to_notfitted",
-        "FAULT_DISABLED"
-    ],
-    [
-        "FAULT_ENABLED",
-        "to_offline",
-        "FAULT_DISABLED"
-    ],
-    [
-        "FAULT_ENABLED",
-        "to_online",
-        "FAULT_ENABLED"
-    ],
-    [
-        "FAULT_ENABLED",
-        "to_maintenance",
-        "FAULT_ENABLED"
-    ],
-    [
-        "FAULT_ENABLED",
-        "reset_succeeded",
-        "OFF"
-    ],
-    [
-        "FAULT_ENABLED",
-        "reset_failed",
-        "FAULT_ENABLED"
-    ],
-    [
-        "FAULT_ENABLED",
-        "fatal_error",
-        "FAULT_ENABLED"
-    ],
-    [
-        "DISABLED",
-        "to_notfitted",
-        "DISABLED"
-    ],
-    [
-        "DISABLED",
-        "to_offline",
-        "DISABLED"
-    ],
-    [
-        "DISABLED",
-        "to_online",
-        "OFF"
-    ],
-    [
-        "DISABLED",
-        "to_maintenance",
-        "OFF"
-    ],
-    [
-        "DISABLED",
-        "fatal_error",
-        "FAULT_DISABLED"
-    ],
-    [
-        "OFF",
-        "to_notfitted",
-        "DISABLED"
-    ],
-    [
-        "OFF",
-        "to_offline",
-        "DISABLED"
-    ],
-    [
-        "OFF",
-        "to_online",
-        "OFF"
-    ],
-    [
-        "OFF",
-        "to_maintenance",
-        "OFF"
-    ],
-    [
-        "OFF",
-        "on_succeeded",
-        "EMPTY"
-    ],
-    [
-        "OFF",
-        "on_failed",
-        "FAULT_ENABLED"
-    ],
-    [
-        "OFF",
-        "fatal_error",
-        "FAULT_ENABLED"
-    ],
-    [
-        "EMPTY",
-        "off_succeeded",
-        "OFF"
-    ],
-    [
-        "EMPTY",
-        "off_failed",
-        "FAULT_ENABLED"
-    ],
-    [
-        "EMPTY",
-        "assign_started",
-        "RESOURCING"
-    ],
-    [
-        "EMPTY",
-        "fatal_error",
-        "FAULT"
-    ],
-    [
-        "RESOURCING",
-        "off_succeeded",
-        "OFF"
-    ],
-    [
-        "RESOURCING",
-        "off_failed",
-        "FAULT_ENABLED"
-    ],
-    [
-        "RESOURCING",
-        "resourcing_succeeded_some_resources",
-        "IDLE"
-    ],
-    [
-        "RESOURCING",
-        "resourcing_succeeded_no_resources",
-        "EMPTY"
-    ],
-    [
-        "RESOURCING",
-        "resourcing_failed",
-        "FAULT"
-    ],
-    [
-        "RESOURCING",
-        "fatal_error",
-        "FAULT"
-    ],
-    [
-        "IDLE",
-        "off_succeeded",
-        "OFF"
-    ],
-    [
-        "IDLE",
-        "off_failed",
-        "FAULT_ENABLED"
-    ],
-    [
-        "IDLE",
-        "assign_started",
-        "RESOURCING"
-    ],
-    [
-        "IDLE",
-        "release_started",
-        "RESOURCING"
-    ],
-    [
-        "IDLE",
-        "configure_started",
-        "CONFIGURING"
-    ],
-    [
-        "IDLE",
-        "abort_started",
-        "ABORTING"
-    ],
-    [
-        "IDLE",
-        "fatal_error",
-        "FAULT"
-    ],
-    [
-        "CONFIGURING",
-        "off_succeeded",
-        "OFF"
-    ],
-    [
-        "CONFIGURING",
-        "off_failed",
-        "FAULT_ENABLED"
-    ],
-    [
-        "CONFIGURING",
-        "configure_succeeded",
-        "READY"
-    ],
-    [
-        "CONFIGURING",
-        "configure_failed",
-        "FAULT"
-    ],
-    [
-        "CONFIGURING",
-        "abort_started",
-        "ABORTING"
-    ],
-    [
-        "CONFIGURING",
-        "fatal_error",
-        "FAULT"
-    ],
-    [
-        "READY",
-        "off_succeeded",
-        "OFF"
-    ],
-    [
-        "READY",
-        "off_failed",
-        "FAULT_ENABLED"
-    ],
-    [
-        "READY",
-        "end_succeeded",
-        "IDLE"
-    ],
-    [
-        "READY",
-        "end_failed",
-        "FAULT"
-    ],
-    [
-        "READY",
-        "configure_started",
-        "CONFIGURING"
-    ],
-    [
-        "READY",
-        "abort_started",
-        "ABORTING"
-    ],
-    [
-        "READY",
-        "scan_started",
-        "SCANNING"
-    ],
-    [
-        "READY",
-        "fatal_error",
-        "FAULT"
-    ],
-    [
-        "SCANNING",
-        "off_succeeded",
-        "OFF"
-    ],
-    [
-        "SCANNING",
-        "off_failed",
-        "FAULT_ENABLED"
-    ],
-    [
-        "SCANNING",
-        "scan_succeeded",
-        "READY"
-    ],
-    [
-        "SCANNING",
-        "scan_failed",
-        "FAULT"
-    ],
-    [
-        "SCANNING",
-        "end_scan_succeeded",
-        "READY"
-    ],
-    [
-        "SCANNING",
-        "end_scan_failed",
-        "FAULT"
-    ],
-    [
-        "SCANNING",
-        "abort_started",
-        "ABORTING"
-    ],
-    [
-        "SCANNING",
-        "fatal_error",
-        "FAULT"
-    ],
-    [
-        "ABORTING",
-        "off_succeeded",
-        "OFF"
-    ],
-    [
-        "ABORTING",
-        "off_failed",
-        "FAULT_ENABLED"
-    ],
-    [
-        "ABORTING",
-        "abort_succeeded",
-        "ABORTED"
-    ],
-    [
-        "ABORTING",
-        "abort_failed",
-        "FAULT"
-    ],
-    [
-        "ABORTING",
-        "fatal_error",
-        "FAULT"
-    ],
-    [
-        "ABORTED",
-        "off_succeeded",
-        "OFF"
-    ],
-    [
-        "ABORTED",
-        "off_failed",
-        "FAULT_ENABLED"
-    ],
-    [
-        "ABORTED",
-        "obs_reset_started",
-        "RESETTING"
-    ],
-    [
-        "ABORTED",
-        "restart_started",
-        "RESTARTING"
-    ],
-    [
-        "ABORTED",
-        "fatal_error",
-        "FAULT"
-    ],
-    [
-        "FAULT",
-        "off_succeeded",
-        "OFF"
-    ],
-    [
-        "FAULT",
-        "off_failed",
-        "FAULT_ENABLED"
-    ],
-    [
-        "FAULT",
-        "obs_reset_started",
-        "RESETTING"
-    ],
-    [
-        "FAULT",
-        "restart_started",
-        "RESTARTING"
-    ],
-    [
-        "FAULT",
-        "fatal_error",
-        "FAULT"
-    ],
-    [
-        "RESETTING",
-        "off_succeeded",
-        "OFF"
-    ],
-    [
-        "RESETTING",
-        "off_failed",
-        "FAULT_ENABLED"
-    ],
-    [
-        "RESETTING",
-        "obs_reset_succeeded",
-        "IDLE"
-    ],
-    [
-        "RESETTING",
-        "obs_reset_failed",
-        "FAULT"
-    ],
-    [
-        "RESETTING",
-        "abort_started",
-        "ABORTING"
-    ],
-    [
-        "RESETTING",
-        "fatal_error",
-        "FAULT"
-    ],
-    [
-        "RESTARTING",
-        "off_succeeded",
-        "OFF"
-    ],
-    [
-        "RESTARTING",
-        "off_failed",
-        "FAULT_ENABLED"
-    ],
-    [
-        "RESTARTING",
-        "restart_succeeded",
-        "EMPTY"
-    ],
-    [
-        "RESTARTING",
-        "restart_failed",
-        "FAULT"
-    ],
-    [
-        "RESTARTING",
-        "fatal_error",
-        "FAULT"
+{
+    "states": {
+        "INIT_MAINTENANCE": {
+            "admin_mode": "MAINTENANCE",
+            "op_state": "INIT",
+            "obs_state": "EMPTY"
+        },
+        "INIT_ONLINE": {
+            "admin_mode": "ONLINE",
+            "op_state": "INIT",
+            "obs_state": "EMPTY"
+        },
+        "INIT_OFFLINE": {
+            "admin_mode": "OFFLINE",
+            "op_state": "INIT",
+            "obs_state": "EMPTY"
+        },
+        "INIT_NOTFITTED": {
+            "admin_mode": "NOT_FITTED",
+            "op_state": "INIT",
+            "obs_state": "EMPTY"
+        },
+        "INIT_RESERVED": {
+            "admin_mode": "RESERVED",
+            "op_state": "INIT",
+            "obs_state": "EMPTY"
+        },
+        "FAULT_MAINTENANCE": {
+            "admin_mode": "MAINTENANCE",
+            "op_state": "FAULT",
+            "obs_state": "EMPTY"
+        },
+        "FAULT_ONLINE": {
+            "admin_mode": "ONLINE",
+            "op_state": "FAULT",
+            "obs_state": "EMPTY"
+        },
+        "FAULT_OFFLINE": {
+            "admin_mode": "OFFLINE",
+            "op_state": "FAULT",
+            "obs_state": "EMPTY"
+        },
+        "FAULT_NOTFITTED": {
+            "admin_mode": "NOT_FITTED",
+            "op_state": "FAULT",
+            "obs_state": "EMPTY"
+        },
+        "FAULT_RESERVED": {
+            "admin_mode": "RESERVED",
+            "op_state": "FAULT",
+            "obs_state": "EMPTY"
+        },
+        "DISABLE_MAINTENANCE": {
+            "admin_mode": "MAINTENANCE",
+            "op_state": "DISABLE",
+            "obs_state": "EMPTY"
+        },
+        "DISABLE_ONLINE": {
+            "admin_mode": "ONLINE",
+            "op_state": "DISABLE",
+            "obs_state": "EMPTY"
+        },
+        "DISABLE_OFFLINE": {
+            "admin_mode": "OFFLINE",
+            "op_state": "DISABLE",
+            "obs_state": "EMPTY"
+        },
+        "DISABLE_NOTFITTED": {
+            "admin_mode": "NOT_FITTED",
+            "op_state": "DISABLE",
+            "obs_state": "EMPTY"
+        },
+        "DISABLE_RESERVED": {
+            "admin_mode": "RESERVED",
+            "op_state": "DISABLE",
+            "obs_state": "EMPTY"
+        },
+        "STANDBY_MAINTENANCE": {
+            "admin_mode": "MAINTENANCE",
+            "op_state": "STANDBY",
+            "obs_state": "EMPTY"
+        },
+        "STANDBY_ONLINE": {
+            "admin_mode": "ONLINE",
+            "op_state": "STANDBY",
+            "obs_state": "EMPTY"
+        },
+        "OFF_MAINTENANCE": {
+            "admin_mode": "MAINTENANCE",
+            "op_state": "OFF",
+            "obs_state": "EMPTY"
+        },
+        "OFF_ONLINE": {
+            "admin_mode": "ONLINE",
+            "op_state": "OFF",
+            "obs_state": "EMPTY"
+        },
+        "EMPTY_MAINTENANCE": {
+            "admin_mode": "MAINTENANCE",
+            "op_state": "ON",
+            "obs_state": "EMPTY"
+        },
+        "EMPTY_ONLINE": {
+            "admin_mode": "ONLINE",
+            "op_state": "ON",
+            "obs_state": "EMPTY"
+        },
+        "RESOURCING_MAINTENANCE": {
+            "admin_mode": "MAINTENANCE",
+            "op_state": "ON",
+            "obs_state": "RESOURCING"
+        },
+        "RESOURCING_ONLINE": {
+            "admin_mode": "ONLINE",
+            "op_state": "ON",
+            "obs_state": "RESOURCING"
+        },
+        "IDLE_MAINTENANCE": {
+            "admin_mode": "MAINTENANCE",
+            "op_state": "ON",
+            "obs_state": "IDLE"
+        },
+        "IDLE_ONLINE": {
+            "admin_mode": "ONLINE",
+            "op_state": "ON",
+            "obs_state": "IDLE"
+        },
+        "CONFIGURING_MAINTENANCE": {
+            "admin_mode": "MAINTENANCE",
+            "op_state": "ON",
+            "obs_state": "CONFIGURING"
+        },
+        "CONFIGURING_ONLINE": {
+            "admin_mode": "ONLINE",
+            "op_state": "ON",
+            "obs_state": "CONFIGURING"
+        },
+        "READY_MAINTENANCE": {
+            "admin_mode": "MAINTENANCE",
+            "op_state": "ON",
+            "obs_state": "READY"
+        },
+        "READY_ONLINE": {
+            "admin_mode": "ONLINE",
+            "op_state": "ON",
+            "obs_state": "READY"
+        },
+        "SCANNING_MAINTENANCE": {
+            "admin_mode": "MAINTENANCE",
+            "op_state": "ON",
+            "obs_state": "SCANNING"
+        },
+        "SCANNING_ONLINE": {
+            "admin_mode": "ONLINE",
+            "op_state": "ON",
+            "obs_state": "SCANNING"
+        },
+        "ABORTING_MAINTENANCE": {
+            "admin_mode": "MAINTENANCE",
+            "op_state": "ON",
+            "obs_state": "ABORTING"
+        },
+        "ABORTING_ONLINE": {
+            "admin_mode": "ONLINE",
+            "op_state": "ON",
+            "obs_state": "ABORTING"
+        },
+        "ABORTED_MAINTENANCE": {
+            "admin_mode": "MAINTENANCE",
+            "op_state": "ON",
+            "obs_state": "ABORTED"
+        },
+        "ABORTED_ONLINE": {
+            "admin_mode": "ONLINE",
+            "op_state": "ON",
+            "obs_state": "ABORTED"
+        },
+        "OBSFAULT_MAINTENANCE": {
+            "admin_mode": "MAINTENANCE",
+            "op_state": "ON",
+            "obs_state": "FAULT"
+        },
+        "OBSFAULT_ONLINE": {
+            "admin_mode": "ONLINE",
+            "op_state": "ON",
+            "obs_state": "FAULT"
+        },
+        "RESETTING_MAINTENANCE": {
+            "admin_mode": "MAINTENANCE",
+            "op_state": "ON",
+            "obs_state": "RESETTING"
+        },
+        "RESETTING_ONLINE": {
+            "admin_mode": "ONLINE",
+            "op_state": "ON",
+            "obs_state": "RESETTING"
+        },
+        "RESTARTING_MAINTENANCE": {
+            "admin_mode": "MAINTENANCE",
+            "op_state": "ON",
+            "obs_state": "RESTARTING"
+        },
+        "RESTARTING_ONLINE": {
+            "admin_mode": "ONLINE",
+            "op_state": "ON",
+            "obs_state": "RESTARTING"
+        }
+    },
+    "transitions": [
+        {
+            "from": "INIT_MAINTENANCE",
+            "to": "INIT_OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "INIT_MAINTENANCE",
+            "to": "INIT_MAINTENANCE",
+            "trigger": "to_maintenance"
+        },
+        {
+            "from": "INIT_MAINTENANCE",
+            "to": "INIT_ONLINE",
+            "trigger": "to_online"
+        },
+        {
+            "from": "INIT_MAINTENANCE",
+            "to": "DISABLE_MAINTENANCE",
+            "trigger": "init_succeeded_disable"
+        },
+        {
+            "from": "INIT_MAINTENANCE",
+            "to": "STANDBY_MAINTENANCE",
+            "trigger": "init_succeeded_standby"
+        },
+        {
+            "from": "INIT_MAINTENANCE",
+            "to": "OFF_MAINTENANCE",
+            "trigger": "init_succeeded_off"
+        },
+        {
+            "from": "INIT_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "init_failed"
+        },
+        {
+            "from": "INIT_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "INIT_ONLINE",
+            "to": "INIT_MAINTENANCE",
+            "trigger": "to_maintenance"
+        },
+        {
+            "from": "INIT_ONLINE",
+            "to": "INIT_ONLINE",
+            "trigger": "to_online"
+        },
+        {
+            "from": "INIT_ONLINE",
+            "to": "INIT_OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "INIT_ONLINE",
+            "to": "DISABLE_ONLINE",
+            "trigger": "init_succeeded_disable"
+        },
+        {
+            "from": "INIT_ONLINE",
+            "to": "STANDBY_ONLINE",
+            "trigger": "init_succeeded_standby"
+        },
+        {
+            "from": "INIT_ONLINE",
+            "to": "OFF_ONLINE",
+            "trigger": "init_succeeded_off"
+        },
+        {
+            "from": "INIT_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "init_failed"
+        },
+        {
+            "from": "INIT_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "INIT_OFFLINE",
+            "to": "INIT_ONLINE",
+            "trigger": "to_online"
+        },
+        {
+            "from": "INIT_OFFLINE",
+            "to": "INIT_MAINTENANCE",
+            "trigger": "to_maintenance"
+        },
+        {
+            "from": "INIT_OFFLINE",
+            "to": "INIT_OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "INIT_OFFLINE",
+            "to": "INIT_RESERVED",
+            "trigger": "to_reserved"
+        },
+        {
+            "from": "INIT_OFFLINE",
+            "to": "INIT_NOTFITTED",
+            "trigger": "to_notfitted"
+        },
+        {
+            "from": "INIT_OFFLINE",
+            "to": "DISABLE_OFFLINE",
+            "trigger": "init_succeeded_disable"
+        },
+        {
+            "from": "INIT_OFFLINE",
+            "to": "FAULT_OFFLINE",
+            "trigger": "init_failed"
+        },
+        {
+            "from": "INIT_OFFLINE",
+            "to": "FAULT_OFFLINE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "INIT_NOTFITTED",
+            "to": "INIT_OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "INIT_NOTFITTED",
+            "to": "INIT_RESERVED",
+            "trigger": "to_reserved"
+        },
+        {
+            "from": "INIT_NOTFITTED",
+            "to": "INIT_NOTFITTED",
+            "trigger": "to_notfitted"
+        },
+        {
+            "from": "INIT_NOTFITTED",
+            "to": "DISABLE_NOTFITTED",
+            "trigger": "init_succeeded_disable"
+        },
+        {
+            "from": "INIT_NOTFITTED",
+            "to": "FAULT_NOTFITTED",
+            "trigger": "init_failed"
+        },
+        {
+            "from": "INIT_NOTFITTED",
+            "to": "FAULT_NOTFITTED",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "INIT_RESERVED",
+            "to": "INIT_NOTFITTED",
+            "trigger": "to_notfitted"
+        },
+        {
+            "from": "INIT_RESERVED",
+            "to": "INIT_OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "INIT_RESERVED",
+            "to": "INIT_RESERVED",
+            "trigger": "to_reserved"
+        },
+        {
+            "from": "INIT_RESERVED",
+            "to": "DISABLE_RESERVED",
+            "trigger": "init_succeeded_disable"
+        },
+        {
+            "from": "INIT_RESERVED",
+            "to": "FAULT_RESERVED",
+            "trigger": "init_failed"
+        },
+        {
+            "from": "INIT_RESERVED",
+            "to": "FAULT_RESERVED",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "FAULT_MAINTENANCE",
+            "to": "FAULT_OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "FAULT_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "to_maintenance"
+        },
+        {
+            "from": "FAULT_MAINTENANCE",
+            "to": "FAULT_ONLINE",
+            "trigger": "to_online"
+        },
+        {
+            "from": "FAULT_MAINTENANCE",
+            "to": "DISABLE_MAINTENANCE",
+            "trigger": "reset_succeeded_disable"
+        },
+        {
+            "from": "FAULT_MAINTENANCE",
+            "to": "STANDBY_MAINTENANCE",
+            "trigger": "reset_succeeded_standby"
+        },
+        {
+            "from": "FAULT_MAINTENANCE",
+            "to": "OFF_MAINTENANCE",
+            "trigger": "reset_succeeded_off"
+        },
+        {
+            "from": "FAULT_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "reset_failed"
+        },
+        {
+            "from": "FAULT_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "FAULT_ONLINE",
+            "to": "FAULT_OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "FAULT_ONLINE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "to_maintenance"
+        },
+        {
+            "from": "FAULT_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "to_online"
+        },
+        {
+            "from": "FAULT_ONLINE",
+            "to": "DISABLE_ONLINE",
+            "trigger": "reset_succeeded_disable"
+        },
+        {
+            "from": "FAULT_ONLINE",
+            "to": "STANDBY_ONLINE",
+            "trigger": "reset_succeeded_standby"
+        },
+        {
+            "from": "FAULT_ONLINE",
+            "to": "OFF_ONLINE",
+            "trigger": "reset_succeeded_off"
+        },
+        {
+            "from": "FAULT_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "reset_failed"
+        },
+        {
+            "from": "FAULT_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "FAULT_OFFLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "to_online"
+        },
+        {
+            "from": "FAULT_OFFLINE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "to_maintenance"
+        },
+        {
+            "from": "FAULT_OFFLINE",
+            "to": "FAULT_OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "FAULT_OFFLINE",
+            "to": "FAULT_RESERVED",
+            "trigger": "to_reserved"
+        },
+        {
+            "from": "FAULT_OFFLINE",
+            "to": "FAULT_NOTFITTED",
+            "trigger": "to_notfitted"
+        },
+        {
+            "from": "FAULT_OFFLINE",
+            "to": "DISABLE_OFFLINE",
+            "trigger": "reset_succeeded_disable"
+        },
+        {
+            "from": "FAULT_OFFLINE",
+            "to": "FAULT_OFFLINE",
+            "trigger": "reset_failed"
+        },
+        {
+            "from": "FAULT_OFFLINE",
+            "to": "FAULT_OFFLINE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "FAULT_NOTFITTED",
+            "to": "FAULT_OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "FAULT_NOTFITTED",
+            "to": "FAULT_NOTFITTED",
+            "trigger": "to_notfitted"
+        },
+        {
+            "from": "FAULT_NOTFITTED",
+            "to": "FAULT_RESERVED",
+            "trigger": "to_reserved"
+        },
+        {
+            "from": "FAULT_NOTFITTED",
+            "to": "DISABLE_NOTFITTED",
+            "trigger": "reset_succeeded_disable"
+        },
+        {
+            "from": "FAULT_NOTFITTED",
+            "to": "FAULT_NOTFITTED",
+            "trigger": "reset_failed"
+        },
+        {
+            "from": "FAULT_NOTFITTED",
+            "to": "FAULT_NOTFITTED",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "FAULT_RESERVED",
+            "to": "FAULT_NOTFITTED",
+            "trigger": "to_notfitted"
+        },
+        {
+            "from": "FAULT_RESERVED",
+            "to": "FAULT_RESERVED",
+            "trigger": "to_reserved"
+        },
+        {
+            "from": "FAULT_RESERVED",
+            "to": "FAULT_OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "FAULT_RESERVED",
+            "to": "DISABLE_RESERVED",
+            "trigger": "reset_succeeded_disable"
+        },
+        {
+            "from": "FAULT_RESERVED",
+            "to": "FAULT_RESERVED",
+            "trigger": "reset_failed"
+        },
+        {
+            "from": "FAULT_RESERVED",
+            "to": "FAULT_RESERVED",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "DISABLE_MAINTENANCE",
+            "to": "DISABLE_OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "DISABLE_MAINTENANCE",
+            "to": "DISABLE_MAINTENANCE",
+            "trigger": "to_maintenance"
+        },
+        {
+            "from": "DISABLE_MAINTENANCE",
+            "to": "DISABLE_ONLINE",
+            "trigger": "to_online"
+        },
+        {
+            "from": "DISABLE_MAINTENANCE",
+            "to": "DISABLE_MAINTENANCE",
+            "trigger": "disable_succeeded"
+        },
+        {
+            "from": "DISABLE_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "disable_failed"
+        },
+        {
+            "from": "DISABLE_MAINTENANCE",
+            "to": "STANDBY_MAINTENANCE",
+            "trigger": "standby_succeeded"
+        },
+        {
+            "from": "DISABLE_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "standby_failed"
+        },
+        {
+            "from": "DISABLE_MAINTENANCE",
+            "to": "OFF_MAINTENANCE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "DISABLE_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "DISABLE_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "DISABLE_ONLINE",
+            "to": "DISABLE_OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "DISABLE_ONLINE",
+            "to": "DISABLE_MAINTENANCE",
+            "trigger": "to_maintenance"
+        },
+        {
+            "from": "DISABLE_ONLINE",
+            "to": "DISABLE_ONLINE",
+            "trigger": "to_online"
+        },
+        {
+            "from": "DISABLE_ONLINE",
+            "to": "DISABLE_ONLINE",
+            "trigger": "disable_succeeded"
+        },
+        {
+            "from": "DISABLE_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "disable_failed"
+        },
+        {
+            "from": "DISABLE_ONLINE",
+            "to": "STANDBY_ONLINE",
+            "trigger": "standby_succeeded"
+        },
+        {
+            "from": "DISABLE_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "standby_failed"
+        },
+        {
+            "from": "DISABLE_ONLINE",
+            "to": "OFF_ONLINE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "DISABLE_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "DISABLE_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "DISABLE_OFFLINE",
+            "to": "DISABLE_OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "DISABLE_OFFLINE",
+            "to": "DISABLE_MAINTENANCE",
+            "trigger": "to_maintenance"
+        },
+        {
+            "from": "DISABLE_OFFLINE",
+            "to": "DISABLE_ONLINE",
+            "trigger": "to_online"
+        },
+        {
+            "from": "DISABLE_OFFLINE",
+            "to": "DISABLE_NOTFITTED",
+            "trigger": "to_notfitted"
+        },
+        {
+            "from": "DISABLE_OFFLINE",
+            "to": "DISABLE_RESERVED",
+            "trigger": "to_reserved"
+        },
+        {
+            "from": "DISABLE_OFFLINE",
+            "to": "DISABLE_OFFLINE",
+            "trigger": "disable_succeeded"
+        },
+        {
+            "from": "DISABLE_OFFLINE",
+            "to": "FAULT_OFFLINE",
+            "trigger": "disable_failed"
+        },
+        {
+            "from": "DISABLE_OFFLINE",
+            "to": "FAULT_OFFLINE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "DISABLE_NOTFITTED",
+            "to": "DISABLE_NOTFITTED",
+            "trigger": "to_notfitted"
+        },
+        {
+            "from": "DISABLE_NOTFITTED",
+            "to": "DISABLE_OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "DISABLE_NOTFITTED",
+            "to": "DISABLE_RESERVED",
+            "trigger": "to_reserved"
+        },
+        {
+            "from": "DISABLE_NOTFITTED",
+            "to": "DISABLE_NOTFITTED",
+            "trigger": "disable_succeeded"
+        },
+        {
+            "from": "DISABLE_NOTFITTED",
+            "to": "FAULT_NOTFITTED",
+            "trigger": "disable_failed"
+        },
+        {
+            "from": "DISABLE_NOTFITTED",
+            "to": "FAULT_NOTFITTED",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "DISABLE_RESERVED",
+            "to": "DISABLE_RESERVED",
+            "trigger": "to_reserved"
+        },
+        {
+            "from": "DISABLE_RESERVED",
+            "to": "DISABLE_NOTFITTED",
+            "trigger": "to_notfitted"
+        },
+        {
+            "from": "DISABLE_RESERVED",
+            "to": "DISABLE_OFFLINE",
+            "trigger": "to_offline"
+        },
+        {
+            "from": "DISABLE_RESERVED",
+            "to": "DISABLE_RESERVED",
+            "trigger": "disable_succeeded"
+        },
+        {
+            "from": "DISABLE_RESERVED",
+            "to": "FAULT_RESERVED",
+            "trigger": "disable_failed"
+        },
+        {
+            "from": "DISABLE_RESERVED",
+            "to": "FAULT_RESERVED",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "STANDBY_MAINTENANCE",
+            "to": "DISABLE_MAINTENANCE",
+            "trigger": "disable_succeeded"
+        },
+        {
+            "from": "STANDBY_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "disable_failed"
+        },
+        {
+            "from": "STANDBY_MAINTENANCE",
+            "to": "STANDBY_MAINTENANCE",
+            "trigger": "standby_succeeded"
+        },
+        {
+            "from": "STANDBY_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "standby_failed"
+        },
+        {
+            "from": "STANDBY_MAINTENANCE",
+            "to": "OFF_MAINTENANCE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "STANDBY_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "STANDBY_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "STANDBY_ONLINE",
+            "to": "DISABLE_ONLINE",
+            "trigger": "disable_succeeded"
+        },
+        {
+            "from": "STANDBY_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "disable_failed"
+        },
+        {
+            "from": "STANDBY_ONLINE",
+            "to": "STANDBY_ONLINE",
+            "trigger": "standby_succeeded"
+        },
+        {
+            "from": "STANDBY_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "standby_failed"
+        },
+        {
+            "from": "STANDBY_ONLINE",
+            "to": "OFF_ONLINE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "STANDBY_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "STANDBY_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "OFF_MAINTENANCE",
+            "to": "DISABLE_MAINTENANCE",
+            "trigger": "disable_succeeded"
+        },
+        {
+            "from": "OFF_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "disable_failed"
+        },
+        {
+            "from": "OFF_MAINTENANCE",
+            "to": "STANDBY_MAINTENANCE",
+            "trigger": "standby_succeeded"
+        },
+        {
+            "from": "OFF_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "standby_failed"
+        },
+        {
+            "from": "OFF_MAINTENANCE",
+            "to": "OFF_MAINTENANCE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "OFF_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "OFF_MAINTENANCE",
+            "to": "EMPTY_MAINTENANCE",
+            "trigger": "on_succeeded"
+        },
+        {
+            "from": "OFF_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "on_failed"
+        },
+        {
+            "from": "OFF_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "OFF_ONLINE",
+            "to": "DISABLE_ONLINE",
+            "trigger": "disable_succeeded"
+        },
+        {
+            "from": "OFF_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "disable_failed"
+        },
+        {
+            "from": "OFF_ONLINE",
+            "to": "STANDBY_ONLINE",
+            "trigger": "standby_succeeded"
+        },
+        {
+            "from": "OFF_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "standby_failed"
+        },
+        {
+            "from": "OFF_ONLINE",
+            "to": "OFF_ONLINE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "OFF_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "OFF_ONLINE",
+            "to": "EMPTY_ONLINE",
+            "trigger": "on_succeeded"
+        },
+        {
+            "from": "OFF_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "on_failed"
+        },
+        {
+            "from": "OFF_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "EMPTY_MAINTENANCE",
+            "to": "OFF_MAINTENANCE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "EMPTY_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "EMPTY_MAINTENANCE",
+            "to": "EMPTY_MAINTENANCE",
+            "trigger": "on_succeeded"
+        },
+        {
+            "from": "EMPTY_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "on_failed"
+        },
+        {
+            "from": "EMPTY_MAINTENANCE",
+            "to": "OBSFAULT_MAINTENANCE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "EMPTY_ONLINE",
+            "to": "OFF_ONLINE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "EMPTY_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "EMPTY_ONLINE",
+            "to": "EMPTY_ONLINE",
+            "trigger": "on_succeeded"
+        },
+        {
+            "from": "EMPTY_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "on_failed"
+        },
+        {
+            "from": "EMPTY_ONLINE",
+            "to": "OBSFAULT_ONLINE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "EMPTY_ONLINE",
+            "to": "RESOURCING_ONLINE",
+            "trigger": "assign_started"
+        },
+        {
+            "from": "EMPTY_MAINTENANCE",
+            "to": "RESOURCING_MAINTENANCE",
+            "trigger": "assign_started"
+        },
+        {
+            "from": "RESOURCING_ONLINE",
+            "to": "OFF_ONLINE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "RESOURCING_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "RESOURCING_ONLINE",
+            "to": "RESOURCING_ONLINE",
+            "trigger": "on_succeeded"
+        },
+        {
+            "from": "RESOURCING_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "on_failed"
+        },
+        {
+            "from": "RESOURCING_ONLINE",
+            "to": "IDLE_ONLINE",
+            "trigger": "resourcing_succeeded_some_resources"
+        },
+        {
+            "from": "RESOURCING_ONLINE",
+            "to": "EMPTY_ONLINE",
+            "trigger": "resourcing_succeeded_no_resources"
+        },
+        {
+            "from": "RESOURCING_ONLINE",
+            "to": "OBSFAULT_ONLINE",
+            "trigger": "resourcing_failed"
+        },
+        {
+            "from": "RESOURCING_ONLINE",
+            "to": "OBSFAULT_ONLINE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "RESOURCING_MAINTENANCE",
+            "to": "OFF_MAINTENANCE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "RESOURCING_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "RESOURCING_MAINTENANCE",
+            "to": "RESOURCING_MAINTENANCE",
+            "trigger": "on_succeeded"
+        },
+        {
+            "from": "RESOURCING_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "on_failed"
+        },
+        {
+            "from": "RESOURCING_MAINTENANCE",
+            "to": "IDLE_MAINTENANCE",
+            "trigger": "resourcing_succeeded_some_resources"
+        },
+        {
+            "from": "RESOURCING_MAINTENANCE",
+            "to": "EMPTY_MAINTENANCE",
+            "trigger": "resourcing_succeeded_no_resources"
+        },
+        {
+            "from": "RESOURCING_MAINTENANCE",
+            "to": "OBSFAULT_MAINTENANCE",
+            "trigger": "resourcing_failed"
+        },
+        {
+            "from": "RESOURCING_MAINTENANCE",
+            "to": "OBSFAULT_MAINTENANCE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "IDLE_ONLINE",
+            "to": "OFF_ONLINE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "IDLE_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "IDLE_ONLINE",
+            "to": "IDLE_ONLINE",
+            "trigger": "on_succeeded"
+        },
+        {
+            "from": "IDLE_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "on_failed"
+        },
+        {
+            "from": "IDLE_ONLINE",
+            "to": "RESOURCING_ONLINE",
+            "trigger": "assign_started"
+        },
+        {
+            "from": "IDLE_ONLINE",
+            "to": "RESOURCING_ONLINE",
+            "trigger": "release_started"
+        },
+        {
+            "from": "IDLE_ONLINE",
+            "to": "CONFIGURING_ONLINE",
+            "trigger": "configure_started"
+        },
+        {
+            "from": "IDLE_ONLINE",
+            "to": "ABORTING_ONLINE",
+            "trigger": "abort_started"
+        },
+        {
+            "from": "IDLE_ONLINE",
+            "to": "OBSFAULT_ONLINE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "IDLE_MAINTENANCE",
+            "to": "OFF_MAINTENANCE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "IDLE_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "IDLE_MAINTENANCE",
+            "to": "IDLE_MAINTENANCE",
+            "trigger": "on_succeeded"
+        },
+        {
+            "from": "IDLE_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "on_failed"
+        },
+        {
+            "from": "IDLE_MAINTENANCE",
+            "to": "RESOURCING_MAINTENANCE",
+            "trigger": "assign_started"
+        },
+        {
+            "from": "IDLE_MAINTENANCE",
+            "to": "RESOURCING_MAINTENANCE",
+            "trigger": "release_started"
+        },
+        {
+            "from": "IDLE_MAINTENANCE",
+            "to": "CONFIGURING_MAINTENANCE",
+            "trigger": "configure_started"
+        },
+        {
+            "from": "IDLE_MAINTENANCE",
+            "to": "ABORTING_MAINTENANCE",
+            "trigger": "abort_started"
+        },
+        {
+            "from": "IDLE_MAINTENANCE",
+            "to": "OBSFAULT_MAINTENANCE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "CONFIGURING_ONLINE",
+            "to": "OFF_ONLINE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "CONFIGURING_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "CONFIGURING_ONLINE",
+            "to": "CONFIGURING_ONLINE",
+            "trigger": "on_succeeded"
+        },
+        {
+            "from": "CONFIGURING_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "on_failed"
+        },
+        {
+            "from": "CONFIGURING_ONLINE",
+            "to": "READY_ONLINE",
+            "trigger": "configure_succeeded"
+        },
+        {
+            "from": "CONFIGURING_ONLINE",
+            "to": "OBSFAULT_ONLINE",
+            "trigger": "configure_failed"
+        },
+        {
+            "from": "CONFIGURING_ONLINE",
+            "to": "ABORTING_ONLINE",
+            "trigger": "abort_started"
+        },
+        {
+            "from": "CONFIGURING_ONLINE",
+            "to": "OBSFAULT_ONLINE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "CONFIGURING_MAINTENANCE",
+            "to": "OFF_MAINTENANCE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "CONFIGURING_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "CONFIGURING_MAINTENANCE",
+            "to": "CONFIGURING_MAINTENANCE",
+            "trigger": "on_succeeded"
+        },
+        {
+            "from": "CONFIGURING_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "on_failed"
+        },
+        {
+            "from": "CONFIGURING_MAINTENANCE",
+            "to": "READY_MAINTENANCE",
+            "trigger": "configure_succeeded"
+        },
+        {
+            "from": "CONFIGURING_MAINTENANCE",
+            "to": "OBSFAULT_MAINTENANCE",
+            "trigger": "configure_failed"
+        },
+        {
+            "from": "CONFIGURING_MAINTENANCE",
+            "to": "ABORTING_MAINTENANCE",
+            "trigger": "abort_started"
+        },
+        {
+            "from": "CONFIGURING_MAINTENANCE",
+            "to": "OBSFAULT_MAINTENANCE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "READY_ONLINE",
+            "to": "OFF_ONLINE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "READY_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "READY_ONLINE",
+            "to": "READY_ONLINE",
+            "trigger": "on_succeeded"
+        },
+        {
+            "from": "READY_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "on_failed"
+        },
+        {
+            "from": "READY_ONLINE",
+            "to": "IDLE_ONLINE",
+            "trigger": "end_succeeded"
+        },
+        {
+            "from": "READY_ONLINE",
+            "to": "OBSFAULT_ONLINE",
+            "trigger": "end_failed"
+        },
+        {
+            "from": "READY_ONLINE",
+            "to": "CONFIGURING_ONLINE",
+            "trigger": "configure_started"
+        },
+        {
+            "from": "READY_ONLINE",
+            "to": "ABORTING_ONLINE",
+            "trigger": "abort_started"
+        },
+        {
+            "from": "READY_ONLINE",
+            "to": "SCANNING_ONLINE",
+            "trigger": "scan_started"
+        },
+        {
+            "from": "READY_ONLINE",
+            "to": "OBSFAULT_ONLINE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "READY_MAINTENANCE",
+            "to": "OFF_MAINTENANCE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "READY_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "READY_MAINTENANCE",
+            "to": "READY_MAINTENANCE",
+            "trigger": "on_succeeded"
+        },
+        {
+            "from": "READY_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "on_failed"
+        },
+        {
+            "from": "READY_MAINTENANCE",
+            "to": "IDLE_MAINTENANCE",
+            "trigger": "end_succeeded"
+        },
+        {
+            "from": "READY_MAINTENANCE",
+            "to": "OBSFAULT_MAINTENANCE",
+            "trigger": "end_failed"
+        },
+        {
+            "from": "READY_MAINTENANCE",
+            "to": "CONFIGURING_MAINTENANCE",
+            "trigger": "configure_started"
+        },
+        {
+            "from": "READY_MAINTENANCE",
+            "to": "ABORTING_MAINTENANCE",
+            "trigger": "abort_started"
+        },
+        {
+            "from": "READY_MAINTENANCE",
+            "to": "SCANNING_MAINTENANCE",
+            "trigger": "scan_started"
+        },
+        {
+            "from": "READY_MAINTENANCE",
+            "to": "OBSFAULT_MAINTENANCE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "SCANNING_ONLINE",
+            "to": "OFF_ONLINE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "SCANNING_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "SCANNING_ONLINE",
+            "to": "SCANNING_ONLINE",
+            "trigger": "on_succeeded"
+        },
+        {
+            "from": "SCANNING_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "on_failed"
+        },
+        {
+            "from": "SCANNING_ONLINE",
+            "to": "READY_ONLINE",
+            "trigger": "scan_succeeded"
+        },
+        {
+            "from": "SCANNING_ONLINE",
+            "to": "OBSFAULT_ONLINE",
+            "trigger": "scan_failed"
+        },
+        {
+            "from": "SCANNING_ONLINE",
+            "to": "READY_ONLINE",
+            "trigger": "end_scan_succeeded"
+        },
+        {
+            "from": "SCANNING_ONLINE",
+            "to": "OBSFAULT_ONLINE",
+            "trigger": "end_scan_failed"
+        },
+        {
+            "from": "SCANNING_ONLINE",
+            "to": "ABORTING_ONLINE",
+            "trigger": "abort_started"
+        },
+        {
+            "from": "SCANNING_ONLINE",
+            "to": "OBSFAULT_ONLINE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "SCANNING_MAINTENANCE",
+            "to": "OFF_MAINTENANCE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "SCANNING_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "SCANNING_MAINTENANCE",
+            "to": "SCANNING_MAINTENANCE",
+            "trigger": "on_succeeded"
+        },
+        {
+            "from": "SCANNING_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "on_failed"
+        },
+        {
+            "from": "SCANNING_MAINTENANCE",
+            "to": "READY_MAINTENANCE",
+            "trigger": "scan_succeeded"
+        },
+        {
+            "from": "SCANNING_MAINTENANCE",
+            "to": "OBSFAULT_MAINTENANCE",
+            "trigger": "scan_failed"
+        },
+        {
+            "from": "SCANNING_MAINTENANCE",
+            "to": "READY_MAINTENANCE",
+            "trigger": "end_scan_succeeded"
+        },
+        {
+            "from": "SCANNING_MAINTENANCE",
+            "to": "OBSFAULT_MAINTENANCE",
+            "trigger": "end_scan_failed"
+        },
+        {
+            "from": "SCANNING_MAINTENANCE",
+            "to": "ABORTING_MAINTENANCE",
+            "trigger": "abort_started"
+        },
+        {
+            "from": "SCANNING_MAINTENANCE",
+            "to": "OBSFAULT_MAINTENANCE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "ABORTING_ONLINE",
+            "to": "OFF_ONLINE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "ABORTING_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "ABORTING_ONLINE",
+            "to": "ABORTING_ONLINE",
+            "trigger": "on_succeeded"
+        },
+        {
+            "from": "ABORTING_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "on_failed"
+        },
+        {
+            "from": "ABORTING_ONLINE",
+            "to": "ABORTED_ONLINE",
+            "trigger": "abort_succeeded"
+        },
+        {
+            "from": "ABORTING_ONLINE",
+            "to": "OBSFAULT_ONLINE",
+            "trigger": "abort_failed"
+        },
+        {
+            "from": "ABORTING_ONLINE",
+            "to": "OBSFAULT_ONLINE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "ABORTING_MAINTENANCE",
+            "to": "OFF_MAINTENANCE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "ABORTING_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "ABORTING_MAINTENANCE",
+            "to": "ABORTING_MAINTENANCE",
+            "trigger": "on_succeeded"
+        },
+        {
+            "from": "ABORTING_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "on_failed"
+        },
+        {
+            "from": "ABORTING_MAINTENANCE",
+            "to": "ABORTED_MAINTENANCE",
+            "trigger": "abort_succeeded"
+        },
+        {
+            "from": "ABORTING_MAINTENANCE",
+            "to": "OBSFAULT_MAINTENANCE",
+            "trigger": "abort_failed"
+        },
+        {
+            "from": "ABORTING_MAINTENANCE",
+            "to": "OBSFAULT_MAINTENANCE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "ABORTED_ONLINE",
+            "to": "OFF_ONLINE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "ABORTED_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "ABORTED_ONLINE",
+            "to": "ABORTED_ONLINE",
+            "trigger": "on_succeeded"
+        },
+        {
+            "from": "ABORTED_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "on_failed"
+        },
+        {
+            "from": "ABORTED_ONLINE",
+            "to": "RESETTING_ONLINE",
+            "trigger": "obs_reset_started"
+        },
+        {
+            "from": "ABORTED_ONLINE",
+            "to": "RESTARTING_ONLINE",
+            "trigger": "restart_started"
+        },
+        {
+            "from": "ABORTED_ONLINE",
+            "to": "OBSFAULT_ONLINE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "ABORTED_MAINTENANCE",
+            "to": "OFF_MAINTENANCE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "ABORTED_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "ABORTED_MAINTENANCE",
+            "to": "ABORTED_MAINTENANCE",
+            "trigger": "on_succeeded"
+        },
+        {
+            "from": "ABORTED_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "on_failed"
+        },
+        {
+            "from": "ABORTED_MAINTENANCE",
+            "to": "RESETTING_MAINTENANCE",
+            "trigger": "obs_reset_started"
+        },
+        {
+            "from": "ABORTED_MAINTENANCE",
+            "to": "RESTARTING_MAINTENANCE",
+            "trigger": "restart_started"
+        },
+        {
+            "from": "ABORTED_MAINTENANCE",
+            "to": "OBSFAULT_MAINTENANCE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "OBSFAULT_ONLINE",
+            "to": "OFF_ONLINE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "OBSFAULT_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "OBSFAULT_ONLINE",
+            "to": "OBSFAULT_ONLINE",
+            "trigger": "on_succeeded"
+        },
+        {
+            "from": "OBSFAULT_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "on_failed"
+        },
+        {
+            "from": "OBSFAULT_ONLINE",
+            "to": "RESETTING_ONLINE",
+            "trigger": "obs_reset_started"
+        },
+        {
+            "from": "OBSFAULT_ONLINE",
+            "to": "RESTARTING_ONLINE",
+            "trigger": "restart_started"
+        },
+        {
+            "from": "OBSFAULT_ONLINE",
+            "to": "OBSFAULT_ONLINE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "OBSFAULT_MAINTENANCE",
+            "to": "OFF_MAINTENANCE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "OBSFAULT_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "OBSFAULT_MAINTENANCE",
+            "to": "OBSFAULT_MAINTENANCE",
+            "trigger": "on_succeeded"
+        },
+        {
+            "from": "OBSFAULT_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "on_failed"
+        },
+        {
+            "from": "OBSFAULT_MAINTENANCE",
+            "to": "RESETTING_MAINTENANCE",
+            "trigger": "obs_reset_started"
+        },
+        {
+            "from": "OBSFAULT_MAINTENANCE",
+            "to": "RESTARTING_MAINTENANCE",
+            "trigger": "restart_started"
+        },
+        {
+            "from": "OBSFAULT_MAINTENANCE",
+            "to": "OBSFAULT_MAINTENANCE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "RESETTING_ONLINE",
+            "to": "OFF_ONLINE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "RESETTING_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "RESETTING_ONLINE",
+            "to": "RESETTING_ONLINE",
+            "trigger": "on_succeeded"
+        },
+        {
+            "from": "RESETTING_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "on_failed"
+        },
+        {
+            "from": "RESETTING_ONLINE",
+            "to": "IDLE_ONLINE",
+            "trigger": "obs_reset_succeeded"
+        },
+        {
+            "from": "RESETTING_ONLINE",
+            "to": "OBSFAULT_ONLINE",
+            "trigger": "obs_reset_failed"
+        },
+        {
+            "from": "RESETTING_ONLINE",
+            "to": "ABORTING_ONLINE",
+            "trigger": "abort_started"
+        },
+        {
+            "from": "RESETTING_ONLINE",
+            "to": "OBSFAULT_ONLINE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "RESETTING_MAINTENANCE",
+            "to": "OFF_MAINTENANCE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "RESETTING_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "RESETTING_MAINTENANCE",
+            "to": "RESETTING_MAINTENANCE",
+            "trigger": "on_succeeded"
+        },
+        {
+            "from": "RESETTING_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "on_failed"
+        },
+        {
+            "from": "RESETTING_MAINTENANCE",
+            "to": "IDLE_MAINTENANCE",
+            "trigger": "obs_reset_succeeded"
+        },
+        {
+            "from": "RESETTING_MAINTENANCE",
+            "to": "OBSFAULT_MAINTENANCE",
+            "trigger": "obs_reset_failed"
+        },
+        {
+            "from": "RESETTING_MAINTENANCE",
+            "to": "ABORTING_MAINTENANCE",
+            "trigger": "abort_started"
+        },
+        {
+            "from": "RESETTING_MAINTENANCE",
+            "to": "OBSFAULT_MAINTENANCE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "RESTARTING_ONLINE",
+            "to": "OFF_ONLINE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "RESTARTING_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "RESTARTING_ONLINE",
+            "to": "RESTARTING_ONLINE",
+            "trigger": "on_succeeded"
+        },
+        {
+            "from": "RESTARTING_ONLINE",
+            "to": "FAULT_ONLINE",
+            "trigger": "on_failed"
+        },
+        {
+            "from": "RESTARTING_ONLINE",
+            "to": "EMPTY_ONLINE",
+            "trigger": "restart_succeeded"
+        },
+        {
+            "from": "RESTARTING_ONLINE",
+            "to": "OBSFAULT_ONLINE",
+            "trigger": "restart_failed"
+        },
+        {
+            "from": "RESTARTING_ONLINE",
+            "to": "OBSFAULT_ONLINE",
+            "trigger": "fatal_error"
+        },
+        {
+            "from": "RESTARTING_MAINTENANCE",
+            "to": "OFF_MAINTENANCE",
+            "trigger": "off_succeeded"
+        },
+        {
+            "from": "RESTARTING_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "off_failed"
+        },
+        {
+            "from": "RESTARTING_MAINTENANCE",
+            "to": "RESTARTING_MAINTENANCE",
+            "trigger": "on_succeeded"
+        },
+        {
+            "from": "RESTARTING_MAINTENANCE",
+            "to": "FAULT_MAINTENANCE",
+            "trigger": "on_failed"
+        },
+        {
+            "from": "RESTARTING_MAINTENANCE",
+            "to": "EMPTY_MAINTENANCE",
+            "trigger": "restart_succeeded"
+        },
+        {
+            "from": "RESTARTING_MAINTENANCE",
+            "to": "OBSFAULT_MAINTENANCE",
+            "trigger": "restart_failed"
+        },
+        {
+            "from": "RESTARTING_MAINTENANCE",
+            "to": "OBSFAULT_MAINTENANCE",
+            "trigger": "fatal_error"
+        }
     ]
-]
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/tests/test_base_device.py b/tests/test_base_device.py
index be517b0e744fcbbd5beb528e24f82587dd533386..049b61a60d4d5b69b9d27da1e807db9e6f23e4c4 100644
--- a/tests/test_base_device.py
+++ b/tests/test_base_device.py
@@ -27,12 +27,12 @@ from ska.base.base_device import (
     _PYTHON_TO_TANGO_LOGGING_LEVEL,
     LoggingUtils,
     LoggingTargetError,
-    SKABaseDeviceStateModel,
+    DeviceStateModel,
     TangoLoggingServiceHandler,
 )
 from ska.base.faults import StateModelError
 
-from .conftest import load_data, StateMachineTester
+from .conftest import load_state_machine_spec, StateMachineTester
 
 # PROTECTED REGION END #    //  SKABaseDevice.test_additional_imports
 # Device test case
@@ -326,42 +326,28 @@ class TestLoggingUtils:
 @pytest.fixture
 def device_state_model():
     """
-    Yields a new SKABaseDeviceStateModel for testing
+    Yields a new DeviceStateModel for testing
+
+    :yields: a DeviceStateModel instance to be tested
     """
-    yield SKABaseDeviceStateModel(logging.getLogger())
+    yield DeviceStateModel(logging.getLogger())
 
 
-@pytest.mark.state_machine_tester(load_data("base_device_state_machine"))
-class TestSKABaseDeviceStateModel(StateMachineTester):
+@pytest.mark.state_machine_tester(load_state_machine_spec("device_state_machine"))
+class TestDeviceStateModel(StateMachineTester):
     """
     This class contains the test suite for the ska.base.SKABaseDevice class.
     """
+
     @pytest.fixture
     def machine(self, device_state_model):
         """
         Fixture that returns the state machine under test in this class
+
+        :yields: the state machine under test
         """
         yield device_state_model
 
-    state_checks = {
-        "UNINITIALISED":
-            (None, None),
-        "FAULT_ENABLED":
-            ([AdminMode.ONLINE, AdminMode.MAINTENANCE], DevState.FAULT),
-        "FAULT_DISABLED":
-            ([AdminMode.NOT_FITTED, AdminMode.OFFLINE], DevState.FAULT),
-        "INIT_ENABLED":
-            ([AdminMode.ONLINE, AdminMode.MAINTENANCE], DevState.INIT),
-        "INIT_DISABLED":
-            ([AdminMode.NOT_FITTED, AdminMode.OFFLINE], DevState.INIT),
-        "DISABLED":
-            ([AdminMode.NOT_FITTED, AdminMode.OFFLINE], DevState.DISABLE),
-        "OFF":
-            ([AdminMode.ONLINE, AdminMode.MAINTENANCE], DevState.OFF),
-        "ON":
-            ([AdminMode.ONLINE, AdminMode.MAINTENANCE], DevState.ON),
-    }
-
     def assert_state(self, machine, state):
         """
         Assert the current state of this state machine, based on the
@@ -372,29 +358,35 @@ class TestSKABaseDeviceStateModel(StateMachineTester):
         :type machine: state machine object instance
         :param state: the state that we are asserting to be the current
             state of the state machine under test
-        :type state: str
+        :type state: dict
+        """
+        assert machine.admin_mode == state["admin_mode"]
+        assert machine.op_state == state["op_state"]
+
+    def is_action_allowed(self, machine, action):
         """
+        Returns whether the state machine under test thinks an action
+        is permitted in its current state
 
-        (admin_modes, op_state) = self.state_checks[state]
-        if admin_modes is None:
-            assert machine.admin_mode is None
-        else:
-            assert machine.admin_mode in admin_modes
-        if op_state is None:
-            assert machine.op_state is None
-        else:
-            assert machine.op_state == op_state
+        :param machine: the state machine under test
+        :type machine: state machine object instance
+        :param action: action to be performed on the state machine
+        :type action: str
+        """
+        return machine.is_action_allowed(action)
 
     def perform_action(self, machine, action):
         """
         Perform a given action on the state machine under test.
 
+        :param machine: the state machine under test
+        :type machine: state machine object instance
         :param action: action to be performed on the state machine
         :type action: str
         """
         machine.perform_action(action)
 
-    def check_action_disallowed(self, machine, action):
+    def check_action_fails(self, machine, action):
         """
         Assert that performing a given action on the state maching under
         test fails in its current state.
@@ -415,9 +407,9 @@ class TestSKABaseDeviceStateModel(StateMachineTester):
         :type machine: state machine object instance
         :param target_state: the state that we want to get the state
             machine under test into
-        :type target_state: str
+        :type target_state: dict
         """
-        machine._straight_to_state(target_state)
+        machine._straight_to_state(**target_state)
 
 
 # PROTECTED REGION END #    //  SKABaseDevice.test_SKABaseDevice_decorators
@@ -509,45 +501,51 @@ class TestSKABaseDevice(object):
         state_callback.assert_call(DevState.ON)
         status_callback.assert_call("The device is in ON state.")
 
-        # Check that we can't turn it on when it is already on
-        with pytest.raises(DevFailed):
-            tango_context.device.On()
+        # Check that we can turn it on when it is already on
+        tango_context.device.On()
         state_callback.assert_not_called()
         status_callback.assert_not_called()
 
-        # Now turn it off and check that we can turn it on again.
-        tango_context.device.Off()
-        state_callback.assert_call(DevState.OFF)
-        status_callback.assert_call("The device is in OFF state.")
+    def test_Disable(self, tango_context):
+        """
+        Test for Disable command
+        """
+        assert tango_context.device.state() == DevState.OFF
 
-        tango_context.device.On()
-        state_callback.assert_call(DevState.ON)
-        status_callback.assert_call("The device is in ON state.")
+        # Check that we can disable it
+        tango_context.device.Disable()
+        assert tango_context.device.state() == DevState.DISABLE
+
+        # Check that we can disable it when it is already disabled
+        tango_context.device.Disable()
+
+    def test_Standby(self, tango_context):
+        """
+        Test for Standby command
+        """
+        assert tango_context.device.state() == DevState.OFF
+
+        # Check that we can put it on standby
+        tango_context.device.Standby()
+        assert tango_context.device.state() == DevState.STANDBY
+
+        # Check that we can put it on standby when it is already on standby
+        tango_context.device.Standby()
 
     def test_Off(self, tango_context, tango_change_event_helper):
         """
-        Test for On command
+        Test for Off command
         """
         state_callback = tango_change_event_helper.subscribe("state")
         status_callback = tango_change_event_helper.subscribe("status")
         state_callback.assert_call(DevState.OFF)
         status_callback.assert_call("The device is in OFF state.")
 
-        # Check that we can't turn off a device that isn't on
-        with pytest.raises(DevFailed):
-            tango_context.device.Off()
+        # Check that we can turn off a device that is already off
+        tango_context.device.Off()
         state_callback.assert_not_called()
         status_callback.assert_not_called()
 
-        # Now turn it on and check that we can turn it off
-        tango_context.device.On()
-        state_callback.assert_call(DevState.ON)
-        status_callback.assert_call("The device is in ON state.")
-
-        tango_context.device.Off()
-        state_callback.assert_call(DevState.OFF)
-        status_callback.assert_call("The device is in OFF state.")
-
     # PROTECTED REGION ID(SKABaseDevice.test_buildState_decorators) ENABLED START #
     # PROTECTED REGION END #    //  SKABaseDevice.test_buildState_decorators
     def test_buildState(self, tango_context):
@@ -651,15 +649,24 @@ class TestSKABaseDevice(object):
     def test_adminMode(self, tango_context, tango_change_event_helper):
         """Test for adminMode"""
         # PROTECTED REGION ID(SKABaseDevice.test_adminMode) ENABLED START #
+        tango_context.device.Disable()
         assert tango_context.device.adminMode == AdminMode.MAINTENANCE
 
         admin_mode_callback = tango_change_event_helper.subscribe("adminMode")
         admin_mode_callback.assert_call(AdminMode.MAINTENANCE)
 
+        tango_context.device.adminMode = AdminMode.OFFLINE
+        assert tango_context.device.adminMode == AdminMode.OFFLINE
+        admin_mode_callback.assert_call(AdminMode.OFFLINE)
+
         tango_context.device.adminMode = AdminMode.ONLINE
         assert tango_context.device.adminMode == AdminMode.ONLINE
         admin_mode_callback.assert_call(AdminMode.ONLINE)
 
+        tango_context.device.adminMode = AdminMode.ONLINE
+        assert tango_context.device.adminMode == AdminMode.ONLINE
+        admin_mode_callback.assert_not_called()
+
         # PROTECTED REGION END #    //  SKABaseDevice.test_adminMode
 
     # PROTECTED REGION ID(SKABaseDevice.test_controlMode_decorators) ENABLED START #
diff --git a/tests/test_state_machines.py b/tests/test_state_machines.py
index d44b641b982f856ed419691b5c16c4ee9ba28a94..dfa9208f45d7a04b4a04e69fc289324ff664d927 100644
--- a/tests/test_state_machines.py
+++ b/tests/test_state_machines.py
@@ -3,31 +3,57 @@ This module contains the tests for the ska.base.state_machine module.
 """
 import pytest
 
-from ska.base.state_machine import BaseDeviceStateMachine, ObservationStateMachine
-from .conftest import load_data, TransitionsStateMachineTester
+from ska.base.state_machine import (
+    AdminModeStateMachine,
+    OperationStateMachine,
+    ObservationStateMachine,
+)
+from .conftest import load_state_machine_spec, TransitionsStateMachineTester
 
 
-@pytest.mark.state_machine_tester(load_data("base_device_state_machine"))
-class BaseDeviceStateMachineTester(TransitionsStateMachineTester):
+@pytest.mark.state_machine_tester(load_state_machine_spec("operation_state_machine"))
+class TestOperationStateMachine(TransitionsStateMachineTester):
     """
-    This class contains the test for the BaseDeviceStateMachine class.
+    This class contains the test for the DeviceStateMachine class.
     """
+
     @pytest.fixture
     def machine(self):
         """
         Fixture that returns the state machine under test in this class
+
+        :yields: the state machine under test
         """
-        yield BaseDeviceStateMachine()
+        yield OperationStateMachine()
 
 
-@pytest.mark.state_machine_tester(load_data("observation_state_machine"))
+@pytest.mark.state_machine_tester(load_state_machine_spec("admin_mode_state_machine"))
+class TestAdminModeStateMachine(TransitionsStateMachineTester):
+    """
+    This class contains the test for the DeviceStateMachine class.
+    """
+
+    @pytest.fixture
+    def machine(self):
+        """
+        Fixture that returns the state machine under test in this class
+
+        :yields: the state machine under test
+        """
+        yield AdminModeStateMachine()
+
+
+@pytest.mark.state_machine_tester(load_state_machine_spec("observation_state_machine"))
 class TestObservationStateMachine(TransitionsStateMachineTester):
     """
     This class contains the test for the ObservationStateMachine class.
     """
+
     @pytest.fixture
     def machine(self):
         """
         Fixture that returns the state machine under test in this class
+
+        :yields: the state machine under test
         """
         yield ObservationStateMachine()
diff --git a/tests/test_subarray_device.py b/tests/test_subarray_device.py
index 7f91bb27e9bd4db38f136af1ef1d3aa19cfdfa1d..2676f4aa3bf9244031b2c7a61c3355cd3843d078 100644
--- a/tests/test_subarray_device.py
+++ b/tests/test_subarray_device.py
@@ -18,11 +18,18 @@ from tango import DevState, DevFailed
 from ska.base import SKASubarray, SKASubarrayResourceManager, SKASubarrayStateModel
 from ska.base.commands import ResultCode
 from ska.base.control_model import (
-    AdminMode, ControlMode, HealthState, ObsMode, ObsState, SimulationMode, TestMode
+    AdminMode,
+    ControlMode,
+    HealthState,
+    ObsMode,
+    ObsState,
+    SimulationMode,
+    TestMode,
 )
 from ska.base.faults import CommandError, StateModelError
 
-from .conftest import load_data, StateMachineTester
+from .conftest import load_state_machine_spec, StateMachineTester
+
 # PROTECTED REGION END #    //  SKASubarray.test_additional_imports
 
 
@@ -34,11 +41,12 @@ def subarray_state_model():
     yield SKASubarrayStateModel(logging.getLogger())
 
 
-@pytest.mark.state_machine_tester(load_data("subarray_state_machine"))
+@pytest.mark.state_machine_tester(load_state_machine_spec("subarray_state_machine"))
 class TestSKASubarrayStateModel(StateMachineTester):
     """
     This class contains the test for the SKASubarrayStateModel class.
     """
+
     @pytest.fixture
     def machine(self, subarray_state_model):
         """
@@ -46,46 +54,6 @@ class TestSKASubarrayStateModel(StateMachineTester):
         """
         yield subarray_state_model
 
-    state_checks = {
-        "UNINITIALISED":
-            (None, None, ObsState.EMPTY),
-        "FAULT_ENABLED":
-            ([AdminMode.ONLINE, AdminMode.MAINTENANCE], DevState.FAULT, ObsState.EMPTY),
-        "FAULT_DISABLED":
-            ([AdminMode.NOT_FITTED, AdminMode.OFFLINE], DevState.FAULT, ObsState.EMPTY),
-        "INIT_ENABLED":
-            ([AdminMode.ONLINE, AdminMode.MAINTENANCE], DevState.INIT, ObsState.EMPTY),
-        "INIT_DISABLED":
-            ([AdminMode.NOT_FITTED, AdminMode.OFFLINE], DevState.INIT, ObsState.EMPTY),
-        "DISABLED":
-            ([AdminMode.NOT_FITTED, AdminMode.OFFLINE], DevState.DISABLE, ObsState.EMPTY),
-        "OFF":
-            ([AdminMode.ONLINE, AdminMode.MAINTENANCE], DevState.OFF, ObsState.EMPTY),
-        "EMPTY":
-            ([AdminMode.ONLINE, AdminMode.MAINTENANCE], DevState.ON, ObsState.EMPTY),
-        "RESOURCING":
-            ([AdminMode.ONLINE, AdminMode.MAINTENANCE], DevState.ON, ObsState.RESOURCING),
-        "IDLE":
-            ([AdminMode.ONLINE, AdminMode.MAINTENANCE], DevState.ON, ObsState.IDLE),
-        "CONFIGURING":
-            ([AdminMode.ONLINE, AdminMode.MAINTENANCE], DevState.ON, ObsState.CONFIGURING),
-        "READY":
-            ([AdminMode.ONLINE, AdminMode.MAINTENANCE], DevState.ON, ObsState.READY),
-        "SCANNING":
-            ([AdminMode.ONLINE, AdminMode.MAINTENANCE], DevState.ON, ObsState.SCANNING),
-        "ABORTING":
-            ([AdminMode.ONLINE, AdminMode.MAINTENANCE], DevState.ON, ObsState.ABORTING),
-        "ABORTED":
-            ([AdminMode.ONLINE, AdminMode.MAINTENANCE], DevState.ON, ObsState.ABORTED),
-        "FAULT":
-            ([AdminMode.ONLINE, AdminMode.MAINTENANCE], DevState.ON, ObsState.FAULT),
-        "RESETTING":
-            ([AdminMode.ONLINE, AdminMode.MAINTENANCE], DevState.ON, ObsState.RESETTING),
-        "RESTARTING":
-            ([AdminMode.ONLINE, AdminMode.MAINTENANCE], DevState.ON, ObsState.RESTARTING),
-
-    }
-
     def assert_state(self, machine, state):
         """
         Assert the current state of this state machine, based on the
@@ -98,22 +66,21 @@ class TestSKASubarrayStateModel(StateMachineTester):
             state of the state machine under test
         :type state: str
         """
-        # Debugging only -- machine is already tested
-        # assert self.model._state == state
-        # print(f"State is {state}")
-        (admin_modes, op_state, obs_state) = self.state_checks[state]
-        if admin_modes is None:
-            assert machine.admin_mode is None
-        else:
-            assert machine.admin_mode in admin_modes
-        if op_state is None:
-            assert machine.op_state is None
-        else:
-            assert machine.op_state == op_state
-        if obs_state is None:
-            assert machine.obs_state is None
-        else:
-            assert machine.obs_state == obs_state
+        assert machine.admin_mode == state["admin_mode"]
+        assert machine.op_state == state["op_state"]
+        assert machine.obs_state == state["obs_state"]
+
+    def is_action_allowed(self, machine, action):
+        """
+        Returns whether the state machine under state thinks an action
+        is permitted in its current state
+
+        :param machine: the state machine under test
+        :type machine: state machine object instance
+        :param action: action to be performed on the state machine
+        :type action: str
+        """
+        return machine.is_action_allowed(action)
 
     def perform_action(self, machine, action):
         """
@@ -126,9 +93,9 @@ class TestSKASubarrayStateModel(StateMachineTester):
         """
         machine.perform_action(action)
 
-    def check_action_disallowed(self, machine, action):
+    def check_action_fails(self, machine, action):
         """
-        Assert that performing a given action on the state maching under
+        Assert that attempting a given action on the state machine under
         test fails in its current state.
 
         :param machine: the state machine under test
@@ -149,7 +116,7 @@ class TestSKASubarrayStateModel(StateMachineTester):
             machine under test into
         :type target_state: str
         """
-        machine._straight_to_state(target_state)
+        machine._straight_to_state(**target_state)
 
 
 class TestSKASubarray:
@@ -163,7 +130,7 @@ class TestSKASubarray:
         'SkaLevel': '4',
         'LoggingTargetsDefault': '',
         'SubID': '',
-        }
+    }
 
     @classmethod
     def mocking(cls):
@@ -418,18 +385,19 @@ class TestSKASubarray:
         """Test for adminMode"""
         # PROTECTED REGION ID(SKASubarray.test_adminMode) ENABLED START #
         assert tango_context.device.adminMode == AdminMode.MAINTENANCE
-        assert tango_context.device.state() == DevState.OFF
+
+        tango_context.device.Disable()
+        assert tango_context.device.state() == DevState.DISABLE
 
         admin_mode_callback = tango_change_event_helper.subscribe("adminMode")
         dev_state_callback = tango_change_event_helper.subscribe("state")
         admin_mode_callback.assert_call(AdminMode.MAINTENANCE)
-        dev_state_callback.assert_call(DevState.OFF)
+        dev_state_callback.assert_call(DevState.DISABLE)
 
         tango_context.device.adminMode = AdminMode.OFFLINE
         assert tango_context.device.adminMode == AdminMode.OFFLINE
         assert tango_context.device.state() == DevState.DISABLE
         admin_mode_callback.assert_call(AdminMode.OFFLINE)
-        dev_state_callback.assert_call(DevState.DISABLE)
 
         # PROTECTED REGION END #    //  SKASubarray.test_adminMode
 
@@ -538,6 +506,8 @@ class TestSKASubarray:
 def resource_manager():
     """
     Fixture that yields an SKASubarrayResourceManager
+
+    :yields: a SKASubarrayResourceManager instance
     """
     yield SKASubarrayResourceManager()
 
@@ -546,6 +516,7 @@ class TestSKASubarrayResourceManager:
     """
     Test suite for SKASubarrayResourceManager class
     """
+
     def test_ResourceManager_assign(self, resource_manager):
         """
         Test that the ResourceManager assigns resource correctly.
@@ -582,7 +553,6 @@ class TestSKASubarrayResourceManager:
         """
         Test that the ResourceManager releases resource correctly.
         """
-        resource_manager = SKASubarrayResourceManager()
         resource_manager.assign('{"example": ["A", "B", "C", "D"]}')
 
         # okay to release resources not assigned; does nothing
@@ -625,40 +595,51 @@ class TestSKASubarray_commands:
             subarray_state_model
         )
 
-        all_states = {
-            "UNINITIALISED", "FAULT_ENABLED", "FAULT_DISABLED", "INIT_ENABLED",
-            "INIT_DISABLED", "DISABLED", "OFF", "EMPTY", "RESOURCING", "IDLE",
-            "CONFIGURING", "READY", "SCANNING", "ABORTING", "ABORTED", "FAULT",
-            "RESETTING", "RESTARTING",
-        }
-
+        machine_spec = load_state_machine_spec("subarray_state_machine")
+        states = machine_spec["states"]
         # in all states except EMPTY and IDLE, the assign resources command is
         # not permitted, should not be allowed, should fail, should have no
         # side-effect
-        for state in all_states - {"EMPTY", "IDLE"}:
-            subarray_state_model._straight_to_state(state)
+        for state in set(states) - {
+            "EMPTY_ONLINE",
+            "EMPTY_MAINTENANCE",
+            "IDLE_ONLINE",
+            "IDLE_MAINTENANCE",
+        }:
+
+            subarray_state_model._straight_to_state(**states[state])
             assert not assign_resources.is_allowed()
             with pytest.raises(CommandError):
                 assign_resources('{"example": ["foo"]}')
             assert not len(resource_manager)
             assert resource_manager.get() == set()
-            assert subarray_state_model._state == state
+            assert subarray_state_model.admin_mode == states[state]["admin_mode"]
+            assert subarray_state_model.op_state == states[state]["op_state"]
+            assert subarray_state_model.obs_state == states[state]["obs_state"]
 
         # now push to empty, a state in which is IS allowed
-        subarray_state_model._straight_to_state("EMPTY")
+        subarray_state_model._straight_to_state(**states["EMPTY_ONLINE"])
         assert assign_resources.is_allowed()
         assert assign_resources('{"example": ["foo"]}') == (
-            ResultCode.OK, "AssignResources command completed OK"
+            ResultCode.OK,
+            "AssignResources command completed OK",
         )
         assert len(resource_manager) == 1
         assert resource_manager.get() == set(["foo"])
 
-        assert subarray_state_model._state == "IDLE"
+        assert subarray_state_model.admin_mode == states["IDLE_ONLINE"]["admin_mode"]
+        assert subarray_state_model.op_state == states["IDLE_ONLINE"]["op_state"]
+        assert subarray_state_model.obs_state == states["IDLE_ONLINE"]["obs_state"]
 
-        # AssignResources is still allowed in ON_IDLE
+        # AssignResources is still allowed in IDLE
         assert assign_resources.is_allowed()
         assert assign_resources('{"example": ["bar"]}') == (
-            ResultCode.OK, "AssignResources command completed OK"
+            ResultCode.OK,
+            "AssignResources command completed OK",
         )
         assert len(resource_manager) == 2
         assert resource_manager.get() == set(["foo", "bar"])
+
+        assert subarray_state_model.admin_mode == states["IDLE_ONLINE"]["admin_mode"]
+        assert subarray_state_model.op_state == states["IDLE_ONLINE"]["op_state"]
+        assert subarray_state_model.obs_state == states["IDLE_ONLINE"]["obs_state"]