Automation/Orchestration Design Patterns

I’m in OH2. I’d be interested to see an example of what this looks like once the OH2 support is complete and ready for the average user’s consideration.

You would still have to write the logic to deal with the inadequacies of the underlying technology. So what does OO really buy you? What benefit is gained by adding yet more complexity to OH overall and adding another place where one can write behavior logic? I just don’t see the benefits. All I see is “I like to solve problems using OO.”

Solving these sorts of inadequacies with the underlying technologies is one of the main purposes of the Rules layer. I really do not see the benefit of having a two layer logic where solving one type of problem requires using one type of coding and other types of logic require a different type of logic.

I guess it comes down to, why do you think solving these sorts of problems are not Rules?

In an ideal world, the lock would report appropriately. But this is home automation, about as far as we can get from ideal.

Boy, you would have hated OH 1.x. Things are so much better abstracted now that we have Things and Channels. Imagine the complexities we faced when ALL we had were Items and everything had to be declared and configured on the Item.

So let’s go back to my point 2 above and elaborate on what I mean by OH being an event based system. In OH we have Items. Items change state based on external stimulus (update from a Channel, 1.x binding, or from a Rule). State changes and updates are events.

Rules get triggered by events, either from Items or Time or system events (e.g. system started). The body of a Rule is to perform some logic in response to the event. Often that logic is to change the state of one or more other Items.

So one can view as defining an event stream. I think this is one of the reasons why systems like NodeRed are so successful because they make this event stream flow much more apparent given their graphical lines and nodes presentation.

Given this, writing a Rule to handle linking the ALARM events t the lock’s Switch seems perfectly natural. In fact, it is probably one line of code (minus the rule boilerplate) and there is no need for a proxy Item.

rule "Lock manually opened"
when
    Item MyLockAlarm received update // don't know this device so don't know if you get a command or just an update
then
    MyLock.postUpdate(ON) // I'm assuming the Lock is represented as a Switch
end

Of course, this is an aberrant case. Chris already has an Issue to correct this in the Binding.

BUT, now that I read more closely what you are really objecting to is the extra Things and Items, not the Rule themselves.

I really don’t see how adding an OO logic layer would help you in this case either. Things are the abstraction layer to the outside world. Each Thing has one or more Channels or control and/or information. This is how devices are abstracted to OH. So even if you had some OO logic on your Lock Thing, you would still need to write the code like the above. You would still need to deal with both Channels.

So is it really worth completely reworking the entire OH architecture to solve a 6 LOC problem? (one for the Item linked to the Alarm Channel and five for the complete Rule). It could even be 1 if you don’t mind run-on lines of code.

Unfortunatelty, every system I have dealt with like OH across multiple domains will have one or more places where an abstraction layer is incapable of completely hiding the complexity of the layer below. In OH2’s case that is the Things layer. It is sooooo much better now but the complexity is still there. But the Things and Items layers are declarative by nature. So the complexity really comes from the proliferation of them, not inherent logic. So personally I’d rather have lots of the Things and Items if I can make all my logic concise and easy to write and read. I think OH 2 is successful in this regard.

“I can program Fortran in any language.” :slight_smile:

Here’s the point I’m trying to make when I say Rules are event based. There are no separations of concerns or isolation from change in an event-based system, at least not in the way you think about from an OO perspective. Instead of Objects, you have Actors. Actors are atomic isolated chunks of logic that process an event in an isolated fashion and which cause change through well defined and constrained interfaces. In a way, an Actor is like an Object that has no state, only methods. Actors are great because they scale really well because they process each event in isolation. They also work great because their ability to modify state is tightly constrained.

In the Rules DLS’s case, the Actors are the Rules. The system state is stored in Items (and sometimes in global vals/vars which are a whole other philosophical discussion; suffice to say global vals and vars are kind of like primitives in Java, incredibly useful but totally antithetical to the purity of the programming paradigm). The interface for changing state is sendCommand and postUpdate.

The language isn’t a wild free for all where anything goes. It is in fact very constrained with very strong isolation. But it is following an Actor based model, not an OO model. I’ll also add that as an Actor based language, the Rule’

I completely agree and that is one of the major accusations against the DSL that I wholly agree with. It is not based on a popular language (I’d never heard of Xtext before using OH), the documentation leaves much to be desired, and even then there have been so many modifications to create the Rules DSL that one has to be careful with the documentation that does exist for Xtext (e.g. there are no classes or arrays in the Rules DSL but there are in Xtext).

I’ve found in my years helping newcomers on this and the old forum that the only users who end up hanging themselves in complexity are the programmers who come to the Rules DSL expecting it to work like an OO or procedural language. The non-programmers seem to do pretty well with it largely because they don’t come to it with any preconceived notion of how it ought to work.

I too struggled with the language for well over a year. My rules were lengthy, complex, brittle and ugly. I felt like the language was fighting me every step of the way. “Come on, I can only pass 7 arguments to a Lambda?!” “Really, there are not arrays?! How am I supposed to save this data structure?” So I started to study the architecture a little more closely and I realized:

  1. The language is best thought of as an Actor based language with the Rules being the Actors.
  2. State really belongs in Items, not global vars and vals
  3. Use Groups to create “data structures” out of your Items

