Jump to content

Interesting way of looking at programming on ISY994...


x046866x

Recommended Posts

I had an interesting epiphany the other day that has helped my way of looking at programming on the ISY994.

I have been programming since the early 1980's so I'm familiar with most of paradigm's.  When working with programming on the ISY994 it was always referred to as "Event based", which it is, but the trap I kept falling down was that I would apply a server-based view of "Event based", where an action is triggered by an Event but then the subsequent coding is (generally speaking) procedural. 

What was happening was I was expecting the subsequent flow to adhere to traditional procedural pattern....and it doesn't.  Calls to programs are not procedurally nested (synchronous) and, in some cases, I would trigger other events incidentally (which would really confuse things).

I came to this realization when I read a comment from someone (I will look for their name for proper credit) who said something to the effect of "...every time an Event is triggered all programs are searched for whether they may have interest in the Event, if so the program is executed, otherwise ignored...". 

The epiphany I had was that the ISY behaves far more like a State machine than a traditional server.  Managing behaviors by controlling the internal state, State variables being key (of course).  I have found that treating it this way has allowed me to reduce the code I'm using while increasing the reliability.  What were unexplained behaviors before are now all explained.

This helped me.  Dunno if it may help others.

P.S.: Like many Epiphany's, once my eyes are opened I am like "Duh....I'm an idiot".  I am kicking myself for taking this long to come to this realization, especially considering how long I've been working on this platform.  :)

Edited by x046866x
  • Like 2
Link to comment
  • 2 months later...

Long time control system programmer, and developer of embedded controls using real-time operating systems.

I have always tried to fit most control programs into a State Machine model, and rigorously use the Mealy State Model in my many years.

Therefore, I only "do something" on state transitions (never on state).  And I always start with a State Diagram.

The ISY programming construct is pretty simple for simple things, but it is easy to get into trouble for more complex programs, and becomes impossible to read a year later when you have many "programs" interacting with each other.

There are quite a few idiosyncrasies in the programming model, and there does not appear to be any document that warns you of these things situations and how to avoid problems.

As such, I only use IF and THEN (not else).  I NEVER use WAIT or REPEAT in the state machine.  I have a timer service folder that services each timer with a decrementing WAIT (by the second, minute or hour).  The instant that I set a Timer in the State Machine, that service program decrements the timer to zero, and there is usually another state transition in my machine that checks for TIMER_1 = 0 in a condition.

******************************

In any event, I struggle to see that the event-based paradigm of the ISY programming is "state-like."  All control programing is about "controlling the internal state,"  whether linear, procedural, object-oriented, or in this unusual paradigm for event-driven. 

The ISY event-driven model, is, as you point out, a change-in-state model.  Internally, the ISY is creating an interrupt for each and every change of status of every device/statevariable in the system, and allowing YOU to create an interrupt service routine for that individual generated interrupt (that is what a singular program is...and interrupt service routine).  That paradigm is fine for a smaller system.  But when you have many hundredor thousands of devices in larger systems, it becomes very inefficient and very confusing.  Better to snapshot the entry state of all devices, run your logic, modifying variables and device state in as output.

Traditionally, for control systems, interrupts can cause lots of unforeseen problems, and you use them sparingly for only those things that need incredibly fast response time.  And you severely limit the the length of code behind the interrupt service routine.

I think the ISY, and now the Polisy, are fantastic, incredibly robust products.  The event-driven paradigm works well for the intended target audience.

*********************

Back to the State Machine Model for programming ISY:

The beauty of sticking to one State-Machine model (I prefer Mealy), is you can implement your State Machine model on ANY programming environment, and spend 90% of your time on a scrap of paper working through your State Diagram.  Converting that to code can be done by someone else.  And a year later, you simply look at your diagram to dig into any required changes.

Link to comment

Nice!

I use integer variables profusely for constants with labels and my only records are imbedded comments and ISY element names.

eg. $cTRUE

$cFALSE

Element names are always positive logic and try not to be ambiguous.

eg. Program: deviceName.batt.ok


All just good programming practices from inline code habits learned the hard way.

I avoid hidden and obscure things like using program state logic etc.


Sent from my SM-G781W using Tapatalk


 

Edited by larryllix
  • Like 1
Link to comment

For most ISY programming, I just sit down and do it, as the inputs and outputs for many things are pretty trivial.

