HELP - Last Thursday of the Month - how to trigger?

mjpcomp

Member
I am trying to setup a rule that will display text and announce a message when the system is disarmed on the last thursday of each month. However, I'm trying to make it as efficient as possible, but thanks to February, and a few months with less than 31 days, it doesn't look as easy. I was referencing this to see if I could create a pattern: http://www.elkproducts.com/support/M1_Appl...ews092605_2.htm but these really only target the two months in which DST changes. In this example, on http://www.elkproducts.com/support/M1_Appl...1news030205.htm - I can see that there is a line with "AND THE MONTH IS A MULTIPLE OF 6" - how do we do these?

The following is my attempt at figuring out the logic to determine when the last thursday of each month is. I have written some possible rule sets for each condition (based on when the 1st of each month is).

Code:
SMTWTFS
1234567
8901234
5678901
2345678
901

Last Thursday for ALL months is 26th

Possible Rule:
WHENEVER THE HOUR IS 5:XX AM
  AND THE DAY(S) OF THE WEEK IS/ARE S------
  AND THE DAY OF THE MONTH IS 1
  THEN SET COUNTER X TO 26

OR, ANOTHER POSSIBLE.. Since if Thursday is the 26th, it's the last Thursday...

WHENEVER AREA 1 ARM STATE BECOMES DISARMED
  AND THE DAY(S) OF THE WEEK IS/ARE ----T--
  AND THE DAY OF THE MONTH IS 26
  THEN....

--------------------------------------------

SMTWTFS
-123456
7890123
4567890
1234567
8901

Last Thursday for all months is 25th

Possible Rule:
WHENEVER THE HOUR IS 5:XX AM
  AND THE DAY(S) OF THE WEEK IS/ARE -M-----
  AND THE DAY OF THE MONTH IS 1
  THEN SET COUNTER X TO 25

OR, ANOTHER POSSIBLE.. Since if Thursday is the 25th, it's the last Thursday...

WHENEVER AREA 1 ARM STATE BECOMES DISARMED
  AND THE DAY(S) OF THE WEEK IS/ARE ----T--
  AND THE DAY OF THE MONTH IS 25
  THEN....

--------------------------------------------

SMTWTFS
--12345
6789012
3456789
0123456
78901

Last Thursday for months with less than 31 days is 24th, otherwise it's 31st

--------------------------------------------

SMTWTFS
---1234
5678901
2345678
9012345
678901

Last Thursday for all months except February is 30th. For February it's 23rd

Possible Rule:
WHENEVER THE HOUR IS 5:XX AM
  AND THE DAY(S) OF THE WEEK IS/ARE ---W---
  AND THE DAY OF THE MONTH IS 1
  AND THE MONTH IS NOT FEBRUARY
  THEN SET COUNTER X TO 30

AND

WHENEVER THE HOUR IS 5:XX AM
  AND THE DAY(S) OF THE WEEK IS/ARE ---W---
  AND THE DAY OF THE MONTH IS 1
  AND THE MONTH IS FEBRUARY
  THEN SET COUNTER X TO 23

OR, ANOTHER POSSIBLE SET:

WHENEVER AREA 1 ARM STATE BECOMES DISARMED
  AND THE DAY(S) OF THE WEEK IS/ARE ----T--
  AND THE MONTH IS NOT FEBRUARY
  AND THE DAY OF THE MONTH IS 30
  THEN....

AND

WHENEVER AREA 1 ARM STATE BECOMES DISARMED
  AND THE DAY(S) OF THE WEEK IS/ARE ----T--
  AND THE MONTH IS FEBRUARY
  AND THE DAY OF THE MONTH IS 23
  THEN....

--------------------------------------------

SMTWTFS
----123
4567890
1234567
8901234
5678901

Last Thursday for all months (and February in leap year) is 29th. For February in non-leap it's 22nd.

--------------------------------------------

SMTWTFS
-----12
3456789
0123456
7890123
4567890
1

Last Thursday for all months is 28th.

Possible Rule:
WHENEVER THE HOUR IS 5:XX AM
  AND THE DAY(S) OF THE WEEK IS/ARE -----F-
  AND THE DAY OF THE MONTH IS 1
  THEN SET COUNTER X TO 28

OR, ANOTHER POSSIBLE.. Since if Thursday is the 28th, it's the last Thursday...

WHENEVER AREA 1 ARM STATE BECOMES DISARMED
  AND THE DAY(S) OF THE WEEK IS/ARE ----T--
  AND THE DAY OF THE MONTH IS 28
  THEN....

--------------------------------------------

SMTWTFS
------1
2345678
9012345
6789012
3456789
01

Last Thursday for all months is 27th.

Possible Rule:
WHENEVER THE HOUR IS 5:XX AM
  AND THE DAY(S) OF THE WEEK IS/ARE ------S
  AND THE DAY OF THE MONTH IS 1
  THEN SET COUNTER X TO 27

OR, ANOTHER POSSIBLE.. Since if Thursday is the 27th, it's the last Thursday...

WHENEVER AREA 1 ARM STATE BECOMES DISARMED
  AND THE DAY(S) OF THE WEEK IS/ARE ----T--
  AND THE DAY OF THE MONTH IS 27
  THEN....

