Upgrade 2 to 3 strategy/planning

It should be possible to add ( no export in front )

EXTRA_JAVA_OPTS="-Duser.timezone=America/New_York"

to
/etc/default/openhab
that file is sourced from within start.sh which is at /usr/share/openhab/start.sh.

That file already contains:

EXTRA_JAVA_OPTS="-Xms192m -Xmx320m"

So, I should make it?:

EXTRA_JAVA_OPTS="-Xms192m -Xmx320m -Duser.timezone=America/New_York"

Edit: that appears to be good.

Thanks!!!

1 Like

There is a lot going on here. It looks like you’ve had help with the timezone issue and the rrd4j issue. But I see two questions unanswered.

Probably but I can’t say for sure. That’s really an InfluxDB question about how to transition storage from one machine to another. Typically one would execute a dump of the database on the old instance and a restore on the other machine. But I haven’t used InfluxDB in quite some time so I can’t comment on more than that.

MapDB is very much still supported but it’s a separate add-on. I don’t think you can reuse the old mapdb files in OH 3. But you are now out much. MapDB only saves the most recent values for each Item.

Thanks for the reply.

the rrd4j appears to be working for my number items I want to persist, though it is apparently using whatever default is configured when it is activated.

At this point I still don’t know what I was persisting in mapdb… But, it is not on the addons website, at least I couldn’t find it yesterday.

So this is much like rrd4j, but can handle more than numbers?

I have the old influxdb .cfg file. and I’m wasn’t putting much into it, so ground zero wouldn’t be much of a problem (done that a lot with this…). But, the Graphana pages would be nice to migrate.

Is it best to install Influx from the openhab tool?

on a different note I saw a reference by you about Joda time in OH3.

I think I get the change to

With the Joda way this is 23:00 (I think)

val night_start = now.withTimeAtStartOfDay.plusDays(1).minusHours(1)

and the equivalent would be:

val night_start = now.withHour(23).withMinute(0).withSecond(0)

Did I get that right?

Default strategies are a new thing in OH 3. For rrd4j it’s persist all supported Items on every change and every minute with restoreOnStartup. To change that you need to create an rrd4j.persist file with a different set of strategies.

Probably. I don’t know everything that it does but suspect it will create the DB user and database for you and if you install be hand you’ll have to do those things manually.

Looks like it should work. However, be careful with daylight savings days. You might convert now to a LocalDateTime which takes those things into account better.

val nighty_start = now.toLocalDateTime().withHour(23)...

Yeah, that makes sense…silly DST…

So I now have a astro thing:

astro:sun:local

In my old rules I reference:

when
  System started or // run at system start in case the time changed when OH was offline
  Channel 'astro:sun:home:rise#event'    triggered START or
  Channel 'astro:sun:home:set#event'     triggered START or
  Channel 'astro:sun:minus90:set#event'  triggered START or

I think I need to change this to:

when
  System started or // run at system start in case the time changed when OH was offline
  Channel 'astro:sun:local:rise#event'    triggered START or
  Channel 'astro:sun:local:set#event'     triggered START or
  Channel 'astro:sun:minus90:set#event'  triggered START or

Am I right in thinking the last line implies I need to add a sun thing called minus90 astro:sun:minus90 with set offset of 90 minutes?

Yes but only if you want to keep things the same. You could also pick on of the other channels on your astro:sun:home Thing, for example nauticalDusk or something like that and apply the offset to that one Channel.

Still debugging…

When the log says there was an error in play-12, I think this is supposed indicate the 12th rule in the file play.rules. In my case the error is being thrown from the 8th rule in the file. (If it was 1 off…I’d say it was a starts at 0 rather than 1 discrepancy…but, a delta of 4 I don’t get.)

Also the error in the log is:

Script execution of rule with UID 'play-12' failed: An error occurred during the script execution: null in play

Not sure how I ma that to a line in the file…

I have a good idea where it is because I’ve added log entries.

It has something to do with changing:

val morning_start = now.withTimeAtStartOfDay.plusDays(1).minusHours(18) 

To:

val morning_start = now.toLocalDateTime().withHour(6).withMinute(0).withSecond(0)

Then subsequently the line:

vMorning_Time.postUpdate(morning_start.toString)

I’m guessing the return type is different, but not being savy with JAVA, I’ll need to research that.

The major question of this post: is there a better way that adding loginfo() lines to narrow down errors like this?

