Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Internal conditional state transition #155

Closed
ETYFun opened this issue Apr 2, 2024 · 4 comments
Closed

Internal conditional state transition #155

ETYFun opened this issue Apr 2, 2024 · 4 comments

Comments

@ETYFun
Copy link

ETYFun commented Apr 2, 2024

I'm a novice trying to create an internally triggered state transition but was unsuccessful. Is there any way to trigger a state transition within the state machine instead of relying on external commands?

Here's my example timer code that should ring after 5 seconds:

import time

class Counter(object):
    machine = MethodicalMachine()

    def __init__(self):
        self.timer = 5

    @machine.state(initial=True)
    def _dormant(self):
        "not counting"
        self.reset()

    @machine.state()
    def _counting(self):
        "counting"
        print('in counting mode')
        self.countdown()

    @machine.input()
    def press_button(self):
        "press button to start count down"

    @machine.input()
    def stop_timer(self):
        "stop timer"

    @machine.output()
    def _click(self):
        "button clicks"
        # print('CLICKKKK')
        return 'CLICKKKK'

    @machine.output()
    def _ring(self):
        "ring once timer is zero"
        # print('RINGGGGGGGGG')
        return 'RINGGGGGGGGG'

    @machine.output()
    def countdown(self):
        "counting down"
        while self.timer - 0 >= 0:
            print(f'Timer: {self.timer} seconds')
            time.sleep(1)
            self.timer -= 1

        self.stop_timer()
        print('The timer should have stopped and reset')

    def _reset(self):
        "reset timer"
        self.timer = 5

    _dormant.upon(press_button, enter=_counting, outputs=[countdown, _click], collector=itemgetter(0))
    _counting.upon(stop_timer, enter=_dormant, outputs=[_ring])

# main
counter = Counter()
counter.press_button()

This code does not trigger a state transition to _dormant state (by _stop_timer). Please show me a way to correct this.

Thank you

@glyph
Copy link
Owner

glyph commented Apr 5, 2024

I think this is a duplicate of #41 . This example seems rather contrived though, can you explain what you're actually trying to do here? You can't trigger a state transition in an output, but then, this only provides one external method call (the press_button at the bottom) so I'm not sure why a state machine would be helpful to you at all for this example.

@ETYFun
Copy link
Author

ETYFun commented Apr 11, 2024

@glyph I'm trying to trigger a state transition based on internal timer or any conditional triggers. Not sure if the automat was originally developed for finite state machines or agents.

@glyph
Copy link
Owner

glyph commented Apr 11, 2024

A timer cannot be "internal" to the automat state machine, unless you're literally talking about time.sleep.

The usual solution here is a private input method with a public method that does the transition around it, but I think I would need a much more comprehensive picture of the actual application you are trying to build here, not just "internal state transition" or "conditional trigger". You can implement a conditional trigger in Python as an if statement so at that level it's not clear how that fits in to the state machine itself.

@glyph
Copy link
Owner

glyph commented Aug 19, 2024

Similar to #72 this should now be addressed by https://automat.readthedocs.io/en/latest/tutorial.html#conditional-state-transitions

@glyph glyph closed this as completed Aug 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants