AnswersFile

Question

How to Monitor OpenWRT Stats in Home Assistant via SNMP?

Answer

Step 1: Install SNMP on OpenWRT

SSH into your OpenWRT router and install the SNMP daemon:

opkg update
opkg install snmpd

Enable and start the service:

/etc/init.d/snmpd enable
/etc/init.d/snmpd start

Step 2: Add sensors to Home Assistant

Add the following configuration to your Home Assistant configuration.yaml. Replace 192.168.1.1 with your router's IP address.

What this monitors:

  • CPU usage (per-core and overall)
  • Memory usage
  • WAN bandwidth (download/upload in Mbps)
  • LAN bandwidth (download/upload in Mbps)
  • Total data transferred (GB)
  • WAN status (up/down)
  • System uptime and load average
# ============================================
# OPENWRT ROUTER SNMP MONITORING
# TUF-AX4200 at 192.168.1.1
# ============================================

sensor:
  # ============================================
  # RAW SNMP COUNTERS - 64-BIT (HIGH CAPACITY)
  # ============================================

  # WAN interface (index 3 = eth1) - 64-bit counters
  - platform: snmp
    host: 192.168.1.1
    community: public
    version: '2c'
    scan_interval: 30
    name: "Router WAN RX Bytes Raw"
    baseoid: 1.3.6.1.2.1.31.1.1.1.6.3
    accept_errors: true
    unit_of_measurement: 'B'

  - platform: snmp
    host: 192.168.1.1
    community: public
    version: '2c'
    scan_interval: 30
    name: "Router WAN TX Bytes Raw"
    baseoid: 1.3.6.1.2.1.31.1.1.1.10.3
    accept_errors: true
    unit_of_measurement: 'B'

  # LAN interface (index 9 = br-lan) - 64-bit counters
  - platform: snmp
    host: 192.168.1.1
    community: public
    version: '2c'
    scan_interval: 30
    name: "Router LAN RX Bytes Raw"
    baseoid: 1.3.6.1.2.1.31.1.1.1.6.9
    accept_errors: true
    unit_of_measurement: 'B'

  - platform: snmp
    host: 192.168.1.1
    community: public
    version: '2c'
    scan_interval: 30
    name: "Router LAN TX Bytes Raw"
    baseoid: 1.3.6.1.2.1.31.1.1.1.10.9
    accept_errors: true
    unit_of_measurement: 'B'

  # ============================================
  # SYSTEM METRICS
  # ============================================
  - platform: snmp
    host: 192.168.1.1
    community: public
    version: '2c'
    name: "Router Uptime Raw"
    baseoid: 1.3.6.1.2.1.1.3.0
    accept_errors: true

  - platform: snmp
    host: 192.168.1.1
    community: public
    version: '2c'
    name: "Router WAN Status Raw"
    baseoid: 1.3.6.1.2.1.2.2.1.8.3
    accept_errors: true

  - platform: snmp
    host: 192.168.1.1
    community: public
    version: '2c'
    name: "Router Load Average"
    baseoid: 1.3.6.1.4.1.2021.10.1.3.1
    accept_errors: true

  - platform: snmp
    host: 192.168.1.1
    community: public
    version: '2c'
    name: "Router Memory Total"
    baseoid: 1.3.6.1.4.1.2021.4.5.0
    accept_errors: true
    unit_of_measurement: 'KB'

  - platform: snmp
    host: 192.168.1.1
    community: public
    version: '2c'
    name: "Router Memory Free"
    baseoid: 1.3.6.1.4.1.2021.4.6.0
    accept_errors: true
    unit_of_measurement: 'KB'

  # ============================================
  # CPU METRICS (PER-CORE)
  # ============================================
  - platform: snmp
    host: 192.168.1.1
    community: public
    version: '2c'
    scan_interval: 10
    name: "Router CPU Core 0"
    baseoid: 1.3.6.1.2.1.25.3.3.1.2.196608
    accept_errors: true
    unit_of_measurement: '%'

  - platform: snmp
    host: 192.168.1.1
    community: public
    version: '2c'
    scan_interval: 10
    name: "Router CPU Core 1"
    baseoid: 1.3.6.1.2.1.25.3.3.1.2.196609
    accept_errors: true
    unit_of_measurement: '%'

  - platform: snmp
    host: 192.168.1.1
    community: public
    version: '2c'
    scan_interval: 10
    name: "Router CPU Core 2"
    baseoid: 1.3.6.1.2.1.25.3.3.1.2.196610
    accept_errors: true
    unit_of_measurement: '%'

  - platform: snmp
    host: 192.168.1.1
    community: public
    version: '2c'
    scan_interval: 10
    name: "Router CPU Core 3"
    baseoid: 1.3.6.1.2.1.25.3.3.1.2.196611
    accept_errors: true
    unit_of_measurement: '%'

  - platform: snmp
    host: 192.168.1.1
    community: public
    version: '2c'
    scan_interval: 10
    name: "Router CPU Idle"
    baseoid: 1.3.6.1.4.1.2021.11.11.0
    accept_errors: true
    unit_of_measurement: '%'

  # ============================================
  # CALCULATE RATES (bytes per second)
  # ============================================
  - platform: derivative
    source: sensor.router_wan_rx_bytes_raw
    name: "Router WAN RX Rate"
    unit_time: s
    time_window: "00:00:30"
    unit: B/s

  - platform: derivative
    source: sensor.router_wan_tx_bytes_raw
    name: "Router WAN TX Rate"
    unit_time: s
    time_window: "00:00:30"
    unit: B/s

  - platform: derivative
    source: sensor.router_lan_rx_bytes_raw
    name: "Router LAN RX Rate"
    unit_time: s
    time_window: "00:00:30"
    unit: B/s

  - platform: derivative
    source: sensor.router_lan_tx_bytes_raw
    name: "Router LAN TX Rate"
    unit_time: s
    time_window: "00:00:30"
    unit: B/s

