Compare commits

...

15 Commits

Author SHA1 Message Date
Stefan Allius
5623231aec check received counter in unit test 2025-05-03 23:34:22 +02:00
Stefan Allius
c5f25b5728 add mqtt-fetch test 2025-05-03 22:58:15 +02:00
Stefan Allius
0e99551064 fix Mqtt init call for unit tests 2025-05-03 22:56:49 +02:00
Stefan Allius
5c2be5b0c7 don't fetch notes list for the log-page 2025-05-03 22:55:30 +02:00
Stefan Allius
c591bba8b1 translate mqtt page 2025-05-03 22:07:15 +02:00
Stefan Allius
73d7593505 add mqtt info table 2025-05-03 20:19:20 +02:00
Stefan Allius
ccf21d5355 remove stripped table rows 2025-05-03 20:18:31 +02:00
Stefan Allius
62f1f63baf cleanup 2025-05-03 20:12:58 +02:00
Stefan Allius
3293e6741f make version string translateable 2025-05-03 20:12:00 +02:00
Stefan Allius
b79112b005 remove footer from index page 2025-05-03 20:11:27 +02:00
Stefan Allius
d2849e0e1e migrate the conn table to a general table
- rename the template file
- get headline from table description
2025-05-03 17:50:15 +02:00
Stefan Allius
46ebfd9751 fix unit tests 2025-05-03 16:46:22 +02:00
Stefan Allius
d7769599d2 styles adjusted on the different pages
- use same colors
- add bordered shadow to all cards and tables
2025-05-03 16:29:11 +02:00
Stefan Allius
d1b21abc4d add MQTT page 2025-05-03 16:27:59 +02:00
Stefan Allius
f799bf9a17 display proxy version on dashboard 2025-05-03 16:25:20 +02:00
16 changed files with 264 additions and 54 deletions

View File

