Previous
      We have built a 4G/LTE router but how do I know its network usage? How much will it cost me?
        
          Goal
      We are now going to write a Python script to send Email notificatoin for network usage and set a threshold for it.
I assume you know the basic pattern how to code in Python
        
          Requirements.txt
      | 12
 3
 
 | psutilpython_http_client
 sendgrid
 
 | 
You can install them by typing in terminal:
| 1
 | $ pip3 install psutil python_http_client sendgrid
 | 
You may need to specify pip3 in Raspbian as both Python 2.x and Python 3.x were installed.
        
          Coding Python
      | 12
 3
 
 | $ mkdir network-monitor$ cd network-monitor
 $ nano monitor.py
 
 | 
And then we start coding
        
          Get network usage
      | 12
 3
 4
 5
 6
 7
 8
 
 | import psutil
 NETWORK_INTERFACE = 'ppp0'
 
 netio = psutil.net_io_counters(pernic=True)
 net_usage = netio[NETWORK_INTERFACE].bytes_sent + netio[NETWORK_INTERFACE].bytes_recv
 
 print(net_usage, "bytes")
 
 | 
It will show you how many bytes it has transfered for upload and download.
If it shows zero, change NETWORK_INTERFACE to wwan0.
        
          Set threshold
      | 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | import psutil
 NETWORK_INTERFACE = 'wwan0'
 NETWORK_LIMIT = 5000000
 
 while True:
 netio = psutil.net_io_counters(pernic=True)
 net_usage = netio[NETWORK_INTERFACE].bytes_sent + netio[NETWORK_INTERFACE].bytes_recv
 
 if net_usage > NETWORK_LIMIT:
 print("Meets network limit!")
 
 print(net_usage, "bytes has been used")
 
 | 
Once it over the NETWORK_LIMIT it will print a lot of lines of “Meets network limit!”. We can add a timer to check the network limit every X second.
        
          Separate the config and code
      Try to separate the cnofiguratoin and the Python script so we can reuse this project on other devices.
configparser is really a good helper on this.
Create a file monitor.conf
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | [Email]SENDGRID_API_KEY = Your.Keyfrom_SendGrid
 from = helper@raspberry.pi
 to = your@email.address
 subject = From your Raspberry Pi
 
 [Network]
 INTERFACE = wwan0
 LIMIT = 45000000000
 
 [Misc]
 TIME_INTER = 36
 
 | 
Now we can load the configuration in Python
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 
 | import timeimport psutil
 import configparser
 config = configparser.ConfigParser()
 config.optionxform = str
 config.read('monitor.conf')
 
 NETWORK_INTERFACE = config.get('Network', 'INTERFACE')
 NETWORK_LIMIT = int(config.get('Network', 'LIMIT'))
 SENDGRID_API_KEY = config.get('Email', 'SENDGRID_API_KEY')
 TIME_INTER = config.get('Misc', 'TIME_INTER')
 
 while True:
 time.sleep(TIME_INTER)
 netio = psutil.net_io_counters(pernic=True)
 net_usage = netio[NETWORK_INTERFACE].bytes_sent + netio[NETWORK_INTERFACE].bytes_recv
 
 if net_usage > NETWORK_LIMIT:
 print("Meets network limit!")
 
 print(net_usage, "bytes has been used")
 
 | 
          Prepare for the Email
      We use SendGrid to send the Email notification in this tutorial.
You may need to sign up on SendGrid. I choose it because of 100 free email quota every day.
        
          Generate SendGrid API Key
      The option is in Setting -> API Keys -> Create API Key Creating an API key
        
          Copy the Key and paste to monitor.conf
      | 12
 
 | [Email]SENDGRID_API_KEY = Your.Keyfrom_SendGrid
 
 | 
          Write python script
      Refer to their official guide SendGrid GitHub repo
| 12
 3
 4
 
 | import timeimport psutil
 import sendgrid
 from sendgrid.helpers.mail import *
 
 | 
Read the monitor.conf
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | import configparserconfig = configparser.ConfigParser()
 config.optionxform = str
 config.read('netio-mon.conf')
 
 NETWORK_INTERFACE = config.get('Network', 'INTERFACE')
 NETWORK_LIMIT = int(config.get('Network', 'LIMIT'))
 NETWORK_MAX = int(config.get('Network', 'MAX'))
 SENDGRID_API_KEY = config.get('Email', 'SENDGRID_API_KEY')
 TIME_INTER = config.get('Misc', 'TIME_INTER')
 
 | 
I would like to have some loggings too so I added this line
| 12
 3
 4
 5
 6
 7
 8
 
 | import logging
 loggingFile = logging.FileHandler('my.log', 'w', 'utf-8')
 
 logging.basicConfig(level=logging.DEBUG,
 format='%(asctime)s %(levelname)s %(message)s',
 datefmt='%Y-%m-%d %H:%M',
 handlers=[loggingFile, ])
 
 | 
Declare two methods for sending Email
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | def create_message(sender, to, subject, message_text):logging.info("send email::" + message_text)
 from_email = Email(sender)
 to_email = To(to)
 subject = subject
 content = Content("text/plain", message_text)
 return Mail(from_email, to_email, subject, content)
 
 
 def send_message(service, message):
 return service.client.mail.send.post(request_body=message.get())
 
 | 
Now the mean loop to check the network usage periodically.
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | service = sendgrid.SendGridAPIClient(api_key=SENDGRID_API_KEY)
 
 
 have_sent = False
 
 while True:
 time.sleep(TIME_INTER)
 netio = psutil.net_io_counters(pernic=True)
 net_usage = netio[NETWORK_INTERFACE].bytes_sent + netio[NETWORK_INTERFACE].bytes_recv
 if net_usage > NETWORK_LIMIT and not have_sent:
 message = create_message(
 config.get('Email', 'from'),
 config.get('Email', 'to'),
 config.get('Email', 'subject'),
 'The network have used %s bytes' %net_usage)
 send_message(service, message)
 have_sent = True
 
 | 
          Improvement
      
- Prevent network usage lost, save the usage in the last email with pickle
- In order to monitoring network usage continuously, set one more NETWORK_MAXfor reseting the flag after first email notification
 See my GitHub Repo