Bonjour à tous,
En passant sur la Livebox 7 (XGS-PON), j'ai constaté que les anciennes méthodes de monitoring de l'API locale (notamment getNetDevStats utilisée sur les générations précédentes) ne remontaient plus les compteurs de trafic de manière fiable.
Après avoir fouillé dans le sysbus de la box, j'ai réécrit un petit script d'extraction propre en Bash et JQ.
Il interroge l'API interne (/ws) en réutilisant intelligemment le contextID dans un fichier temporaire pour éviter de spammer la box avec des requêtes d'authentification.
Le script extrait de manière brute :
- Les puissances optiques : SignalRxPower (Réception) et SignalTxPower (Émission).
- La température interne de la box.
- Les compteurs réseau cumulés via la nouvelle API fonctionnelle sur LB7 : HomeLan.Interface.<intf>.Stats.
Vous pouvez bien sur étendre le monitoring a toute autre variable qui vous fera plaisir en éditant le code.
Utilisation:Il faut d'abord créer le fichier
/etc/livebox.pass qui devra contenir le mdp de votre box. (idéalement chmod 600 dessus pour garantir la privacy.)
Si votre box n'est pas en 192.168.1.1, éditez le code ou définissez la variable d'environnement LB_HOST
Ensuite, lancez le script. (il est intelligent il sauvegarde les cookies et context de session dans /run, pour ne pas spammer l'authentification de la box.)
Si tout se passe bien, il affiche un json avec les données.
Le script de relève:
#!/usr/bin/env bash
# livebox-ont.sh — relève ONT + compteurs WAN d'une Livebox 7 (XGS-PON)
set -uo pipefail
LB_HOST="${LB_HOST:-192.168.1.1}" # À adapter selon votre IP Livebox
LB_USER="${LB_USER:-admin}"
LB_PASS_FILE="${LB_PASS_FILE:-/etc/livebox.pass}" # chmod 600
STATE="${STATE:-/run/livebox}"
JAR="$STATE/cookies"
CTXF="$STATE/ctx"
CURL_OPTS=(-s -m 10)
die() { echo "livebox-ont: $*" >&2; exit 1; }
warn() { echo "livebox-ont: $*" >&2; }
mkdir -p "$STATE" || die "impossible de créer $STATE"
[[ -r "$LB_PASS_FILE" ]] || die "mot de passe illisible ($LB_PASS_FILE)"
LB_PASS="$(< "$LB_PASS_FILE")"
auth() {
local out ctx
out=$(jq -n --arg u "$LB_USER" --arg p "$LB_PASS" \
'{service:"sah.Device.Information",method:"createContext",
parameters:{applicationName:"so_sdkut",username:$u,password:$p}}' \
| curl "${CURL_OPTS[@]}" -c "$JAR" \
-H 'Content-Type: application/x-sah-ws-4-call+json' \
-H 'Authorization: X-Sah-Login' \
-d @- "http://$LB_HOST/ws") || { warn "auth: pas de réponse"; return 1; }
ctx=$(jq -re '.data.contextID' <<< "$out") || { warn "auth refusée: $out"; return 1; }
umask 077
printf '%s' "$ctx" > "$CTXF"
}
call() {
local ctx
[[ -s "$CTXF" ]] || return 1
ctx=$(< "$CTXF")
jq -n --arg s "$1" --arg m "$2" --argjson p "$3" \
'{service:$s, method:$m, parameters:$p}' \
| curl "${CURL_OPTS[@]}" -b "$JAR" \
-H 'Content-Type: application/x-sah-ws-4-call+json' \
-H "Authorization: X-Sah $ctx" \
-H "X-Context: $ctx" \
-d @- "http://$LB_HOST/ws"
}
get_gpon() {
local raw
raw=$(call NeMo.Intf.data getMIBs '{"mibs":"gpon","traverse":"down"}') || return 1
jq -e '.status.gpon | to_entries[0] | select(.value | type == "object")' <<< "$raw" \
|| { warn "gpon: réponse inattendue"; return 1; }
}
get_stats() {
local intf raw
intf="$1"
raw=$(call "HomeLan.Interface.$intf.Stats" get '{}') || return 1
jq -e '.status | select(type == "object") | select(has("BytesReceived"))' <<< "$raw" \
|| { warn "stats: réponse inattendue"; return 1; }
}
collect() {
local g n intf
g=$(get_gpon) || return 1
intf=$(jq -r '.key' <<< "$g")
n=$(get_stats "$intf") || return 1
jq -nc --arg ts "$(date -Is)" --argjson g "$g" --argjson n "$n" \
'{timestamp: $ts, interface: $g.key, gpon: $g.value, stats: $n}'
}
out=$(collect) || { auth || die "authentification impossible"; \
out=$(collect) || die "collecte impossible"; }
printf '%s\n' "$out"Le script retourne un json sur sa sortie standard:
{
"timestamp": "2026-09-06T17:07:58+02:00",
"interface": "veip0",
"gpon": {
"RegistrationID": "",
"RegistrationIDIsInHexFormat": false,
"VeipPptpUni": true,
"MaxBitRateSupported": 10000,
"SignalRxPower": -18696,
"SignalTxPower": 5998,
"Temperature": 50,
"Voltage": 32957,
"Bias": 14080,
"PonMode": "XGS-PON",
"SerialNumber": "REDACTED",
"HardwareVersion": "SMBSXLB7270500",
"EquipmentId": "SagemcomFast5698OFR",
"VendorId": "SMBS",
"VendorProductCode": 0,
"ONTSoftwareVersion0": "SAHEOFR030102",
"ONTSoftwareVersion1": "SAHEOFR030803",
"ONTSoftwareVersionActive": 1,
"LowerOpticalThreshold": -35000,
"UpperOpticalThreshold": 0,
"LowerTransmitPowerThreshold": -1000,
"UpperTransmitPowerThreshold": 7000,
"Mode": "Normal",
"CustomVendorID": "",
"CustomEquipmentID": "",
"VLANs": "840,851,832,835,838",
"RogueOnu": false,
"RogueOnuCount": 0,
"RogueOnuLastOccurence": "0001-01-01T00:00:00Z",
"OnuState": "O5_Operation",
"OnuId": 75,
"PonId": "",
"DownstreamMaxRate": 9953280,
"UpstreamMaxRate": 9953280,
"DownstreamCurrRate": 9953280,
"UpstreamCurrRate": 9953280,
"WanMode": ""
},
"stats": {
"BytesSent": 19347472212,
"BytesReceived": 42607859388
}
}A partir de la, vous pouvez utiliser l'outil de votre choix pour parser le json et insérer cela dans votre outil de monitoring.
Perso, j'insère cela dans mon influxdb/grafana et j'en fait des graphiques (cf la PJ)
Enjoy.