With these realizations, the light bulb went off and I’ve really grown to appreciate how well suited this style of programming is to this domain. As I applied them across my rules I saw a drop from

It’s not perfect. @Spaceman_Spiff will be sure to tell you that JSR233 with Jython runs much faster (does it work in OH 2 yet?). There is no mechanism for reusable libraries. It isn’t a well-known language and is relatively poorly documented. While it will let you code in a more OO style should you choose, realize it won’t address your problems with the proliferation of Things and Items. That layer remains unchanged.

Nor do the developers of OH 2 which is why they are building a replacement for the Rules DSL (more on that below).

Just realize you are not the first to bring this up. There are dozens of similar threads on this and the old Google Groups forum discussing this exact issue. There is a whole binding written to allow users who simply do not want to use the Rules DSL to program using more OO style languages like Jython or JavaScript.

Then you are referring to the Experimental Rules Engine. This is a complete rewrite of the Rules Engine into a new language which is being positioned I think to better support graphically writing rules (a la Scratch and NodeRed) and code reuse. So I could, for example, write a State Engine library and share the library, not just post an article with the code on how to write your own. That is what he means by Recipies and Templates.

I don’t mean to say OO can’t solve the problem nor that it isn’t a good choice in many cases. But given the interface, OH presents to the Rules I’ve found in my experience (having had to code to similar interfaces both ways in the past) that an Actor based approach results in shorter, simpler, easier to reason about and model, and easier to debug code than the OO approaches.

It largely depends on the amount and types of information that needs to be processed through the events. There are relatively few event types and relatively few data types one has to contend with in the Rules DSL. I’ve found in those situations an Actor based approach works better.

So, just to be clear because I do see that some of the things I say do seem like generalizations, I’m primarily referencing event driven systems with relatively few event types and states.

That is mostly what I mean. I’m mainly talking about the Item based approach to integrating events and state to the rules. I think my thoughts would hold equally well under OH 1.x.

The Rules DSL is really like an Actor based language. I don’t think it is strict enough to truly be considered one. But thinking about it as one I find really helps one reason about and write their rules.

Clearly, I’m not one to back away from such a debate. And I’m even willing to have my mind changed. :slight_smile:

By closely-related data, I assume you mean Items?

So I have my closely-related data in the same Group and process events on those Items through the same Rule(s). I have lambdas as extension points to override behaviors (see this). And I don’t have to teach non-programmers the surprisingly difficult to grasp the concept of OO in order for them to start coding rules.

And I still don’t understand the “spilled across Items and Rules”. OO is a different way to slice and dice the problem but I don’t see it actually addressing the problem that you will have multiple implementations to handle multiple different cases.

I am, and that makes much more sense. Even when I wrote that a little voice in the back of my mind said “really, does Go run on the JVM?” but I was tired so didn’t go check.

Sorry

It should be pretty much the same as documented here.

4 Likes

@rlkoshak: I really admire the patience you have explaining stuff to people!
Keep it up - I really like it! :thumbsup: :slight_smile:
The community lives from people like you.

3 Likes

@rlkoshak, I really appreciate the effort you invest in supporting the user community. You are a valuable asset to the project and I have great respect for you. However, this is one topic where we have very different opinions.

The language is best thought of as an Actor based language with the Rules being the Actors.

It seems to me that OH Rules are quite different than Actors in the Actor model of computation. For example:

  • Actors can have private state. Rules can’t.
  • Actors process messages sequentially. Rules don’t (mutexes may be required).
  • Actors can create other Actors. Rules can’t create other Rules.
  • Actors have an address for receiving messages. Rules don’t.
  • Actors can send messages to an actor address. Rules can’t send messages directly to other Rules.

The purposes are different too. The Actor model of computation is addressing asynchrony, concurrency, and fault tolerance. My understanding is that the OH Rule Engine was a replacement for the Drools engine they previously used. Drools is a Rete-based forward-chaining inference engine (production rule system) and is not well-suited for home automation applications. The OH Rule Engine is an improvement in several ways, but I wonder if the automation support would have evolved in a different direction without the Drools influence.

Here’s another way to look at it. Someone can create simple rules in Jython or Javascript as easily as with the Rule DSL (and with well-documented languages, third-party library support, and a variety of IDEs). However, they can do much more with the JSR223 languages. You mentioned several benefits already. Having the option (not requirement) to use OO techniques is just one of the benefits. You could use functional programming or procedural techniques, for example. If someone is interested in abstractions (very useful for modeling real-world objects like devices and services), polymorphism, encapsulation and all the other benefits of OO, they at least have the option to use it. I know you say the limitations of the Rule DSL are its strength for new users, but if they can effectively program the lambda/Group-based workarounds you promote with the DSL, I believe they can write programs in any of the supported JSR223 languages.

State really belongs in Items, not global vars and vals

Items are just a different type of global variable that generates update/changed events.

Use Groups to create “data structures” out of your Items