But, that said, even some code that controls several lights based on motion, time of day, and perhaps some other factors, may be difficult to juggle clearly in your head.

Some time ago I programmed control of the many zones in the house using a rigorous machine state approach, integrating prioritization, outside weather, time of day, season, location, manual requests for increased heat/cool, etc.

And yes, you start on paper (virtual or otherwise), but then the implementation is dog simple, robust and understandable years later -- when you need to inevitably come back and make changes.

* Orest

 

Edited by oskrypuch
  • Like 1
Link to comment

Yeah, Larry. 

In my world, these options here do not exist in ANY program:

image.png.3ffc9d7417601da3aa7ff8ebb1e90375.png

You are making a more complex program almost impossible to understand a year later, likely making troubleshooting in development far more painful, and in general, adding another confusing layer on top of confusion.

Rarely in the controls world is the quickest, easiest program change, the proper change.  Those that do not understand that will spend most of their time in frustration with troubleshooting, and use trial and error to fix problems. (which inevitably results in the dreaded "spaghetti code.")

 

Edited by dcard
Link to comment
2 hours ago, dcard said:

Yeah, Larry. 

In my world, these options here do not exist in ANY program:

image.png.3ffc9d7417601da3aa7ff8ebb1e90375.png

You are making a more complex program almost impossible to understand a year later, likely making troubleshooting in development far more painful, and in general, adding another confusing layer on top of confusion.

Rarely in the controls world is the quickest, easiest program change, the proper change.  Those that do not understand that will spend most of their time in frustration with troubleshooting, and use trial and error to fix problems. (which inevitably results in the dreaded "spaghetti code.")

 

Yeah, Spaghetti code can't  really exist in ISY event programming. Although you can make some very interdependent event driven code that can oscillate. Been there, done that. :)

BTW: I use the Repeat While construct as an inline If/Then/Else construct. Since ISY doesn't offer much in the way of inline conditionals, it makes and avenue to get things done. I don't like it but the whole thing would be much better if I could change the names of the construct to suit better. Good inline commenting and labeling helps the confusion a lot.

It can get complicated when you write ISY code to average multiple sensor inputs and discard outliers but it works well for analogue inputs to be reliable in the event of a sensor malfunction and I always like to not use sensor analogues directly from input devices. Passing them through a stats variable has allowed me to swap input devices, change scaling and otherwise massage data that would mean modifying many programs using that data. When I half moved my programs fro ISY to polisy it took one program to synchronise sensor data between devices. Some see that as too complicated and some see it as simplified at the cost of a few more bytes of code.

At least ISY offers many ways to do things and we all have our druthers. This is about the 5th system style I have worked with that used event driven code. If you lived on VB, using their "objects", for a length of time, you would fall right into this style.

Edited by larryllix
Link to comment
3 hours ago, larryllix said:

BTW: I use the Repeat While construct as an inline If/Then/Else construc

Wow.  Great idea! 

My only concern is what I understand to be the open door when a REPEAT (or WAIT) is invoked,  That open door to allow other programs to run (interrupt is now available), and the fact that if original top conditional changes, the remaining code under your REPEAT may not execute.

Do I have this right???

Link to comment
15 hours ago, dcard said:

Wow.  Great idea! 

My only concern is what I understand to be the open door when a REPEAT (or WAIT) is invoked,  That open door to allow other programs to run (interrupt is now available), and the fact that if original top conditional changes, the remaining code under your REPEAT may not execute.

Do I have this right???

Once the state of the IF changes, execution is interrupted at the next break (wait and possibly repeat).  There are many possible constructs to avoid the issue.  I'll write an imaginary abstract example with probably little real world value to illustrate:

Program FanCycle.on

If
    Temp > 80.0
then
     Run Program FanCycle.loop  (then)
else
    (blank)

Program FanCycle.loop

If
    (blank)
then
    Disable Program FanCycle.on
    Enable Program FanCycle.off
    Repeat every 10 minutes
         Turn on Fan
         wait 5 minutes
         Turn off Fan
else
    (blank)

Program FanCycle.off

If
    Temp < 75.0
then
     Stop Program FanCycle.loop
     Turn Fan off
     enable Program FanCycle.on
     disable Program FanCycle.off    *// Note: since this program is disabling itself this MUST BE last. //*

Program FanCycle.startup   (Run at Startup)

If
     (blank)
