{% from "_macros.html" import state_label %} {#- the fixed texts of the rows, translated once instead of once per row (half the time this table takes to render) #} {%- set t = { 'serial': _('Serial'), 'network': _('Network'), 'state': _('State'), 'clients': _('Clients'), 'in_out': _('In / Out'), 'disabled': _('disabled'), 'opened_now': _('device opened now'), 'bridge': _('serial↔serial'), 'read_only': _('read-only'), 'priority': _('priority'), 'cmd_open': _('writable points take MQTT commands over a broker connection without TLS or a username: any client the broker lets publish to the command topics can write them'), 'cmd': _('writable points take MQTT commands (/set or Sparkplug DCMD)'), 'tx_open': _('MQTT messages on <topic>/tx are written to the device over a broker connection without TLS or a username: any client the broker lets publish to that topic can write to it'), 'tx': _('MQTT messages on <topic>/tx are written to the device'), 'link_down': _('link down'), 'connecting': _('connecting'), 'retrying_now': _('retrying now'), 'link_down_title': _('the connection to the remote server is down; it is tried again'), 'dropped': _('data from the network that was not written to the serial device; the mapping’s log says why'), 'trace_not_written': _('trace not written'), 'units_offline': _('polled Modbus units that gave no reply to any of their points in 3 polls in a row; they are polled with one point per cycle until they answer (see the mapping’s log)'), 'mqtt_down': _('the mapping’s connection to its MQTT broker; it keeps trying (see the mapping’s log)'), 'mqtt_off': _('MQTT publishing could not start (see the mapping’s log)'), 'stop': _('Stop'), 'restart': _('Restart'), 'start': _('Start'), 'edit': _('Edit'), 'log': _('Log'), 'monitor': _('Monitor'), 'trace': _('Trace'), 'duplicate': _('Copy'), 'delete': _('Delete'), } %}
| {{ _("Name") }} | {{ t.serial }} | {{ t.network }} | {{ t.state }} | {{ t.clients }} | {{ t.in_out }} | |
|---|---|---|---|---|---|---|
| {% if can_edit %} {% endif %}{{ m.name|softbreak }}{% if not m.enabled %} {{ t.disabled }}{% endif %} |
{{ m.serial.port|softbreak }}{% if m.serial.identity %} USB-ID{% endif %}
{% if st and st.device and st.device != m.serial.port %}→ {{ st.device|softbreak }} {% endif %}
{{ m.serial.compact() }}{% if m.serial.flowcontrol != 'none' %} · {{ m.serial.flowcontrol }}{% endif %}
|
{%- if m.kind == 'serialbridge' -%}{{ m.serial_b.port|softbreak }}
{%- elif m.network.mode == 'client' -%}→ {{ shown_host(m.network.remote_host)|softbreak }}:
{%- if m.kind == 'serialbridge' -%}{{ t.bridge }}
{%- else -%}{{ m.network.mode }}/{{ m.network.protocol }}
{%- if m.network.tls %} TLS{% endif %}
{%- if m.network.read_only %} RO{% endif %}
{%- if m.accepts_mqtt_writes %}{% set open_cmd = not (m.mqtt.tls and m.mqtt.username) %} CMD{% if open_cmd %} ⚠{% endif %}
{%- elif m.accepts_mqtt_tx %}{% set open_cmd = not (m.mqtt.tls and m.mqtt.username) %} CMD{% if open_cmd %} ⚠{% endif %}{% endif %}
{%- endif -%}
|
{{ state_label(state) }}
{%- if link_down %} {{ t.link_down }}
{%- elif st and st.link == 'connecting' and state == 'running' %} {{ t.connecting }}{% endif %}
{% if st and st.last_error and state in ('error','device-missing','reconnecting')
and not (link_down and st.last_error == st.link_error) %}
{#- what it means in the page's language; the error itself in the tooltip. With
state "error" a hint is why the system refused the listener's port and what to
do (the supervisor sets it at each failed start): it says that instead (a
general "ports below 1024" would be wrong on Windows) #}
{%- set bind_hint = st.hint if state == 'error' else '' %}
{{ (bind_hint or st.last_error|explain or st.last_error)|softbreak }}
{#- a serial port's hint (device-missing / reconnecting): what to do, under it #}
{% if st.hint and not bind_hint %}{{ st.hint|softbreak }} {% endif %}
{% endif %}
{% if link_down and st.link_error %}
{{ (st.link_error|explain or st.link_error)|softbreak }}
{% endif %}
{% if st and st.warnings and state == 'running' %}
{% for w in st.warnings %}⚠ {{ w|softbreak }} {% endfor %}
{% endif %}
{% if st and st.retrying and state == 'error' %}
{{ _("retrying in %(n)s s", n=st.next_retry_s) if st.next_retry_s else t.retrying_now }}
{% endif %}
{% set quiet = no_data_for(m, st) %}
{% if quiet %}⚠ {{ _("no data from the device for %(n)s s", n=quiet) if not m.options.no_data_reply_only else _("no answer from the device for %(n)s s", n=quiet) }} {% endif %}
{% set silent = (st.units if st and st.units else [])|selectattr('state', 'equalto', 'offline')|map(attribute='unit')|list %}
{% if state == 'running' and silent %}⚠ {{ ngettext("Modbus unit not answering: %(units)s", "Modbus units not answering: %(units)s", silent|length, units=silent|join(', ')) }} {% endif %}
{% set mq = st.mqtt if st and st.mqtt else {} %}
{% if mq.state == 'down' %}⚠ {{ _("MQTT: no connection to %(broker)s (%(error)s)", broker=mq.broker, error=mq.error) }}
{% elif mq.state == 'off' %}⚠ {{ _("MQTT off: %(error)s", error=mq.error) }} {% endif %}
|
{{ st.client_count if st else 0 }}{% if m.network.max_connections > 1 %}/{{ m.network.max_connections }}{% endif %}
{% if st and st.clients %}
{#- data-since: app.js counts the connection time on (the table is not sent again for it) #}
{#- the time in the page's language (the REST API's duration is English) #}
{% for cl in st.clients %}{% set dur = cl.connected_at|since if cl.connected_at else cl.duration %}{% if cl.priority %}★ {% endif %}{{ cl.peer }} · {{ dur }}{% endfor %}
{% endif %}
{% if st and st.dropped_clients %}⚠ {{ ngettext("%(num)s slow client dropped", "%(num)s slow clients dropped", st.dropped_clients) }} {% endif %}
|
{{ (st.bytes_in|default(0) if st else 0)|bytesize }} / {{ (st.bytes_out|default(0) if st else 0)|bytesize }}
{% if st and st.bytes_dropped %} ⚠ {{ ngettext("%(num)s byte dropped", "%(num)s bytes dropped", st.bytes_dropped) }} {% endif %}
{% if st and st.trace_error %}⚠ {{ t.trace_not_written }} {% endif %} |
{% if can_edit %}
{% if m.enabled %}
{#- asked only while clients are connected: they are disconnected (a question at
every click would soon be clicked through) #}
{% set n = st.client_count|default(0) if st else 0 %}
{% else %}
{% endif %}
{% endif %}
{% if can_edit and (m.options.trace_both or m.id in traced) %}{% endif %}
{% if can_edit %}
{% endif %}
|
| {{ _("No mappings yet. Click “Add mapping” to create one.") if can_edit else _("No mappings yet.") }} | ||||||