Automation/Orchestration Design Patterns

@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.

Hi Rich,

I have not tested it, just got the error in VC and tried to fix it here.

Maybe is will work without this line. I will try it tomorrow, but I like it to have no errors in VC code. Makes it more readable

I am getting following error when using Time of Day Design Pattern rule,

2018-07-19 05:15:44.924 [INFO ] [el.core.internal.ModelRepositoryImpl] - Loading model 'timeofday.rules'
2018-07-19 05:15:46.089 [INFO ] [el.core.internal.ModelRepositoryImpl] - Validation issues found in configuration model 'timeofday.rules', using it anyway:
The use of wildcard imports is deprecated.
The use of wildcard imports is deprecated.
The use of wildcard imports is deprecated.
Function3 is a raw type. References to generic type Function3<P1, P2, P3, Result> should be parameterized
The method getCalendar() from the type DateTimeType is deprecated
The method getCalendar() from the type DateTimeType is deprecated
The method getCalendar() from the type DateTimeType is deprecated
2018-07-19 05:15:46.093 [INFO ] [el.core.internal.ModelRepositoryImpl] - Refreshing model 'timeofday.rules'
2018-07-19 05:15:51.214 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Error during the execution of startup rule 'Get time period for right now': Could not cast NULL to org.eclipse.smarthome.core.library.types.DateTimeType; line 22, column 37, length 34

Any idea what is the issue?

Please see Design Pattern: Time Of Day