@@ -7,13 +7,18 @@ from modbus import Modbus
from messages import Message from messages import Message
from cnf.config import Config from cnf.config import Config
from singleton import Singleton from singleton import Singleton
from datetime import datetime
logger_mqtt = logging.getLogger('mqtt') logger_mqtt = logging.getLogger('mqtt')
class Mqtt(metaclass=Singleton): class Mqtt(metaclass=Singleton):
__client = None __client: aiomqtt.Client = None
__cb_mqtt_is_up = None __cb_mqtt_is_up = None
ctime = None
published: int = 0
received: int = 0
def __init__(self, cb_mqtt_is_up): def __init__(self, cb_mqtt_is_up):
logger_mqtt.debug('MQTT: __init__') logger_mqtt.debug('MQTT: __init__')
@@ -52,6 +57,7 @@ class Mqtt(metaclass=Singleton):
| int | float | None = None) -> None: | int | float | None = None) -> None:
if self.__client: if self.__client:
await self.__client.publish(topic, payload) await self.__client.publish(topic, payload)
self.published += 1
async def __loop(self) -> None: async def __loop(self) -> None:
mqtt = Config.get('mqtt') mqtt = Config.get('mqtt')
@@ -69,6 +75,9 @@ class Mqtt(metaclass=Singleton):
try: try:
async with self.__client: async with self.__client:
logger_mqtt.info('MQTT broker connection established') logger_mqtt.info('MQTT broker connection established')
self.ctime = datetime.now()
self.published = 0
self.received = 0
if self.__cb_mqtt_is_up: if self.__cb_mqtt_is_up:
await self.__cb_mqtt_is_up() await self.__cb_mqtt_is_up()
@@ -84,6 +93,8 @@ class Mqtt(metaclass=Singleton):
await self.dispatch_msg(message) await self.dispatch_msg(message)
except aiomqtt.MqttError: except aiomqtt.MqttError:
self.ctime = None
if Config.is_default('mqtt'): if Config.is_default('mqtt'):
logger_mqtt.info( logger_mqtt.info(
"MQTT is unconfigured; Check your config.toml!") "MQTT is unconfigured; Check your config.toml!")
@@ -101,11 +112,14 @@ class Mqtt(metaclass=Singleton):
return return
except Exception: except Exception:
# self.inc_counter('SW_Exception') # fixme # self.inc_counter('SW_Exception') # fixme
self.ctime = None
logger_mqtt.error( logger_mqtt.error(
f"Exception:\n" f"Exception:\n"
f"{traceback.format_exc()}") f"{traceback.format_exc()}")
async def dispatch_msg(self, message): async def dispatch_msg(self, message):
self.received += 1
if message.topic.matches(self.ha_status_topic): if message.topic.matches(self.ha_status_topic):
status = message.payload.decode("UTF-8") status = message.payload.decode("UTF-8")
logger_mqtt.info('Home-Assistant Status:' logger_mqtt.info('Home-Assistant Status:'

View File

@@ -145,6 +145,10 @@ def main(): # pragma: no cover
serv_name = os.getenv('SERVICE_NAME', 'proxy') serv_name = os.getenv('SERVICE_NAME', 'proxy')
version = os.getenv('VERSION', 'unknown') version = os.getenv('VERSION', 'unknown')
@app.context_processor
def utility_processor():
return dict(version=version)
setattr(logging.handlers, "log_path", args.log_path) setattr(logging.handlers, "log_path", args.log_path)
setattr(logging.handlers, "log_backups", args.log_backups) setattr(logging.handlers, "log_backups", args.log_backups)
os.makedirs(args.log_path, exist_ok=True) os.makedirs(args.log_path, exist_ok=True)

View File

@@ -48,6 +48,7 @@ def _get_row(inv: InverterBase):
def get_table_data(): def get_table_data():
'''build the connection table''' '''build the connection table'''
table = { table = {
"headline": _('Connections'),
"col_classes": [ "col_classes": [
"w3-hide-small w3-hide-medium", "w3-hide-large", "w3-hide-small w3-hide-medium", "w3-hide-large",
"", "",
@@ -75,7 +76,7 @@ async def data_fetch():
"proxy-cnt": f"<h3>{Infos.get_counter('ProxyMode_Cnt')}</h3>", "proxy-cnt": f"<h3>{Infos.get_counter('ProxyMode_Cnt')}</h3>",
"emulation-cnt": f"<h3>{Infos.get_counter('EmuMode_Cnt')}</h3>", "emulation-cnt": f"<h3>{Infos.get_counter('EmuMode_Cnt')}</h3>",
} }
data["conn-table"] = await render_template('templ_conn_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')

View File

@@ -40,7 +40,6 @@ async def file_fetch():
data["file-list"] = await render_template('templ_log_files_list.html.j2', data["file-list"] = await render_template('templ_log_files_list.html.j2',
dir_list=get_list_data()) dir_list=get_list_data())
data["notes-list"] = await render_template('templ_notes_list.html.j2')
return data return data

58
app/src/web/mqtt_table.py Normal file
View File

@@ -0,0 +1,58 @@
from inverter_base import InverterBase
from quart import render_template
from quart_babel import format_datetime, _
from mqtt import Mqtt
from . import web
def _get_row(inv: InverterBase):
'''build one row for the connection table'''
entity_prfx = inv.entity_prfx
inv_serial = inv.local.stream.inv_serial
node_id = inv.local.stream.node_id
sug_area = inv.local.stream.sug_area
row = []
row.append(inv_serial)
row.append(entity_prfx+node_id)
row.append(sug_area)
return row
def get_table_data():
'''build the connection table'''
table = {
"headline": _('MQTT devices'),
"col_classes": [
"",
"",
"",
],
"thead": [[
_("Serial-No"),
_('Node-ID'),
_('HA-Area'),
]],
"tbody": []
}
for inverter in InverterBase:
table['tbody'].append(_get_row(inverter))
return table
@web.route('/mqtt-fetch')
async def mqtt_fetch():
mqtt = Mqtt(None)
ctime = format_datetime(dt=mqtt.ctime, format='short')
data = {
"update-time": format_datetime(format="medium"),
"mqtt-ctime": f"<h3>{ctime}</h3>",
"mqtt-tx": f"<h3>{mqtt.published}</h3>",
"mqtt-rx": f"<h3>{mqtt.received}</h3>",
}
data["mqtt-table"] = await render_template('templ_table.html.j2',
table=get_table_data())
return data

View File

@@ -11,9 +11,11 @@ async def index():
fetch_url=url_for('.data_fetch')) fetch_url=url_for('.data_fetch'))
@web.route('/page') @web.route('/mqtt')
async def empty(): async def mqtt():
return await render_template('empty.html.j2') return await render_template(
'page_mqtt.html.j2',
fetch_url=url_for('.mqtt_fetch'))
@web.route('/logging') @web.route('/logging')

View File

@@ -41,12 +41,12 @@
<!-- Sidebar/menu --> <!-- Sidebar/menu -->
<nav class="w3-sidebar w3-collapse w3-white" style="z-index:3;width:250px;" id="mySidebar"><br> <nav class="w3-sidebar w3-collapse w3-white" style="z-index:3;width:250px;" id="mySidebar"><br>
<div class="w3-container w3-row"> <div class="w3-container w3-cell-row">
<div class="w3-col s4"> <div class="w3-cell w3-cell-middle">
<img src="{{url_for('static', filename= 'images/favicon.svg') }}" alt="" class="w3-circle w3-margin-right" style="width:60px"> <img src="{{url_for('static', filename= 'images/favicon.svg') }}" alt="" class="w3-circle w3-margin-right" style="width:60px">
</div> </div>
<div class="w3-col s8 w3-bar"> <div class="w3-cell">
<h3>TSUN-Proxy</h3><br> <span><b class="w3-xlarge">TSUN-Proxy</b><br>{{_('Version:')}} {{version}}</span>
</div> </div>
</div> </div>
<hr> <hr>
@@ -56,7 +56,7 @@
<div class="w3-bar-block"> <div class="w3-bar-block">
<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('.empty')}}" 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('.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>
</div> </div>
</nav> </nav>

