diff --git a/database/__init__.py b/database/__init__.py index b9bc64035..210a4dad0 100755 --- a/database/__init__.py +++ b/database/__init__.py @@ -51,7 +51,7 @@ class Database(SmartPlugin): """ ALLOW_MULTIINSTANCE = True - PLUGIN_VERSION = '1.6.11' + PLUGIN_VERSION = '1.6.12' # SQL queries: {item} = item table name, {log} = log table name # time, item_id, val_str, val_num, val_bool, changed @@ -1075,7 +1075,7 @@ def _series(self, func, start, end='now', count=100, ratio=1, update=False, step :return: data structure in the form needed by the websocket plugin return it to the visu """ - #self.logger.warning("_series: item={}, func={}, start={}, end={}, count={}".format(item, func, start, end, count)) + #self.logger.debug("_series: item={}, func={}, start={}, end={}, count={}".format(item, func, start, end, count)) init = not update if sid is None: sid = item + '|' + func + '|' + str(start) + '|' + str(end) + '|' + str(count) @@ -1084,7 +1084,10 @@ def _series(self, func, start, end='now', count=100, ratio=1, update=False, step 'avg': 'MIN(time), ' + self._precision_query('AVG(val_num * duration) / AVG(duration)'), 'avg.order': 'ORDER BY time ASC', 'integrate': 'MIN(time), SUM(val_num * duration)', - 'differentiate': 'MIN(time), (val_num - LAG(val_num,1, -1)) / duration', + 'diff': 'MIN(time), (val_num - LAG(val_num,1) OVER (ORDER BY val_num))', + 'duration': 'MIN(time), duration', + # differentiate (d/dt) is scaled to match the conversion from d/dt (kWh) = kWh: time is in ms, val_num in kWh, therefore scale by 1000ms and 3600s/h to obtain the result in kW: + 'differentiate': 'MIN(time), (val_num - LAG(val_num,1) OVER (ORDER BY val_num)) / ( (time - LAG(time,1) OVER (ORDER BY val_num)) / (3600 * 1000) )', 'count': 'MIN(time), SUM(CASE WHEN val_num{op}{value} THEN 1 ELSE 0 END)'.format(**expression['params']), 'countall': 'MIN(time), COUNT(*)', 'min': 'MIN(time), MIN(val_num)', @@ -1103,22 +1106,26 @@ def _series(self, func, start, end='now', count=100, ratio=1, update=False, step group = 'GROUP BY ROUND(time / :step)' if func + '.group' not in queries else queries[func + '.group'] logs = self._fetch_log(item, queries[func], start, end, step=step, count=count, group=group, order=order) tuples = logs['tuples'] - if tuples: - if logs['istart'] > tuples[0][0]: - tuples[0] = (logs['istart'], tuples[0][1]) - if end != 'now': - tuples.append((logs['iend'], tuples[-1][1])) - else: - tuples = [] - item_change = self._timestamp(logs['item'].last_change()) - if item_change < logs['iend']: - value = float(logs['item']()) - if item_change < logs['istart']: - tuples.append((logs['istart'], value)) - elif init: - tuples.append((item_change, value)) - if init: - tuples.append((logs['iend'], value)) + + # Append tuples by addition values (not for func differentiate) + if func != 'differentiate': + + if tuples: + if logs['istart'] > tuples[0][0]: + tuples[0] = (logs['istart'], tuples[0][1]) + if end != 'now': + tuples.append((logs['iend'], tuples[-1][1])) + else: + tuples = [] + item_change = self._timestamp(logs['item'].last_change()) + if item_change < logs['iend']: + value = float(logs['item']()) + if item_change < logs['istart']: + tuples.append((logs['istart'], value)) + elif init: + tuples.append((item_change, value)) + if init: + tuples.append((logs['iend'], value)) if expression['finalizer']: tuples = self._finalize(expression['finalizer'], tuples) @@ -1129,14 +1136,14 @@ def _series(self, func, start, end='now', count=100, ratio=1, update=False, step 'step': logs['step'], 'sid': sid}, 'update': self.shtime.now() + datetime.timedelta(seconds=int(logs['step'] / 1000)) } - #self.logger.warning("_series: result={}".format(result)) + #self.logger.debug("_series: result={}".format(result)) + return result def _single(self, func, start, end='now', item=None): """ - As far as it has been checked, this method is never called. - It is attached to the item object but no other plugin is known that calls this method. + This function is not used by any other plugin but can be used in logics :param func: :param start: @@ -1148,11 +1155,11 @@ def _single(self, func, start, end='now', item=None): queries = { 'avg': self._precision_query('AVG(val_num * duration) / AVG(duration)'), 'integrate': 'SUM(val_num * duration)', - 'differentiate': 'val_num - LAG(val_num) / duration', 'count': 'SUM(CASE WHEN val_num{op}{value} THEN 1 ELSE 0 END)'.format(**expression['params']), 'countall': 'COUNT(*)', 'min': 'MIN(val_num)', 'max': 'MAX(val_num)', + 'diff': 'MAX(val_num) - MIN(val_num)', 'on': self._precision_query('SUM(val_bool * duration) / SUM(duration)'), 'sum': 'SUM(val_num)', 'raw': 'val_num', diff --git a/database/plugin.yaml b/database/plugin.yaml index 968df0c42..ec4076689 100755 --- a/database/plugin.yaml +++ b/database/plugin.yaml @@ -11,7 +11,7 @@ plugin: keywords: database support: https://knx-user-forum.de/forum/supportforen/smarthome-py/1021844-neues-database-plugin - version: 1.6.11 # Plugin version + version: 1.6.12 # Plugin version sh_minversion: 1.9.3.2 # minimum shNG version to use this plugin # sh_maxversion: # maximum shNG version to use this plugin (leave empty if latest) multi_instance: True # plugin supports multi instance @@ -97,7 +97,7 @@ item_attributes: # Definition of item attributes defined by this plugin database: type: str - valid_list_ci: ['', 'no', 'yes', 'init', 'init2', 'true'] + valid_list_ci: ['', 'yes', 'init', 'true'] duplicate_use: True description: de: "Wenn auf 'yes' oder 'true' gesetzt, werden die Werte des Items in die Datenbank geschrieben. Wenn auf 'init' gesetzt, wird zusätzlich beim Start von SmartHomeNG der Wert des Items aus der Datenbank gelesen."