Skip to content

Commit

Permalink
stateengine plugin: improve se_use handling when searching for attrib…
Browse files Browse the repository at this point in the history
…utes (gets evaluated only once in the beginning)
  • Loading branch information
onkelandy committed Jul 25, 2024
1 parent 7aeb57b commit 5b00ffe
Show file tree
Hide file tree
Showing 7 changed files with 39 additions and 32 deletions.
30 changes: 15 additions & 15 deletions stateengine/StateEngineAction.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,10 +286,10 @@ def check_getitem_fromeval(self, check_item, check_value=None, check_mindelta=No
'issueorigin': [{'state': 'unknown', 'action': self._function}]}}
return check_item, check_value, check_mindelta, _issue

def check_complete(self, state, check_item, check_status, check_mindelta, check_value, action_type, evals_items=None):
def check_complete(self, state, check_item, check_status, check_mindelta, check_value, action_type, evals_items=None, use=None):
_issue = {self._name: {'issue': None,
'issueorigin': [{'state': state.id, 'action': self._function}]}}
self._log_develop("Check item {} status {} value {} evals_items {}", check_item, check_status, check_value, evals_items)
self._log_develop("Check item {} status {} value {} use {} evals_items {}", check_item, check_status, check_value, use, evals_items)
try:
_name = evals_items.get(self.name)
if _name is not None:
Expand All @@ -311,13 +311,13 @@ def check_complete(self, state, check_item, check_status, check_mindelta, check_
self._log_info("No valid item info for action {}, trying to get differently. Problem: {}", self._name, ex)
# missing item in action: Try to find it.
if check_item is None:
item = StateEngineTools.find_attribute(self._sh, state, "se_item_" + self._name)
item = StateEngineTools.find_attribute(self._sh, state, "se_item_" + self._name, 0, use)
if item is not None:
check_item, _issue = self._abitem.return_item(item)
_issue = {self._name: {'issue': _issue,
'issueorigin': [{'state': state.id, 'action': self._function}]}}
else:
item = StateEngineTools.find_attribute(self._sh, state, "se_eval_" + self._name)
item = StateEngineTools.find_attribute(self._sh, state, "se_eval_" + self._name, 0, use)
if item is not None:
check_item = str(item)

Expand All @@ -326,14 +326,14 @@ def check_complete(self, state, check_item, check_status, check_mindelta, check_
'issueorigin': [{'state': state.id, 'action': self._function}]}}
# missing status in action: Try to find it.
if check_status is None:
status = StateEngineTools.find_attribute(self._sh, state, "se_status_" + self._name)
status = StateEngineTools.find_attribute(self._sh, state, "se_status_" + self._name, 0, use)
if status is not None:
check_status, _issue = self._abitem.return_item(status)
_issue = {self._name: {'issue': _issue,
'issueorigin': [{'state': state.id, 'action': self._function}]}}

if check_mindelta.is_empty():
mindelta = StateEngineTools.find_attribute(self._sh, state, "se_mindelta_" + self._name)
mindelta = StateEngineTools.find_attribute(self._sh, state, "se_mindelta_" + self._name, 0, use)
if mindelta is not None:
check_mindelta.set(mindelta)

Expand Down Expand Up @@ -522,7 +522,7 @@ def update(self, value):

# Complete action
# state: state (item) to read from
def complete(self, state, evals_items=None):
def complete(self, state, evals_items=None, use=None):
raise NotImplementedError("Class {} doesn't implement complete()".format(self.__class__.__name__))

# Check if execution is possible
Expand Down Expand Up @@ -625,9 +625,9 @@ def update(self, value):

# Complete action
# state: state (item) to read from
def complete(self, state, evals_items=None):
def complete(self, state, evals_items=None, use=None):
self.__item, self.__status, self.__mindelta, self.__value, _issue = self.check_complete(
state, self.__item, self.__status, self.__mindelta, self.__value, "set", evals_items)
state, self.__item, self.__status, self.__mindelta, self.__value, "set", evals_items, use)
self._action_status = _issue
return _issue

Expand Down Expand Up @@ -775,7 +775,7 @@ def update(self, value):

# Complete action
# state: state (item) to read from
def complete(self, state, evals_items=None):
def complete(self, state, evals_items=None, use=None):
self._scheduler_name = "{}-SeByAttrDelayTimer".format(self.__byattr)
_issue = {self._name: {'issue': None, 'attribute': self.__byattr,
'issueorigin': [{'state': 'unknown', 'action': self._function}]}}
Expand Down Expand Up @@ -833,7 +833,7 @@ def update(self, value):