then
    Turn Fan off
    Enable Program FanCycle.on
    Disable Program FanCycle.off
else
    (blank)
 

Program FanCycle.on watches for the temp to exceed 80, when it does it runs

Program FanCycle.loop which immediately disables Program 1 and enables Program 3.  Program 2 then cycles a Fan on and off for 5 of every 10 minutes.

Program FanCycle.off get us out of the loop when the temp drops below 75

Program FanCycle.loop insures that the devices and programs are returned to known states when the ISY is rebooted.  If the power to the ISY (or the house) was interrupted while the loop was running, if we didn't have program 4 when power was restored the fan might be on or off (insteon returns to it's last state) and Program FanCycle.on would be disabled which would mean the loop would never begin again.

If we don't write these programs as segments like this, the problem is that as the temperature bounces around unanticipated things happen... for example consider this:

Program FanCycle

If
   Temp > 80.0
then
   Repeat every 10 minutes
         Turn on Fan
         wait 5 minutes
         Turn off Fan
else
    Turn Off Fan

here are some of the unintended things that happen:

  • If the temp is rising, the loop will first execute at 80.1 or above, if the next temp change is 80.5 the current Then block will stop running, and a new Identical Then block will start running with timers reset.
  • if the temp is wavering around 80 like 80.1, 79.9, 80.5, 79.0, etc the fan will stop and start everytime the temp updates
  • if the temp is falling and had dropped below 80 this program will create ALOT of unneeded insteon traffic, because each time the temperature update the ISY will send the command to the switch to Turn Off.

 

In conclusion: ISY program is a different beast.  While you might be able to use some constructs from other languages/styles one must also consider what's happening under the hood (example: it doesn't make sense to turn the fan off everytime the temp changes by .1 degree all WINTER long.

Edited by MrBill
  • Like 2
Link to comment
19 hours ago, dcard said:

Wow.  Great idea! 

My only concern is what I understand to be the open door when a REPEAT (or WAIT) is invoked,  That open door to allow other programs to run (interrupt is now available), and the fact that if original top conditional changes, the remaining code under your REPEAT may not execute.

Do I have this right???

Yes. IIRC this is only event driven system I have worked with, that can have processes stopped and restarted.

I would guess in the beginning UDI had to decide what to do when a new event happens that is the same as one already being processed.

  • Continue like nothing happened and ignore the new event
  • Continue like nothing happened and stack the new event for sequential operation
  • Stop the current process and handle the new even like the previous process wasn't happening.

The choice they made provides a lot of strange happenings in even processing and program writing. It definitely puts a hiccough in the logical thinking of experienced inline code writers.

Now I would like UDI to add a program disable command that allows a program to finish what it started. Currently the Disable program command line also stops the affected program. "They just have no self-control..." :)

Edited by larryllix
Link to comment
3 hours ago, MrBill said:

Once the state of the IF changes, execution is interrupted at the next break (wait and possibly repeat).  There are many possible constructs to avoid the issue.  I'll write an imaginary abstract example with probably little real world value to illustrate:

<snipped>

 

In conclusion: ISY program is a different beast.  While you might be able to use some constructs from other languages/styles one must also consider what's happening under the hood (example: it doesn't make sense to turn the fan off everytime the temp changes by .1 degree all WINTER long.

I can see you are a man of experience. Not many would even realise these quirks without sweating through it themselves. Still have any hair left? :)

Edited by larryllix
  • Like 1
Link to comment
5 minutes ago, larryllix said:

He couldn't live up to the blonde image giving ood advice like that.

Sent from my SM-G781W using Tapatalk
 

BTW I was in Ontario this Summer and tried to find  "     Northern SouthWestern Ontario         " on the map, but I could not :-) 

  • Like 1
Link to comment
On 9/23/2022 at 5:32 PM, dcard said:

Wow.  Great idea! 

My only concern is what I understand to be the open door when a REPEAT (or WAIT) is invoked,  That open door to allow other programs to run (interrupt is now available), and the fact that if original top conditional changes, the remaining code under your REPEAT may not execute.

Do I have this right???

Yes, and often times that ability to be interrupted is a useful tool.  If you intend to have a wait or repeat always execute to completion, you need to have a separate programs for trigger and execution.

 

If 
whatever you want
Then
Run then program 2

If
blank
Then
disable program 1
do something
wait
do something
wati
etc.
enable program 1

 