This is limited and inflexible, but I do understand the issue of “when you only have a hammer…”. You can create a Group of Items for a specific purpose (like a motion/light/presence-controls lighting actuator) and use nested lambda functions to extract information from the items. But what about the second instance? You could create a Group of Groups and another level of lambda functions and the code becomes even more complex. Or one could create a copy of the rule implementation. With an OO approach, you just create another instance of the class (same implementation, different state).

For example, I’ve created a ClockDrivenCommand class. Instance can be constructed with a cron spec or with an absolute time of day (which is parsed and converted into a cron spec in the implementation). Now, my associated “rule” instance declarations look like:

...
ClockDrivenCommand("17:00", CarportLight, ON),
ClockDrivenCommand("23:00", CarportLight, OFF),
...

It would be easy to make this even more terse and have something like:

OnBetween(CarportLight, "17:00", "23:00")

Sure you can write DSL Rules for each of these, but if you have 20 or 30 or more of them it becomes messy. If you want to make a small change to the implementation, then every rule must be edited.

For example, if I want to add additional behavior to only enable some schedules when the house is in “vacation mode”, then I just subclass ClockDrivenCommand and create a VacationCommand class that uses an Item (so it can be controlled from the UI) to determine the vacation mode. All the rest of the functionality is inherited from ClockDrivenCommand.

As another example, I have several IP surveillance cameras. I have created a class that represents a camera and manages all the related Items and external behavior (API calls to take snapshots, turn on/off motion control, parse the network logs to look for suspicious IP addressed, send security notifications, etc.). When I buy a new camera I just create a new instance of that class and I’m done. Almost. Of course, I still have to define the Items separately. However, in OH2 I’ll be able to create the “private” items automatically from JSR223 code. Even for the UI items, I’m going to experiment with generating those automatically and using a site map template to automatically include new aggregates of items related to a specific function.

I do something similar for motion-controlled lights, where the class implements relatively complex functionality (daytime determination, light level detection, stale data detection, etc.) and I just create a new instance when I get a new motion detector and I want to control one or more lights or other on/off actuators.

By closely-related data, I assume you mean Items?

No, I don’t mean that. Items are one way to represent data and data structures. Other languages, like Python have far more powerful support for data structures. With the Rule DSL (AFAIK) you are limited to Items or file-scoped variables. If I have private state, I’d prefer to keep it private (encapsulated), rather than in a global Item. It’s even worse that I have to edit a separate file to “declare” my private data Item (some people call these “virtual items”).

I’m mainly talking about the Item based approach to integrating events and state to the rules. I think my thoughts would hold equally well under OH 1.x.

There are triggers that are not Item based. In OH1 there is the “startup” trigger and time triggers. OH2 will be more flexible and there will be the possibility to define other trigger types that are not Item-based. As examples, there could be a file change trigger, a JMX MBean notification trigger, a process shutdown trigger, or a raw MQTT message trigger that bypasses the Things/Channels/Items. My point is that although Items are a key architectural component of OH, there are other possibilities in some cases.

I too struggled with the language for well over a year. My rules were lengthy, complex, brittle and ugly. I felt like the language was fighting me every step of the way. “Come on, I can only pass 7 arguments to a Lambda?!” “Really, there are not arrays?! How am I supposed to save this data structure?”

Dude, you are one persistent guy! I spent about 30 minutes with the Rule DSL and could immediately see the issues with it. I switched to JSR223 and never looked back. I’ve never felt like the language (Jython) was fighting me.

1 Like

I’m not ignoring you. I’m waiting to reply when I can sit at a real keyboard.

My initial thought is perhaps I’ve been a little too literal when I call the rules DSL an actor based language. I mean it to mean it helps, at least it helps me, to approach rules from that mental framework. But I clearly see that is not what my actual words that I’ve written say.

More discussion to follow…

I’m willing to accept others have differing opinions. I’m even willing to accept I may be wrong. :slight_smile:

So what I mean by this statement is that approaching the Rules DSL from the mental framework of an Actor based programming paradigm is helpful. If one things about Rules as Actors I find, at least for me, it leads to better rules. I’m well aware that the Rules DSL falls far short of a true Actor Based programming language.

Perhaps my insistence of comparing it to an Actor based language is more confusing than helpful, despite how much it has helped me reason about my rules.

If one uses the old maxum “I can program Fortran in any langauge”…

One rule per file and a global var.

Actors _can_vprocess messages sequentially. They can also process them in parallel.

True.

I’d argue the entire “when” clause is the address for sending a message to an Actor. See this. The “address” of the “Dispatch Info Notification” is the Notification_Proxy_Info Item.

They can; see above.

All of which I think are very applicable to the Home Automation problem domain. And I think my argument is, even if the Rules DSL falls short of being a true Actor based langauge approaching it as if it were can result in rules that are more asynchronous, support concurrency, and fault tolerant.

That is a very interesting bit of history I was unaware of. I agree, I wonder if the Rules DSL would have gone in the same direction had it not had this history. Honestly, though I’m a bit of a Rules DSL champion, I am aware of its flaws. And I think I agree with @watou, it would be far better if the Rules DSL were based on a more common and well documented language (Python, JavaScript, Groovy, Luau, etc.) if for no other reason than we wouldn’t be responsible for writing the language documentation.