View File

@@ -1,9 +0,0 @@
{% extends 'base.html.j2' %}
{% block title %} TSUN Proxy - View {% endblock title%}
{% block menu2_class %}w3-blue{% endblock %}
{% block content %}
{% endblock content%}
{% block footer %}{% endblock footer %}

View File

@@ -7,6 +7,7 @@
{% block content %} {% block content %}
<div class="w3-row-padding w3-margin-bottom"> <div class="w3-row-padding w3-margin-bottom">
<div class="w3-quarter"> <div class="w3-quarter">
<div class="w3-card-4">
<div class="w3-container w3-indigo w3-padding-16"> <div class="w3-container w3-indigo w3-padding-16">
<div class="w3-left"><i class="fa fa-upload w3-xxxlarge fa-rotate-180"></i></div> <div class="w3-left"><i class="fa fa-upload w3-xxxlarge fa-rotate-180"></i></div>
<div id = "server-cnt" class="w3-right"> <div id = "server-cnt" class="w3-right">
@@ -16,8 +17,10 @@
<h4>{{_('Server Mode')}}</h4> <h4>{{_('Server Mode')}}</h4>
<div class="w3-hide-small w3-hide-medium" style="min-height:50px">{{_('Established from device to proxy')}}</div> <div class="w3-hide-small w3-hide-medium" style="min-height:50px">{{_('Established from device to proxy')}}</div>
</div> </div>
</div>
</div> </div>
<div class="w3-quarter"> <div class="w3-quarter">
<div class="w3-card-4">
<div class="w3-container w3-purple w3-padding-16"> <div class="w3-container w3-purple w3-padding-16">
<div class="w3-left"><i class="fa fa-download w3-xxxlarge fa-rotate-180"></i></div> <div class="w3-left"><i class="fa fa-download w3-xxxlarge fa-rotate-180"></i></div>
<div id = "client-cnt" class="w3-right"> <div id = "client-cnt" class="w3-right">
@@ -27,8 +30,10 @@
<h4>{{_('Client Mode')}}</h4> <h4>{{_('Client Mode')}}</h4>
<div class="w3-hide-small w3-hide-medium" style="min-height:50px">{{_('Established from proxy to device')}}</div> <div class="w3-hide-small w3-hide-medium" style="min-height:50px">{{_('Established from proxy to device')}}</div>
</div> </div>
</div>
</div> </div>
<div class="w3-quarter"> <div class="w3-quarter">
<div class="w3-card-4">
<div class="w3-container w3-orange w3-text-white w3-padding-16"> <div class="w3-container w3-orange w3-text-white w3-padding-16">
<div class="w3-left"><i class="fa fa-cloud w3-xxxlarge"></i></div> <div class="w3-left"><i class="fa fa-cloud w3-xxxlarge"></i></div>
<div id = "proxy-cnt" class="w3-right"> <div id = "proxy-cnt" class="w3-right">
@@ -38,8 +43,10 @@
<h4>{{_('Proxy Mode')}}</h4> <h4>{{_('Proxy Mode')}}</h4>
<div class="w3-hide-small w3-hide-medium" style="min-height:50px">{{_('Forwarding data to cloud')}}</div> <div class="w3-hide-small w3-hide-medium" style="min-height:50px">{{_('Forwarding data to cloud')}}</div>
</div> </div>
</div>
</div> </div>
<div class="w3-quarter"> <div class="w3-quarter">
<div class="w3-card-4">
<div class="w3-container w3-teal w3-padding-16"> <div class="w3-container w3-teal w3-padding-16">
<div class="w3-left"><i class="fa fa-cloud-arrow-up-alt w3-xxxlarge"></i></div> <div class="w3-left"><i class="fa fa-cloud-arrow-up-alt w3-xxxlarge"></i></div>
<div id = "emulation-cnt" class="w3-right"> <div id = "emulation-cnt" class="w3-right">
@@ -49,9 +56,12 @@
<h4>{{_('Emu Mode')}}</h4> <h4>{{_('Emu Mode')}}</h4>
<div class="w3-hide-small w3-hide-medium" style="min-height:50px">{{_('Emulation sends data to cloud')}}</div> <div class="w3-hide-small w3-hide-medium" style="min-height:50px">{{_('Emulation sends data to cloud')}}</div>
</div> </div>
</div>
</div> </div>
</div> </div>
<div class="w3-container" id="notes-list"></div> <div id="notes-list"></div>
<div class="w3-container" id="conn-table"></div> <div id="conn-table"></div>
{% endblock content%} {% endblock content%}
{% block footer %}{% endblock footer %}

