Hi,
I honestly haven’t tested it, but I think I have a solution to the following problem:
Under Time-based Triggers you can find the trigger condition:
Time is <item> [timeOnly]
timeOnly means:
When using an item and you want to ignore the date-portion of that item the timeOnly
option can be used.
Specifically, you use a DateTime item and if this DateTime or only the Time (timeOnly) is reached, this rule is triggered!
So as example you have following two options as rule:
rule "Morning Greeting"
when
Time is Morning_Time
then
// Aktionen, die am Morgen ausgeführt werden sollen
logInfo("Morning Greeting", "Guten Morgen!")
end
or:
rule "Morning Greeting"
when
Time is Morning_Time timeOnly
then
// Aktionen, die am Morgen ausgeführt werden sollen
logInfo("Morning Greeting", "Guten Morgen!")
end
In Jython you don’t have this trigger condition.
You have:
# Cron
@when("Time cron 55 55 5 * * ?")
# Items and Groups
@when("Item ITEM_NAME received update [NEW_STATE]")
@when("Item GROUP_NAME received update [NEW_STATE]")
@when("Member of GROUP_NAME received update [NEW_STATE]")
@when("Descendent of GROUP_NAME received update [NEW_STATE]")
@when("Item ITEM_NAME changed [from OLD_STATE] [to NEW_STATE]")
@when("Item GROUP_NAME changed [from OLD_STATE] [to NEW_STATE]")
@when("Member of GROUP_NAME changed [from OLD_STATE] [to NEW_STATE]")
@when("Descendent of GROUP_NAME changed [from OLD_STATE] [to NEW_STATE]")
@when("Item ITEM_NAME received command [COMMAND]")
@when("Item GROUP_NAME received command [COMMAND]")
@when("Member of GROUP_NAME received command [COMMAND]")
@when("Descendent of GROUP_NAME received command [COMMAND]")
# Thing Event
@when("Thing THING:NAME received update [NEW_STATE]")
@when("Thing THING:NAME changed [from OLD_STATE] [to NEW_STATE]")
# Channel Event
@when("Channel CHANNEL:NAME triggered [EVENT]")
# System based
@when("System started")
I am trying a workaround and my approach looks like this:
import core
from core.rules import rule
from core.triggers import when
from core.actions import LogAction
from datetime import datetime
def datetime_item_to_cron_expression(item_name, timeOnly=False):
"""
Convert a DateTime Item to a cron expression.
Args:
item_name (str): The name of the DateTime Item.
timeOnly (bool): When using an item and you want to ignore the date-portion of that item the timeOnly option can be used.
Returns:
str: The generated cron expression.
"""
# Annahme: Hier wird der Zustand des DateTime-Items abgerufen
item_state = ir.getItem(str(item_name)).state
# Annahme: Hier wird der Zustand des DateTime-Items in ein datetime-Objekt konvertiert
date_time = datetime.strptime(item_state, "%Y-%m-%dT%H:%M:%S.%f%z")
# Extrahiere Jahr, Monat, Tag, Stunde und Minute aus dem datetime-Objekt
if timeOnly:
year = 0
month = 0
day = 0
else:
year = date_time.year
month = date_time.month
day = date_time.day
hour = date_time.hour
minute = date_time.minute
# Erstelle die Cron-Expression im Format: "Minute Stunde Tag Monat ? Jahr"
cron_expression = "{} {} {} {} ? {}".format(minute, hour, day, month, year)
return cron_expression
@rule("Time is <item> time test rule")
@when("Time cron {}".format(datetime_item_to_cron_expression("testDateTimeItem"))) # Beispiel für 8 Uhr morgens
def time_is_datetime_item(event):
# Aktionen, die am Morgen ausgeführt werden sollen
LogAction.logInfo("Time is <item> test rule", "Rule successfully triggered!")
What other problem is there?
Right, I create the trigger for the rule when loading the rule. So if the state of my DateTime item changes, the trigger would not be changed. This makes the dependency on a DateTime item for a trigger in the DSL rules very efficient.
What solution could there be?
I delete the old rule as soon as the state of the DateTime item changes and create a new rule. My approach would be to create this rule using a function and delete it accordingly. Because nothing changes in the actual rule. So I only have to time when I create or recreate this rule.
The rule looks like this:
import core
#from core import osgi
from core.rules import rule
from core.triggers import when
from core.actions import LogAction
from datetime import datetime
from core.jsr223.scope import scriptExtension
import time
ruleRegistry = scriptExtension.get("ruleRegistry")
RULE_NAME = "Time is <item> time test rule"
ITEM = "testDateTime"
def datetime_item_to_cron_expression(item_name, timeOnly=False):
"""
Convert a DateTime Item to a cron expression.
Args:
item_name (str): The name of the DateTime Item.
timeOnly (bool): When using an item and you want to ignore the date-portion of that item the timeOnly option can be used.
Returns:
str: The generated cron expression.
"""
# Annahme: Hier wird der Zustand des DateTime-Items abgerufen
item_state = str(ir.getItem(str(item_name)).state)
# Annahme: Hier wird der Zustand des DateTime-Items in ein datetime-Objekt konvertiert
# Annahme: Hier wird der Zustand des DateTime-Items in ein datetime-Objekt konvertiert
date_time = datetime.strptime(item_state[:-5], "%Y-%m-%dT%H:%M:%S.%f")
# Extrahiere Jahr, Monat, Tag, Stunde und Minute aus dem datetime-Objekt
if timeOnly:
year = "*"
month = "*"
day = "*"
else:
year = date_time.year
month = date_time.month
day = date_time.day
day_of_week = "?"
hour = date_time.hour
minute = date_time.minute
second = date_time.second
# Erstelle die Cron-Expression im Format: "Sekunden Minuten Stunden Tag Monat ? Jahr"
cron_expression = "{} {} {} {} {} {} {}".format(second, minute, hour, day, month, day_of_week, year)
return cron_expression
@rule("Time is <time> creation at system start")
@when("System started")
def init(event):
create_rule()
@rule("Change Time is <item> trigger condition")
@when("Item {} changed".format(ITEM))
def change_rule_trigger(event):
delete_rule()
time.sleep(2)
create_rule()
def create_rule():
@rule(RULE_NAME)
@when("Time cron {}".format(datetime_item_to_cron_expression(ITEM)))
def time_is_datetime_item(event):
# Aktionen, die am Morgen ausgeführt werden sollen
LogAction.logInfo("Time is <item> test rule", "Rule successfully triggered!")
def delete_rule():
for objRule in [objRule for objRule in ruleRegistry.getAll() if objRule.name == RULE_NAME]:
ruleRegistry.remove(objRule.UID)
As I said, it is still untested. I won’t get round to testing it until tomorrow or the day after.
What could be implemented in a similar way?
“Time is midnight” or “Time is noon” and the like could also be implemented using functions that are then simply converted to cron expressions.
What can be done better?
- I can of course import my functions for Time is , Midnight, Noon, etc. So I can use it in different Python/Jython files.
- Of course, I can also write functions for Create and Delete in a more generalised way and thus reuse them more skilfully.
- I can of course check whether the state is empty.
- Of course, I can also delete the rule for a date that has already expired if no timeOnly is set
- …
Here the tested rule
import core
#from core import osgi
from core.rules import rule
from core.triggers import when
from core.actions import LogAction
from datetime import datetime
from core.jsr223.scope import scriptExtension
import time
ruleRegistry = scriptExtension.get("ruleRegistry")
RULE_NAME = "Time is <item> time test rule"
ITEM = "testDateTime"
def datetime_item_to_cron_expression(item_name, timeOnly=False):
"""
Convert a DateTime Item to a cron expression.
Args:
item_name (str): The name of the DateTime Item.
timeOnly (bool): When using an item and you want to ignore the date-portion of that item the timeOnly option can be used.
Returns:
str: The generated cron expression.
"""
# Annahme: Hier wird der Zustand des DateTime-Items abgerufen
item_state = str(ir.getItem(str(item_name)).state)
# Annahme: Hier wird der Zustand des DateTime-Items in ein datetime-Objekt konvertiert
# Annahme: Hier wird der Zustand des DateTime-Items in ein datetime-Objekt konvertiert
date_time = datetime.strptime(item_state[:-5], "%Y-%m-%dT%H:%M:%S.%f")
# Extrahiere Jahr, Monat, Tag, Stunde und Minute aus dem datetime-Objekt
if timeOnly:
year = "*"
month = "*"
day = "*"
else:
year = date_time.year
month = date_time.month
day = date_time.day
day_of_week = "?"
hour = date_time.hour
minute = date_time.minute
second = date_time.second
# Erstelle die Cron-Expression im Format: "Sekunden Minuten Stunden Tag Monat ? Jahr"
cron_expression = "{} {} {} {} {} {} {}".format(second, minute, hour, day, month, day_of_week, year)
return cron_expression
def time_is_midnight():
return "0 0 0 * * ? *"
def time_is_morning():
return "0 0 8 * * ? *"
def time_is_noon():
return "0 0 12 * * ? *"
def time_is_afternoon():
return "0 0 15 * * ? *"
def time_is_evening():
return "0 0 18 * * ? *"
def time_is_night():
return "0 0 21 * * ? *"
@rule("Time is <time> creation at system start")
@when("System started")
def init(event):
create_rule()
@rule("Change Time is <item> trigger condition")
@when("Item {} changed".format(ITEM))
def change_rule_trigger(event):
delete_rule()
time.sleep(2)
create_rule()
def create_rule():
@rule(RULE_NAME)
@when("Time cron {}".format(datetime_item_to_cron_expression(ITEM)))
def time_is_datetime_item(event):
LogAction.logInfo("Time is <item> test rule", "Rule Time is <item> time successfully triggered!")
def delete_rule():
for objRule in [objRule for objRule in ruleRegistry.getAll() if objRule.name == RULE_NAME]:
ruleRegistry.remove(objRule.UID)
@rule("Rule Time is midnight")
@when("Time cron {}".format(time_is_midnight()))
def time_is_midnight_rule(event):
LogAction.logInfo("Time is <item> test rule", "Rule Time is midnight successfully triggered!")
@rule("Rule Time is noon")
@when("Time cron {}".format(time_is_noon()))
def time_is_noon_rule(event):
LogAction.logInfo("Time is <item> test rule", "Rule Time is noon successfully triggered!")
@rule("Rule Time is morning")
@when("Time cron {}".format(time_is_morning()))
def time_is_morning_rule(event):
LogAction.logInfo("Time is <item> test rule", "Rule Time is morning successfully triggered!")
@rule("Rule Time is afternoon")
@when("Time cron {}".format(time_is_afternoon()))
def time_is_afternoon_rule(event):
LogAction.logInfo("Time is <item> test rule", "Rule Time is afternoon successfully triggered!")
@rule("Rule Time is evening")
@when("Time cron {}".format(time_is_evening()))
def time_is_evening_rule(event):
LogAction.logInfo("Time is <item> test rule", "Rule Time is evening successfully triggered!")
@rule("Rule Time is night")
@when("Time cron {}".format(time_is_night()))
def time_is_night_rule(event):
LogAction.logInfo("Time is <item> test rule", "Rule Time is night successfully triggered!")
This works fine.
Perhaps this approach will help one or two people.
Kind regards
Michael