But it is the default language and so I try to come up with ways to approach the language so users and avoid some of the pitfalls they might encounter if they were to try and treat the DSL as if it were an OO or procedural language. I hope you would agree, the Rules DSL is neither one of these. And trying to code in it as if it were will lead to trouble. That is truly the problem I’m trying to address. I tend to try to explain things using similis and metaphores. If using the Actor Based paradigm as a simili is not helpful I’m very willing to use something else.

I don’t think I’ve ever argued against this. I completely agree: one has more libraries, better documentation, and more overall language support with any of the languages in the JSR223 languages than ever will exist with the Rules DSL, or the Experimental DSL for that matter. None of my defenses of the Rules DSL is intended to be in any way mean that these languages are less capable.

Where I’m coming from is that:

  1. The Rules DSL is the default so for most users it will be THE way to write rules
  2. I find, if approached with a certain frame of mind, the Rules DSL is particularly well suited to event-based programming

So I guess my main point in defending the Rules DSL is not that other languages are worse but that the Rules DSL is pretty good in its own right.

Point taken. I agree.

Actually, I find that using Groups like I describe here there is very rarely a need for lambdas at all. That is one reason I promote their use so heavily. If you have lambdas I treat that as a slight code smell. If you have nested lambdas I start to look for the skunk. That doesn’t mean those are never appropriate, but I’ve found that more often than not using Groups leads you to a place where you don’t need lambdas at all. It is all in the rules themselves and there is no need to call out to a lambda.

And I think that is my point. When programmers approach the rule as a procedural or OO language they end up with HashMaps and Lambdas all over the place. You might even be passing whole HashMap data structures to lambdas to get over the 7 argument limitation in lambdas. I say this because that is what my rules looked like once upon a time.

But by tagging like Items with Groups one can centralize their processing into the Rule, no more need to lambdas or data structures.

Granted, this does move some complexity from your rules to the items files because the number of Groups can proliferate quite a bit. And there are some limitations with the OH architecture that make this approach a little clunky (e.g. the Thread::sleep that is required to give persistence a chance to catch up when figuring out which Item triggered a rule).

So on this point, I disagree. One would create a single Group, applying this, and have a single chunk of code in one rule to process that specific purpose. When one uses Groups, one can treat their Groups as if they were Databases (a NoSQL database to be specific, there is even a map/reduce methods).

For the second instance, one would create a second Group and, if the first rule was complex enough, move the common parts into a lambda called by these two rules, if not duplicate the two to three lines of common code and just have the two rules. Or one might simply add and if/else to their existing rule to handle the two cases. It all depends on how different the two are and how complex the behaviors are.

The code remains actually very simple and easy to understand.

That is what I am trying to get across with my Design Pattern postings, my defenses of the Rules DSL, and trying to bring in the mental framework of Actor Based Programming. Applying Groups and the well-defined operations on Groups one can move A LOT of rule complexity into the Items files and out of the Rules. Honestly, I think these approaches also would apply very well to JSR233 languages as well and when/if that plugin ever makes it into OH 2 I plan on revisiting all of my Design Patterns and adding at least a Jython (I like Python) and JavaScript versions of those where it is applicable.

And at some point, I would like to combine all of those into a unified document for how to approach the Rules DSL. I’ll probably get around to it six months after the Rules DSL becomes deprecated. :wink:

An example may be informative. Here is my lighting rule:

val logName = "lights"

rule "Set lights based on Time of Day"
when
  Item vTimeOfDay changed
then
  val offGroupName = "gLights_OFF_"+vTimeOfDay.state.toString
  val onGroupName = "gLights_ON_"+vTimeOfDay.state.toString

  logInfo(logName, "Turning off lights in " + offGroupName)
  val GroupItem offItems = gLights_OFF.members.filter[g|g.name == offGroupName].head as GroupItem
  offItems.members.filter[l|l.state != OFF].forEach[l | l.sendCommand(OFF)
  ]

  logInfo(logName, "Turning on lights for " + onGroupName)
  val GroupItem onItems = gLights_ON.members.filter[g|g.name == onGroupName].head as GroupItem
  onItems.members.filter[l|l.state != ON].forEach[l | l.sendCommand(ON)
  ]

end

It is a basic timer based rule that turns on and off lights based on the time of day.

The Items are:

Group:Switch:OR(ON,OFF) gLights_ALL "All Lights"

Group:Switch:OR(ON, OFF) gLights_ON
Group:Switch:OR(ON, OFF) gLights_OFF
Group:Switch:OR(ON, OFF) gLights_ON_MORNING    (gLights_ON)
Group:Switch:OR(ON, OFF) gLights_OFF_MORNING   (gLights_OFF)
Group:Switch:OR(ON, OFF) gLights_ON_DAY        (gLights_ON)
Group:Switch:OR(ON, OFF) gLights_OFF_DAY       (gLights_OFF)
Group:Switch:OR(ON, OFF) gLights_ON_AFTERNOON  (gLights_ON)
Group:Switch:OR(ON, OFF) gLights_OFF_AFTERNOON (gLights_OFF)
Group:Switch:OR(ON, OFF) gLights_ON_EVENING    (gLights_ON)
Group:Switch:OR(ON, OFF) gLights_OFF_EVENING   (gLights_OFF)
Group:Switch:OR(ON, OFF) gLights_ON_NIGHT      (gLights_ON)
Group:Switch:OR(ON, OFF) gLights_OFF_NIGHT     (gLights_OFF)
Group:Switch:OR(ON, OFF) gLights_ON_BED        (gLights_ON)
Group:Switch:OR(ON, OFF) gLights_OFF_BED       (gLights_OFF)

