Security System: Finite State Machine

FSM are an abstraction to perform state-based computing which are a collection of nodes with edges. In this tutorial an implementation of FSMs in Python are going to be shown as the start to a series to write a security system. The implemented FSM is basic and doesn’t provide things like interrupts or other necessities.

The requirements for the project are to provide a lightweight application which saves a video when movement occurs in front of a web cam with the ability to ping the person via email when movement occurs.

Different implementation could have an “init” state to set up the dependences but because of how they are going to be inserted the initialization happens elsewhere.

Before implementing this; try using the native app. Start the camera then scan through the footage when you come back inside. That way if a problem exists; you know it isn’t your application’s fault. You have to ask Apple and Microsoft to stop messing with you. Not sure how to send them the message though.

The abstract base class provides the necessary methods for every state.

from abc import ABC 
from __future__ import annotations
class State(ABC):
@abstractmethod
def __init__(self, *args):
raise NotImplementedError
@abstractmethod
def on_pulse(self, *args, **kwargs) -> str:
raise NotImplementedError
@abstractmethod
def on_event(self, event: str) -> State:
raise NotImplementedError

The pattern being on a tick the on_cycle method gets invokes which returns an event. The event is then given into the on_event which returns the new state.

The Idle state does nothing but wait for motion to occur.

class Idle(State): 
def __init__(self, cease: Cease, init: Init):
self._cease = cease
self._init = init
def on_pulse(self) -> str:
raise NotImplementedError
def on_event(self, event) -> State:
if event == MT:
return self._init
elif event == KS:
return self._cease
return self

The InitSaving state does nothing as of yet. In the later sections a job will be provided.

class InitSaving(State): 
def __init__(self, saving: Saving):
self._saving = saving
def on_pulse(self) -> str:
raise NotImplementedError
def on_event(self, event) -> State:
return saving

The Saving performs starts to record the footage.

class Saving(State): 
def __init__(self, writing: Writing, saving_idle: SavingIdle):
self._writing = writing
self._saving_idle = saving_idle
def on_pulse(self) -> str:
raise NotImplementedError
def on_event(self, event) -> State:
if event == MT:
return self
elif event == KS:
return self._writing
return self._saving_idle

The SavingIdle continues to save the footage, but a timer starts to count down unless movement takes place.

class SavingIdle(State): 
def __init__(self, writing: Writing, saving: Saving):
self._writing = writing
self._saving = saving
def on_pulse(self) -> str:
raise NotImplementedError
def on_event(self, event) -> State:
if event == MT:
return self._saving
elif event == TF || event == KS:
return self._writing
return self

The Writing state moves the recorded footage into the appropriate location.

class Writing(State): 
def __init__(self, idle: Idle):
self._idle = idle
def on_pulse(self) -> str:
raise NotImplementedError
def on_event(self, event) -> State:
return self._idle

The Cease state closes the open resources.

class Cease(State):
def on_pulse(self) -> str:
raise NotImplementedError
def on_event(self, event) -> State:
return self

Now the on_cycle needs to be implemented for each of the states; but before that the higher level abstraction which will help the transitions take place will be shown.

class FSM:
_state: State
_event: str
def __init__(self, starting_state: State):
self._state = starting_state
self._event = None
def on_pulse(self):
self._transition()
self._action()
def _transitions(self):
self._state = self._state.on_event(self._event)
def _action(self):
self._event = self._state.on_cycle()
Simple but effective structure.

From here different tools for profiling the FSM or generating plots can be added easily.

awake, software engineer.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store