Automation/Orchestration Design Patterns

Julian, any chance you can post your working code? I’m trying to do the same thing - kitchen switch which detects motion, but when I want light on permanently I want to override it at the manual switch. I go past my motion sensor on the way in and the way out.

Posting this here so I can easily find it later. Two more design patterns came to mind.

Separation of Behaviors

Problem Statement:
I have found in my rules and from helping others that often times certain sorts of checks, conditionals, etc. cross cut multiple functionality categories. For example, lighting and HVAC may both care about what time of day it is. Just about anything may want to send a notification. Lighting, blind/rollershutter controls/HVAC may all care whether it is cloudy.

What can often happen is the same logic gets duplicated in multiple places as the rules check for these states or generate the actions. For example, if today we are using my.openhab for notifications we might have a call to sendNotification() all over our files and if we decide we don’t like my.openhab and want to use Notify My Android instead we have to change it everywhere.

Concept:

Set up a proxy Item to represent the state or trigger the action and a rule to centralize the logic. There are two approaches depending on the direction of the logic.

The first approach is to set up a String or Number Item that your rules sendCommand some value to that triggers an action, such as sending a Notification. In this rule you can then start to take into consideration additional traits or add additional logic which would be difficult to implement across your files as lambdas such as, as illustrated below, use a different notification service depending on the time of day.

Items

String Notification_Proxy_Info
String Notification_Proxy_Alarm

Rules

val String logNameNotification = "notification"

rule "Dispatch Info Notification"
when
        Item Notification_Proxy_Info received update
then
        val String msg = Notification_Proxy_Info.state.toString
        logInfo(logNameNotification, msg)
        if(TimeOfDay.state != "Night") sendPushToDefaultDevice(msg)
end

rule "Dispatch Alarm Notification"
when
        Item Notification_Proxy_Alarm received update
then
        val String msg = Notification_Proxy_Alarm.state.toString
        logError(logNameNotification, msg)
        if(TimeOfDay.state == "Night") sendPushToDefaultDevice(msg) else sendNotification("email", msg)
end

I can send a notification with a simple Notification_Proxy_Info.sendCommand("Notification text!")

The second approach is to set up a proxy Item to hold the result of a complex calculation (e.g. a Number of a Switch) and the state of this Item is checked in other rules. For example, below I have a Weather_Cloudy Item Switch which gets set to ON when the Weather’s Condition ID says it is cloudy. By centralizing this check I can now react in rules across my environment without duplicating logic and change it if needed in one location (e.g. switch from Yahoo to Wunderground).

NOTE: This is an update to the Lighting rule int eh Group and Filter example above.

Item

Switch      Weather_Cloudy       "Conditions are Cloudy [%s]" <rain>

Rule

rule "Update Cloudy Switch"
when
        Item Condition_Id changed
then
    // Yahoo cloudy weather condition IDs
    val Set<String> yahooCloudyIds = newImmutableSet("0",   "1",  "2",  "3",  "4",  "5",  "6",  "7",  "8",
                                                         "9",  "10", "11", "12", "13", "14", "15", "16", "17",
                                                         "18", "19", "20", "26", "28", "35", "41", "43", "45",
                                                         "46", "30", "38", "29", "30", "44")
    // https://www.wunderground.com/weather/api/d/docs?d=resources/phrase-glossary
        val Set<String> wundergroundCloudyIds = newImmutableSet("2",  "3",   "4",  "6", "9", "10", "11", "13",
                                                                "14", "15", "16", "18","19", "20", "21", "22",
                                                                "23", "24")
        val isCloudy = yahooCloudyIds.contains(Condition_Id.state.toString)
        if(isCloudy && Weather_Cloudy.state != ON){
                Weather_Cloudy.sendCommand(ON)
        }
        else if(!isCloudy && Weather_Cloudy.state != OFF) {
                Weather_Cloudy.sendCommand(OFF)
        }
end

In the lighting rule I can check if it is cloudy with a simple Weather_Cloudy.state == ON.

Dead Man’s Switch

Problem Statement
This one is a bit more complex in both implementation and concept. Sometimes you are in a situation where you want to know where a certain command came from but there is no way built into the binding or the device to tell the difference between a manually initiated command at the device or a command initiated by a rule. For example, when one wants to override a rule’s behavior when a light switch is manually triggered.