Switch aFrontLamp "Front Room Lamp"
  (gLights_ALL, gLights_ON_MORNING, gLights_OFF_DAY, gLights_OFF_AFTERNOON, gLights_ON_EVENING, gLights_OFF_NIGHT, gLights_OFF_BED)
  { channel="zwave:device:dongle:node3:switch_binary" }

Switch aFamilyLamp "Family Room Lamp"
  (gLights_ALL, gLights_OFF_MORNING, gLights_OFF_DAY, gLights_ON_AFTERNOON, gLights_ON_EVENING, gLights_OFF_NIGHT, gLights_OFF_BED)
  { channel="zwave:device:dongle:node10:switch_binary" }

Switch aPorchLight "Front Porch"
  (gLights_ALL, gLights_OFF_MORNING, gLights_OFF_DAY, gLights_OFF_AFTERNOON, gLights_ON_EVENING, gLights_OFF_NIGHT, gLights_OFF_BED)
  { channel="zwave:device:dongle:node6:switch_binary" }

So the theory of operation is I add a Light to the “ON” group that corresponds to the time period I want the light ON and the “OFF” group that corresponds to the time period I want the light to be OFF. So all that complicated if/then/else logic goes away simply through prudent naming of my Items and use of Groups. If I want to add a new time period or dozens of new Lights and never have to touch this 20 LOC or so Rule. No lambdas. No data structures (outside of the Groups). Very simply rules.

And when I go back to using the weather to drive my lighting (i.e. turn them on when the weather is cloudy) I’ll add those lights to a Group and add a Rule that gets triggered by the weather changing and figure out which lights to turn on and off based on group membership.

Actually, I would end up having one Rule with 20 or 30 triggers and maybe a switch statement. I’d need to see a concrete use case to say how I would implement it. To add a mode to only enable some schedules when the house is in vacation mode I would either have some if/else or switch statements or potentially one additional rule. So this is why I challenge the OO paradigm. You have one additional function and so do I. Mox nix, no?

And I just add the new camera to my “gCameras” group and I’m done. I might need to add some additional code in the form of Rules if the Item based interfaces are different enough (see Separation of Behaviors). I will grant that the Rules DSL code may not be packaged up into as convenient of a package as a class, but I don’t think it takes any more code to implement. You have to override certain methods and I may have to write a new Rule for certain behaviors.

I completely agree. But I’ll also say that Groups are exceptionally powerful in this regard. They are akin to the way Perl makes everything a hashmap. The language only gives you one really big hammer but wow its a really powerful hammer. Maybe closer to Dr. Who’s Sonic Screwdriver. :wink:

Global is global to a single file, not global to all Rules. You can divide your rules such that “global” vals and vars are only available to the rule or rules that should have access to them. I put “global” in quotes because it is somewhat of a misnomer. They are only global to the one file. So from that perspective, depending on how one organizes their rules files, “global” vals and vars can be every bit as private as a private member of a class. This is one reason I recommend users divide their rules by function rather than geographic location. It more naturally leads to the vals and vars being only available to those rules that should have access to them.

I do agree, the Rules DSL does not enforce this or make it obvious (e.g. like Java’s one class per file). That is one of the many flaws in the Rules DSL. But one can still encapsulate data.

