Hi,
if I understand correctly this problem is already treated but I can’t find the solution.
Short story is I try to add a new rule dynamically from a Python module.
First time when the module is called by a script everything works but when the same code is run by a rule doesn’t work and I get this error in log:
File "/etc/openhab2/automation/lib/python/core/log.py", line 51, in wrapper
return fn(*args, **kwargs)
File "/etc/openhab2/automation/lib/python/personal/setpoint_programmer.py", line 128, in setDailyProgram
a = AD(rule) #addRule(rule)
File "/etc/openhab2/automation/lib/python/core/rules.py", line 130, in addRule
return get_automation_manager().addRule(rule)
File "/etc/openhab2/automation/lib/python/core/jsr223.py", line 68, in get_automation_manager
scope = get_scope()
File "/etc/openhab2/automation/lib/python/core/jsr223.py", line 27, in get_scope
raise EnvironmentError("No JSR223 scope is available")
EnvironmentError: No JSR223 scope is available
I understand the problem is the difference between the two execution context but I don’t know how to solve.
Before posting the code here is the idea, the plan is a weekly programmed thermostat and reuse the code to do it form some setpoints:
- A daily program is a list of tuple
- each tuple is (time, temperature) that is transfomed in a CronTrigger rule that change setpoint at scheduled time.
- I have map between day and daily program
- at midnight a CrontTrigger run code that change from one program to another
- to change program old rules are deleted and new rule are added.
And here is the code in the module (I left commented lines that I tried):
#from core.jsr223.scope import events, items
from core.log import logging, log_traceback
import inspect
import re, sys
from datetime import date, time, datetime
from core.jsr223.scope import scriptExtension
scriptExtension.importPreset("RuleSimple")
scriptExtension.importPreset("RuleSupport")
rules = scriptExtension.get("ruleRegistry")
# scriptExtension.importPreset("RuleFactories")
# from core.rules import SimpleRule
# from core.jsr223 import get_automation_manager
from core.triggers import CronTrigger
#from core.jsr223.scope import ruleRegistry
from core.jsr223.scope import events
from core.rules import addRule as AD
logger = logging.getLogger("setpoint_programmer")
logger.info("Python version: {}".format(sys.version))
dayNames = ['monday','tuesday','wednesday','thursday','friday','saturday','sunday']
# program_test = {
# 'weekly' : {
# 'monday': 'prog1',
# 'tuesday': 'prog2',
# 'wednesday': 'prog1',
# 'thursday': 'prog2',
# 'friday': 'prog1',
# 'saturday': 'prog2',
# 'sunday' : 'prog1'
# },
# 'daily':{
# 'prog1': [('18:00', 22),('18:05', 20)],
# 'prog2': [('19:00', 25)]
# }
# }
timePattern = re.compile("(?P<hour>\d+):(?P<minute>\d+)")
class ChangeSetPoint(SimpleRule):
def __init__(self, setpoint_item, time, setpoint_value):
super(ChangeSetPoint, self).__init__()
self.setpoint_item = setpoint_item
self.time = time
self.setpoint_value = setpoint_value
m = timePattern.match(self.time)
if m is None:
raise ValueError("Unsupported time string")
self.time_hour = int(m.group('hour'))
self.time_minute = int(m.group('minute'))
if self.time_hour > 24 or self.time_minute > 60:
raise ValueError("Wrong hour or minutes value")
cronString = "0 {0} {1} * * ? *".format(self.time_minute, self.time_hour)
logger.debug("CronString generation: %s '%s'", self.time, cronString)
self.triggers = [CronTrigger(cronString).trigger]
def execute(self, module, info):
events.sendCommand(self.setpoint_item, self.setpoint_value)
class NewDayProgram(SimpleRule):
def __init__(self, thermostat):
super(NewDayProgram, self).__init__()
self.thermostat = thermostat
cronString = "0 5 0 * * ? *"
self.triggers = [CronTrigger(cronString).trigger]
def execute(self, module, info):
logger.debug("execute new Day program")
today = dayNames[date.today().weekday()]
self.thermostat.changeProgram(today)
class ProgramedThermostat():
def __init__(self, setpoint_item, program):
self.setpoint_item = setpoint_item
self.program = program
self.rulelist = []
self.setTodayProgram()
addRule(NewDayProgram(self))
def setTodayProgram(self):
today = dayNames[date.today().weekday()]
self.setDailyProgram(today)
logger.debug("set today %s", today)
def cleanRules(self):
logger.debug("ready to cleanRules")
tmp = self.rulelist
self.rulelist = []
logger.debug("before cycle")
for r in tmp:
logger.debug("delete %s", r)
rules.remove(r)
@log_traceback
def setDailyProgram(self, day):
progName = self.program['weekly'][day]
prog = self.program['daily'][progName]
logger.debug("Set program %s", prog)
now = datetime.now().time()
toApply = None
for p in prog:
rule = ChangeSetPoint(self.setpoint_item, p[0], p[1])
logger.debug("opt0")
logger.debug("opt1 %s")
a = AD(rule) #addRule(rule)
logger.debug("opt2 %s %s", type(a), a)
uid = a.getUID()
logger.debug("opt3 %s", uid)
self.rulelist.append(uid)
logger.debug("ruleadded at %s", p[0])
if datetime.strptime(p[0], "%H:%M").time() <= now:
toApply = p
if toApply is not None:
events.sendCommand(self.setpoint_item, toApply[1])
def changeProgram(self, day):
logger.debug("Change to program for day %s", day)
self.cleanRules()
self.setDailyProgram(day)
#pt = ProgramedThermostat(itemRegistry.get("test_level1"), program_test)
Thanks for any help.
Davide