[BETA] Simple State Machines

Simple State Machines for Hubitat *** BETA ***

Create state machines in Hubitat!

*** This is a BETA ***

I have not yet written up detailed instructions on install. This is a BETA, and should only be used by those already familiar with custom apps and drivers in Hubitat.

There are two custom apps and two drivers to install.

The best way to learn how to use this is to watch a Youtube video I made of it. The first 5 minutes are explaining the concepts. Skip to 5:03 if you just want to see the demo in action. Simple State Machines for Hubitat - YouTube

But until I write up full documentation, I will paste in the discussion that led me to create it:


FYI. I read your comment about state machines back when you made it, and it intrigued me. So for the last week, I've been working on an app for defining state machines in HE.

I'm a software engineer by trade, and I love state machines for certain applications. (Also the old saying about any class eventually becoming a state machine. The distinction is if you know that it's a state machine and plan it out, or you just allow states and transitions at random. The quote at the top of this article is excellent: How I Learned to Stop Worrying and ❤️ the State Machine)

So when I see people posting screenshots of their RM rules with multiple IF - ELSEIF - ELSE blocks with different conditions in each and they wonder why it doesn't catch an edge case, my engineer brain says "That's a place for a state machine!"

However, I'm torn over whether to release it or not. Even RM4 is edging into the point of being powerful enough for non-programmers to get themselves into a lot of trouble, as evidenced by those posts. It has the power to do recursive, iterative conditional logic. For users who aren't used to that kind of power, they don't realize the pitfalls. For professional engineers, we see certain patterns in code and think "code smell!" and then refactor and clean it up.

So for a professional, you see "smelly" code that can be simplified and more reliable by using a state machine. But the tradeoff is an additional level of abstraction. And for typical users, the abstraction of a well-defined state machine is not something they're used to seeing.

However, the most likely result is I release the app and no one uses it because it's too confusing. So I probably will release it when I feel it's ready.

One thing that would help me: what use cases would you want to use a state machine for? This is the first thing I've built for Hubitat that didn't come from one of my own needs. I've tried to keep my automations simple, and haven't needed a state machine yet. I'm just building it because it's cool.

To give an idea of the "spec" of my app:

  • ability to define "states"
    • a state is a child device that implements the "switch" capability, so you can use RM to perform actions either when you enter or leave a state.
  • ability to define "events"
    • an event is a child device that implements the "button" capability, so you can use any arbitrary RM rule or other app to trigger the event
  • ability to define "transitions"
    • a transition means that if you are in the "from" state, and the chosen event fires, the state machine should transition to the "to" state. (the from state turns off, and the to state turns on.)
  • don't re-implement RM. Rely on RM to perform actions from the state transitions. Rely on RM to trigger the events. Just be the core of the state machine that manages the state and transitions.
16 Likes

Followup on possible use cases:

  • Mode Manager sets a mode for your entire house. What if you need independent modes for individual rooms? That's a state machine!
  • You want to do something like "If A happens, and then B happens, and then C happens (IN THAT ORDER), then do action D. If any of these events ever occur out of order, just go back to waiting for A."
  • Your Rule Machine rule has gotten really messy, with multiple timers and delays and cancel-delays, and lots of if-then-else. You may have made a state machine without realizing it!
4 Likes

Hello: I just wanted to say that I've appreciated (and used) your code in the past.

Question: Can I use this simple state machine code for the following use case:

I have 4 Ikea Tradfri Bulbs on a Hoodfan in the kitchen. The bulbs are grouped together into a (HE) Group Bulb dimmer. The Tradfri have the ability to change colour (of white).
I'd like to put a Lutron PICO switch beside the Hoodfan. As I press the Up (or Down) button on the PICO, I'd like to vary the Kelvin Temperature of the bulbs (from 2000 -warm white to 4000 ice cold).
What do you think?

1 Like

I don't have any PICOs, so I'm not sure what events they fire, but I think there would be multiple ways to do what you're asking:

  • It probably could be done in Rule Machine, though I'm not very good at designing RM stuff off the top of my head. I kind've have to fiddle with it.
  • You could do it in Simple State Machines by defining states for each discrete color temperature. For example, states could be: Temp2000, Temp3000, Temp4000. And then you could have TempUp and TempDown events that would drive transitions between states. And you could use Rule Machine to fire the SSM events when you press the PICO buttons.
  • And a custom app could do it.
  1. The PICO is essentially a button device, used primarily for Lutron dimmers (but can be used for anything).
  2. Your concept of the simple state machine appeals to my engineering side.
  3. Yes, I'm sure I could do it with multiple IF THEN ELSE blocks in RM, but I'm sure your code will make it much more elegant. I'll give it a shot over the next few days.
1 Like

Joel,

Thanks for the time to put the code and video together! I haven't made it but 1/2 way through the video but I was so excited i wanted to post lol

