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: improve visu #979

Merged
merged 14 commits into from
Dec 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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