Skip to content

Commit

Permalink
Merge pull request #979 from onkelandy/stateengine
Browse files Browse the repository at this point in the history
stateengine plugin: improve visu
  • Loading branch information
Morg42 authored Dec 24, 2024
2 parents 6b1a2de + 1afe7a4 commit 707549d
Show file tree
Hide file tree
Showing 13 changed files with 598 additions and 371 deletions.
11 changes: 6 additions & 5 deletions stateengine/StateEngineAction.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@
from . import StateEngineEval
from . import StateEngineValue
from . import StateEngineDefaults
from . import StateEngineCurrent
import datetime
from lib.shtime import Shtime
import re
from lib.item import Items


# Base class from which all action classes are derived
Expand Down Expand Up @@ -67,6 +67,7 @@ def __cast_seconds(value):
def __init__(self, abitem, name: str):
super().__init__(abitem)
self._se_plugin = abitem.se_plugin
self.itemsApi = Items.get_instance()
self._parent = self._abitem.id
self._caller = StateEngineDefaults.plugin_identification
self.shtime = Shtime.get_instance()
Expand Down Expand Up @@ -431,7 +432,7 @@ def _check_condition(condition: str):
try:
_matching = cond.fullmatch(_updated_current_condition)
if _matching:
self._log_debug("Given {} '{}' matches current one: '{}'", condition, _orig_cond.pattern, _updated_current_condition)
self._log_debug("Given {} '{}' matching current one: '{}'", condition, _orig_cond.pattern, _updated_current_condition)
_condition_met.append(_updated_current_condition)
_conditions_met_count += 1
_conditions_met_type.append(condition)
Expand Down Expand Up @@ -927,7 +928,7 @@ def __repr__(self):
# value: Value of the set_(action_name) attribute
def update(self, value):
self.__byattr = value
_issue = {self._name: {'issue': None, 'attribute': self.__byattr,
_issue = {self._name: {'issue': None, 'attribute': [self.__byattr],
'issueorigin': [{'state': self._state.id, 'action': self._function}]}}
return _issue

Expand All @@ -938,7 +939,7 @@ def complete(self, evals_items=None, use=None):
self._abitem.set_variable('current.action_name', self._name)
self._abitem.set_variable('current.state_name', self._state.name)
self._scheduler_name = "{}-SeByAttrDelayTimer".format(self.__byattr)
_issue = {self._name: {'issue': None, 'attribute': self.__byattr,
_issue = {self._name: {'issue': None, 'attribute': [self.__byattr],
'issueorigin': [{'state': self._state.id, 'action': self._function}]}}
self._abitem.set_variable('current.action_name', '')
self._abitem.set_variable('current.state_name', '')
Expand All @@ -964,7 +965,7 @@ def real_execute(self, state, actionname: str, namevar: str = "", repeat_text: s
self._log_info("{0}: Setting values by attribute '{1}'.{2}", actionname, self.__byattr, repeat_text)
self.update_webif_actionstatus(state, self._name, 'True')
source = self.set_source(current_condition, previous_condition, previousstate_condition, next_condition)
for item in self._sh.find_items(self.__byattr):
for item in self.itemsApi.find_items(self.__byattr):
self._log_info("\t{0} = {1}", item.property.path, item.conf[self.__byattr])
item(item.conf[self.__byattr], caller=self._caller, source=source)
self._abitem.last_run = {self._name: datetime.datetime.now()}
Expand Down
32 changes: 15 additions & 17 deletions stateengine/StateEngineActions.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,10 +164,10 @@ def update(self, attribute, value):
# If we do not have the action yet (mode-attribute before action-attribute), ...
self.__unassigned_modes[name] = value
else:
_val, _issue = self.__actions[name].update_mode(value)
_issue = self.__actions[name].update_mode(value)
if _issue:
_issue_list.append(_issue)
_issue, _action = self.__check_mode_setting(name, _val, self.__actions[name].function, self.__actions[name])
_issue, _action = self.__check_mode_setting(name, value, self.__actions[name].function, self.__actions[name])
if _issue:
_issue_list.append(_issue)
if _action:
Expand All @@ -194,7 +194,7 @@ def update(self, attribute, value):
_count += 1
_issue = StateEngineTools.flatten_list(_issue_list)
except ValueError as ex:
_issue = {name: {'issue': ex, 'issueorigin': [{'state': 'unknown', 'action': self.__actions[name].function}], 'ignore': True}}
_issue = {name: {'issue': [str(ex)], 'attribute': [func], 'issueorigin': [{'state': self.__state.id, 'action': self.__actions[name].function}], 'ignore': True}}
if name in self.__actions:
del self.__actions[name]
self._log_warning("Ignoring action {0} because: {1}", attribute, ex)
Expand All @@ -208,8 +208,7 @@ def __check_force_setting(self, name, value, function):
if function not in ["set", "force"]:
_issue = {
name: {'issue': ['Parameter force not supported for this function'],
'attribute': 'force', 'issueorigin': [{'state': 'unknown', 'action': function}]}}
_issue = "Parameter 'force' not supported for this function"
'attribute': ['force'], 'issueorigin': [{'state': self.__state.id, 'action': function}]}}
self._log_warning("Attribute 'se_action_{0}': Parameter 'force' not supported "
"for function '{1}'", name, function)
elif value and function == "set":
Expand All @@ -230,8 +229,8 @@ def __check_mode_setting(self, name, value, function, action):
_issue = None
# Parameter mode is supported only for type "remove"
if "remove" not in function:
_issue = {name: {'issue': ['Parameter mode only supported for remove function'], 'attribute': 'mode',
'issueorigin': [{'state': 'unknown', 'action': function}]}}
_issue = {name: {'issue': ['Parameter mode only supported for remove function'], 'attribute': ['mode'],
'issueorigin': [{'state': self.__state.id, 'action': function}]}}
self._log_warning("Attribute 'se_action_{0}': Parameter 'mode' not supported for function '{1}'",
name, function)
elif function in ["remove", "remove all from list"]:
Expand All @@ -246,8 +245,8 @@ def __check_mode_setting(self, name, value, function, action):
self._log_info("Attribute 'se_action_{0}': Function 'remove' changed to '{1}'", name, value)
else:
_issue = {
name: {'issue': ['Parameter {} not allowed for mode!'.format(value)], 'attribute': 'mode',
'issueorigin': [{'state': 'unknown', 'action': function}]}}
name: {'issue': ['Parameter {} not allowed for mode!'.format(value)], 'attribute': ['mode'],
'issueorigin': [{'state': self.__state.id, 'action': function}]}}
self._log_warning(
"Attribute 'se_action_{0}': Parameter '{1}' for 'mode' is wrong - can only be {2}",
name, value, possible_mode_list)
Expand Down Expand Up @@ -365,9 +364,9 @@ def __handle_combined_action_attribute(self, name, value_list):
def remove_action(e):
if name in self.__actions:
del self.__actions[name]
i = {name: {'issue': [e], 'issueorigin': [{'state': 'unknown', 'action': parameter['function']}], 'ignore': True}}
i = {name: {'issue': [str(e)], 'attribute': [f'se_action_{name}'], 'issueorigin': [{'state': self.__state.id, 'action': parameter['function']}], 'ignore': True}}
_issue_list.append(i)
self._log_warning("Ignoring action {0} because: {1}", name, e)
self._log_warning("Removed action {0} because: {1}.", name, e)

parameter = {'function': None, 'force': None, 'repeat': None, 'delay': 0, 'order': None, 'nextconditionset': None, 'conditionset': None,
'previousconditionset': None, 'previousstate_conditionset': None, 'mode': None, 'instanteval': None, 'mindelta': None, 'minagedelta': None}
Expand Down Expand Up @@ -395,18 +394,18 @@ def remove_action(e):
else:
parameter[key] = val
except Exception as ex:
remove_action("Problem with entry {} for action {}: {}".format(entry, name, ex))
remove_action("Problem with entry {}: {}".format(entry, ex))
if _issue_list:
return _issue_list
parameter['action'] = name

# function given and valid?
if parameter['function'] is None:
remove_action("Attribute 'se_action_{0}: Parameter 'function' must be set!".format(name))
remove_action("Parameter 'function' must be set!")
return _issue_list
if parameter['function'] not in ('set', 'force', 'run', 'byattr', 'trigger', 'special',
'add', 'remove', 'removeall', 'removefirst', 'removelast'):
remove_action("Attribute 'se_action_{0}: Invalid value '{1}' for parameter 'function'!".format(name, parameter['function']))
remove_action("Invalid value '{}' for parameter 'function'!".format(parameter['function']))
return _issue_list

_issue, parameter['function'] = self.__check_force_setting(name, parameter['force'], parameter['function'])
Expand Down Expand Up @@ -571,8 +570,7 @@ def remove_action(e):
# noinspection PyMethodMayBeStatic
def __raise_missing_parameter_error(self, parameter, param_name):
if param_name not in parameter or parameter[param_name] is None:
raise ValueError("Attribute 'se_action_{0}: Parameter '{1}' must be set for "
"function '{2}'!".format(parameter['action'], param_name, parameter['function']))
raise ValueError("Parameter '{0}' must be set for function '{1}'!".format(param_name, parameter['function']))

# Check the actions optimize and complete them
# state: state (item) to read from
Expand All @@ -584,7 +582,7 @@ def complete(self, evals_items=None, use=None):
try:
_status.update(self.__actions[name].complete(evals_items, use))
except ValueError as ex:
_status.update({name: {'issue': ex, 'issueorigin': {'state': self.__state.id, 'action': 'unknown'}}})
_status.update({name: {'issue': [str(ex)], 'issueorigin': {'state': self.__state.id, 'action': name}}})
raise ValueError("Completing State '{0}', Action '{1}': {2}".format(self.__state.id, name, ex))
return _status

Expand Down
7 changes: 4 additions & 3 deletions stateengine/StateEngineFunctions.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@
# You should have received a copy of the GNU General Public License
# along with this plugin. If not, see <http://www.gnu.org/licenses/>.
#########################################################################
import logging
import threading
import re
from . import StateEngineLogger
from . import StateEngineTools
from . import StateEngineDefaults
from ast import literal_eval
from lib.item import Items


class SeFunctions:
Expand All @@ -44,6 +44,7 @@ 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 @@ -97,7 +98,7 @@ def check_include_exclude(entry_type):
elog.decrease_indent()
return None

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

Expand All @@ -111,7 +112,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.__sh.return_item(elog_item_id)
elog_item = self.itemsApi.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 Down
9 changes: 5 additions & 4 deletions stateengine/StateEngineItem.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

from lib.shtime import Shtime
from lib.item.item import Item
from lib.item.items import Items
from lib.item import Items
import copy
import threading
import queue
Expand Down Expand Up @@ -201,6 +201,7 @@ def ab_alive(self, value):
# se_plugin: smartplugin instance
def __init__(self, smarthome, item, se_plugin):
self.__item = item
self.itemsApi = Items.get_instance()
self.__logger = SeLogger.create(self.__item)
self.__logging_off = False
self.update_lock = threading.Lock()
Expand Down Expand Up @@ -2162,7 +2163,7 @@ def return_item(self, item_id):
if isinstance(item_id, (StateEngineStruct.SeStruct, self.__itemClass)):
return item_id, None
if isinstance(item_id, StateEngineState.SeState):
return self.__sh.return_item(item_id.id), None
return self.itemsApi.return_item(item_id.id), None
if item_id is None:
_issue = "item_id is None"
return None, [_issue]
Expand Down Expand Up @@ -2203,7 +2204,7 @@ def return_item(self, item_id):
self.__logger.warning(_issue)
return None, [_issue]
else:
item = self.__sh.return_item(item_id)
item = self.itemsApi.return_item(item_id)
if item is None:
_issue = "Item '{0}' not found.".format(item_id)
self.__logger.warning(_issue)
Expand All @@ -2226,7 +2227,7 @@ def return_item(self, item_id):
rel_item_id = item_id[parent_level:]
if rel_item_id != "":
result += "." + rel_item_id
item = self.__sh.return_item(result)
item = self.itemsApi.return_item(result)
if item is None:
_issue = "Determined item '{0}' does not exist.".format(item_id)
self.__logger.warning(_issue)
Expand Down
13 changes: 12 additions & 1 deletion stateengine/StateEngineState.py
Original file line number Diff line number Diff line change
Expand Up @@ -592,19 +592,29 @@ def filter_issues(input_dict):
return
for itm, dct in action_status.items():
if itm not in self.__action_status[actn_type]:
self.__action_status[actn_type].update({itm: dct})
self.__action_status[actn_type][itm] = dct
else:
for key, value in dct.items():
if key not in self.__action_status[actn_type][itm]:
self.__action_status[actn_type][itm][key] = value

for (itm, dct) in action_status.items():
issues = dct.get('issue')
attributes = dct.get('attribute')
if not isinstance(attributes, list):
attributes = [attributes]
if not isinstance(self.__action_status[actn_type][itm].get('attribute'), list):
self.__action_status[actn_type][itm]['attribute'] = [self.__action_status[actn_type][itm].get('attribute')]
if issues:
if isinstance(issues, list):
attributes = (attributes + [None] * len(issues))[:len(issues)]
for i, issue in enumerate(issues):
if issue not in self.__action_status[actn_type][itm]['issue']:
self.__action_status[actn_type][itm]['issue'].append(issue)
self.__action_status[actn_type][itm]['attribute'].append(attributes[i])

flattened_dict = {}

for key, action_type_dict in self.__action_status.items():
# Iterate through the inner dictionaries
for inner_key, nested_dict in action_type_dict.items():
Expand All @@ -616,6 +626,7 @@ def filter_issues(input_dict):
flattened_dict[inner_key].update(nested_dict)

self.__used_attributes = deepcopy(flattened_dict)

self.__action_status = filter_issues(self.__action_status)
self._abitem.update_attributes(self.__unused_attributes, self.__used_attributes)

Expand Down
4 changes: 2 additions & 2 deletions stateengine/StateEngineTools.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import datetime
from ast import literal_eval
import re
from lib.item.items import Items
from lib.item import Items


# General class for everything that is below the SeItem Class
Expand Down Expand Up @@ -410,7 +410,7 @@ def get_original_caller(smarthome, elog, caller, source, item=None, eval_keyword
else:
original_source = "None"
while partition_strip(original_caller, ":")[0] in eval_keyword:
original_item = smarthome.return_item(original_source)
original_item = smarthome.items.return_item(original_source)
if original_item is None:
elog.info("get_caller({0}, {1}): original item not found", caller, source)
break
Expand Down
Loading

0 comments on commit 707549d

Please sign in to comment.