VNStat

My router is the X3000 latest 4.8 firmware.

+CFUN: 1

OK

+CSQ: 26,99

OK

+COPS: 0,0,"SFR",13

OK

I found this feature is available already in goodcloud, so I just need to look at goodcloud, under "timeline > device status history".

I’ll post here step by step, but I have vnstat2 installed on my Beryl AX, emailing me the graphs nightly. We can’t use curl to do the email, because it isn’t compiled with the necessary protocol, so it needs to be mstmp. vnstat for older kernels should be similar.

  1. The default install stores the sql database in /tmp so it doesn’t survive a reboot. I chose to move the database to a small USB stick, so in the webgui go into Applcations|Network Storage and set up a samba share on the USB stick. I called mine /external/vnstat.
  2. Go into Luci and install vnstat2, vnstati2, luci-app-vnstat2, core-utils-64base, nano, mstmp.
  3. Refresh the browser window, and you should have Status|vnstat Traffic Monitor. Go to Configuration, and set the interface(s) to monitor. I am using it as a travel router repeating a wifi signal, so that is apclix0 for me. Save and Apply
  4. Still in Luci, have SSH access enabled under System|Administration|SSH Access.
  5. Now SSH into the router. WinSCP or Xshell 8 are good for this. Edit /etc/msmtprc to be able to send email. For Gmail, port 465 auth on user , password , tls on, tls_starttls off, from , logfile /var/log/msmtp.log.
  6. While we’re here, edit /etc/vnstat.conf. Change DatabaseDir to your USB share, e.g. “mnt/external/vnstat”. You need the quotes. You can specify the interface, although that may not be necessary. UpdateInterval can be 300, and SaveInterval 30. Remove the comment marks if you make changes. Everything else I left the same.
  7. Now we need to create the email script in /mnt/external/vnstat. I called it email_vnstat, and it was generated by Gemini. To my surprise, with just a little tweaking, it worked, but it is extremely clunky code. I mean to revise it to create loops for the repetitive code.

#!/bin/sh

Recipient email address

RECIPIENT_EMAIL=""

Sender email address

SENDER_EMAIL=""

Subject of the email

SUBJECT="OpenWrt vnStat Traffic Report for $(date +%F)"

Temporary directory for image generation

TMP_DIR="/tmp"

#Interface to use
INTERFACE="apclix0"

==============================================================================

SCRIPT LOGIC

==============================================================================

Check for required commands

for cmd in vnstat vnstati msmtp base64; do
if ! command -v "$cmd" >/dev/null 2>&1; then
echo "Error: Required command '$cmd' not found. Please install it." >&2
exit 1
fi
done

Generate the graphs

--summary creates an overview of total traffic

--days creates a graph of daily traffic

--months creates a graph of monthly traffic

vnstati --summary -o "$TMP_DIR/summary.png" -i $INTERFACE
vnstati --days -o "$TMP_DIR/daily.png" -i $INTERFACE
vnstati --months -o "$TMP_DIR/monthly.png" -i $INTERFACE
vnstati -hg -o "$TMP_DIR/hourly.png" -i $INTERFACE
vnstati -t -o "$TMP_DIR/top.png" -i $INTERFACE

Check if the images were created successfully

if [ ! -f "$TMP_DIR/summary.png" ] || [ ! -f "$TMP_DIR/daily.png" ] || [ ! -f "$TMP_DIR/monthly.png" ]; then
echo "Error: Failed to generate vnstati graphs." >&2
exit 1
fi

Generate unique boundary strings for the email

BOUNDARY_MIXED="$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 32)"
BOUNDARY_RELATED="$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 32)"

Base64 encode the images

SUMMARY_BASE64=$(base64 "$TMP_DIR/summary.png" | tr -d '\n')
DAILY_BASE64=$(base64 "$TMP_DIR/daily.png" | tr -d '\n')
MONTHLY_BASE64=$(base64 "$TMP_DIR/monthly.png" | tr -d '\n')
HOURLY_BASE64=$(base64 "$TMP_DIR/hourly.png" | tr -d '\n')
TOP_BASE64=$(base64 "$TMP_DIR/top.png" | tr -d '\n')

