Skip to content

Commit

Permalink
Merge pull request #949 from onkelandy/stateengine
Browse files Browse the repository at this point in the history
Stateengine Plugin: multiple updates and fixes
  • Loading branch information
onkelandy committed Jul 30, 2024
2 parents 75f3a0f + fb1ddc7 commit 1cf6936
Show file tree
Hide file tree
Showing 20 changed files with 996 additions and 701 deletions.
223 changes: 122 additions & 101 deletions stateengine/StateEngineAction.py

Large diffs are not rendered by default.

193 changes: 99 additions & 94 deletions stateengine/StateEngineActions.py

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions stateengine/StateEngineCliCommands.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
# noinspection PyUnresolvedReferences
from lib.model.smartplugin import SmartPlugin
from lib.plugin import Plugins
from bin.smarthome import VERSION


class SeCliCommands:
Expand All @@ -42,7 +41,8 @@ def __init__(self, smarthome, items, logger):
self.logger.info("StateEngine: Additional CLI commands not registered because CLI plugin is too old")
else:
cli.commands.add_command("se_list", self.cli_list, "StateEngine", "se_list: list StateEngine items")
cli.commands.add_command("se_detail", self.cli_detail, "StateEngine", "se_detail [seItem]: show details on StateEngine item [seItem]")
cli.commands.add_command("se_detail", self.cli_detail, "StateEngine",
"se_detail [seItem]: show details on StateEngine item [seItem]")
self.logger.info("StateEngine: Two additional CLI commands registered")
except AttributeError as err:
self.logger.error("StateEngine: Additional CLI commands not registered because error occured.")
Expand Down
208 changes: 95 additions & 113 deletions stateengine/StateEngineCondition.py

Large diffs are not rendered by default.

23 changes: 15 additions & 8 deletions stateengine/StateEngineConditionSet.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ def name(self):
def id(self):
return self.__id

@property
def path(self):
return self.__id

# List of conditions that are part of this condition set
@property
def conditions(self):
Expand Down Expand Up @@ -111,6 +115,8 @@ def update(self, item, grandparent_item):
raise ValueError("Condition {0} error: {1}".format(name, ex))

# Update item from grandparent_item
if grandparent_item is None:
return self.__unused_attributes, self.__used_attributes
for attribute in grandparent_item.conf:
func, name = StateEngineTools.partition_strip(attribute, "_")

Expand Down Expand Up @@ -142,21 +148,22 @@ def update(self, item, grandparent_item):
return self.__unused_attributes, self.__used_attributes

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

for name in self.conditions:
try:
if not self.__conditions[name].complete(item_state):
if not self.__conditions[name].complete(state, use):
conditions_to_remove.append(name)
continue
except ValueError as ex:
self._abitem.update_attributes(self.__unused_attributes, self.__used_attributes)
self._abitem.update_issues('state', {item_state.property.path: {'issue': ex, 'issueorigin':
[{'conditionset': self.name, 'condition': name}]}})
self._abitem.update_issues('state', {state.id: {'issue': ex, 'issueorigin':
[{'conditionset': self.name, 'condition': name}]}})
text = "State '{0}', Condition Set '{1}', Condition '{2}' Error: {3}"
raise ValueError(text.format(item_state.property.path, self.name, name, ex))
raise ValueError(text.format(state.id, self.name, name, ex))

# Remove incomplete conditions
for name in conditions_to_remove:
Expand Down Expand Up @@ -184,14 +191,14 @@ def all_conditions_matching(self, state):
try:
self._log_info("Check condition set '{0}'", self.__name)
self._log_increase_indent()
self.__previousconditionset_set(self._abitem.get_variable('current.conditionset_id'), self._abitem.get_variable('current.conditionset_name'))
self.__previousconditionset_set(self._abitem.get_variable('current.conditionset_id'),
self._abitem.get_variable('current.conditionset_name'))
self.__currentconditionset_set(self.__id.property.path, self.__name)

for name in self.__conditions:
if not self.__conditions[name].check(state):
self.__currentconditionset_set('', '')
return False
#self._abitem.previousconditionset_set(self._abitem.get_variable('previous.conditionset_id'), self._abitem.get_variable('previous.conditionset_name'))
self._abitem.lastconditionset_set(self.__id.property.path, self.__name)
return True
finally:
Expand Down
8 changes: 5 additions & 3 deletions stateengine/StateEngineConditionSets.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,12 @@ def update(self, name, item, grandparent_item):
return self.__condition_sets[name].unused_attributes, self.__condition_sets[name].used_attributes