# Complete action
# state: state (item) to read from
def complete(self, state, evals_items=None):
def complete(self, state, evals_items=None, use=None):
self._scheduler_name = "{}-SeLogicDelayTimer".format(self.__logic)
_issue = {self._name: {'issue': None, 'logic': self.__logic,
'issueorigin': [{'state': 'unknown', 'action': self._function}]}}
Expand Down Expand Up @@ -908,7 +908,7 @@ def update(self, value):

# Complete action
# state: state (item) to read from
def complete(self, state, evals_items=None):
def complete(self, state, evals_items=None, use=None):
self._scheduler_name = "{}-SeRunDelayTimer".format(StateEngineTools.get_eval_name(self.__eval))
_issue = {self._name: {'issue': None, 'eval': StateEngineTools.get_eval_name(self.__eval),
'issueorigin': [{'state': 'unknown', 'action': self._function}]}}
Expand Down Expand Up @@ -1003,9 +1003,9 @@ def update(self, value):

# Complete action
# state: state (item) to read from
def complete(self, state, evals_items=None):
def complete(self, state, evals_items=None, use=None):
self.__item, self.__status, self.__mindelta, self.__value, _issue = self.check_complete(
state, self.__item, self.__status, self.__mindelta, self.__value, "force", evals_items)
state, self.__item, self.__status, self.__mindelta, self.__value, "force", evals_items, use)
self._action_status = _issue
return _issue

Expand Down Expand Up @@ -1189,7 +1189,7 @@ def update(self, value):

# Complete action
# state: state (item) to read from
def complete(self, state, evals_items=None):
def complete(self, state, evals_items=None, use=None):
if isinstance(self.__value, list):
item = self.__value[0].property.path
else:
Expand Down
3 changes: 2 additions & 1 deletion stateengine/StateEngineActions.py
Original file line number Diff line number Diff line change
Expand Up @@ -510,9 +510,10 @@ def __raise_missing_parameter_error(self, parameter, param_name):
# state: state (item) to read from
def complete(self, state, evals_items=None):
_status = {}
use = state.use.get()
for name in self.__actions:
try:
_status.update(self.__actions[name].complete(state, evals_items))
_status.update(self.__actions[name].complete(state, evals_items, use))
except ValueError as ex:
_status.update({name: {'issue': ex, 'issueorigin': {'state': state.id, 'action': 'unknown'}}})
raise ValueError("State '{0}', Action '{1}': {2}".format(state.id, name, ex))
Expand Down
17 changes: 9 additions & 8 deletions stateengine/StateEngineCondition.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,18 @@ def __repr__(self):
"'status_eval': {}, 'value': {}".format(self.__item, self.__status, self.__eval,
self.__status_eval, self.__value)

def check_items(self, check, value=None, state=None):
def check_items(self, check, value=None, state=None, use=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 state and use is None:
use = state.use.get()
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, state, "se_item_" + self.__name)
value = StateEngineTools.find_attribute(self._sh, state, "se_item_" + self.__name, 0, use)
if isinstance(value, str):
match = re.match(r'^(.*):', value)
if value.startswith("eval:"):
Expand All @@ -95,7 +97,7 @@ def check_items(self, check, value=None, state=None):
if check == "attribute":
value = _orig_value
if value is None:
value = StateEngineTools.find_attribute(self._sh, state, "se_status_" + self.__name)
value = StateEngineTools.find_attribute(self._sh, state, "se_status_" + self.__name, 0, use)
if isinstance(value, str):
match = re.match(r'^(.*):', value)
if isinstance(value, str) and value.startswith("eval:"):
Expand All @@ -114,7 +116,7 @@ def check_items(self, check, value=None, state=None):
status_value = value
if check == "se_eval" or (check == "attribute" and self.__eval is None):
if value is None:
value = StateEngineTools.find_attribute(self._sh, state, "se_eval_" + self.__name)
value = StateEngineTools.find_attribute(self._sh, state, "se_eval_" + self.__name, 0, use)
if isinstance(value, str):
match = re.match(r'^(.*):', value)
if value.startswith("eval:"):
Expand All @@ -130,7 +132,7 @@ def check_items(self, check, value=None, state=None):
if check == "attribute":
value = _orig_value
if value is None:
value = StateEngineTools.find_attribute(self._sh, state, "se_status_eval_" + self.__name)
value = StateEngineTools.find_attribute(self._sh, state, "se_status_eval_" + self.__name, 0, use)
if isinstance(value, str):
match = re.match(r'^(.*):', value)
if value.startswith("eval:"):
Expand Down Expand Up @@ -225,7 +227,7 @@ def get(self):
# Complete condition (do some checks, cast value, min and max based on item or eval data types)
# state: state (item) to read from
# abitem_object: Related SeItem instance for later determination of current age and current delay
def complete(self, state):
def complete(self, state, use):
# check if it is possible to complete this condition
if self.__min.is_empty() and self.__max.is_empty() and self.__value.is_empty() \
and self.__agemin.is_empty() and self.__agemax.is_empty() \
Expand Down Expand Up @@ -284,8 +286,7 @@ def complete(self, state):
self.__eval = self._abitem.get_update_original_caller
elif self.__name == "original_source":
self.__eval = self._abitem.get_update_original_source

