Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stateengine Plugin: multiple fixes #948

Merged
merged 10 commits into from
Jul 5, 2024
10 changes: 8 additions & 2 deletions stateengine/StateEngineAction.py
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,7 @@ class SeActionSetItem(SeActionBase):
def __init__(self, abitem, name: str):
super().__init__(abitem, name)
self.__item = None
self.__eval_item = None
self.__status = None
self.__delta = 0
self.__value = StateEngineValue.SeValue(self._abitem, "value")
Expand All @@ -606,6 +607,7 @@ def __repr__(self):
def _getitem_fromeval(self):
if self.__item is None:
return
self.__eval_item = self.__item
self.__item, self.__value, self.__mindelta, _issue = self.check_getitem_fromeval(self.__item, self.__value,
self.__mindelta)
if self.__item is None:
Expand Down Expand Up @@ -643,8 +645,6 @@ def write_to_logger(self):
self._log_debug("item: {0}", self.__item.property.path)
else:
self._log_debug("item is not defined! Check log file.")
if self.__status is not None:
self._log_debug("status: {0}", self.__status.property.path)
self.__mindelta.write_to_logger()
self.__value.write_to_logger()

Expand Down Expand Up @@ -710,6 +710,7 @@ def _execute_set_add_remove(self, state, actionname, namevar, repeat_text, item,
self.update_webif_actionstatus(state, re.findall(pat, actionname)[0], 'True')
# noinspection PyCallingNonCallable
item(value, caller=self._caller, source=source)
self.__item = self.__eval_item

def get(self):
orig_item = self.__item
Expand All @@ -733,6 +734,7 @@ def get(self):
value = None
except Exception:
value = None
self.__item = orig_item
mindelta = self.__mindelta.get()
if mindelta is None:
result = {'function': str(self._function), 'item': item, 'item_from_eval': item_from_eval,
Expand Down Expand Up @@ -979,6 +981,7 @@ class SeActionForceItem(SeActionBase):
def __init__(self, abitem, name: str):
super().__init__(abitem, name)
self.__item = None
self.__eval_item = None
self.__status = None
self.__value = StateEngineValue.SeValue(self._abitem, "value")
self.__mindelta = StateEngineValue.SeValue(self._abitem, "mindelta")
Expand Down Expand Up @@ -1045,6 +1048,7 @@ def _can_execute(self, state):
def _getitem_fromeval(self):
if self.__item is None:
return
self.__eval_item = self.__item
self.__item, self.__value, self.__mindelta, _issue = self.check_getitem_fromeval(self.__item, self.__value,
self.__mindelta)
if self.__item is None:
Expand Down Expand Up @@ -1103,6 +1107,7 @@ def real_execute(self, state, actionname: str, namevar: str = "", repeat_text: s
self.update_webif_actionstatus(state, self._name, 'True')
# noinspection PyCallingNonCallable
self.__item(value, caller=self._caller, source=source)
self.__item = self.__eval_item

def get(self):
orig_item = self.__item
Expand All @@ -1126,6 +1131,7 @@ def get(self):
value = None
except Exception:
value = None
self.__item = orig_item
result = {'function': str(self._function), 'item': item, 'item_from_eval': item_from_eval, 'value': value,
'conditionset': str(self.conditionset.get()), 'previousconditionset': str(self.previousconditionset.get()),
'previousstate_conditionset': str(self.previousstate_conditionset.get()), 'actionstatus': {}}
Expand Down
35 changes: 21 additions & 14 deletions stateengine/StateEngineCondition.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,16 @@ def __repr__(self):
def check_items(self, check, value=None, item_state=None):
item_issue, status_issue, eval_issue, status_eval_issue = None, None, None, None
item_value, status_value, eval_value, status_eval_value = None, None, None, None
if check == "attribute":
_orig_value = value
else:
_orig_value = None
if check == "se_item" or (check == "attribute" and self.__item is None and self.__eval is None):
if value is None:
value = StateEngineTools.find_attribute(self._sh, item_state, "se_item_" + self.__name)
if value is not None:
if isinstance(value, str):
match = re.match(r'^(.*):', value)
if isinstance(value, str) and value.startswith("eval:"):
if value.startswith("eval:"):
_, _, value = value.partition(":")
self.__eval = value
self.__item = None
Expand All @@ -87,9 +91,11 @@ def check_items(self, check, value=None, item_state=None):
self.__item = value
item_value = value
if check == "se_status" or (check == "attribute" and self.__status is None and self.__status_eval is None):
if check == "attribute":
value = _orig_value
if value is None:
value = StateEngineTools.find_attribute(self._sh, item_state, "se_status_" + self.__name)
if value is not None:
if isinstance(value, str):
match = re.match(r'^(.*):', value)
if isinstance(value, str) and value.startswith("eval:"):
_, _, value = value.partition(":")
Expand All @@ -108,7 +114,7 @@ def check_items(self, check, value=None, item_state=None):
if check == "se_eval" or (check == "attribute" and self.__eval is None):
if value is None:
value = StateEngineTools.find_attribute(self._sh, item_state, "se_eval_" + self.__name)
if value is not None:
if isinstance(value, str):
match = re.match(r'^(.*):', value)
if value.startswith("eval:"):
_, _, value = value.partition("eval:")
Expand All @@ -120,9 +126,11 @@ def check_items(self, check, value=None, item_state=None):
self.__eval = value
eval_value = value
if check == "se_status_eval" or (check == "attribute" and self.__status_eval is None):
if check == "attribute":
value = _orig_value
if value is None:
value = StateEngineTools.find_attribute(self._sh, item_state, "se_status_eval_" + self.__name)
if value is not None:
if isinstance(value, str):
match = re.match(r'^(.*):', value)
if value.startswith("eval:"):
_, _, value = value.partition("eval:")
Expand Down Expand Up @@ -454,7 +462,7 @@ def __convert(convert_value, convert_current):
else:
self.__value.set_cast(StateEngineTools.cast_str)
convert_value = StateEngineTools.cast_str(convert_value)
convert_current = StateEngineTools.cast_str(convert_value)
convert_current = StateEngineTools.cast_str(convert_current)
if not type(_oldvalue) == type(convert_value):
self._log_debug("Value {} was type {} and therefore not the same"
" type as item value {}. It got converted to {}.",
Expand All @@ -469,7 +477,6 @@ def __convert(convert_value, convert_current):
self.__updatedbynegate if valuetype == "updatedby" else\
self.__triggeredbynegate if valuetype == "triggeredby" else\
self.__negate

if isinstance(value, list):
text = "Condition '{0}': {1}={2} negate={3} current={4}"
_key = ['{}'.format(state.id), 'conditionsets', '{}'.format(self._abitem.get_variable('current.conditionset_name')), '{}'.format(self.__name), 'current', '{}'.format(valuetype)]
Expand Down Expand Up @@ -850,26 +857,26 @@ def check_eval(eval_or_status_eval):

if self.__status is not None:
# noinspection PyUnusedLocal
self._log_debug("Trying to get {} of status item {}", eval_type, self.__status)
self._log_debug("Trying to get {} of status item {}", eval_type, self.__status.property.path)
return self.__status.property.last_change_age if eval_type == 'age' else\
self.__status.property.last_change_by if eval_type == 'changedby' else\
self.__status.property.last_update_by if eval_type == 'updatedby' else\
self.__status.property.last_trigger_by if eval_type == 'triggeredby' else\
self.__status.property.value
elif self.__status_eval is not None:
self._log_debug("Trying to get {} of statuseval {}", eval_type, self.__status_eval)
return_value = check_eval(self.__status_eval)
return return_value
elif self.__item is not None:
# noinspection PyUnusedLocal
self._log_debug("Trying to get {} of item {}", eval_type, self.__item)
self._log_debug("Trying to get {} of item {}", eval_type, self.__item.property.path)
return self.__item.property.last_change_age if eval_type == 'age' else\
self.__item.property.last_change_by if eval_type == 'changedby' else\
self.__item.property.last_update_by if eval_type == 'updatedby' else\
self.__item.property.last_trigger_by if eval_type == 'triggeredby' else\
self.__item.property.value
if self.__status_eval is not None:
self._log_debug("Trying to get {} of statuseval {}", eval_type, self.__status_eval)
return_value = check_eval(self.__status_eval)
return return_value
elif self.__eval is not None:
self._log_debug("Trying to get {} of statuseval {}", eval_type, self.__eval)
self._log_debug("Trying to get {} of eval {}", eval_type, self.__eval)
return_value = check_eval(self.__eval)
return return_value

Expand Down
7 changes: 7 additions & 0 deletions stateengine/StateEngineConditionSet.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ def update(self, item, grandparent_item):
if item is not None:
for attribute in item.conf:
func, name = StateEngineTools.partition_strip(attribute, "_")
if name.startswith("eval_"):
_, name = StateEngineTools.partition_strip(name, "_")
func = f"{func}_eval"
if name == "":
continue
try:
Expand All @@ -97,6 +100,7 @@ def update(self, item, grandparent_item):
self.__conditions[name] = StateEngineCondition.SeCondition(self._abitem, name)
issue = self.__conditions[name].set(func, item.conf[attribute])
self.__conditions.move_to_end(name, last=True)

if issue not in [[], None, [None]]:
self.__unused_attributes.update({name: {'attribute': attribute, 'issue': issue}})
elif name not in self.__used_attributes.keys():
Expand All @@ -110,6 +114,9 @@ def update(self, item, grandparent_item):
for attribute in grandparent_item.conf:
func, name = StateEngineTools.partition_strip(attribute, "_")

if name.startswith("eval_"):
_, name = StateEngineTools.partition_strip(name, "_")
func = f"{func}_eval"
if name == "":
continue
cond1 = name not in self.__used_attributes.keys()
Expand Down
5 changes: 4 additions & 1 deletion stateengine/StateEngineTools.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,10 @@ def cast_time(value):
# attribute: name of attribute to find
def find_attribute(smarthome, base_item, attribute, recursion_depth=0):
# 1: parent of given item could have attribute
parent_item = base_item.return_parent()
try:
parent_item = base_item.return_parent()
except Exception:
return None
try:
_parent_conf = parent_item.conf
if parent_item is not None and attribute in _parent_conf:
Expand Down
Loading