class State(object):

    def __init__(self):
        pass

    @property
    def name(self):
        return ''

    def enter(self, machine):
        pass

    def exit(self, machine):
        pass

    def update(self, machine):
        if switch.fell:
            machine.paused_state = machine.state.name
            machine.pause()
            return False
        return True

class StateMachine(object):

    def __init__(self):
        self.state = None
        self.states = {}
        self.firework_color = 0
        self.firework_step_time = 0
        self.burst_count = 0
        self.shower_count = 0
        self.firework_stop_time = 0
        self.paused_state = None
        self.pixels = []
        self.pixel_index = 0

    def add_state(self, state):
        self.states[state.name] = state

    def go_to_state(self, state_name):
        if self.state:
            log('Exiting %s' % (self.state.name))
            self.state.exit(self)
        self.state = self.states[state_name]
        log('Entering %s' % (self.state.name))
        self.state.enter(self)

    def update(self):
        if self.state:
            log('Updating %s' % (self.state.name))
            self.state.update(self)

    # When pausing, don't exit the state
    def pause(self):
        self.state = self.states['paused']
        log('Pausing')
        self.state.enter(self)

    # When resuming, don't re-enter the state
    def resume_state(self, state_name):
        if self.state:
            log('Exiting %s' % (self.state.name))
            self.state.exit(self)
        self.state = self.states[state_name]
        log('Resuming %s' % (self.state.name))

    def reset_fireworks(self):
        """As indicated, reset the fireworks system's variables."""
        self.firework_color = random_color()
        self.burst_count = 0
        self.shower_count = 0
        self.firework_step_time = time.monotonic() + 0.05
        strip.fill(0)
        strip.show()

class PausedState(State):

    def __init__(self):
        self.switch_pressed_at = 0
        self.paused_servo = 0

    @property
    def name(self):
        return 'paused'

    def enter(self, machine):
        State.enter(self, machine)
        self.switch_pressed_at = time.monotonic()
        if audio.playing:
            audio.pause()
        self.paused_servo = servo.throttle
        servo.throttle = 0.0

    def exit(self, machine):
        State.exit(self, machine)

    def update(self, machine):
        if switch.fell:
            if audio.paused:
                audio.resume()
            servo.throttle = self.paused_servo
            self.paused_servo = 0.0
            machine.resume_state(machine.paused_state)
        elif not switch.value:
            if time.monotonic() - self.switch_pressed_at > 1.0:
                machine.go_to_state('waiting')
				
class WaitingState(State):
  
    @property
    def name(self):
        return 'waiting'

    def enter(self, machine):
        State.enter(self, machine)

    def exit(self, machine):
        State.exit(self, machine)

    def almost_NY(self):
        t = rtc.datetime
        return (t.tm_mday == 31 and
                t.tm_mon == 12 and
                t.tm_hour == 23 and
                t.tm_min == 59 and
                t.tm_sec == 50)

    def update(self, machine):
        if switch.fell or self.almost_NY():
            machine.go_to_state('dropping')
			
class DroppingState(State):

    def __init__(self):
        self.rainbow = None
        self.rainbow_time = 0
        self.drop_finish_time = 0

    @property
    def name(self):
        return 'dropping'

    def enter(self, machine):
        State.enter(self, machine)
        now = time.monotonic()
        start_playing('./countdown.wav')
        servo.throttle = DROP_THROTTLE
        self.rainbow = rainbow_lamp(range(0, 256, 2))
        self.rainbow_time = now + 0.1
        self.drop_finish_time = now + DROP_DURATION

    def exit(self, machine):
        State.exit(self, machine)
        now = time.monotonic()
        servo.throttle = 0.0
        stop_playing()
        machine.reset_fireworks()
        machine.firework_stop_time = now + FIREWORKS_DURATION

    def update(self, machine):
        if State.update(self, machine):
            now = time.monotonic()
            if now >= self.drop_finish_time:
                machine.go_to_state('idle')
            if now >= self.rainbow_time:
                next(self.rainbow)
                self.rainbow_time = now + 0.1
				
class IdleState(State):

    @property
    def name(self):
        return 'idle'

    def enter(self, machine):
        State.enter(self, machine)

    def exit(self, machine):
        State.exit(self, machine)

    def update(self, machine):
        State.update(self, machine)

Và main loop

machine = StateMachine()
machine.add_state(PausedState())
machine.add_state(WaitingState())
machine.add_state(DroppingState())
machine.add_state(IdleState())

machine.go_to_state('waiting')

while True:
    switch.update()
    machine.update()