Concept
Create a dead-man’s-switch which gets set to one value at all times except when a rule is running. When a rule runs it temporarily sets the dead-man’s-switch Item to something beside the default value then changes it back to the default value. A rule gets triggered for ALL changes to the device’s Item. This rule check’s the dead-man’s switch and if it is set to the default value we know the Item was manually triggered.

For example, in the Group and Filter rules above I have a dead-man’s-switch called V_WhoCalled which gets set to “MANUAL” by default, “TIMER” by the rule that changes the lights based on Time Of Day, and “WEATHER” when the weather lighting rule runs.

In a simpler and more genericexample:

Items

String DeadMansSwitch
Group gOverrideItems

// Switches, Dimmers, etc that are members of gOverrideItems which we want to know whether it was manually changed or not

Rules


// Set the Dead Man's Switch off of default during startup
rule "System Started"
when
    System started
then
    DeadMansSwitch.sendCommand("STARTUP")
    createTimer(now.plusSeconds(30), [| DeadMansSwitch.sendCommand("MANUAL")
end

rule "Timer Rule"
when
    Item TimeOfDay changed
then
    DeadMansSwitch.sendCommand("TIMER")
    Thread::sleep(50) // give it time to populate through the event bus
    // do stuff
    Thread::sleep(200) // give stuff time to complete
    DeadMansSwitch.sendCommand("MANUAL")
end

// more rules which trigger members of gOverideItems

rule "Is Manually Triggered?"
when
    Item gOverrideItems received update // we don't care if it triggers more than once per update 
then
    if(DeadMansSwitch.state.toString == "MANUAL") {
        // the Item was manually triggered
    }
end

In the rules above if the Item is updated at the device (assuming the device reports such updates) or on the sitemap DeadMansSwitch will be “MANUAL” and we will know the device was manually updated.

8 Likes

Nice !

One more design pattern to add here so I can find it again and reference is future posts.

#Group Persistence

Problem Statement
There are several reasons why a home automation enthusiast would want to use openHAB persistence: charting, using historical Item states in rules logic, restore previous values on openHAB restart, and my.openhab integration, detailed analysis, access to the data with external tools, etc. However, different databases are more or less well suited to each of these use cases.

Concept
Since no one persistence engine is best for all use cases, configure more than one and use Groups to allocate which Items get saved to which persistence engine and how.

For example, one can set up MapDB for restoreOnStartup, rrd4j for charting recent data and historical data, my.openhab for IFTTT integration, and MySQL for Items for detailed external analysis.

For each use case, create a Group and only use these groups in the .persist files.

Then allocate your Items to whatever group(s) based on how that specific Item will be used.

Example
In my current setup I restoreOnStartup on all my Items, I use rrd4j for charting and historical state, I have a couple of Items I expose to IFTTT through my.openhab, and no Items that I analyze or expose the DB outside of OH.

Items:

// Persistence Groups
Group gMyOpenhab // for Items that are exposed to IFTTT
Group gChart     // for Items to persist for charting
Group gHistory   // for Items to preserve their history
//Group gRestore // for Items to restore on startup (currently everything so commented out)

...
// Example Item that I Chart
Number          Weather_Temp_Min        "Minimum Outside Temp [%.0f] °F"        <temperature> (gChart, gWeather_Temp_Chart)

// Example Item that I use historical data
Contact       N_D_Front                        "Front Door [MAP(en.map):%s]"             <frontdoor>  (gHistory, gDoorSensors, gRemindDoorSensors, gAlarmSensors, gHydraSensors)    { mqtt="<[mosquitto:entry_sensors/main/front_door:state:default]" }

// Example Item that I expose to my.openhab NOTE: it is also a member of gHistory
Switch  T_D_Garage1     "Garage Door 1"         <garagedoor> (gHistory, gMyOpenhab, gGarageOpeners)

*mapdb.persist file: I only use MapDB for restoreOnStartup and restoreOnStartup applies to all Items

Strategies {
        default = everyUpdate
}

Items {
        // persist all items on every change and restore them from the db at startup
        * : strategy = everyChange, restoreOnStartup
}

NOTE: I don’t know if setting a default strategy is required, I included it anyway, but it is basically meaningless because it is never used in the Items section.

To make restoreOnStartup work we need to persist every change. The ‘*’ resolves to all Items.

rrd4j.persist file: I use rrd4j for both charting and historic data. Because of limitations of rrd4j data must be saved at least every minute for charting or else you end up with blank charts. I’ve also found getHistoricState and previousState do not work without saving every minute as well.

Strategies {
        // for rrd charts, we need a cron strategy
        everyMinute : "0 * * * * ?"

        default = everyChange
}

Items {
        // additionally persist weather info every minute
        gHistory* : strategy = everyUpdate, everyMinute
        gChart*   : strategy = everyUpdate, everyMinute
}

myopenhab.persist:

Strategies {
        default = everyUpdate
}

Items {
        gMyOpenhab* : strategy = everyUpdate
}

Advantages

The advantages of this approach include:

  • The persistence behavior for each Item is documented with the Item (i.e. the group membership) keeping as much information about the behavior of the Item in one place
  • Adding new Items or changing how they are persisted simply involves changing that Item’s group membership.
  • Once set up, the .persist files need never be changed unless you decide move from one persistence engine to another
  • Uses the best persist engine for the desired behavior. For example MapDB can save all types of Items but only keeps the last value do it is great for restoreOnStartup but not great for historic data whereas rrd4j is great for charting recent data but can’t save anything that isn’t a numerical value so isn’t so great for restoreOnStartup
12 Likes

Has modeling of things using an object oriented paradigm ever been discussed? I am admittedly new to making rules, but coming from OOP languages, I find it very frustrating that in modeling “things” in openHAB we have perhaps the most apt application of OOP in the history of the universe, and yet here we are stuck in procedural programming.

I’d prefer to be telling my things (objects) to turn off and let some internal logic to the thing that can be reused cleanly deal with the quirks of how that thing should be used. Like in the “someone’s still observed via motion in the kitchen, so we shouldn’t turn off the light yet even if someone tries to” case mentioned by the OP. I’d rather let that logic be baked into the thing (since that’s what it belongs to) rather than have it spilled out across many different items and rules.

I’m not familiar with recipes and templates, but I think that templates and recipes don’t really solve the root problem. They just make it someone else’s (still hard) problem. Better to use recipes to promote reuse, not as a cover up.

It’s probably a contentious topic, but am I off base here? What am I missing? Flame away…

I’ve posted on this before. I’ve not much time so I apologize for being terse.

  1. Rules deal with Items. Not Things.

  2. The rules dsl is not procedural. It is event based (think languages like Erlang). There is a reason why OO languages are rarely chosen in similar event driven systems (asterisk, freeswitch, tasker, telecom systems, etc)

  3. Given the architecture of oh it is debatable whether OO would be a superior approach. I’ve been a professional programmer using OO languages for close to two decades now so I do have experience to back up my opinion.

  4. Home automation behaviors rarely involve just one item or just one class of items. It’s usually all about reacting to events from one Item and generating events sent to other Items. For example, talking a motion sensor event and generating events to turn on the light, but only at night on week days when someone is home. That is a lot of items. It often is not clear on what items such logic would be appropriate to implement it on.

  5. I don’t understand what you mean about being spilled across Items and Rules. I see nothing that an OO approach would do to change this. Nor do I see anything sipping you from organizing your rules in a way too avoid this.

  6. I don’t know what you are referring to by “recipes and templates”. Is this something from the experimental rules engine? If so realize the primary purpose of the experimental rules engine IS to promote reuse. If not realize that recipes and templates are not terms or concepts used in the current rules dsl.

  7. The current rules dsl does not support reusable code. Hence the examples and design patterns to help provide known to work solutions to common problems until the experimental engine gets developed.

  8. If you don’t like the rules dsl, you can use the jsr233 binding and code your rules in jython or javascript, I think go is also supported. I don’t know if it works in oh 2 yet.

1 Like

I definitely had you in mind while writing this post since all of your posts about patterns are what got me thinking about this and because I see many of your posts have an academic mind set (I mean that in a good way).

Here’s an example of what motivated my post. It seems that when manually locked or unlocked, Z-Wave locks send an alarm message instead of updating the status of their lock “switch” (I don’t know the proper term).

So now it gets pushed onto me to handle that in my rules. I’d rather model my lock outside of my rules and interpret a “manually unlocked” alarm message as updating the status of the lock switch to unlocked. Maybe that “outside of my rules” place would be event-driven, but it seems like a good place to use OO.

So how would you handle this kind of scenario? I think you’d say that you’d create a proxy for the lock switch and change it’s status to “unlocked” when the manual unlock alarm message comes in. Maybe I just need to get over it, but I’d prefer to see the ability to replace the thing’s actual item with the proxy item and never have to look at the messy actual thing item ever again. If that was possible, then there wouldn’t be the clutter of non-ideal Thing items hanging around and the complexities of the Thing would effectively be hidden/abstracted from the rule design process. This kind of separation of concerns is what led me to my OO thinking.

Do you agree that there is room for improvement related to these kinds of scenarios?

To respond directly to some of your points:

I am referring to the way that rules do not really encourage proper separation of concerns and isolation from change. I have no doubt that rules can be used to do many things, but that’s kind of the problem. Rules and Items do nothing to encourage proper modeling of the problem they do not acknowledge the patterns that we know exist in this space. You are even perhaps implicitly acknowledging this point by posting patterns to stand in place of the lack of structure to the current rules.

It’s kind of backwards from what I’d like to see. I’d like to see the default rules paradigm be tailored and structured to make it easy to separate concerns and to isolate change, with the option to go to a less constrained rules language like the current one if your needs somehow can’t fit that common mold. Today, the user is pushed into the deep end right off the bat, free to hang themselves in complexity if they are not careful or don’t understand certain programming principles. I can’t see that standing up well in the long term. But I can see why the strategy of a project would start with the powerful language and then see what patterns develop to know how to design the eventual tailored, default language. To be clear, I’m not knocking the project, just trying to plant a seed on the idea of making things better.

I’m referring to Kai’s post here.

I probably should have started a new thread for this.

Overall, I think I need to gain more experience with designing complex rules before I go totally second-guessing everything. Then my ideas would be tested and I would at least be able to put a finer point on the problems I perceive.

1 Like

The rules dsl is not procedural. It is event based (think languages like Erlang). There is a reason why OO languages are rarely chosen in similar event driven systems (asterisk, freeswitch, tasker, telecom systems, etc)

Just curious, what is that reason from your perspective? I’m not wanting to be an apologist for event-driven OO but there are many, many event driven programs written with OO (e.g., event-driven user interfaces). Even openHAB itself, which is clearly event-driven, is written using OO techniques.

Given the architecture of oh it is debatable whether OO would be a superior approach.

But, again, the openHAB architecture is itself written using OO techniques. If, by architecture, you mean the item-based approach to integrating Things/Channels with the user interfaces (and rules) then that would be an interesting debate.

I don’t understand what you mean about being spilled across Items and Rules.
I see nothing that an OO approach would do to change this.

Imagine you have some automation functionality that operates on a set of closely-related data and has nontrivial functionality that operates on that data when an event occurs. An OO approach provides encapsulation of the data and the operations on that data. Using inheritance, you could potentially have a basic implementation of something like a motion-driven light/actuator that has extension points (polymorphic methods) to override behavior in subclasses for new types of sensors and/or actuators.

If you don’t like the rules dsl, you can use the jsr233 binding and code your rules in jython or javascript, I think go is also supported. I don’t know if it works in oh 2 yet.

@scurrier03 I’ve been very happy with JSR223 Jython (Python) in OH1. The OH2 JSR223 support is being actively developed and should be ready soon. The rules must still operate on items but I’ve been experimenting with techniques to hide some of that interaction.

@rlkoshak Are you thinking of Groovy rather than Go? I haven’t heard of any JSR223 support for Go.

Yeah, I think he must be thinking of Groovy (or something else). My heart jumped a happy beat at the thought of being able to use Go (my current favorite language) for OpenHAB, but… yeah I don’t think it’ll be available as a JSR223 language anytime soon.

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.