View File

@@ -1,6 +1,6 @@
{% extends 'base.html.j2' %} {% extends 'base.html.j2' %}
{% block title %} TSUN Proxy - Downloads {% endblock title%} {% block title %} TSUN Proxy - Log Files {% endblock title%}
{% block menu3_class %}w3-blue{% endblock %} {% block menu3_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 %}
@@ -16,7 +16,7 @@
</div> </div>
</div> </div>
<div class="w3-container" id="file-list"></div> <div id="file-list"></div>
<script> <script>
function deleteFile() { function deleteFile() {
@@ -28,4 +28,3 @@
{% endblock content%} {% endblock content%}
{% block footer %}{% endblock footer %} {% block footer %}{% endblock footer %}

View File

@@ -0,0 +1,51 @@
{% extends 'base.html.j2' %}
{% block title %} TSUN Proxy - MQTT Status {% endblock title%}
{% block menu2_class %}w3-blue{% endblock %}
{% block headline %}<i class="fa fa-database"></i>  {{_('MQTT Overview')}}{% endblock headline %}
{% block content %}
<div class="w3-row-padding w3-margin-bottom">
<div class="w3-third">
<div class="w3-card-4">
<div class="w3-container w3-indigo w3-padding-16">
<div class="w3-left"><i class="fa fa-link w3-xxxlarge"></i></div>
<div id = "mqtt-ctime" class="w3-right">
<h3>-</h3>
</div>
<div class="w3-clear"></div>
<h4>{{_('Connection Time')}}</h4>
<div class="w3-hide-small w3-hide-medium" style="min-height:50px">{{_('Time at which the connection was established')}}</div>
</div>
</div>
</div>
<div class="w3-third">
<div class="w3-card-4">
<div class="w3-container w3-purple w3-padding-16">
<div class="w3-left"><i class="fa fa-server w3-xxxlarge"></i></div>
<div id = "mqtt-tx" class="w3-right">
<h3>-</h3>
</div>
<div class="w3-clear"></div>
<h4>{{_('Published Topics')}}</h4>
<div class="w3-hide-small w3-hide-medium" style="min-height:50px">{{_('Number of published topics')}}</div>
</div>
</div>
</div>
<div class="w3-third">
<div class="w3-card-4">
<div class="w3-container w3-orange w3-text-white w3-padding-16">
<div class="w3-left"><i class="fa fa-user w3-xxxlarge"></i></div>
<div id = "mqtt-rx" class="w3-right">
<h3>-</h3>
</div>
<div class="w3-clear"></div>
<h4>{{_('Received Topics')}}</h4>
<div class="w3-hide-small w3-hide-medium" style="min-height:50px">{{_('Number of topics received')}}</div>
</div>
</div>
</div>
</div>
<div id="mqtt-table"></div>
{% endblock content%}
{% block footer %}{% endblock footer %}

View File

@@ -3,7 +3,7 @@
<div class="w3-quarter w3-margin-bottom"> <div class="w3-quarter w3-margin-bottom">
<div class="w3-card-4"> <div class="w3-card-4">
<header class="w3-container w3-blue" style="min-height:80px"> <header class="w3-container w3-teal" style="min-height:80px">
<h4>{{file.name}}</h4> <h4>{{file.name}}</h4>
</header> </header>
@@ -16,9 +16,9 @@
{% endfor %} {% endfor %}
</table> </table>
<footer class="w3-blue"> <footer class="w3-teal">
<a href="{{ url_for('.send',file=file.name)}}" class="w3-button w3-hover-blue w3-hover-text-black"><i class="fa fa-file-download"></i>  {{_('Download File')}}</a> <a href="{{ url_for('.send',file=file.name)}}" class="w3-button w3-hover-teal w3-hover-text-black"><i class="fa fa-file-download"></i>  {{_('Download File')}}</a>
<a class="w3-button w3-right w3-hover-blue w3-hover-text-black" <a class="w3-button w3-right w3-hover-teal w3-hover-text-black"
onclick="document.getElementById('id03').innerHTML='{{file.name}}'; document.getElementById('id02').href='{{ url_for('.delete',file=file.name)}}'; document.getElementById('id01').style.display='block';"><i class="fa fa-trash"></i></a> onclick="document.getElementById('id03').innerHTML='{{file.name}}'; document.getElementById('id02').href='{{ url_for('.delete',file=file.name)}}'; document.getElementById('id01').style.display='block';"><i class="fa fa-trash"></i></a>
</footer> </footer>
</div> </div>

View File

@@ -12,8 +12,11 @@
{% endif %} {% endif %}
{%- endmacro%} {%- endmacro%}
<h5>{{_('Connections')}}</h5> <div class="w3-container w3-margin-bottom">
<table class="w3-table w3-striped w3-bordered w3-border w3-hoverable w3-white"> <h5>{{table.headline}}</h5>
<div class="w3-card-4">
<table class="w3-table w3-bordered w3-hoverable w3-white">
{% if table.thead is defined%} {% if table.thead is defined%}
<thead> <thead>
{% for row in table.thead %} {% for row in table.thead %}
@@ -35,3 +38,5 @@
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
</div>
</div>

View File

@@ -140,6 +140,7 @@ async def test_ha_reconnect(config_mqtt_conn):
assert on_connect.is_set() assert on_connect.is_set()
finally: finally:
assert m.received == 2
await m.close() await m.close()
@pytest.mark.asyncio @pytest.mark.asyncio

View File

@@ -7,6 +7,7 @@ from gen3plus.inverter_g3p import InverterG3P
from test_inverter_g3p import FakeReader, FakeWriter, config_conn from test_inverter_g3p import FakeReader, FakeWriter, config_conn
from cnf.config import Config from cnf.config import Config
from mock import patch from mock import patch
from proxy import Proxy
import os, errno import os, errno
pytest_plugins = ('pytest_asyncio',) pytest_plugins = ('pytest_asyncio',)
@@ -53,16 +54,16 @@ async def test_home(client):
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_page(client): async def test_page(client):
"""Test the empty page route.""" """Test the mqtt page route."""
response = await client.get('/page') response = await client.get('/mqtt')
assert response.status_code == 200 assert response.status_code == 200
assert response.mimetype == 'text/html' assert response.mimetype == 'text/html'
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_rel_page(client): async def test_rel_page(client):
"""Test the empty page route.""" """Test the mqtt route."""
web.build_relative_urls = True web.build_relative_urls = True
response = await client.get('/page') response = await client.get('/mqtt')
assert response.status_code == 200 assert response.status_code == 200
assert response.mimetype == 'text/html' assert response.mimetype == 'text/html'
web.build_relative_urls = False web.build_relative_urls = False
@@ -152,7 +153,7 @@ async def test_language_en(client):
assert response.mimetype == 'text/html' assert response.mimetype == 'text/html'
client.set_cookie('test', key='language', value='de') client.set_cookie('test', key='language', value='de')
response = await client.get('/page') response = await client.get('/mqtt')
assert response.status_code == 200 assert response.status_code == 200
assert response.mimetype == 'text/html' assert response.mimetype == 'text/html'
@@ -174,6 +175,16 @@ async def test_language_unknown(client):
assert response.mimetype == 'text/html' assert response.mimetype == 'text/html'
@pytest.mark.asyncio
async def test_mqtt_fetch(client, create_inverter):
"""Test the mqtt-fetch route."""
_ = create_inverter
Proxy.class_init()
response = await client.get('/mqtt-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."""

View File

@@ -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-02 17:00+0200\n" "POT-Creation-Date: 2025-05-03 21:59+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,34 +19,49 @@ 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:57 #: src/web/conn_table.py:51 src/web/templates/base.html.j2:58
msgid "Connections"
msgstr "Verbindungen"
#: src/web/conn_table.py:58
msgid "Device-IP:Port" msgid "Device-IP:Port"
msgstr "Geräte-IP:Port" msgstr "Geräte-IP:Port"
#: src/web/conn_table.py:57 #: src/web/conn_table.py:58
msgid "Device-IP" msgid "Device-IP"
msgstr "Geräte-IP" msgstr "Geräte-IP"
#: src/web/conn_table.py:58 #: src/web/conn_table.py:59 src/web/mqtt_table.py:33
msgid "Serial-No" msgid "Serial-No"
msgstr "Seriennummer" msgstr "Seriennummer"
#: src/web/conn_table.py:59 #: src/web/conn_table.py:60
msgid "Cloud-IP:Port" msgid "Cloud-IP:Port"
msgstr "Cloud-IP:Port" msgstr "Cloud-IP:Port"
#: src/web/conn_table.py:59 #: src/web/conn_table.py:60
msgid "Cloud-IP" msgid "Cloud-IP"
msgstr "Cloud-IP" msgstr "Cloud-IP"
#: src/web/mqtt_table.py:26
msgid "MQTT devices"
msgstr "MQTT Geräte"
#: src/web/mqtt_table.py:34
msgid "Node-ID"
msgstr ""
#: src/web/mqtt_table.py:35
msgid "HA-Area"
msgstr ""
#: src/web/templates/base.html.j2:37 #: src/web/templates/base.html.j2:37
msgid "Updated:" msgid "Updated:"
msgstr "Aktualisiert:" msgstr "Aktualisiert:"
#: src/web/templates/base.html.j2:58 #: src/web/templates/base.html.j2:49
#: src/web/templates/templ_conn_table.html.j2:15 msgid "Version:"
msgid "Connections" msgstr ""
msgstr "Verbindungen"
#: 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_logging.html.j2:5
msgid "Log Files" msgid "Log Files"
@@ -56,35 +71,35 @@ msgstr "Log Dateien"
msgid "Proxy Connection Overview" msgid "Proxy Connection Overview"
msgstr "Proxy Verbindungen" msgstr "Proxy Verbindungen"
#: src/web/templates/page_index.html.j2:16 #: src/web/templates/page_index.html.j2:17
msgid "Server Mode" msgid "Server Mode"
msgstr "Server Modus" msgstr "Server Modus"
#: src/web/templates/page_index.html.j2:17 #: src/web/templates/page_index.html.j2:18
msgid "Established from device to proxy" msgid "Established from device to proxy"
msgstr "Vom Gerät zum Proxy aufgebaut" msgstr "Vom Gerät zum Proxy aufgebaut"
#: src/web/templates/page_index.html.j2:27 #: src/web/templates/page_index.html.j2:30
msgid "Client Mode" msgid "Client Mode"
msgstr "Client Modus" msgstr "Client Modus"
#: src/web/templates/page_index.html.j2:28 #: src/web/templates/page_index.html.j2:31
msgid "Established from proxy to device" msgid "Established from proxy to device"
msgstr "Vom Proxy zum Gerät aufgebaut" msgstr "Vom Proxy zum Gerät aufgebaut"
#: src/web/templates/page_index.html.j2:38 #: src/web/templates/page_index.html.j2:43
msgid "Proxy Mode" msgid "Proxy Mode"
msgstr "Proxy Modus" msgstr "Proxy Modus"
#: src/web/templates/page_index.html.j2:39 #: src/web/templates/page_index.html.j2:44
msgid "Forwarding data to cloud" msgid "Forwarding data to cloud"
msgstr "Weiterleitung in die Cloud" msgstr "Weiterleitung in die Cloud"
#: src/web/templates/page_index.html.j2:49 #: src/web/templates/page_index.html.j2:56
msgid "Emu Mode" msgid "Emu Mode"
msgstr "Emu Modus" msgstr "Emu Modus"
#: src/web/templates/page_index.html.j2:50 #: src/web/templates/page_index.html.j2:57
msgid "Emulation sends data to cloud" msgid "Emulation sends data to cloud"
msgstr "Emulation sendet in die Cloud" msgstr "Emulation sendet in die Cloud"
@@ -100,6 +115,34 @@ msgstr "File löschen"
msgid "Abort" msgid "Abort"
msgstr "Abbruch" msgstr "Abbruch"
#: src/web/templates/page_mqtt.html.j2:5
msgid "MQTT Overview"
msgstr "MQTT Überblick"
#: src/web/templates/page_mqtt.html.j2:16
msgid "Connection Time"
msgstr "Verbindungszeit"
#: src/web/templates/page_mqtt.html.j2:17
msgid "Time at which the connection was established"
msgstr "Zeitpunkt des Verbindungsaufbaus"
#: src/web/templates/page_mqtt.html.j2:29
msgid "Published Topics"
msgstr "Gesendete Topics"
#: src/web/templates/page_mqtt.html.j2:30
msgid "Number of published topics"
msgstr "Anzahl der veröffentlichten Topics"
#: src/web/templates/page_mqtt.html.j2:42
msgid "Received Topics"
msgstr "Empfangene Topics"
#: src/web/templates/page_mqtt.html.j2:43
msgid "Number of topics received"
msgstr "Anzahl der empfangenen Topics"
#: 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"
@@ -116,3 +159,24 @@ msgstr "Größe"
msgid "Download File" msgid "Download File"
msgstr "Datei Download" msgstr "Datei Download"
#~ msgid "MQTT Server"
#~ msgstr ""
#~ msgid "MQTT User"
#~ msgstr ""
#~ msgid "MQTT Connected"
#~ msgstr ""
#~ msgid "Home Assistant Status"
#~ msgstr ""
#~ msgid "MQTT Publish Count"
#~ msgstr ""
#~ msgid "MQTT Reveiced Count"
#~ msgstr ""
#~ msgid "MQTT Connect Time"
#~ msgstr "MQTT Verbindungszeit"