Déc 302025
 

8 years ago I had come with a dirty solution to graph my router bandwidth usage (here).

Now, we have AI (chatgpt here) and with a single prompt (« over ssh, retrieve my ddwrt bandwidth usage »), it provided me with a neat script/solution.

I then get a web page, refreshed hourly.

#!/bin/bash
set -e

# ==================================================
# Configuration
# ==================================================
ROUTER_IP="192.168.1.250"
ROUTER_USER="root"
SSH_KEY="$HOME/.ssh/id_ed25519"
OUTPUT_HTML="/var/www/html/traffic.html"

MONTH=$(date +%m)
YEAR=$(date +%Y)
NVRAM_KEY="traff-$MONTH-$YEAR"

GENERATED_AT=$(date '+%d/%m/%Y à %H:%M')

# ==================================================
# Récupération des données depuis le routeur
# ==================================================
RAW_DATA=$(ssh -i "$SSH_KEY" -q "$ROUTER_USER@$ROUTER_IP" "nvram get $NVRAM_KEY")

# Total mensuel [incoming:outgoing]
TOTAL=$(echo "$RAW_DATA" | grep -o '\[.*\]')

# Données journalières uniquement
DATA=$(echo "$RAW_DATA" | sed 's/\[.*\]//')

# ==================================================
# Génération de la page HTML (écriture root)
# ==================================================
sudo tee "$OUTPUT_HTML" > /dev/null <<EOF
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Trafic DD-WRT - $MONTH/$YEAR</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
  body {
    font-family: Arial, sans-serif;
    background: #f4f4f9;
    margin: 40px;
  }
  h1 {
    text-align: center;
  }
  #chart-container {
    max-width: 1100px;
    margin: auto;
  }
  .generated {
    position: fixed;
    bottom: 10px;
    right: 15px;
    font-size: 0.85em;
    color: #666;
  }
</style>
</head>
<body>

<h1>Trafic journalier DD-WRT – $MONTH/$YEAR</h1>

<div id="chart-container">
  <canvas id="trafficChart"></canvas>
</div>

<p style="text-align:center; font-size:1.1em;">
  <strong>Total du mois :</strong> $TOTAL MB (incoming : outgoing)
</p>

<div class="generated">
  Généré le $GENERATED_AT
</div>

<script>
const rawData = "$DATA";

const incoming = [];
const outgoing = [];

rawData.trim().split(' ').forEach(pair => {
  const [inVal, outVal] = pair.split(':').map(Number);
  incoming.push(inVal);
  outgoing.push(outVal);
});

const labels = Array.from({ length: incoming.length }, (_, i) => 'Jour ' + (i + 1));

const ctx = document.getElementById('trafficChart').getContext('2d');
new Chart(ctx, {
  type: 'bar',
  data: {
    labels: labels,
    datasets: [
      {
        label: 'Incoming (MB)',
        data: incoming,
        backgroundColor: 'rgba(54, 162, 235, 0.7)'
      },
      {
        label: 'Outgoing (MB)',
        data: outgoing,
        backgroundColor: 'rgba(255, 99, 132, 0.7)'
      }
    ]
  },
  options: {
    responsive: true,
    plugins: {
      legend: { position: 'top' },
      tooltip: {
        callbacks: {
          label: ctx =>
            ctx.dataset.label + ': ' + ctx.raw.toLocaleString() + ' MB'
        }
      }
    },
    scales: {
      x: { stacked: true },
      y: {
        stacked: true,
        beginAtZero: true,
        title: {
          display: true,
          text: 'MB'
        }
      }
    }
  }
});
</script>

</body>
</html>
EOF

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(required)

(required)

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur la façon dont les données de vos commentaires sont traitées.