I use interruptible waits all the time as a hysteresis type mechanism.  My dryer has a wrinkle protector that turns it on every few minutes.  And using the notation option in an ISY program you save yourself confusion when a year or two or whatever later you can't remember.  The notes included below are in the program, not added by me to this post.  This sort of explanation in your programs is invaluable.

Master Drier Copy - [ID 0163][Parent 00F7]

If
        'WebControl8 / Input8' Status is 0
 
Then
        Wait  5 minutes 
        Enable Program 'Master Drier'
 
Else
   - No Actions - (To add one, press 'Action')
 
Input 8 is 1 when drier off.  When air vent flapper opens input becomes 0.  If the drier is on for 5 continuous minutes, master drier is enabled.  At this point, the next time the flap closes (or in other words when it shuts off), it will 
send a notification and disable itself.  It will not send a notification again until it the drier has run for 5 continuous minutes.


Master Drier - [ID 00C6][Parent 00F7][Not Enabled][Run At Startup]

If
        'WebControl8 / Input8' Status is 1
 
Then
        Send Notification to 'lou text' content 'Master Dryer Done'
        Wait  1 second
        Disable Program 'Master Drier'
 
Else
   - No Actions - (To add one, press 'Action')
 

 

Edited by apostolakisl
Link to comment
2 hours ago, apostolakisl said:

Yes, and often times that ability to be interrupted is a useful tool.  If you intend to have a wait or repeat always execute to completion, you need to have a separate programs for trigger and execution.

 

If 
whatever you want
Then
Run then program 2

If
blank
Then
disable program 1
do something
wait
do something
wati
etc.
enable program 1

 

I use interruptible waits all the time as a hysteresis type mechanism.  My dryer has a wrinkle protector that turns it on every few minutes.  And using the notation option in an ISY program you save yourself confusion when a year or two or whatever later you can't remember.  The notes included below are in the program, not added by me to this post.  This sort of explanation in your programs is invaluable.

Master Drier Copy - [ID 0163][Parent 00F7]

If
        'WebControl8 / Input8' Status is 0
 
Then
        Wait  5 minutes 
        Enable Program 'Master Drier'
 
Else
   - No Actions - (To add one, press 'Action')
 
Input 8 is 1 when drier off.  When air vent flapper opens input becomes 0.  If the drier is on for 5 continuous minutes, master drier is enabled.  At this point, the next time the flap closes (or in other words when it shuts off), it will 
send a notification and disable itself.  It will not send a notification again until it the drier has run for 5 continuous minutes.


Master Drier - [ID 00C6][Parent 00F7][Not Enabled][Run At Startup]

If
        'WebControl8 / Input8' Status is 1
 
Then
        Send Notification to 'lou text' content 'Master Dryer Done'
        Wait  1 second
        Disable Program 'Master Drier'
 
Else
   - No Actions - (To add one, press 'Action')
 

 

Here is what I would like to see...

Program 1

If
    condition = True
Then
      deTrigger Program 1 <------ disable If section without stopping it
      do something
      wait 5 seconds
      do something else
      enable Program 1     <----- enable If section
Else
    ----

Link to comment
18 hours ago, larryllix said:

Here is what I would like to see...

Program 1

If
    condition = True
Then
      deTrigger Program 1 <------ disable If section without stopping it
      do something
      wait 5 seconds
      do something else
      enable Program 1     <----- enable If section
Else
    ----

Being able to disable a program (either from within the program or from another program) without terminating it would be nice.  But since you can accomplish the same goal by just separating the trigger and execution into two programs, I really doubt UD would put such a wish on the short list of things to do.

  • Sad 1
Link to comment
4 hours ago, apostolakisl said:

Being able to disable a program (either from within the program or from another program) without terminating it would be nice.  But since you can accomplish the same goal by just separating the trigger and execution into two programs, I really doubt UD would put such a wish on the short list of things to do.

Yeah, It seems like it would be so easy to add another pulldown option in the menu, and add the same code without the "program Stop"

Link to comment
42 minutes ago, larryllix said:

Yeah, It seems like it would be so easy to add another pulldown option in the menu, and add the same code without the "program Stop"

Two "disable" options would do it.   Easy enough to add it to a drop down menu, not sure how hard it would be to add it to the back end.

"disable"  

"disable auto-triggering" 

  • Like 1
Link to comment
Guest
This topic is now closed to further replies.

×
×
  • Create New...