diff --git a/Pipfile b/Pipfile index d7bf6c58b5bc64506e92946c854174dcb057ad77..149e8a443c2f5277df2ab8326b8db1606a5fb038 100644 --- a/Pipfile +++ b/Pipfile @@ -24,4 +24,7 @@ Babel = "==2.8.0" icalendar = "==4.0.7" python-jenkins = "==1.5.0" +# tiles +timeago = "==1.0.15" + [dev-packages] diff --git a/src/logic/tile/tiles/SensorLineChartTile.html b/src/logic/tile/tiles/SensorLineChartTile.html index ad76f3d9df7024014b75d05a5d664488836f23ac..4293a180b7421827e1a517730ab88b178c9105bb 100644 --- a/src/logic/tile/tiles/SensorLineChartTile.html +++ b/src/logic/tile/tiles/SensorLineChartTile.html @@ -42,8 +42,11 @@ padding-left: 5%; } - .sensorLineChartTile i { + .sensorLineChartTile .header-right { margin-right: 5%; + } + + .sensorLineChartTile i { {% if showAxes %} font-size: 2.5vmin; {% else %} @@ -51,6 +54,32 @@ {% endif %} } + .sensorLineChartTile .warning { + display: flex; + flex-direction: row; + color: #FF0000; + padding-right: 2vmin; + align-items: center; + align-self: flex-start; + flex-grow: 1; + justify-content: flex-end; + + {% if showAxes %} + padding-top: 1%; + {% else %} + padding-top: 3%; + {% endif %} + } + + .sensorLineChartTile .warning i { + font-size: 2.5vmin; + padding-right: 1vmin; + } + + .sensorLineChartTile .warning-text { + font-size: 1.5vmin; + } + .sensorLineChartTile .title, .sensorLineChartTile .value { text-align: left; @@ -66,7 +95,15 @@ <div class="value">{{ latest }}{{ unit }}</div> {% endif %} </div> - <i class="wi {{ icon }}"></i> + {% if timeAgo %} + <div class="warning"> + <i class="material-icons icon-warning">warning</i> + <div class="warning-text">{{ timeAgo }}</div> + </div> + {% endif %} + <div class="header-right"> + <i class="wi {{ icon }}"></i> + </div> </div> <div class="chart" id="{{ chartId }}"></div> </div> diff --git a/src/logic/tile/tiles/SensorLineChartTile.py b/src/logic/tile/tiles/SensorLineChartTile.py index 6e070c1cff1dc3fd739ebd4d0b3e993861d59302..a8f006d076e80451eb0dd63a8d02d5a3cd68fc94 100644 --- a/src/logic/tile/tiles/SensorLineChartTile.py +++ b/src/logic/tile/tiles/SensorLineChartTile.py @@ -5,6 +5,7 @@ import uuid from datetime import datetime, timedelta from typing import Dict, Tuple, List +from timeago import format from TheCodeLabs_BaseUtils.MultiCacheKeyService import MultiCacheKeyService from flask import Blueprint @@ -30,7 +31,8 @@ class SensorLineChartTile(Tile): "decimals": 1, "lineColor": "rgba(254, 151, 0, 1)", "fillColor": "rgba(254, 151, 0, 0.2)", - "showAxes": True + "showAxes": True, + "outdatedValueWarningLimitInSeconds": 300 # use -1 to disable warning } UNIT_BY_SENSOR_TYPE = { @@ -68,7 +70,8 @@ class SensorLineChartTile(Tile): sensorData = storageLeafService.get_data(cacheKey, self._intervalInSeconds, serviceSettings) x, y = self.__prepare_measurement_data(sensorData['sensorValue']) - latest = y[-1] if y else '' + latestTime = datetime.strptime(x[-1], self.DATE_FORMAT) if x else datetime(year=1970, month=1, day=1, hour=0, minute=0, second=0) + latestValue = y[-1] if y else '' minValue, maxValue = self.__get_min_and_max(pageName, sensorData['sensorInfo']['type'], @@ -87,14 +90,15 @@ class SensorLineChartTile(Tile): ghostTraceY = [minValue, minValue] return { - 'latest': latest, + 'latest': latestValue, 'x': x, 'y': y, 'sensorInfo': sensorData['sensorInfo'], 'min': minValue, 'max': maxValue, 'ghostTraceX': ghostTraceX, - 'ghostTraceY': ghostTraceY + 'ghostTraceY': ghostTraceY, + 'latestTime': latestTime } def __get_min_and_max(self, pageName: str, sensorType: Dict, @@ -152,6 +156,14 @@ class SensorLineChartTile(Tile): days = int(self._settings['numberOfHoursToShow'] / 24) title = f'{title} - {days} days' + now = datetime.now() + timeAgo = '' + outdatedValueWarningLimitInSeconds = self._settings['outdatedValueWarningLimitInSeconds'] + if outdatedValueWarningLimitInSeconds > 0: + timeDifference = now - data['latestTime'] + if timeDifference.total_seconds() > outdatedValueWarningLimitInSeconds: + timeAgo = format(timeDifference) + return Tile.render_template(os.path.dirname(__file__), __class__.__name__, x=data['x'], y=data['y'], @@ -167,7 +179,8 @@ class SensorLineChartTile(Tile): chartId=str(uuid.uuid4()), ghostTraceX=data['ghostTraceX'], ghostTraceY=data['ghostTraceY'], - showAxes=self._settings['showAxes']) + showAxes=self._settings['showAxes'], + timeAgo=timeAgo) def __format_date(self, dateTime: str): parsedDateTime = datetime.strptime(dateTime, self.DATE_FORMAT) diff --git a/src/templates/index.html b/src/templates/index.html index 26d46ebacf02ab091c8b9a512f642a294f64fb16..47dafc7ba01f65d91f62caaf83cd0a2e9bb0cf33 100644 --- a/src/templates/index.html +++ b/src/templates/index.html @@ -3,7 +3,7 @@ <head> <title>DashboardLeaf</title> {% import 'macros.html' as macros %} - {{ macros.header() }} + {{ macros.header(true) }} </head> <body> diff --git a/src/templates/macros.html b/src/templates/macros.html index 312689384071ffbc2801c8e2471bd85e97004c5c..af241d701a9588896d18ae97c06e1cb22b83fbdd 100644 --- a/src/templates/macros.html +++ b/src/templates/macros.html @@ -1,4 +1,4 @@ -{% macro header() -%} +{% macro header(addViewport) -%} <meta charset="UTF-8"/> <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> @@ -6,5 +6,7 @@ <link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}"/> - <meta name="viewport" content="width=device-width, initial-scale=1.0"/> + {% if addViewport %} + <meta name="viewport" content="width=device-width, initial-scale=1.0"/> + {% endif%} {%- endmacro %} diff --git a/src/templates/page.html b/src/templates/page.html index f92ebd559027d45841a9c4e1d166597833ce812a..cdd5f52c6a3985976ebe99afd6ee67b15c8aae10 100644 --- a/src/templates/page.html +++ b/src/templates/page.html @@ -1,16 +1,19 @@ <!DOCTYPE html> <html> <head> - <meta charset="UTF-8"> <title>DashboardLeaf</title> + + {% import 'macros.html' as macros %} + {{ macros.header(false) }} + <script src="../static/js/libs/socket.io.min.js"></script> <script src="../static/js/libs/gridstack.min.js"></script> <script src="../static/js/libs/plotly.min.js"></script> <script src="../static/js/libs/plotly.locale.de.min.js"></script> + <link type="text/css" rel="stylesheet" href="../static/css/libs/weather-icons.min.css" /> <link type="text/css" rel="stylesheet" href="../static/css/libs/weather-icons-wind.min.css" /> <link type="text/css" rel="stylesheet" href="../static/css/libs/gridstack.min.css" /> - <link type="text/css" rel="stylesheet" href="../static/css/main.css" /> </head> <body> <div class="grid-stack">