Just add more and more log statements, perhaps to the point where they are every other line of code if you need to.

But I suspect you should not assume the error is lying to you. Add some logging to that 12th rule and see what that rule is doing. That error usually occurs when trying to use something that is incompatible with the operation you are trying to do. For example, if you cast the state of a Number Item to Number but the Item’s state is actually NULL or UNDEF will make an error like that.

I have worked past that, by, indeed, adding copious log statements.

I’m a bit confused about “now.” at this point.

val morning_start = now.toLocalDateTime().withHour(6).withMinute(0).withSecond(0)

This returns a ZonedDateTIme, right?

val day_start = new DateTimeType(vSunrise_Time.state.toString) 

This returns a ZonedDataTIme, right? vSunrise_Time is a DateTIme Item linked to an Astro thing.

case now.isAfter(morning_start)   && now.isBefore(day_start):       curr = "MORNING"

The error now is that it can’t invoke isAfter on morning_start.

No, you converted it to a LocalDateTime. But that should be compatible with most of the stuff you’d use a ZonedDateTime for. But maybe not because LocalDateTime strips the time zone information out and ZonedDateTime needs the timezone information.

No, that is a DateTimeType you are creating there. And that line is pretty redundant because vSunrise_Time.state already is a DateTimeType. You need a ZonedDateTime (or something compatible like LocalDateTime) to do comparisons like isAfter.

val day_start = (vSunrise_Time.state as DateTimeType).getZonedDateTime

This all looks like snippets from the Time of Day design pattern. Are you aware that I rewrote that code in a way that all you need to do is copy it and configure your Items? No more need to modify any code.

Also, there are several postings near the bottom of the thread that show what needs to change to make the old Rules DSL version work with OH 3.

Yes, that is the case.

I assume you mean this thread: Design Pattern: Time Of Day

That’s pretty much the only one.

In the very near future I’ll be able to distribute it as something that is installable through MainUI. In the mean time it takes some copying and pasting to install and use. But one “installed” all you need to do is create and configure some Items.

You asked a while back in this thread if I had any comments on what could be better in the docs…this is certainly not criticism (I help with the docs and support for another relatively popular opensource app and I also moderate one of it’s social media forums, so, I do get it, it ain’t a cake walk.)

I have now read the thread: Design Pattern: Time Of Day a few times. I grant, not every post and not every word.

To me this is a broad sweeping topic. There is much in the thread that I have no clue if it pertains to implementing the pattern or to what I need/want to do etc. The examples include things that seem superfluous to what I think I need, for example a custom dayset/Trash. I get it is an example/extension of the concept being discussed, but, it might be better handled in a section “Beyond the Basic Implementation” so as not to cloud the early discussion.

For some reason, if there is a graphic with the Concepts section, I can’t see it. It’s just a big empty space.

The Concepts might be modified to include a numbered list of one line each of the steps that need to be implemented to make the pattern work at it’s most basic level. Essentially an overview that allows a reader to determine what of the following voluminous comments may be ignored in the initial setup.