Construct the email body with HTML and inline images

(
echo "From: $SENDER_EMAIL"
echo "To: $RECIPIENT_EMAIL"
echo "Subject: $SUBJECT"
echo "MIME-Version: 1.0"
echo "Content-Type: multipart/mixed; boundary="$BOUNDARY_MIXED""
echo
echo "--$BOUNDARY_MIXED"
echo "Content-Type: multipart/related; boundary="$BOUNDARY_RELATED""
echo
echo "--$BOUNDARY_RELATED"
echo "Content-Type: text/html; charset="UTF-8""
echo "Content-Transfer-Encoding: 7bit"
echo
echo ""
echo ""
echo ""
echo "

Traffic Report for $(uname -n) - $(date +'%B %d, %Y')

"
echo "

Attached below are the network traffic graphs generated by vnStat.

"
echo "

Summary

"
echo "<img src="cid:summary_graph" alt="Daily Summary" width="600">"
echo "
"
echo "

Hourly Traffic

"
echo "<img src="cid:hourly_graph" alt="Hourly Traffic" width="600">"
echo "
"
echo "

Top Traffic

"
echo "<img src="cid:top_graph" alt="Top Traffic" width="600">"
echo "
"
echo "

Daily Traffic

"
echo "<img src="cid:daily_graph" alt="Daily Traffic" width="600">"
echo "
"
echo "

Monthly Traffic

"
echo "<img src="cid:monthly_graph" alt="Monthly Traffic" width="600">"
echo ""
echo ""
echo
echo "--$BOUNDARY_RELATED"
echo "Content-Type: image/png"
echo "Content-Transfer-Encoding: base64"
echo "Content-Disposition: inline; filename="summary.png""
echo "Content-ID: <summary_graph>"
echo
echo "$SUMMARY_BASE64"
echo
echo "--$BOUNDARY_RELATED"
echo "Content-Type: image/png"
echo "Content-Transfer-Encoding: base64"
echo "Content-Disposition: inline; filename="daily.png""
echo "Content-ID: <daily_graph>"
echo
echo "$DAILY_BASE64"
echo
echo "--$BOUNDARY_RELATED"
echo "Content-Type: image/png"
echo "Content-Transfer-Encoding: base64"
echo "Content-Disposition: inline; filename="monthly.png""
echo "Content-ID: <monthly_graph>"
echo
echo "$MONTHLY_BASE64"
echo
echo "--$BOUNDARY_RELATED"
echo "Content-Type: image/png"
echo "Content-Transfer-Encoding: base64"
echo "Content-Disposition: inline; filename="hourly.png""
echo "Content-ID: <hourly_graph>"
echo
echo "$HOURLY_BASE64"
echo
echo "--$BOUNDARY_RELATED"
echo "Content-Type: image/png"
echo "Content-Transfer-Encoding: base64"
echo "Content-Disposition: inline; filename="top.png""
echo "Content-ID: <top_graph>"
echo
echo "$TOP_BASE64"
echo
echo "--$BOUNDARY_RELATED--"
echo
echo "--$BOUNDARY_MIXED--"
) | msmtp -t

Clean up temporary image files

rm "$TMP_DIR/summary.png" "$TMP_DIR/daily.png" "$TMP_DIR/monthly.png" "$TMP_DIR/hourly.png" "$TMP_DIR/top.png"

echo "Email with vnStat graphs sent successfully."

  1. Make the file executable, and then execute it as a test.
  2. Go back into Luci|System|Scheduled Tasks, and add a cron job to run it just before midnight each day. "59 23 * * * /mnt/external/vnstat/email_vnstat" (without the quotes).
  3. Remember that Openwrt doesn't run cron jobs by default, so go into the terminal again and run /etc/init.d/cron start, and then /etc/init.d/cron enable.
  4. Reboot.

Hi,

I’m on Flint 2 latest firmware and after updating the list, I can’t find vnstat. Any idea on how to install this?

Hi,

Please check it again, I can find the vnstat in GL repo.