Virtual Items serve a different purpose. And I actually hate that name and prefer to call them “Unbound Items”. Virtual Items are intended to:

  • act as a summary Item, combining the states from multiple disparate Items
  • act as a proxy to provide a layer of separation between the rest of the system and a device (e.g. provide a mechanism to override the controlling of a light under certain conditions)
  • store some public state that may be needed across the system (e.g. Time of Day

If you have private state you want to store, it is best stored as a “global” var or val in a rules file containing only those rules that need that data. Virtual Items are not meant to store “private” state.

From the beginning I wanted to be a resource on the forums to new users. That meant using a pretty standard OH config and being comfortable with the default Rules DSL. And it took some time of fighting with the language to realize that if I bend to what the way the language wants to do things and take advantage of what the OH architecture provides (persistence, Groups) rather than trying to impose my own OO/Procedural (I even tried functional but the 7 arguments to a lambda put the kaibosh on that) I found that the language really does work. I can’t remember specifics (I could maybe look in my git history to see) but across the board, I achieved at least an order of magnitude reduction in my LOC by doing things the way the langauge wants. I have the same or more functionalty, vastly more maintainability, and more expandability. But each of my rules fits on a single Putty screen, none of my rules files are more than few pages, All of them are pretty easy to understand. I have a single lambda across all my rules and I could probably eliminate that if I took a little time to just sit down and do it.

But I had to bend to the langauge.

Had I not chosen to contribute to these forums as my way to give back to the community and I knew about the JSR233 binding I probably would have gone with Jython from the start. I’m kind of glad I did because I think it did make me grow as a programmer. I’m cautiously optimistic about the Experimental DSL. If it lives up to its vision, I’ll be able to just write a library of resusable code instead of these Design Pattern postings (I’d love to write a generic state-machine). I’m hopeful also about JSR support in OH 2 as I do believe options and alternatives are a good thing in this domain. Like I said above, I don’t think OO is necessarily inferior (though upon rereading I do come across as if I do, and I apologize for that). I just think that the Rules DSL is worth consideration.

1 Like

Where I’m coming from is that:

  1. The Rules DSL is the default so for most users it will be THE way to write rules
  2. I find, if approached with a certain frame of mind, the Rules DSL is particularly well suited to event-based programming

So I guess my main point in defending the Rules DSL is not that other languages are worse but that the Rules DSL is pretty good in its own right.

Pretty good relative to what? Yes, the Rule DSL supports event-based programming. However, it’s not any better at event-based programming than a JSR223 rule. In both cases, you have code execution that is triggered by the same OH events. The “when” triggering is almost identical. However, with JSR223 rules can have “templated” triggers or generate the triggers programmatically based on rule instance parameters. The “then” block of code is where the primary difference lies. With the JSR223 languages you have a richer set of options for programming techniques, data structures and for creating reusable, modular code. If you want to use OO techniques, that can done. If you want to use functional techniques, you can do that. You can even use Group-Oriented Item-based programming techniques where appropriate.

The fact that the JSR223 rule themselves are objects provides all the standard benefits of OO: abstraction, encapsulated state, polymorphism, code reuse and so on. And no, defining a DSL Rule per file and using file-scope variables is not the same as OO encapsulation.

I’m not interested in a debate about whether the Rule DSL is theoretically capable of implementing anything that can be implemented in JSR223. I’m assuming they are Turing equivalent. My focus is more on the pragmatics of how to most effectively implement OH automation functionality.

I agree that one advantage of the DSL is that it’s the “default” for OH. However, we’ve established that it is less powerful (relative to language features, documentation, libraries, IDEs, …) than the JSR223 languages. I believe that the Rule DSL is an inferior approach that requires even professional programmers to spend significant amounts of time to “bend to the language”. I don’t find much to like about it, especially since there are better options.

Actually, I find that using Groups like I describe here there is very rarely a need for
lambdas at all. That is one reason I promote their use so heavily. If you have lambdas I treat
that as a slight code smell.

Oddly, the page you linked to shows lambdas being used in many places (and so does the “Set lights based on Time of Day” example). To be clear, I’m not anti-lambda. You have some good examples on that page of using lambda and functional techniques in reasonable ways. However, I think that Group-Oriented programming where lambdas are used to access “fields” of data structures is a clumsy and nonperformant technique. I do understand that this may be the best or only reasonble choice you have with the DSL. I believe that you are giving excellent advice to DSL users and that your techniques are quite clever given the constraints you have.

Actually, I would end up having one Rule with 20 or 30 triggers and maybe a switch statement. I’d need to see a concrete use case to say how I would implement it. To add a mode to only enable some schedules when the house is in vacation mode I would either have some if/else or switch statements or potentially one additional rule. So this is why I challenge the OO paradigm. You have one additional function and so do I. Mox nix, no?

From my perspective, absolutely not. A switch statement with numerous cases that must be modified for each new scheduled action is not the way I want to implement my rules. I also don’t want to create Items for each triggering condition versus using a direct cron trigger that requires no triggering Item. I don’t want to effectively write my own scheduler by having a periodic rule trigger and then evaluating which time constraints are ready to execute. Note that this is a relatively simple use case. It’s better supported in JSR223 because the rule triggers can be parameterized. AFAIK, you can’t use a variable in a Rule DSL trigger. It wouldn’t make sense anyway because there is no support for abstract rule classes that can be instantiated with different trigger parameters.

But I had to bend to the langauge.

Had I not chosen to contribute to these forums as my way to give back to the community and I knew about the JSR233 binding I probably would have gone with Jython from the start. I’m kind of glad I did because I think it did make me grow as a programmer.

The good news is that you want to help people with their DSL programming issues (and you are good at it) and people that use the DSL will almost certainly need your help.

I’m cautiously optimistic about the Experimental DSL. If it lives up to its vision, I’ll be able to just write a library of resusable code instead of these Design Pattern postings (I’d love to write a generic state-machine).

You can do that already in the JSR223 languages and there are several GitHub repos created by users that contain reusable Jython code for OH (and least two for OH2 already).

Hi everybody.

I was not sure whether to post here or not, because for me this is a really deep discussion on programming techniques and all that stuff. And I’m not a programmer or developer at all. So I’m also quite sure I did not understand everything. I consider myself more or less a end user with some basic coding experience. But I think this is a really great and necessary discussion and I will try to add a (my personal) end user point of view.

But let my first say some words about my current experience with rules. I was using OH for about 2 years now (still 1.x branch) and all my rules are written with DSL. I’m aware of the jsr223 engine but never gave it really a try. And also I’m not familiar with the approach of the new experimental engine. So maybe I missed some opportunities to improve my code or do things more efficient compared to the current DSL rules I use.

The thing I was always missing with OH was the possibility to use pre-defined logic patterns (maybe from a official database) like many other home automation systems do (for example Edomi).

Let’s have a look at an (simple?) example: Heating control
I (as an end user) want to have a reusable pattern. I pass two temperature items (actual and target) and the heating mode. And all the logic happens inside a “black box” (is this an object?). I don’t have to care about how to implement a PID element or whatever. I don’t have to care about if-then-else clauses for the different heating mode and so on. Of course this is not as flexible as coding everything from the scratch, but it is easy to use.

I think the expire binding is a first step in this direction and similar to what I have in mind. Just use the binding and don’t care about timers or how to cancel them and so on. But when I want to use a expire time that should be adjustable over the ui the limits of this implementation are there.

I know this all can be done with the current engines, but my point is to lower the barrier for none programmers. And this could even be done with a graphical drag and drop interface like node-red or the mentioned Edomi. Just place your logic patterns on the screen and connect the input and output items. That’s it.

So far my point of view,
I’m looking forward to your comments and an interesting discussion.

Cheers
Sebastian

Personally, I’d like to see more of this and that’s why I try to promote the JSR223 scripting. In OH2, there will be even more opportunity to using JSR223 scripting to create reusable actions that implement a pattern like a PIR controller and that can be used by non-programmers with a UI-based rule editor. This will be an alternative to someone writing the action in Java and needing to know Eclipse, Maven, Git, OSGI and so on.

To follow up on the Actor discussion, note that Actor-based programming is not mutually exclusive with Object-Oriented programming. For example Akka (Java) and [Pykka] (https://github.com/jodal/pykka) (Python) Actors are class instances. In that sense, the JSR223 rule objects are closer to the Actor implementation in those frameworks than the DSL Rules. However, neither one has most of the properties, guarantees or benefits of an Actor-based implementation.

There is an interesting possibility if someone wants to use OH with an Actor model implementation. With JSR223, one could bypass the rule engine completely and tap into the events from OH/OSGI event bus. Those OH bus events would be processed by a bridge actor that would dispatch the messages to other actors that expressed an interest in those types of events. I’ve confirmed that Pykka works with Jython and even Akka could theoretically be used although I haven’t tried it.

Sorry for the tardy reply. I’ve been on travel then was ill. I’m just now playing catch-up on the forum. WAY behind…sigh.

The requirements of defining home automation logic.

This isn’t some zero sum game where if the Rules DSL is good it means JSR233 has to be bad. Beyond the fact that the Rules DSL is the language presented as the language for OH, and JSR233 doesn’t work on OH 2 yet I’d say they are all pretty good at solving this problem. My main purpose is to defend against the sentiment that the Rules DSL is crap and not worth consideration. Not to impinge on JSR233’s languages.

Frankly, if JSR233 became “the face of OH Rules” and worked in OH 2 I’d probably jump to coding my rules in Python in a heart beat.

I agree. JSR233 languages are awesome. I’ve never said otherwise. The awesomeness of JSR233 languages neither adds to nor takes away from the suitability of the Rules DSL.

I never said it was the same thing. I simply pointed out that some encapsulation is possible.

And I agree. And I think I’m coming from the point of view that:

  • the language should not be so complex that non-programmers need to go through a coding boot camp to define their automation logic
  • the types of programming logic required for home automation is not all that complex requiring all that extra complexities that come with OO and other programming paradigms. Said another way, the problems all of those concepts and approaches to programming are rare in this domain.

I may have miss spoke. I don’t see this as an advantage. This is merely an explanation for why I use it, continue to use it, and defend it. [quote=“steve1, post:36, topic:1967”]
I believe that the Rule DSL is an inferior approach that requires even professional programmers to spend significant amounts of time to “bend to the language”. I don’t find much to like about it, especially since there are better options.
[/quote]

I find programmers are the primary ones who have the problems with the language. And that is perhaps the crux of my argument. If we limit Rules programming to only programmers as the audience then we have failed as a community.

Honestly, I don’t think the Rules DSL is all that friendly to non-programmers either, but based on my experience on this forum and elsewhere it is far friendlier to non-programmers than Python or JavaScript are.

And every programmer everywhere “bends to” their chosen languages. The Rules DSL requires no more of a programmer to bed to it than Lisp requires of a Java programmer.

So I miss spoke again. What I’m really referring to here is named lambdas (i.e. a lambda defined at the top of a rules file and stored in a val). Indeed, every call in all of code that uses [ ] are lambdas.

I find it fairly comparable to working with NoSQL databases.

As for performance… show me the rampant problems and I’ll start to agree. Related to what I said above, performance problems in home automation appear to be rare.

So it comes down to personal preference. Which I’m fine with. But I don’t use my personal preferences to denigrate other approaches. And like I said above, I’d have to see a concrete use case to truly say how I would best solve the problem. I usually try to avoid switch statements and the like where I can but when what you end up implementing is a state machine (an admittedly major weakness in the Rules DSL) sometimes it is hard to achieve.

That is true.

Which is fine. It’s a different approach to solving the problem. An approach that I think would be completely beyond the reach or understanding of non-programmers.

I think of these sorts of problems like state machines where the “scheduler” is driving state transitions based on time. The state transition is the event that triggers rules or the rules check for the current state if that matters. I find this approach pretty simple to reason about, to implement in the Rules DSL, and most importantly to teach non-programmers. I would probably end up doing something similar in Python examples of the Design Patterns (which would probably be a whole different set) because of how much easier it is to teach to the non-programmers.

You haven’t missed anything. The Experimental Rules Engine is an OH 2 only thing and not really ready for prime time. I suspect that in its end form it will be basis for development of a graphical Rules editing UI.

That is indeed a stated goal of the Experimental Rules Engine.

And that is also a potential problem and the source of a lot of people migrating from other home automation engines. Often those products ONLY provide such black boxes which is great when the black box does what you want and major problem if it doesn’t.

And this could be an object or collection of objects (i.e. library).

This is indeed a major weakness in the Rules DSL. And I’m not trying to argue that the Rules DSL is great for non-programmers. It isn’t. I just find it better because it is significantly simpler than the other languages unders discussion.

I have conceeded that thinking about the Rules DSL as Actor Based is probably not helpful and will refrain from doing so from now on.

Someone could probably quickly prototype something using MQTT Event Bus (assuming these or other similar languages have MQTT libraries) to prove out the concept and avoid mucking around in OH internals.

@rlkoshak Hi I was hoping you may be able to help me. I have openhab running with my phillips hue bridge. I was able to get all of my phillips hue lights working properly and one sylvania lightify socket/on/off switch with the Phillips Hue Bridge. I grouped all of my lights in Paper UI as “All Lights Switch” however since I had to manually add the socket item via SSH it wont allow me to add it to the “All Lights Switch” group via Paper UI. Can you help advise how to get it to work with the group? Below is the home.items file

//Groups
Group:Switch:OR(OFF,ON) gAll_lights_Switch “All Lights Switch”

//Light Switches
Switch Dining_Room “Dining Room” (gAll_lights_Switch) [ “Switchable” ] {channel=“hue:0010:0017882f1db1:7:switch”}

/* Fibaro Sensors */
Number FibEye01_Movement “FE01 Movement: [%s]” (gZWave) {channel="zwave:device:15ecf0f7$
Number FibEye01_Temp “FE01 Temperature: [%.1f °F]” (gZWave) {channel="zwave:device:15ecf0f7$
Number FibEye01_Lux “FE01 Lux: [%.2f Lux]” (gZWave) {channel="zwave:device:15ecf0f7$
Number FibEye01_Bat “FE01 Battery [%s %%]” (gZWave) {channel="zwave:device:15ecf0f7$
Number FibEye01_Alarm “FE01 Alarm: [%s]” (gZWave) {channel="zwave:device:15ecf0f7$

It isn’t clear but I think your problem is you are mixing PaperUI and .items files. Since you are defining your Items in a .items file, do everything through the .items file. This means, do not add the Items to your all lights group through PaperUI. Generally, PaperUI is not able to do much of anything with Items bound to 1.x version bindings.

Thank you I was able to solve the issue by creating a “All Lights” Rule in paper UI. Now when i click the all lights button in habpanel the socket switches turn off along with all of the phillips hue bulbs.

1 Like

@rlkoshak

Hi rich, is this example from you working in OH 2.2 too?

val Functions$Function4 applySwitch = [ State state,
                                        boolean override,
                                        String whoCalled,
                                        SwitchItem light |
    if(state != light.state) {
        if(!override) {
            logInfo("Lights", whoCalled + " turning " + light.name + " " + state.toString)
            sendCommand(light, state.toString)
        }
        else {
            logInfo("Lights", whoCalled + " " + light.name + " is overridden")
        }
    }
]

I’ve tried to translate it to OH2.2 but ‘State’ is the problem, Error (State cannot resolved to a type).Any idea?

val Functions$Function4<State, Boolean, String, SwitchItem, Boolean> applySwitch = [state, override,  whoCalled,  light |
    if(state != light.state)
    {
        if(!override)
        {
            logInfo("Lights", whoCalled + " turning " + light.name + " " + state.toString)
            sendCommand(light, state.toString)
        }
        else
        {
            logInfo("Lights", whoCalled + " " + light.name + " is overridden")
        }
    }
    true
]

thats 5 input parameters, shouldn’t it be 4? I am not on OH2.2 but

val Functions$Function4 applySwitch = [ State state,
                                        boolean override,
                                        String whoCalled,
                                        SwitchItem light

works fine with oh1.1

@skatun
No this is correct, the last one is the return because it is a function not a procedure. And in OH 2.2 this is needed.

Found it,

import org.eclipse.smarthome.core.types.State

FWIW, you can still use the old syntax in latest OH. It’s throwing warnings but it’s working.

1 Like

That is surprising. I was under the impression that everything from org.eclipse.smarthome.core.types was imported by default.

Do you see the error when you run or just in VSCode/ESH Designer?

Since light is a SwitchItem, you can and should use the more specific OnOffType instead of State anyway. That should work without the import.