Then it jumps to a Simple Example. For me, because I don’t have the list mentioned in the previous paragraph, what of the things shown I need to do. The reader linked to a github and needs to refer to a later sentence to realize it’s the ephemTimeOfDay.yml. Then I notice a comment in the file that links to how to bootstrap items. Do I need to do that? Where did these items come from…the yml is a bunch rules, right?
(And, side question, once the yml is added, are the Things/channels defined by the yml available to rules written in a .rules file? So, If I put the yml in can my file just refer to vTimeOfDay now?

Then I see Python…that does the same thing the yml does. But, but, but…not clear why. Is it just an option in case I want to use Python?

Then we get Rules DSL. This topic appears to have the definition of the Astro things used in the previous yml and Python. (At least that’s what I’m reading.) Then the rules under this heading proceed to use the OH2 time classes.

Now maybe all this is because there are details I don’t know or understand at the moment, or maybe I just have trouble handling multi-faceted concepts until I’ve internalized all the sub-components. Or, maybe it’s just a galactic size onion and there is just no good way to attack it piecemeal.

At this point, if I do understand any of this: I go to the MainUI (I assume this is what I see from the browser at :8080), go to Rules, add the yml, chuck the rule I’ve got for setting vTimeOfDay, and refer to it (vTimeOfDay) in my .rules file. This can’t be right…hmmm.

Firstly, that’s a tutorial, not the docs. These are forum postings instead of available at openhab.org/docs specifically because they are not and never were intended to be documentation for openHAB.

Secondly be sure to read Design Pattern: What is a Design Pattern and How Do I Use Them which is at the top of all my Design Pattern posts. That provides an explanation for what a DP post is and more importantly what it is not.

As mentioned above, a DP is not a comprehensive example. They are a template that one can follow to solve a given class of problems one may encounter while developing Rules.

The example code that is included with the DPs may not be fully explained. The purpose of the example code is to illustrate the DP only. But since the DPs are only templates and not complete in and of themselves, the example code will necessarily include additional code.

While I have provided four complete and comprehensive implementations of that DP (time of day in JavaScript MainUI rules, time of day in Python for OH 2.5, time of day in Rules DSL, and Irrigation in Rules DSL), a complete and detailed discussion about how to use that is beyond the scope of a DP post. For that see the READMEs at GitHub - rkoshak/openhab-rules-tools: Library functions, classes, and examples to reuse in the development of new Rules., particularly openhab-rules-tools/ephem_tod at main · rkoshak/openhab-rules-tools · GitHub.

The whole point of the DP post is not to present a fully realized “thing” you can just take and use, though I have provided that in some cases. The point is to show how to solve a common class of problems. It provides an approach, not a complete solution. You are expected to take the description and apply that approach to your own similar problem. That’s why there is that whole Complex Example that deals with irrigation. That’s showing a second example of using that design pattern to solve a similar problem in a different context. That’s why the code presented isn’t always complete and rarely is it fully explained.

The fact that the DP is called Time of Day is frankly a mistake. What is presented is a time based state machine. The first part is one example of a time based state machine and the complex one is a different example of a time based state machine. But the whole point of the post is the time based state machine, not the Time of Day.

From the Problem Statement:

The overall concept is to create a String Item that represents the current state in the sequence. Rules will check to determine what that state is to determine their behavior or trigger when the String Item changes. One or more additional Rules are responsible for calculating and populating the String Item based on events.

That’s the common problem to solve.

There are two examples presented, a simple example and a complex example. The simple example is the Time of Day implementation.

That section starts with a section titles “Library Implementations”. There are two library implementations, one in JavaScript and another in Python. In both cases the section that briefly introduces them says “See the readme in the repo for more details.” In both of these cases there is just enough presented to explain what those libraries do and a little about how to use them. You are expected to go to the actual instructions for using the library for more instructions.

If you will use one of the library implementations then you are done with that post. The rest doesn’t matter because you are not going to take that knowledge to solve some problem you have. You just want to use the example implementation as is. However, if you are using Rules DSL or want to apply the concept to some other problem you have you would read on to see example implementations of the DP applied to at least two different but related problems.

tl;dr: the whole point of a DP is to help someone implement their own rules, not instructions for how to use a library that use the DP.

The forum must have lost the image. That post is, after all over five years old, a lot can happen in that time.

That is one of the differences between a Design Pattern and just instructions. To use a DP, you should already know what steps need to be implemented because you know what you need to do and you should know what is and is not relevant. Writing in Rules DSL? If you don’t then a DP isn’t going to help you.

At its most basic level the steps need are “do I have a problem to solve that fits the problem statement?” If so you read on to see two or more examples of ways to solve your similar problem. The fact that Time of Day is the example presented is besides the point. It’s an example. The fact that it’s a fully realized example that can be used as is is probably as big of a mistake as misnaming the DP in the first place. Explaining how to use the examples in your setup is and always will be out of scope for a DP post.

The YAML is one single rule. No Items. No Things.

openHAB supports Rules DSL, JavaScript Nashorn, Python, GraalVM JavaScript, Groovy, jRuby(upcoming), and Java (upcoming) as a language to write rules in. I’ve chosen to implement the Time of Day DP in three of the supported languages.

Honestly, the use of Design Patterns and external libraries is not something that can be expected from someone at your level of understanding of OH. I can’t document basic stuff like why there might be two different implementations of a library on each and every DP. I have to assume a certain level of knowledge and expertise to read, understand, and use these. The DPs and libraries are like calculous text books. You have to understand arithmetic first because the calculous text books aren’t going to teach that too.

If you don’t even understand that you are looking a rules that do almost the exact same things implemented in different languages you will not be successful using design patterns. If you don’t understand how to install and use libraries or how to configure Item metadata you will not be successful using anything from openhab-rules-tools.

Hopefully by the end of the year there will be a way to install rules through MainUI. At that point you can install and use stuff like my Time of Day implementations at the click of a button. Until then I recommend taking on of the two following approaches:

  • scrub your rules and eliminate all those that you do not intimately, completely, and thoroughly understand and gradually add them back as you develop your knowledge and understanding; or
  • post your current time of day rule and I’ll fix it; or
  • wait for the end of the year when you can install rules.

Correct, that’s not right.

Prerequistes:

  1. Configure Ephemeris based on what types of days you want to drive the time of day state machine.

From the ephem_tod README:

Requirements

  1. Install the required libraries.

From the openhab_rules_tools README

Clone the repository to your local system. Each library is made up of zero or more library modules and zero or more rule scripts. To make installation of individual capabilities easier, each capability is located in it’s own folder. Copy the automation folder under a given capability’s folder to $OH_CONF.

Pay attention as some libraries depend on others (e.g. timer_mgr depends upon time_utils ).

From the ephem_tod README:

Requirements

  • item_init, optional, used for statically defined times of day (see examples below)
  • timer_mgr to manage the Timers
  • time_utils to process DateTimeTypes and it’s needed by timer_mgr

That one optional library and two required libraries that need to be installed.

  1. Create the required Items

From the JavaScript section of the ephem_tod README. Not it mentions multiple times that the JavaScript version is for OH 3 and the Python version is for OH 2.5.

The rule expects the folliowing Items to already exist and it will generate errors if they do not.

Item Purpose
TimeOfDay String Item that holds the current state of the time of day state machine.
TimesOfDay A Group containing all the DateTime Items that define the starts of the times of day. Each Item must have a valid etod metadata.
  1. Create the Item and copy the contents of the YAML file to the Code tab.

From the openhab_rules_tools README

For JavaScript rules, open the YAML file can copy the contents to the code tab of a new rule in MainUI in openHAB 3.

From the ephem_tod README

To install, in MainUI create a new rule, click on the code tab and paste the contents of ephemTimeOfDay.yml into the form. Add the “Schedule” tag to the rule and it will show up on the schedule.

  1. Add DateTime Items for all the day sets you want to drive your times of day. Add etod metadata as documented on the ephem_tod README to each Item to indicate what type of day the Item will be used for and what the name of the time of day is. If you don’t care about having different times of day on weekends or holidays or whatever, you’ll just have one “default” set of Items.

  2. Each DateTime Item needs to be set to the time you want that time of day to start. You can use Astro, iCal, the Android App’s Alarm Item, or what ever you want to set the time. If you want specific hard coded times you need to set the DateTime Item manually (hence the link in the example for how to boot strap an Item’s state).

But I don’t spell all that out step-by-step because the audience for doing all this is someone who has enough knowledge to understand that there are different programming languages in OH and who understand how to write such rules. They probably already have experience with the Helper Libraries and/or have been using alternatives to Rules DSL for some time.

On the DSL Rules example in the DOP post, I don’t spell everything out because, as I stated in the “what is a DP” post

Because a DP is not a complete solution, the reader needs to possess a few skills in order to apply them to their situation:

  • the basics of how to define Items and use them in Rules code
  • Rule syntax
  • the ability to follow a block of Rules code and understand at a basic level what the code does
  • the ability to recognize and deal with code in a block that is not fully explained or defined in the DP text (e.g. reference to Items not defined in the current DP)
  • the ability to generalize an example to multiple situations

At your current skill level and knowledge I think you lack at least a couple of those prerequisites. So really you probably should have been using the Time of Day DP in the first place and that’s a big reason why you are struggling now. You never understood how your rules worked in the first place so you don’t know how to fix them now.

My TOD rule as it was working for several years on OH2:

rule "Calculate time of day state" 
when
  System started or // run at system start in case the time changed when OH was offline
  Channel 'astro:sun:home:rise#event'    triggered START or
  Channel 'astro:sun:home:set#event'     triggered START or
  Channel 'astro:sun:minus90:set#event'  triggered START or
  Time cron "0 1 0 * * ? *" or // one minute after midnight so give Astro time to calculate the new day's times
  Time cron "0 0 6 * * ? *" or
  Time cron "0 0 23 * * ? *"
then

  logInfo("Calculate TOD State", "Calculating time of day...")

  // Calculate the times for the static tods and populate the associated Items
  // Update when changing static times
  // Jump to tomorrow and subtract to avoid problems at the change over to/from DST
  val morning_start = now.withTimeAtStartOfDay.plusDays(1).minusHours(18)
  vMorning_Time.postUpdate(morning_start.toString) 

  val night_start = now.withTimeAtStartOfDay.plusDays(1).minusHours(1)
  vNight_Time.postUpdate(night_start.toString)

  val bed_start = now.withTimeAtStartOfDay
  vBed_Time.postUpdate(bed_start.toString)

  // Convert the Astro Items to Joda DateTime
  val day_start = new DateTime(vSunrise_Time.state.toString) 
  val evening_start = new DateTime(vSunset_Time.state.toString)
  val afternoon_start = new DateTime(vEvening_Time.state.toString)

  // Calculate the current time of day
  var curr = "UNKNOWN"
  switch now {
  	case now.isAfter(morning_start)   && now.isBefore(day_start):       curr = "MORNING"
  	case now.isAfter(day_start)       && now.isBefore(afternoon_start): curr = "DAY"
  	case now.isAfter(afternoon_start) && now.isBefore(evening_start):   curr = "AFTERNOON"
  	case now.isAfter(evening_start)   && now.isBefore(night_start):     curr = "EVENING"
  	case now.isAfter(night_start):                                      curr = "NIGHT"
  	case now.isAfter(bed_start)       && now.isBefore(morning_start):   curr = "BED"
  }
  // Publish the current state
  logInfo("Calculate TOD State", "Calculated time of day is " + curr)
  vTimeOfDay.sendCommand(curr)


    //Update me for peace of mind
  	/*val String mailTo = "macdroid53@gmail.com"
    val String message = "New TOD: " + curr
	sendMail(mailTo, "New TOD", message)
    */

end

Assuming nothing else see below based on Design Pattern: Time Of Day - #622 by lamero

rule "Calculate time of day state" 
when
  System started or // run at system start in case the time changed when OH was offline
  Channel 'astro:sun:home:rise#event'    triggered START or
  Channel 'astro:sun:home:set#event'     triggered START or
  Channel 'astro:sun:minus90:set#event'  triggered START or
  Time cron "0 1 0 * * ? *" or // one minute after midnight so give Astro time to calculate the new day's times
  Time cron "0 0 6 * * ? *" or
  Time cron "0 0 23 * * ? *"
then

  logInfo("Calculate TOD State", "Calculating time of day...")

  val ZonedDateTime zdt = ZonedDateTime.now()
  val ZonedDateTime start_of_day = zdt.toLocalDate().atStartOfDay(zdt.getOffset())

  // Calculate the times for the static tods and populate the associated Items
  // Update when changing static times
  // Jump to tomorrow and subtract to avoid problems at the change over to/from DST
  //val morning_start = now. withTimeAtStartOfDay.plusDays(1).minusHours(18)
  val morning_start = start_of_day.plusDays(1).minusHours(18)
  vMorning_Time.postUpdate(morning_start.toLocalDateTime.toString) 

  //val night_start = now.withTimeAtStartOfDay.plusDays(1).minusHours(1)
  val night_start = start_of_day.plusDays(1).minusHours(1)
  vNight_Time.postUpdate(night_start.toLocalDateTime.toString)

  //val bed_start = now.withTimeAtStartOfDay
  val bed_start = start_of_day
  vBed_Time.postUpdate(bed_start.toLocalDateTime.toString)

  // Convert the Astro Items to Joda DateTime
  //val day_start = new DateTime(vSunrise_Time.state.toString) 
  val day_start = (vSunrise_Time.state as DateTimeType).getZonedDateTime
  //val evening_start = new DateTime(vSunset_Time.state.toString)
  val evening_start = (vSunset_Time as DateTimeType).getZonedDateTime
  //val afternoon_start = new DateTime(vEvening_Time.state.toString)
  val afternoon_start = (vEvening_Time.state as DateTimeType).getZonedDateTime

  // Calculate the current time of day
  var curr = "UNKNOWN"
  switch now {
  	case now.isAfter(morning_start)   && now.isBefore(day_start):       curr = "MORNING"
  	case now.isAfter(day_start)       && now.isBefore(afternoon_start): curr = "DAY"
  	case now.isAfter(afternoon_start) && now.isBefore(evening_start):   curr = "AFTERNOON"
  	case now.isAfter(evening_start)   && now.isBefore(night_start):     curr = "EVENING"
  	case now.isAfter(night_start):                                      curr = "NIGHT"
  	case now.isAfter(bed_start)       && now.isBefore(morning_start):   curr = "BED"
  }
  // Publish the current state
  logInfo("Calculate TOD State", "Calculated time of day is " + curr)
  vTimeOfDay.sendCommand(curr)


    //Update me for peace of mind
  	/*val String mailTo = "macdroid53@gmail.com"
    val String message = "New TOD: " + curr
	sendMail(mailTo, "New TOD", message)
    */

end

As has always been the case, the above assumes that all the Items have a non NULL or UNDEF state.

And, thread is where this part of the thread started.

I the idea somewhere the whole “plus a day minus hours” stuff was to be replaced Joda time wasn’t supported in OH3.

So I changed:

val morning_start = now.withTimeAtStartOfDay.plusDays(1).minusHours(18)

to:

val morning_start =  now.toLocalDateTime().withHour(6).withMinute(0).withSecond(0)

Which in turn, if I understood made morning_start and day_start incompatible with:

  switch now {
  	case now.isAfter(morning_start)   && now.isBefore(day_start):       curr = "MORNING"
...
  }

And I asked how to make them compatible…

and was told this was redundant because vSunrise_Time was a DateTime.:

val day_start = new DateTimeType(vSunrise_Time.state.toString) 

And, so some other poor bloke isn’t tear their hair out, there is a typo in that code

  val evening_start = (vSunset_Time as DateTimeType).getZonedDateTime

Should be:

  val evening_start = (vSunset_Time.state as DateTimeType).getZonedDateTime

[/quote]

Joda DateTime is now gone. But ZonedDateTime has replaced it. And ZonedDateTime works slightly differently from Joda DateTime. But that doesn’t mean it can’t do all the same things that Joda DateTime did.

Different question, different answer.

val day_start = new DateTimeType(vSunrise_Time.state.toString)

is redundant. vSunrise_Time.state already is a DateTimeType. There is no point in creating a new DateTimeType out of a DateTimeType. That line does nothing functionally. In the end you have a DateTimeType and you need a ZonedDateTime.

I apologize for the typo but honestly I’m just about done trying to support Rules DSL. Even before this thread I had every intention of eliminating the Rules DSL examples in most if not all of the Design Pattern posts. It’s now been multiple years since I’ve written any Rules DSL in my system. And I’ve no plans to start again.

Programming is hard. The only thing harder is to try to help someone who doesn’t know how to program and doesn’t generalize very well fix their code remotely. You may be frustrated but I guarantee you I’m as frustrated if not more. And a big cause of my frustration is that I see no end to it. I just don’t see how you will ever be able to stand on your own so I and the rest of us on this forum will be forever giving up, as I have, and just coding it for you.

I think what I’m going to do is once the marketplace is available and I can make rules installable I’m going to eliminate the DP posts or at least handy capping them to the point where you have to understand programming to use them. After all, that’s the audience the DPs are geared for. The examples I have in there now just promote cargo cult programming which does nothing but waist everyone’s time.

Indeed, I whole hardheartedly agree that coding is hard. It is even harder when someone assumes, they know, you don’t know what you are doing. Even harder when the system involves a large number of disparate tools, functionality, subsystems, a plethora of interfaces and a huge amount of documentation.

For the record, I may not generalize as good as you think I should. But, there is a difference between generalizing and not having found all the methods, class documentation, conversions, etc, for a language/system, and other documentation. I programmed professionally for 45+ years before I retired. I wrote my first state engine, in assembly language, in the late 1970’s. And, I have programmed in more languages than most know every existed. Notably not JAVA.

I would point out that my understanding of what this particular rule was never the my issue. It was what needed to be changed to make it OH 3 compliant and how to get the time methods to play together. The other 50 or so rules, of my own design, seem to work just fine.

But, none of this gets my system back to fully working again. So, I’m going to stop talking about this particular topic. Maybe I’ll look at it again when it is and addon.

I’m sorry that my questions are so bothersome. I will try not to bother you. But, of course, it may be, on my part, unavoidable in some cases.

But, I will say, again, thanks for your help in the past.