# Check the condition sets, optimize and complete them
# item_state: item to read from
def complete(self, item_state):
# state: item (item) to read from
def complete(self, state, use=None):
if use is None:
use = state.use.get()
for name in self.__condition_sets:
self.__condition_sets[name].complete(item_state)
self.__condition_sets[name].complete(state, use)

# Write all condition sets to logger
def write_to_logger(self):
Expand Down
46 changes: 26 additions & 20 deletions stateengine/StateEngineEval.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ def remap(_value, _minoutput):
_lamella_open_value = StateEngineDefaults.lamella_open_value
_lamella_text = " (based on lamella open value of {0})".format(_lamella_open_value)
value = remap(90 - altitude, _lamella_open_value) + offset
self._log_debug("Blinds at right angle to the sun at {0}° with an offset of {1}°{2}", value, offset, _lamella_text)
self._log_debug("Blinds at right angle to the sun at {0}° with an offset of {1}°{2}",
value, offset, _lamella_text)

self._log_decrease_indent()
self._eval_lock.release()
Expand Down Expand Up @@ -94,8 +95,8 @@ def get_variable(self, varname):
self._eval_lock.acquire()
self._log_debug("Executing method 'get_variable({0})'", varname)
try:
if self._abitem._initactionname and varname == 'current.action_name':
returnvalue = self._abitem._initactionname
if self._abitem.initactionname and varname == 'current.action_name':
returnvalue = self._abitem.initactionname
self._log_debug("Return '{}' for variable {} during init", returnvalue, varname)
else:
returnvalue = self._abitem.get_variable(varname)
Expand All @@ -115,8 +116,8 @@ def get_relative_itemid(self, subitem_id):
self._eval_lock.acquire()
self._log_debug("Executing method 'get_relative_itemid({0})'", subitem_id)
try:
if self._abitem._initstate and subitem_id == '..state_name':
returnvalue = self._abitem.return_item(self._abitem._initstate.id)[0].property.path
if self._abitem.initstate and subitem_id == '..state_name':
returnvalue = self._abitem.return_item(self._abitem.initstate.id)[0].property.path
self._log_debug("Return item path '{0}' during init", returnvalue)
else:
returnvalue = self._abitem.return_item(subitem_id)[0].property.path
Expand All @@ -136,8 +137,8 @@ def get_relative_item(self, subitem_id):
self._eval_lock.acquire()
self._log_debug("Executing method 'get_relative_item({0})'", subitem_id)
try:
if self._abitem._initstate and subitem_id == '..state_name':
returnvalue, issue = self._abitem.return_item(self._abitem._initstate.id)
if self._abitem.initstate and subitem_id == '..state_name':
returnvalue, issue = self._abitem.return_item(self._abitem.initstate.id)
self._log_debug("Return item '{0}' during init", returnvalue)
else:
returnvalue, issue = self._abitem.return_item(subitem_id)
Expand All @@ -158,14 +159,16 @@ def get_relative_itemvalue(self, subitem_id):
returnvalue = []
self._log_debug("Executing method 'get_relative_itemvalue({0})'", subitem_id)
try:
if self._abitem._initstate and subitem_id == '..state_name':
returnvalue = self._abitem._initstate.text
if self._abitem.initstate and subitem_id == '..state_name':
returnvalue = self._abitem.initstate.text
self._log_debug("Return item value '{0}' during init", returnvalue)
else:
item, issue = self._abitem.return_item(subitem_id)
returnvalue = item.property.value
returnvalue = StateEngineTools.convert_str_to_list(returnvalue)
self._log_debug("Return item value '{0}' for item {1}", returnvalue, subitem_id)
issue = f" Issue: {issue}" if issue not in [[], None, [None]] else ""
self._log_debug("Return item value '{0}' for item {1}.{2}",
returnvalue, subitem_id, issue)
except Exception as ex:
self._log_warning("Problem evaluating value of '{0}': {1}", subitem_id, ex)
finally:
Expand All @@ -182,16 +185,17 @@ def get_relative_itemproperty(self, subitem_id, prop):
self._eval_lock.acquire()
self._log_debug("Executing method 'get_relative_itemproperty({0}, {1})'", subitem_id, prop)
try:
item, issue = self._abitem.return_item(subitem_id)
item, _ = self._abitem.return_item(subitem_id)
except Exception as ex:
self._log_warning("Problem evaluating property of {0} - relative item might not exist. Error: {1}", subitem_id, ex)
self._log_warning("Problem evaluating property of {0} - relative item might not exist. Error: {1}",
subitem_id, ex)
self._eval_lock.release()
return
try:
if self._abitem._initstate and subitem_id == '..state_name':
returnvalue = getattr(self._abitem.return_item(self._abitem._initstate.id)[0].property, prop)
if self._abitem.initstate and subitem_id == '..state_name':
returnvalue = getattr(self._abitem.return_item(self._abitem.initstate.id)[0].property, prop)
self._log_debug("Return item property '{0}' from {1}: {2} during init", prop,
self._abitem.return_item(self._abitem._initstate.id)[0].property.path, returnvalue)
self._abitem.return_item(self._abitem.initstate.id)[0].property.path, returnvalue)
else:
returnvalue = getattr(item.property, prop)
if prop == "value":
Expand Down Expand Up @@ -221,20 +225,22 @@ def get_attribute_value(self, item, attrib):
def get_attributevalue(self, item, attrib):
self._eval_lock.acquire()
self._log_debug("Executing method 'get_attributevalue({0}, {1})'", item, attrib)
issue = None
if ":" in item:
var_type, item = StateEngineTools.partition_strip(item, ":")
if var_type == "var":
item, issue = self._abitem.return_item(self._abitem.get_variable(item))
else:
item, issue = self._abitem.return_item(item)
try:
if self._abitem._initstate and item == '..state_name':
returnvalue = self._abitem.return_item(self._abitem._initstate.id).conf[attrib]
self._log_debug("Return item attribute '{0}' from {1}: {2} during init",
attrib, self._abitem.return_item(self._abitem._initstate.id)[0].property.path, returnvalue)
if self._abitem.initstate and item == '..state_name':
returnvalue, issue = self._abitem.return_item(self._abitem.initstate.id).conf[attrib]
self._log_debug("Return item attribute '{0}' from {1}: {2} during init. Issue {3}", attrib,
self._abitem.return_item(self._abitem.initstate.id)[0].property.path, returnvalue, issue)
else:
returnvalue = item.conf[attrib]
self._log_debug("Return item attribute {0} from {1}: {2}", attrib, item.property.path, returnvalue)
self._log_debug("Return item attribute {0} from {1}: {2}. Issue {3}",
attrib, item.property.path, returnvalue, issue)
except Exception as ex:
returnvalue = None
self._log_warning("Problem evaluating attribute {0} of {1} - attribute might not exist. "
Expand Down
8 changes: 3 additions & 5 deletions stateengine/StateEngineFunctions.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
from . import StateEngineLogger
from . import StateEngineTools
from . import StateEngineDefaults
from lib.item import Items
from ast import literal_eval


Expand All @@ -45,7 +44,6 @@ def __init__(self, smarthome=None, logger=None):
self.__locks = {}
self.__global_struct = {}
self.__ab_alive = False
self.itemsApi = Items.get_instance()

def __repr__(self):
return "SeFunctions"
Expand Down Expand Up @@ -99,7 +97,7 @@ def check_include_exclude(entry_type):
elog.decrease_indent()
return None

item = self.itemsApi.return_item(item_id)
item = self.__sh.return_item(item_id)
if item is None:
self.logger.error("manual_item_update_eval: item {0} not found!".format(item_id))

Expand All @@ -113,7 +111,7 @@ def check_include_exclude(entry_type):

if "se_manual_logitem" in item.conf:
elog_item_id = item.conf["se_manual_logitem"]
elog_item = self.itemsApi.return_item(elog_item_id)
elog_item = self.__sh.return_item(elog_item_id)
if elog_item is None:
self.logger.error("manual_item_update_item: se_manual_logitem {0} not found!".format(elog_item_id))
elog = StateEngineLogger.SeLoggerDummy()
Expand All @@ -128,7 +126,7 @@ def check_include_exclude(entry_type):
retval_trigger = not item()
elog.info("Current value of item {0} is {1}", item_id, retval_no_trigger)

original_caller, original_source = StateEngineTools.get_original_caller(elog, caller, source)
original_caller, original_source = StateEngineTools.get_original_caller(self.__sh, elog, caller, source)
elog.info("get_caller({0}, {1}): original trigger by {2}:{3}", caller, source,
original_caller, original_source)
original = "{}:{}".format(original_caller, original_source)
Expand Down
Loading

0 comments on commit 1cf6936

Please sign in to comment.