S allius/issue397 (#405)
* add Dashboards log handler to all known loggers * add list of last 3 warnings/errors to page * add note list to page * create LogHandler for the dashboard - simple memory log handler which stores the last 64 warnings/errors for the dashboard * render warnings/errors as note list * add page for warnings and errors * fix double defined build target * add well done message if no errors in the logs * translate page titles * more translations * add Notes page and table for important messages * add unit tests
This commit is contained in:
@@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [unreleased]
|
## [unreleased]
|
||||||
|
|
||||||
|
- Dashboard: add Notes page and table for important messages
|
||||||
- Dashboard: add Log-File page
|
- Dashboard: add Log-File page
|
||||||
- Dashboard: add Connection page
|
- Dashboard: add Connection page
|
||||||
- add web UI to add-on
|
- add web UI to add-on
|
||||||
|
|||||||
2
Makefile
2
Makefile
@@ -6,7 +6,7 @@ babel:
|
|||||||
build:
|
build:
|
||||||
$(MAKE) -C ha_addons $@
|
$(MAKE) -C ha_addons $@
|
||||||
|
|
||||||
clean build:
|
clean:
|
||||||
$(MAKE) -C app $@
|
$(MAKE) -C app $@
|
||||||
$(MAKE) -C ha_addons $@
|
$(MAKE) -C ha_addons $@
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ Usage:
|
|||||||
from quart import Quart, Blueprint
|
from quart import Quart, Blueprint
|
||||||
from quart_babel import Babel
|
from quart_babel import Babel
|
||||||
from utils import load_modules
|
from utils import load_modules
|
||||||
|
from .log_handler import LogHandler
|
||||||
|
import logging
|
||||||
|
|
||||||
web = Blueprint('web', __name__)
|
web = Blueprint('web', __name__)
|
||||||
|
|
||||||
@@ -30,3 +32,8 @@ class Web:
|
|||||||
locale_selector=get_locale,
|
locale_selector=get_locale,
|
||||||
timezone_selector=get_tz,
|
timezone_selector=get_tz,
|
||||||
default_translation_directories=translation_directories)
|
default_translation_directories=translation_directories)
|
||||||
|
|
||||||
|
h = LogHandler()
|
||||||
|
logging.getLogger().addHandler(h)
|
||||||
|
for name in logging.root.manager.loggerDict:
|
||||||
|
logging.getLogger(name).addHandler(h)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from quart_babel import format_datetime, _
|
|||||||
from infos import Infos
|
from infos import Infos
|
||||||
|
|
||||||
from . import web
|
from . import web
|
||||||
|
from .log_handler import LogHandler
|
||||||
|
|
||||||
|
|
||||||
def _get_device_icon(client_mode: bool):
|
def _get_device_icon(client_mode: bool):
|
||||||
@@ -79,5 +80,8 @@ async def data_fetch():
|
|||||||
data["conn-table"] = await render_template('templ_table.html.j2',
|
data["conn-table"] = await render_template('templ_table.html.j2',
|
||||||
table=get_table_data())
|
table=get_table_data())
|
||||||
|
|
||||||
data["notes-list"] = await render_template('templ_notes_list.html.j2')
|
data["notes-list"] = await render_template(
|
||||||
|
'templ_notes_list.html.j2',
|
||||||
|
notes=LogHandler().get_buffer(3),
|
||||||
|
hide_if_empty=True)
|
||||||
return data
|
return data
|
||||||
|
|||||||
24
app/src/web/log_handler.py
Normal file
24
app/src/web/log_handler.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
from logging import Handler
|
||||||
|
from logging import LogRecord
|
||||||
|
import logging
|
||||||
|
from collections import deque
|
||||||
|
|
||||||
|
from singleton import Singleton
|
||||||
|
|
||||||
|
|
||||||
|
class LogHandler(Handler, metaclass=Singleton):
|
||||||
|
def __init__(self, capacity=64):
|
||||||
|
super().__init__(logging.WARNING)
|
||||||
|
self.capacity = capacity
|
||||||
|
self.buffer = deque(maxlen=capacity)
|
||||||
|
|
||||||
|
def emit(self, record: LogRecord):
|
||||||
|
self.buffer.append({
|
||||||
|
'ctime': record.created,
|
||||||
|
'level': record.levelno,
|
||||||
|
'lname': record.levelname,
|
||||||
|
'msg': record.getMessage()
|
||||||
|
})
|
||||||
|
|
||||||
|
def get_buffer(self, elms=0) -> list:
|
||||||
|
return list(self.buffer)[-elms:]
|
||||||
@@ -4,6 +4,7 @@ from quart_babel import format_datetime, _
|
|||||||
from mqtt import Mqtt
|
from mqtt import Mqtt
|
||||||
|
|
||||||
from . import web
|
from . import web
|
||||||
|
from .log_handler import LogHandler
|
||||||
|
|
||||||
|
|
||||||
def _get_row(inv: InverterBase):
|
def _get_row(inv: InverterBase):
|
||||||
@@ -55,4 +56,9 @@ async def mqtt_fetch():
|
|||||||
data["mqtt-table"] = await render_template('templ_table.html.j2',
|
data["mqtt-table"] = await render_template('templ_table.html.j2',
|
||||||
table=get_table_data())
|
table=get_table_data())
|
||||||
|
|
||||||
|
data["notes-list"] = await render_template(
|
||||||
|
'templ_notes_list.html.j2',
|
||||||
|
notes=LogHandler().get_buffer(3),
|
||||||
|
hide_if_empty=True)
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|||||||
19
app/src/web/notes_list.py
Normal file
19
app/src/web/notes_list.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
from quart import render_template
|
||||||
|
from quart_babel import format_datetime
|
||||||
|
|
||||||
|
from . import web
|
||||||
|
from .log_handler import LogHandler
|
||||||
|
|
||||||
|
|
||||||
|
@web.route('/notes-fetch')
|
||||||
|
async def notes_fetch():
|
||||||
|
data = {
|
||||||
|
"update-time": format_datetime(format="medium"),
|
||||||
|
}
|
||||||
|
|
||||||
|
data["notes-list"] = await render_template(
|
||||||
|
'templ_notes_list.html.j2',
|
||||||
|
notes=LogHandler().get_buffer(),
|
||||||
|
hide_if_empty=False)
|
||||||
|
|
||||||
|
return data
|
||||||
@@ -18,6 +18,13 @@ async def mqtt():
|
|||||||
fetch_url=url_for('.mqtt_fetch'))
|
fetch_url=url_for('.mqtt_fetch'))
|
||||||
|
|
||||||
|
|
||||||
|
@web.route('/notes')
|
||||||
|
async def notes():
|
||||||
|
return await render_template(
|
||||||
|
'page_notes.html.j2',
|
||||||
|
fetch_url=url_for('.notes_fetch'))
|
||||||
|
|
||||||
|
|
||||||
@web.route('/logging')
|
@web.route('/logging')
|
||||||
async def logging():
|
async def logging():
|
||||||
return await render_template(
|
return await render_template(
|
||||||
|
|||||||
@@ -57,7 +57,8 @@
|
|||||||
<button href="#" class="w3-bar-item w3-button w3-padding-16 w3-hide-large w3-dark-grey w3-hover-black" onclick="w3_close()" title="close menu"><i class="fa fa-remove fa-fw"></i> Close Menu</button>
|
<button href="#" class="w3-bar-item w3-button w3-padding-16 w3-hide-large w3-dark-grey w3-hover-black" onclick="w3_close()" title="close menu"><i class="fa fa-remove fa-fw"></i> Close Menu</button>
|
||||||
<a href="{{ url_for('.index')}}" class="w3-bar-item w3-button w3-padding {% block menu1_class %}{% endblock %}"><i class="fa fa-network-wired fa-fw"></i> {{_('Connections')}}</a>
|
<a href="{{ url_for('.index')}}" class="w3-bar-item w3-button w3-padding {% block menu1_class %}{% endblock %}"><i class="fa fa-network-wired fa-fw"></i> {{_('Connections')}}</a>
|
||||||
<a href="{{ url_for('.mqtt')}}" class="w3-bar-item w3-button w3-padding {% block menu2_class %}{% endblock %}"><i class="fa fa-database fa-fw"></i> MQTT</a>
|
<a href="{{ url_for('.mqtt')}}" class="w3-bar-item w3-button w3-padding {% block menu2_class %}{% endblock %}"><i class="fa fa-database fa-fw"></i> MQTT</a>
|
||||||
<a href="{{ url_for('.logging')}}" class="w3-bar-item w3-button w3-padding {% block menu3_class %}{% endblock %}"><i class="fa fa-file-export fa-fw"></i> {{_('Log Files')}}</a>
|
<a href="{{ url_for('.notes')}}" class="w3-bar-item w3-button w3-padding {% block menu3_class %}{% endblock %}"><i class="fa fa-exclamation-triangle fa-fw"></i> {{_('Important Messages')}}</a>
|
||||||
|
<a href="{{ url_for('.logging')}}" class="w3-bar-item w3-button w3-padding {% block menu4_class %}{% endblock %}"><i class="fa fa-file-export fa-fw"></i> {{_('Log Files')}}</a>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{% extends 'base.html.j2' %}
|
{% extends 'base.html.j2' %}
|
||||||
|
|
||||||
{% block title %} TSUN Proxy - Connections {% endblock title%}
|
{% block title %}{{_("TSUN Proxy - Connections")}}{% endblock title %}
|
||||||
{% block menu1_class %}w3-blue{% endblock %}
|
{% block menu1_class %}w3-blue{% endblock %}
|
||||||
{% block headline %}<i class="fa fa-network-wired"></i> {{_('Proxy Connection Overview')}}{% endblock headline %}
|
{% block headline %}<i class="fa fa-network-wired"></i> {{_('Proxy Connection Overview')}}{% endblock headline %}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{% extends 'base.html.j2' %}
|
{% extends 'base.html.j2' %}
|
||||||
|
|
||||||
{% block title %} TSUN Proxy - Log Files {% endblock title%}
|
{% block title %}{{_("TSUN Proxy - Log Files")}}{% endblock title %}
|
||||||
{% block menu3_class %}w3-blue{% endblock %}
|
{% block menu4_class %}w3-blue{% endblock %}
|
||||||
{% block headline %}<i class="fa fa-file-export fa-fw"></i> {{_('Log Files')}}{% endblock headline %}
|
{% block headline %}<i class="fa fa-file-export fa-fw"></i> {{_('Log Files')}}{% endblock headline %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div id="id01" class="w3-modal">
|
<div id="id01" class="w3-modal">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{% extends 'base.html.j2' %}
|
{% extends 'base.html.j2' %}
|
||||||
|
|
||||||
{% block title %} TSUN Proxy - MQTT Status {% endblock title%}
|
{% block title %}{{_("TSUN Proxy - MQTT Status")}}{% endblock title %}
|
||||||
{% block menu2_class %}w3-blue{% endblock %}
|
{% block menu2_class %}w3-blue{% endblock %}
|
||||||
{% block headline %}<i class="fa fa-database"></i> {{_('MQTT Overview')}}{% endblock headline %}
|
{% block headline %}<i class="fa fa-database"></i> {{_('MQTT Overview')}}{% endblock headline %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
@@ -45,6 +45,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="notes-list"></div>
|
||||||
<div id="mqtt-table"></div>
|
<div id="mqtt-table"></div>
|
||||||
{% endblock content%}
|
{% endblock content%}
|
||||||
|
|
||||||
|
|||||||
10
app/src/web/templates/page_notes.html.j2
Normal file
10
app/src/web/templates/page_notes.html.j2
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{% extends 'base.html.j2' %}
|
||||||
|
|
||||||
|
{% block title %}{{_("TSUN Proxy - Important Messages")}}{% endblock title %}
|
||||||
|
{% block menu3_class %}w3-blue{% endblock %}
|
||||||
|
{% block headline %}<i class="fa fa-exclamation-triangle fa-fw"></i> {{_('Important Messages')}}{% endblock headline %}
|
||||||
|
{% block content %}
|
||||||
|
<div id="notes-list"></div>
|
||||||
|
{% endblock content%}
|
||||||
|
|
||||||
|
{% block footer %}{% endblock footer %}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
{% if notes|length > 0 %}
|
||||||
|
<div class="w3-container w3-margin-bottom">
|
||||||
|
<h5>{{_("Warnings and error messages")}} </h5>
|
||||||
|
<ul class="w3-ul w3-card-4">
|
||||||
|
{% for note in notes %}
|
||||||
|
<li class="{% if note.level is le(30) %}w3-leftbar w3-rightbar w3-pale-blue w3-border-blue{% else %}w3-leftbar w3-rightbar w3-pale-red w3-border-red{% endif %}">
|
||||||
|
<span class="w3-col" style="width:150px">{{note.ctime|datetimeformat(format='short')}}</span>
|
||||||
|
<span class="w3-col w3-hide-small" style="width:100px">{{note.lname|e}}</span>
|
||||||
|
<span class="w3-rest">{{note.msg|e}}</span>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% elif not hide_if_empty %}
|
||||||
|
<div class="w3-container w3-margin-bottom">
|
||||||
|
<div class="w3-leftbar w3-rightbar w3-pale-green w3-border-green">
|
||||||
|
<div class="w3-container">
|
||||||
|
<h2>{{_("Well done!")}}</h2>
|
||||||
|
<p>{{_("No warnings or errors have been logged since the last proxy start.")}}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
@@ -68,6 +68,13 @@ async def test_rel_page(client):
|
|||||||
assert response.mimetype == 'text/html'
|
assert response.mimetype == 'text/html'
|
||||||
web.build_relative_urls = False
|
web.build_relative_urls = False
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_notes(client):
|
||||||
|
"""Test the notes page route."""
|
||||||
|
response = await client.get('/notes')
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.mimetype == 'text/html'
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_logging(client):
|
async def test_logging(client):
|
||||||
"""Test the logging page route."""
|
"""Test the logging page route."""
|
||||||
@@ -185,6 +192,15 @@ async def test_mqtt_fetch(client, create_inverter):
|
|||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_notes_fetch(client, config_conn):
|
||||||
|
"""Test the notes-fetch route."""
|
||||||
|
_ = create_inverter
|
||||||
|
|
||||||
|
response = await client.get('/notes-fetch')
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_file_fetch(client, config_conn):
|
async def test_file_fetch(client, config_conn):
|
||||||
"""Test the data-fetch route."""
|
"""Test the data-fetch route."""
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: tsun-gen3-proxy 0.14.0\n"
|
"Project-Id-Version: tsun-gen3-proxy 0.14.0\n"
|
||||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||||
"POT-Creation-Date: 2025-05-03 21:59+0200\n"
|
"POT-Creation-Date: 2025-05-04 18:16+0200\n"
|
||||||
"PO-Revision-Date: 2025-04-18 16:24+0200\n"
|
"PO-Revision-Date: 2025-04-18 16:24+0200\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language: de\n"
|
"Language: de\n"
|
||||||
@@ -19,39 +19,39 @@ msgstr ""
|
|||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Generated-By: Babel 2.17.0\n"
|
"Generated-By: Babel 2.17.0\n"
|
||||||
|
|
||||||
#: src/web/conn_table.py:51 src/web/templates/base.html.j2:58
|
#: src/web/conn_table.py:52 src/web/templates/base.html.j2:58
|
||||||
msgid "Connections"
|
msgid "Connections"
|
||||||
msgstr "Verbindungen"
|
msgstr "Verbindungen"
|
||||||
|
|
||||||
#: src/web/conn_table.py:58
|
#: src/web/conn_table.py:59
|
||||||
msgid "Device-IP:Port"
|
msgid "Device-IP:Port"
|
||||||
msgstr "Geräte-IP:Port"
|
msgstr "Geräte-IP:Port"
|
||||||
|
|
||||||
#: src/web/conn_table.py:58
|
#: src/web/conn_table.py:59
|
||||||
msgid "Device-IP"
|
msgid "Device-IP"
|
||||||
msgstr "Geräte-IP"
|
msgstr "Geräte-IP"
|
||||||
|
|
||||||
#: src/web/conn_table.py:59 src/web/mqtt_table.py:33
|
#: src/web/conn_table.py:60 src/web/mqtt_table.py:34
|
||||||
msgid "Serial-No"
|
msgid "Serial-No"
|
||||||
msgstr "Seriennummer"
|
msgstr "Seriennummer"
|
||||||
|
|
||||||
#: src/web/conn_table.py:60
|
#: src/web/conn_table.py:61
|
||||||
msgid "Cloud-IP:Port"
|
msgid "Cloud-IP:Port"
|
||||||
msgstr "Cloud-IP:Port"
|
msgstr "Cloud-IP:Port"
|
||||||
|
|
||||||
#: src/web/conn_table.py:60
|
#: src/web/conn_table.py:61
|
||||||
msgid "Cloud-IP"
|
msgid "Cloud-IP"
|
||||||
msgstr "Cloud-IP"
|
msgstr "Cloud-IP"
|
||||||
|
|
||||||
#: src/web/mqtt_table.py:26
|
#: src/web/mqtt_table.py:27
|
||||||
msgid "MQTT devices"
|
msgid "MQTT devices"
|
||||||
msgstr "MQTT Geräte"
|
msgstr "MQTT Geräte"
|
||||||
|
|
||||||
#: src/web/mqtt_table.py:34
|
#: src/web/mqtt_table.py:35
|
||||||
msgid "Node-ID"
|
msgid "Node-ID"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/web/mqtt_table.py:35
|
#: src/web/mqtt_table.py:36
|
||||||
msgid "HA-Area"
|
msgid "HA-Area"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -63,10 +63,18 @@ msgstr "Aktualisiert:"
|
|||||||
msgid "Version:"
|
msgid "Version:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/web/templates/base.html.j2:60 src/web/templates/page_logging.html.j2:5
|
#: src/web/templates/base.html.j2:60 src/web/templates/page_notes.html.j2:5
|
||||||
|
msgid "Important Messages"
|
||||||
|
msgstr "Wichtige Hinweise"
|
||||||
|
|
||||||
|
#: src/web/templates/base.html.j2:61 src/web/templates/page_logging.html.j2:5
|
||||||
msgid "Log Files"
|
msgid "Log Files"
|
||||||
msgstr "Log Dateien"
|
msgstr "Log Dateien"
|
||||||
|
|
||||||
|
#: src/web/templates/page_index.html.j2:3
|
||||||
|
msgid "TSUN Proxy - Connections"
|
||||||
|
msgstr "TSUN Proxy - Verbindungen"
|
||||||
|
|
||||||
#: src/web/templates/page_index.html.j2:5
|
#: src/web/templates/page_index.html.j2:5
|
||||||
msgid "Proxy Connection Overview"
|
msgid "Proxy Connection Overview"
|
||||||
msgstr "Proxy Verbindungen"
|
msgstr "Proxy Verbindungen"
|
||||||
@@ -103,6 +111,10 @@ msgstr "Emu Modus"
|
|||||||
msgid "Emulation sends data to cloud"
|
msgid "Emulation sends data to cloud"
|
||||||
msgstr "Emulation sendet in die Cloud"
|
msgstr "Emulation sendet in die Cloud"
|
||||||
|
|
||||||
|
#: src/web/templates/page_logging.html.j2:3
|
||||||
|
msgid "TSUN Proxy - Log Files"
|
||||||
|
msgstr "TSUN Proxy - Log Dateien"
|
||||||
|
|
||||||
#: src/web/templates/page_logging.html.j2:10
|
#: src/web/templates/page_logging.html.j2:10
|
||||||
msgid "Do you really want to delete the log file"
|
msgid "Do you really want to delete the log file"
|
||||||
msgstr "Soll die Datei wirklich gelöscht werden"
|
msgstr "Soll die Datei wirklich gelöscht werden"
|
||||||
@@ -115,6 +127,10 @@ msgstr "File löschen"
|
|||||||
msgid "Abort"
|
msgid "Abort"
|
||||||
msgstr "Abbruch"
|
msgstr "Abbruch"
|
||||||
|
|
||||||
|
#: src/web/templates/page_mqtt.html.j2:3
|
||||||
|
msgid "TSUN Proxy - MQTT Status"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/web/templates/page_mqtt.html.j2:5
|
#: src/web/templates/page_mqtt.html.j2:5
|
||||||
msgid "MQTT Overview"
|
msgid "MQTT Overview"
|
||||||
msgstr "MQTT Überblick"
|
msgstr "MQTT Überblick"
|
||||||
@@ -143,6 +159,10 @@ msgstr "Empfangene Topics"
|
|||||||
msgid "Number of topics received"
|
msgid "Number of topics received"
|
||||||
msgstr "Anzahl der empfangenen Topics"
|
msgstr "Anzahl der empfangenen Topics"
|
||||||
|
|
||||||
|
#: src/web/templates/page_notes.html.j2:3
|
||||||
|
msgid "TSUN Proxy - Important Messages"
|
||||||
|
msgstr "TSUN Proxy - Wichtige Hinweise"
|
||||||
|
|
||||||
#: src/web/templates/templ_log_files_list.html.j2:11
|
#: src/web/templates/templ_log_files_list.html.j2:11
|
||||||
msgid "Created"
|
msgid "Created"
|
||||||
msgstr "Erzeugt"
|
msgstr "Erzeugt"
|
||||||
@@ -159,24 +179,17 @@ msgstr "Größe"
|
|||||||
msgid "Download File"
|
msgid "Download File"
|
||||||
msgstr "Datei Download"
|
msgstr "Datei Download"
|
||||||
|
|
||||||
#~ msgid "MQTT Server"
|
#: src/web/templates/templ_notes_list.html.j2:3
|
||||||
#~ msgstr ""
|
msgid "Warnings and error messages"
|
||||||
|
msgstr "Warnungen und Fehlermeldungen"
|
||||||
|
|
||||||
#~ msgid "MQTT User"
|
#: src/web/templates/templ_notes_list.html.j2:18
|
||||||
#~ msgstr ""
|
msgid "Well done!"
|
||||||
|
msgstr "Gut gemacht!"
|
||||||
|
|
||||||
#~ msgid "MQTT Connected"
|
#: src/web/templates/templ_notes_list.html.j2:19
|
||||||
#~ msgstr ""
|
msgid "No warnings or errors have been logged since the last proxy start."
|
||||||
|
msgstr ""
|
||||||
#~ msgid "Home Assistant Status"
|
"Seit dem letzten Proxystart wurden keine Warnungen oder Fehler "
|
||||||
#~ msgstr ""
|
"protokolliert."
|
||||||
|
|
||||||
#~ msgid "MQTT Publish Count"
|
|
||||||
#~ msgstr ""
|
|
||||||
|
|
||||||
#~ msgid "MQTT Reveiced Count"
|
|
||||||
#~ msgstr ""
|
|
||||||
|
|
||||||
#~ msgid "MQTT Connect Time"
|
|
||||||
#~ msgstr "MQTT Verbindungszeit"
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user