type: sections
max_columns: 4
title: Meshtastic
path: meshtastic
sections:
- type: grid
  cards:
  - type: heading
    heading: My node
    heading_style: title
    icon: mdi:access-point
  - type: tile
    entity: sensor.meshtastic_last_packet
    name: Last packet
  - type: tile
    entity: sensor.meshtastic_battery_percent
    name: Battery
  - type: tile
    entity: sensor.meshtastic_battery_voltage
    name: Voltage
  - type: tile
    entity: sensor.meshtastic_uptime
    name: Uptime
  - type: tile
    entity: sensor.meshtastic_channel_utilisation
    name: Channel use
  - type: tile
    entity: sensor.meshtastic_air_util_tx
    name: Airtime TX
  - type: history-graph
    title: Battery
    hours_to_show: 48
    entities:
    - entity: sensor.meshtastic_battery_percent
      name: Battery
    grid_options:
      columns: 12
  - type: history-graph
    title: Channel use and airtime
    hours_to_show: 48
    entities:
    - entity: sensor.meshtastic_channel_utilisation
      name: Channel use
    - entity: sensor.meshtastic_air_util_tx
      name: Airtime TX
    grid_options:
      columns: 12
- type: grid
  cards:
  - type: heading
    heading: Mesh
    heading_style: title
    icon: mdi:radar
  - type: tile
    entity: sensor.meshtastic_nodes_heard
    name: Nodes heard (24h)
  - type: tile
    entity: sensor.meshtastic_node_registry
    name: Nodes known
  - type: markdown
    content: |-
      {% set nodes = state_attr('sensor.meshtastic_nodes_heard', 'nodes') or {} %}
      {% set ns = namespace(rows=[]) %}
      {% for k, v in nodes.items() if v is mapping %}{% set ns.rows = ns.rows + [v] %}{% endfor %}
      {% if ns.rows %}
      | Node | Hops | SNR | RSSI | Heard |
      |:--|:-:|--:|--:|--:|
      {% for v in (ns.rows | sort(attribute='last', reverse=true))[:25] -%}
      | {{ v.name | replace('|', '/') }} | {{ v.hops if v.hops is not none else '?' }} | {{ v.snr if v.snr is not none else '' }} | {{ v.rssi if v.rssi is not none else '' }} | {{ ((as_timestamp(now()) - v.last) / 60) | int }} min ago |
      {% endfor %}
      {% if ns.rows | count > 25 %}_and {{ ns.rows | count - 25 }} more_{% endif %}
      _SNR and RSSI are for the last hop into my node, not from the sender itself._
      {% else %}No nodes heard yet.{% endif %}
    grid_options:
      columns: 12
- type: grid
  cards:
  - type: heading
    heading: Messages
    heading_style: title
    icon: mdi:message-text
  - type: tile
    entity: sensor.meshtastic_last_message
    name: Last message
    vertical: false
    grid_options:
      columns: 12
      rows: 1
  - type: markdown
    content: |-
      {% set m = state_attr('sensor.meshtastic_chat_log', 'messages') or [] %}
      {% if m %}
      | When | From | Message |
      |:--|:--|:--|
      {% for x in m -%}
      | {{ x.time }} | {{ x['from'] | replace('|', '/') }} | {{ x.text | replace('|', '/') | replace('\n', ' ') }} |
      {% endfor %}
      {% else %}No messages since the log was set up.{% endif %}
    grid_options:
      columns: 12