self.check_items("attribute", None, state)
self.check_items("attribute", None, state, use)

# now we should have either 'item' or '(status)eval' set. If not, raise ValueError
if all(item is None for item in [self.__item, self.__status, self.__eval, self.__status_eval]):
Expand Down
4 changes: 2 additions & 2 deletions stateengine/StateEngineConditionSet.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,13 +149,13 @@ def update(self, item, grandparent_item):

# Check the condition set, optimize and complete it
# state: state (item) to read from
def complete(self, state):
def complete(self, state, use):
conditions_to_remove = []
# try to complete conditions

for name in self.conditions:
try:
if not self.__conditions[name].complete(state):
if not self.__conditions[name].complete(state, use):
conditions_to_remove.append(name)
continue
except ValueError as ex:
Expand Down
3 changes: 2 additions & 1 deletion stateengine/StateEngineConditionSets.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,9 @@ def update(self, name, item, grandparent_item):
# Check the condition sets, optimize and complete them
# state: item (item) to read from
def complete(self, state):
use = state.use.get()
for name in self.__condition_sets:
self.__condition_sets[name].complete(state)
self.__condition_sets[name].complete(state, use)

# Write all condition sets to logger
def write_to_logger(self):
Expand Down
2 changes: 2 additions & 0 deletions stateengine/StateEngineState.py
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,8 @@ def update_action_status(action_status, actiontype):
else:
self.__use_done.append(element)
self.__fill(element, recursion_depth + 1, _name)
elif _fill and element is not None and element in self.__use_done:
self._log_debug("Ignoring element {} as it is already added.", element)
self.__use.set(cleaned_use_list)
# Get action sets and condition sets
parent_item = item_state.return_parent()
Expand Down
12 changes: 7 additions & 5 deletions stateengine/StateEngineTools.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ def cast_time(value):
# smarthome: instance of smarthome.py base class
# base_item: base item to search in
# attribute: name of attribute to find
def find_attribute(smarthome, state, attribute, recursion_depth=0):
def find_attribute(smarthome, state, attribute, recursion_depth=0, use=None):
if isinstance(state, list):
for element in state:
result = find_attribute(smarthome, element, attribute, recursion_depth)
Expand All @@ -269,11 +269,13 @@ def find_attribute(smarthome, state, attribute, recursion_depth=0):
try:
# if state is state object, get the item and se_use information
base_item = state.state_item
_use = state.use.get()
if use is None:
use = state.use.get()
print(f"got use {use}")
except Exception:
# if state is a standard item (e.g. evaluated by se_use, just take it as it is
base_item = state
_use = None
use = None
parent_item = base_item.return_parent()
if parent_item == Items.get_instance():
pass
Expand All @@ -286,10 +288,10 @@ def find_attribute(smarthome, state, attribute, recursion_depth=0):
return None

# 2: if state has attribute "se_use", get the item to use and search this item for required attribute
if _use is not None:
if use is not None:
if recursion_depth > 5:
return None
result = find_attribute(smarthome, _use, attribute, recursion_depth + 1)
result = find_attribute(smarthome, use, attribute, recursion_depth + 1)
if result is not None:
return result

Expand Down

0 comments on commit 5b00ffe

Please sign in to comment.