# ============================================
# MODERN TEMPLATE SYNTAX - FIXED
# ============================================
template:
  - sensor:
      # BANDWIDTH SENSORS - CORRECTED (RX=Download, TX=Upload)
      - name: "Router WAN Download"
        unique_id: router_wan_download
        unit_of_measurement: "Mbps"
        icon: mdi:download-network
        state: >
          {% set rate = states('sensor.router_wan_rx_rate') | float(0) %}
          {% set mbps = ((rate * 8) / 1000000) | round(2) %}
          {{ [mbps, 0] | max }}
        availability: >
          {{ states('sensor.router_wan_rx_rate') not in ['unknown', 'unavailable', 'none'] }}

      - name: "Router WAN Upload"
        unique_id: router_wan_upload
        unit_of_measurement: "Mbps"
        icon: mdi:upload-network
        state: >
          {% set rate = states('sensor.router_wan_tx_rate') | float(0) %}
          {% set mbps = ((rate * 8) / 1000000) | round(2) %}
          {{ [mbps, 0] | max }}
        availability: >
          {{ states('sensor.router_wan_tx_rate') not in ['unknown', 'unavailable', 'none'] }}

      - name: "Router LAN Download"
        unique_id: router_lan_download
        unit_of_measurement: "Mbps"
        icon: mdi:download
        state: >
          {% set rate = states('sensor.router_lan_rx_rate') | float(0) %}
          {% set mbps = ((rate * 8) / 1000000) | round(2) %}
          {{ [mbps, 0] | max }}

      - name: "Router LAN Upload"
        unique_id: router_lan_upload
        unit_of_measurement: "Mbps"
        icon: mdi:upload
        state: >
          {% set rate = states('sensor.router_lan_tx_rate') | float(0) %}
          {% set mbps = ((rate * 8) / 1000000) | round(2) %}
          {{ [mbps, 0] | max }}

      # CPU SENSORS
      - name: "Router CPU Usage"
        unique_id: router_cpu_usage
        unit_of_measurement: "%"
        icon: mdi:cpu-64-bit
        state: >
          {% set idle = states('sensor.router_cpu_idle') | float(0) %}
          {{ (100 - idle) | round(1) }}
        availability: >
          {{ states('sensor.router_cpu_idle') not in ['unknown', 'unavailable', 'none'] }}

      # SYSTEM SENSORS
      - name: "Router Uptime"
        unique_id: router_uptime
        icon: mdi:clock-outline
        state: >
          {% set timeticks = states('sensor.router_uptime_raw') | float(0) %}
          {% set seconds = (timeticks / 100) | int %}
          {% set days = (seconds / 86400) | int %}
          {% set hours = ((seconds % 86400) / 3600) | int %}
          {% set minutes = ((seconds % 3600) / 60) | int %}
          {% if days > 0 %}
            {{ days }}d {{ hours }}h {{ minutes }}m
          {% elif hours > 0 %}
            {{ hours }}h {{ minutes }}m
          {% else %}
            {{ minutes }}m
          {% endif %}

      - name: "Router WAN Total Download"
        unique_id: router_wan_total_download
        unit_of_measurement: "GB"
        icon: mdi:download-network
        state: >
          {% set bytes = states('sensor.router_wan_rx_bytes_raw') | float(0) %}
          {{ (bytes / 1000000000) | round(3) }}

      - name: "Router WAN Total Upload"
        unique_id: router_wan_total_upload
        unit_of_measurement: "GB"
        icon: mdi:upload-network
        state: >
          {% set bytes = states('sensor.router_wan_tx_bytes_raw') | float(0) %}
          {{ (bytes / 1000000000) | round(3) }}

      - name: "Router Memory Usage"
        unique_id: router_memory_usage
        unit_of_measurement: "%"
        icon: mdi:memory
        state: >
          {% set total = states('sensor.router_memory_total') | float(0) %}
          {% set free = states('sensor.router_memory_free') | float(0) %}
          {% if total > 0 %}
            {{ (((total - free) / total) * 100) | round(1) }}
          {% else %}
            0
          {% endif %}

      - name: "Router WAN Status"
        unique_id: router_wan_status
        icon: >
          {% if states('sensor.router_wan_status_raw') == '1' %}
            mdi:check-network
          {% else %}
            mdi:close-network
          {% endif %}
        state: >
          {% if states('sensor.router_wan_status_raw') == '1' %}
            Up
          {% elif states('sensor.router_wan_status_raw') == '2' %}
            Down
          {% else %}
            Unknown
          {% endif %}

Important notes

  • Replace 192.168.1.1 with your router's IP address throughout the configuration
  • Interface indices may vary by router. On the TUF-AX4200, WAN (eth1) is index 3 and br-lan is index 9. Use snmpwalk -v2c -c public 192.168.1.1 1.3.6.1.2.1.2.2.1.2 to find your interface indices
  • CPU core OIDs (196608, 196609, etc.) may differ on your router. Adjust or remove cores based on your CPU
  • The SNMP community string defaults to public. For security, consider changing it in /etc/config/snmpd
  • Restart Home Assistant after adding the configuration