root@GL-MT6000:~# opkg update
Downloading https://fw.gl-inet.com/releases/mt798x/kmod-5.4.246/aarch64_cortex-a53/mediatek/Packages.gz
Updated list of available packages in /var/opkg-lists/glinet_core
Downloading https://fw.gl-inet.com/releases/mt798x/packages-4.5/aarch64_cortex-a53/glinet/Packages.gz
Updated list of available packages in /var/opkg-lists/glinet_gli_pub
Downloading https://fw.gl-inet.com/releases/mt798x/packages-4.5/aarch64_cortex-a53/packages/Packages.gz
Updated list of available packages in /var/opkg-lists/glinet_gli_packages
Updating database.
Database update completed.
root@GL-MT6000:~# opkg list |grep vnstat
luci-app-vnstat - git-20.108.38431-8f34e10 - LuCI Support for VnStat
luci-app-vnstat2 - git-20.332.74200-03c77da - LuCI Support for vnStat 2
luci-i18n-vnstat-ar - git-22.277.72334-3923199 - Translation for luci-app-vnstat - العربية (Arabic)
luci-i18n-vnstat-bg - git-22.277.72334-3923199 - Translation for luci-app-vnstat - български (Bulgarian)
luci-i18n-vnstat-bn - git-22.277.72334-3923199 - Translation for luci-app-vnstat - বাংলা (Bengali)
luci-i18n-vnstat-ca - git-22.277.72334-3923199 - Translation for luci-app-vnstat - Català (Catalan)
luci-i18n-vnstat-cs - git-22.277.72334-3923199 - Translation for luci-app-vnstat - Čeština (Czech)
luci-i18n-vnstat-da - git-22.277.72334-3923199 - Translation for luci-app-vnstat - Dansk (Danish)
...
root@GL-MT6000:~# cat /etc/glversion
4.8.2

For the Flint 2, I think you want vnstat2. Both should show up if you are on "available" and filter for vnstat.