For the counter based rules, there would then be a rule that subtracts 1 from COUNTER X at midnight, every night. Then, when the counter hits "1" that should be the last thursday of the month, and I can have the rule fire off of that condition.

For the non-counter based rules, I wouldn't need to worry about a counter... Just fire off the rule on that day when the system is disarmed... To save rule space, I would probably tell it to turn on an Output for 30 seconds or whatever. Then, when that output is turned off, it would fire off the announcement rule.

Anyway, for those two month conditions, if anyone knows of an easy way to incorporate the multiple possibilities in as little number of rules as possible, that would be great.

Thanks!
 
I attempted to solve this problem by searching for a solution implemented in a scripting language (Javascript or VBScript). My intent was to translate the solution using the M1's scripting language. Unfortunately, most algorithms rely on math functions that aren't supported by the M1 like rounding down a number (Javascript "math.floor", VBScript "int") and acquiring the remainder of a division (Javascript "%" operator, VBScript "mod").

If you have Home Automation software with an ELK M1 driver, you can use the following functions:

Code:
' Sunday is the first day of the week.

' Get the date (DayOfMonth) of the nth instance of a weekday in a given month.
function NthDay(iNth, iWeekday, iMonth, iYear)
	NthDay = (iNth - 1) * 7 + 1 + (7 + iWeekday - DayOfWeek((iNth-1) * 7 + 1, iMonth, iYear)) mod 7
end function

' Get the weekday of a given date.
function DayOfWeek(iDay, iMonth, iYear)
	a = int((14 - iMonth) / 12)
	y = iYear - a
	m = iMonth + 12 * a - 2
	d = (iDay + y + int(y / 4) - int(y / 100) + int(y / 400) + int((31 * m) / 12)) mod 7
	DayOfWeek = d + 1
end function

' Find the date of the fourth instance of Thursday (day 5) for the month of February, 2008.
wscript.echo NthDay(4, 5, 2, 2008)

The functions come from here and have been converted from JavaScript to VBScript. If you need free HA software, you can use Premise with my ELK M1 driver.

Good luck with your attempt to do this exclusively in the M1; it is a challenging project!
 
Thanks for the VB code... I guess I'll have to give Premise a whirl...

Does it run under Vista x64? I read through the driver manual that you had posted - the keypad texts are triggered via a fake Relay.. How would this work out since something would need to trigger the relay?

Thanks again!
 
Have you tried brute force by hard coding in the dates for each last Thurs for the next year or so? When date = xxxx then xxxx. Not fancy and might take a line of code for each Thurs but it looks like a lot less code than you have now. Of course, it is not a perpetual calendar with that approach and would require a a revision after the last date you loaded.
 
Seems to me that this can be done with three rules, if you ignore Leap Years or deal with Leap Years separately. These use Output 208 as a proxy or signal for your task. I know these rules are not pretty. Also I have not tested them.


/* For months with 31 days */
WHENEVER THE TIME IS 12:01 AM
AND THE MONTH IS NOT February
AND THE MONTH IS NOT April
AND THE MONTH IS NOT June
AND THE MONTH IS NOT September
AND THE MONTH IS NOT November
AND THE DAY(S) OF THE WEEK IS/ARE ----T--
AND THE DAY OF THE MONTH IS LATER THAN 24
THEN TURN Output 208 ON

/* For months with 30 days */
WHENEVER THE TIME IS 12:01 AM
AND THE MONTH IS NOT January
AND THE MONTH IS NOT February
AND THE MONTH IS NOT March
AND THE MONTH IS NOT May
AND THE MONTH IS NOT July
AND THE MONTH IS NOT August
AND THE MONTH IS NOT October
AND THE MONTH IS NOT December
AND THE DAY(S) OF THE WEEK IS/ARE ----T--
AND THE DAY OF THE MONTH IS LATER THAN 23
THEN TURN Output 208 ON

/* For February not Leap Year */
WHENEVER THE TIME IS 12:01 AM
AND THE MONTH IS February
AND THE DAY(S) OF THE WEEK IS/ARE ----T--
AND THE DAY OF THE MONTH IS LATER THAN 21
THEN TURN Output 208 ON
 
davidvind's solution appears to handle most situations (except leap years) and may be all you need to get the job done.


Regarding the Premise keypad-text example, it used a relay device to trigger the message but that's just one example of a trigger ... you can use most anything including a scheduled time.

For example, I created a Schedule that runs every Thursday at 8:00AM. When it runs, it executes the following code:
Code:
' Check if today is the fourth Thursday of this month
if times.sysDay = NthDay(4, 6, times.sysMonth, times.sysYear) then
   with Devices.CustomDevices.M1_Panel
	  ' Play a preconfigured M1 message called SpecialThursday
	  .Voice.SpecialThursday.Play = True
	  ' Display my message on all keypads in area 1
	  .Keypads.MessageArea = 1
	  .Keypads.MessageLine1 = "It is Special"
	  .Keypads.MessageLine2 = "Thursday!"
	  .Keypads.MessageBeep = False
	  .Keypads.MessageMode = 1
	  .Keypads.MessageSend = True
   end with
end if

You'd construct the voice message in the ELK M1 driver as a custom Sentence called "SpecialThursday" (or whatever you'd lke to call it). The NthDay and DayOfWeek functions would reside in a Module (in GlobalScripts), thereby making them available throughout Premise.

Fairly routine stuff.
 
Back
Top