I've been having throughts of something like this to make a complicated task easier in my house, which is trying to tame automation in my master bathroom to turn the lights on and off based on mode/motion/different-presses-on-my-Zooz-ZEN21

I've got three rules total:

  • one for the switch to set a global variable,
  • one for the motion to set the global variable
  • and lastly a rule to react to having the variable changed

it's a mess! and it doesn't work reliably enough, but I'm thinking the concept of your beta code would make this all better and more importantly, sensical, I'm definitely going to install the code today and give it a spin

Awesome! Yes, use of global variables and multiple rules to achieve one thing seems like a possible indicator of "this might be improved by redo-ing it as a well-defined state machine".

I can definitely see a use for this. Would it be possible to have the child events and devices be children of the parent State machine in the device list? I think this would be easier to manage/visualize.

Interesting idea. Right now the parent state machine isn’t a device. It’s an app. Although if I made a virtual device representing the state machine, I could make the states and events be children of it. I could probably make it expose a “current state” text field for display in dashboards too.

I don’t have much time in the next week, but I’ll mull this over.

1 Like

One complication to be aware of: I have specifically decided NOT to re-implement Rule Machine. That means that you need to use Rule Machine (or another tool) to fire off SSM's "events" as a result of other events happening in your home. And I have no way of visually connecting SSM to those RM rules, or showing that they are involved. So, if you make a bunch of rules, it could be easy to lose track of what is doing what.

My suggestion would be to define a naming scheme for your RM rules. So if you had a state machine called "Home Theater State Machine", and maybe you want an event to fire in it if a contact sensor on the door opens, I might make an RM rule and call it something like "Home Theater State Machine - Bind door contact sensor".

It doesn't really matter what your naming scheme is. Just that you have one to keep things organized.

These binding rules should be very, very simple and straightforward: "If trigger occurs, then fire off the "push" on the SSM Event."

The most complication in the rules that I might imagine would be:

  • Having multiple triggers that can fire the same event
  • Including a condition so that an event doesn't fire during a certain timespan. (Maybe the event can't fire at night or something)

If the rules are more complicated than that, it's probably a bad idea, and an indicator that your SSM states and events should be refined a little more. KISS principle!

1 Like

The beauty to this approach is that it does keep the logic for state transitions simple by separating the triggers that are watched (or cared about) in each state. This makes it easier to debug if the system is not behaving as expected.

Compared to a multilevel if-else if-else where you can easily have a trigger intended for another state have an effect when the specific trigger should be ignored.

Beautiful.

1 Like

Joel, this is a brilliant idea. Elegant = Simple yet Powerful. Thank you. I'm using it for tracking appliance states (washer, dryer, toaster, etc.) and for my mailbox.

1 Like

@jwetzel1492 Thank you so much for this, simple elegant & useful!!

1 Like

Just stumbled across this - great stuff!! Nice to see something designed for the widest range of use cases, it is very refreshing!

1 Like

@jwetzel1492 - thanks for publishing this, it's just what I was looking for!

On small request, I noticed that if the table is a little too big, it grows off the screen (see screenshot below) and there doesn't seem to be a way to view it.

Is it possible to put the text state transitions above or below the table and have the table left justified?

EDIT: just after I posted, I found that if I zoom out on my browser, it allows me to see the entire table.

1 Like

Thanks for sharing. This is what I was looking for and has a lot potential. When I purchased HE, I actually thought it would have a State Machine app integrated, maybe with drag&drop UI.
Creating states as boxes and dragging lines between as transitions, with simple logics. When I did read about RM, I thought it's something like that. Maybe someone knows Simulink Stateflow..?
Probably should have done better research on that topic.

Anyway, I would like to let you know that I miss a RENAME feature, next to ADD and DELETE. I often end up realizing I should rename some state or transition as I've iterated over the implementation.

I also agree with above post and would suggest that the transition-table visualisation would be better underneath the text, rather than next to it.

1 Like

Also, I just removed a state I made earlier and then got this error. It crashes the instance, so I can't enter it anymore. Which in return means I can't remove this app-instance, because there is no option to do so from the parent app..

[error] java.lang.NullPointerException: Cannot execute null+1 on line 458 (mainPage)

That's a really good idea, and I will add it to the backlog.

Shoot. Yeah, definitely a bug. I'm really glad some people are starting to use this app. While it's one of the more complicated ones I've made, it's also one of the least developed and "bulletproofed", because I haven't had a lot of users.

1 Like

Just want to say that this app is fantastic. I've tried to implement state machines within Hubitat using additional modes, variables, and even switches with all sorts of gobbly bits of rules and such. That was a mess.

This is what I've been looking to use for all sorts of applications. It's also an excellent way to learn how to separate state from action so we get a little bit of MVC going or at least a little M and C separation of concern. Thank you so much for building this.

I would like to go reimplementing a bundle of things in my home. The bug that @leinadleisure discovered is concerning. Have you had a chance to fix that?

Are you actively working on this? Are you considering making it a bit less beta and a bit more release?