Ok, I've now revised the AI-generated script to cover all configured interfaces and loop through the interfaces and the graphs that are selected. The revised script for step #7:

  #!/bin/sh
  
  #  Recipient email address
  RECIPIENT_EMAIL="<where you are sending this>"
  
  #  Sender email address
 SENDER_EMAIL="<who is sending this>"
  
 >#  Subject of the email
  SUBJECT="OpenWrt vnStat Traffic Report for $(date +%F)"
  
  #  Temporary directory for image generation
  TMP_DIR="/mnt/external/vnstat"
  
  #  Get the interfaces vnstat is monitoring
  interfaces=$(uci get vnstat.@vnstat[0].interface)
  
  # If you only want a particular interface, comment out prior line and uncomment next line
  #INTERFACE="apclix0"
  #Make sure these are active in Luci or the script will error output
  
  #Select outputs
  # -s creates an overview of total traffic
  # -d creates a graph of daily traffic
  # -m creates a graph of monthly traffic
  # -hg creates a graph of hourly Traffic
  # -t creates a graph of top traffic days
  outputs=" s d m hg t"
  #
  #Boundary strings for the email
  BOUNDARY_MIXED="$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 32)"
  BOUNDARY_RELATED="$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 32)"
  #
 >Encode_Image ()
  {
 	(
 		echo "";
  		echo "--$BOUNDARY_RELATED";
  		echo "Content-Type: image/png;name=\"$1.png\"";
  		echo "Content-Transfer-Encoding: base64";
 		echo "Content-Disposition: inline;filename=\"$1.png\"";
  		echo "Content-Id: <$1_graph>";
  		echo "";
  		echo "$2";
  	) >> "$3"
  }
  
  # ==============================================================================
  #                      SCRIPT LOGIC
  # ==============================================================================
  
  # Check for required commands
  for cmd in vnstat vnstati msmtp base64; do
    if ! command -v "$cmd" >/dev/null 2>&1; then
      echo "Error: Required command '$cmd' not found. Please install it." >&2
      exit 1
    fi
  done
  
  # Generate the graphs
  
  for output in $outputs
  	do
  		for interface in $interfaces
  		do
  			filename="$TMP_DIR/vnstat"_"$output"_"$interface".png
 			vnstati -$output -o "$filename" -i $interface
  		done
  	done
  	
  # Construct the email body with HTML and inline images
  (
    echo "From: $SENDER_EMAIL"
    echo "To: $RECIPIENT_EMAIL"
    echo "Subject: $SUBJECT"
    echo "MIME-Version: 1.0"
    echo "Content-Type: multipart/mixed; boundary=\"$BOUNDARY_MIXED\""
    echo
    echo "--$BOUNDARY_MIXED"
    echo "Content-Type: multipart/related; boundary=\"$BOUNDARY_RELATED\""
    echo
    echo "--$BOUNDARY_RELATED"
    echo "Content-Type: text/html; charset=\"UTF-8\""
    echo "Content-Transfer-Encoding: 7bit"
    echo
    echo "<!DOCTYPE html>"
    echo "<html>"
    echo "<body>"
    echo "<h3>Traffic Report for $(uname -n) - $(date +'%B %d, %Y')</h3>"
    echo "<p>Attached below are the network traffic graphs generated by vnStat.</p>"
    ) > mail.txt
    
   # Loop through the interfaces to provide inline places for the graphs
   # Note to script: need to limit these for desired outputs
    for interface in $interfaces
  	do
  		graphname="$interface""_graph"
  		(
  		echo "<h4>Summary for $interface</h4>"
  		echo "<img src=\"cid:vnstat_s_$graphname\" alt=\"Daily Summary\" width=\"600\">"
  		echo "<br/>"
  		echo "<h4>Hourly Traffic for $interface</h4>"
  		echo "<img src=\"cid:vnstat_hg_$graphname\" alt=\"Hourly Traffic\" width=\"600\">"
  		echo "<br/>"	
  		echo "<h4>Daily Traffic for $interface</h4>"
  		echo "<img src=\"cid:vnstat_d_$graphname\" alt=\"Daily Traffic\" width=\"600\">"
  		echo "<br/>"
 		echo "<h4>Monthly Traffic for $interface</h4>"
  		echo "<img src=\"cid:vnstat_m_$graphname\" alt=\"Monthly Traffic\" width=\"600\">"
  		echo "<h4>Top Traffic for $interface</h4>"
  		echo "<img src=\"cid:vnstat_t_$graphname\" alt=\"Top Traffic\" width=\"600\">"
  		echo "<br/>"
  		echo "</body>"
  		echo "</html>"
  		echo 
  		) >> $TMP_DIR/mail.txt
    
  	done
    
    for interface in $interfaces
  	do
  	for output in $outputs
 	do	
 		filename="vnstat"_"$output"_"$interface"
 		image_base64="$(base64 "$filename.png" | tr -d '\n')"
 		Encode_Image "$filename" "$image_base64" "$TMP_DIR/mail.txt"
  	done
 	done
  
    (
    echo ""
    ) >> $TMP_DIR/mail.txt
     
  
    (
    echo "--$BOUNDARY_RELATED--"
    echo ""
    echo "--$BOUNDARY_MIXED--"
  ) >> $TMP_DIR/mail.txt
  msmtp -t < "$TMP_DIR/mail.txt"
  rm "$TMP_DIR/mail.txt"
  # Clean up temporary image files
  echo "" > "$TMP_DIR/report"
  for output in $outputs
  	do
  		for interface in $interfaces
  		do
  			filename="$TMP_DIR/vnstat"_"$output"_"$interface".png
  			echo $filename >> "$TMP_DIR/report"
  			rm $filename
  		done
  	done
  
  echo "Email with vnStat graphs sent successfully."

If you upgrade firmware, you will need to rework this a bit even if you keep settings. The packages will need to be reinstalled, which will wipe the vnstat database. So you will want to rename it, install the packages, and then restore the name. The script if saved in the same folder will also be wiped and need to be reinstalled.

Note also that I've found it necessary now to revise the cron job to first cd to the script directory, and join the command with &&: "59 23 * * * cd /mnt/external/vnstat && ./email_vnstat".