Python Programming Language LogoIn yesterday’s article, I showed you how to create a Python script that broadcasts a systems’ vitals (diskspace, memory, & CPU) out onto the network. As promised, today I will show you how to create a Python script that listens for these broadcasts and displays the results. I use this script as part of my home automation system and display the results on a touchscreen TFT that’s exposed out the front of an enclosure that houses the main-brain of my home automation system (see pictures below). But, you can do all kinds of other cool things with the results such as selecting Raspberry Pis with unused resources to act as slaves in a distributed computing application (which I will explain in another article). But for now, let’s get started.

To get started, create a new file called “pybcastserver.py” and copy the code from below into the file and save it. Test the script by running the following command:

python2 pybcastserver.py

If you have systems running the client code from yesterday, you should be seeing their system vitals on your screen at this point. If so, you’ll want to set this script to run every time your Raspberry Pi starts by following the tutorial found here. You can also run this code on a non-Raspberry Pi computer if you want. If you run it on Windows, just make sure you swap out the “osclearcmd” variable at the top of the code. You might also want to change the listening port which is currently set to 15000. If you do change the listening port, make sure you also change the broadcast port in your client code.

import asyncore, socket
import threading, Queue
import json, os, collections, math

#osclearcmd = 'cls'   # windows
osclearcmd = 'clear' # linux

server_port = 15000

q = Queue.Queue()
nodes = {}

class UDPServer(asyncore.dispatcher):
    def __init__(self, addr):
        asyncore.dispatcher.__init__(self)
        self.create_socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        self.bind(addr)

    def handle_read(self):
        data, address = self.recvfrom(1024)
        json_obj = json.loads(data.strip())
        addr = address[0]
        json_obj['address'] = addr
        if addr not in nodes:
            nodes[addr] = {}
        nodes[addr] = json_obj
        q.put(nodes)

def convertSize(size):
    size_name = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB")
    i = int(math.floor(math.log(size, 1024)))
    p = math.pow(1024, i)
    s = round(size / p, 2)
    if (s > 0):
        return '%s %s' % (s, size_name[i])
    else:
        return '0B'

def print_table(data):
    col_width = max(len(word) for row in data for word in row) + 2
    for row in data:
        line = "".join(word.ljust(col_width) for word in row)
        line = "%s" % (line)
        print line

def print_report():
    while 1:
        recs = q.get()
        recs = collections.OrderedDict(sorted(recs.items()))
        data = []

        total_diskspace_total = 0
        total_diskspace_free  = 0
        total_memory_total    = 0
        total_memory_free     = 0
        total_cpu_usage       = 0

        data.append(["Address", "Disk Total", "Disk Free", "Memory Total", "Memory Free", "CPU"])
        
        for rec in recs:
            json_obj = recs[rec]
            diskspace_total   = convertSize(json_obj['diskspace_total'])
            diskspace_used    = convertSize(json_obj['diskspace_used'])
            diskspace_free    = convertSize(json_obj['diskspace_free'])
            diskspace_percent = "%s%%" % json_obj['diskspace_percent']
            memory_total      = convertSize(json_obj['memory_total'])
            memory_available  = convertSize(json_obj['memory_available'])
            memory_used       = convertSize(json_obj['memory_used'])
            memory_free       = convertSize(json_obj['memory_free'])
            memory_percent    = "%s%%" % json_obj['memory_percent']
            cpu               = "%s%%" % json_obj['cpu']
            address           = json_obj['address']

            total_diskspace_total = (total_diskspace_total + json_obj['diskspace_total'])
            total_diskspace_free  = (total_diskspace_free + json_obj['diskspace_free'])
            total_memory_total    = (total_memory_total + json_obj['memory_total'])
            total_memory_free     = (total_memory_free + json_obj['memory_free'])
            total_cpu_usage       = (total_cpu_usage + json_obj['cpu'])

            data.append([address, diskspace_total, diskspace_free, memory_total, memory_free, cpu])

        data.append(["", "", "", "", "", ""])

        data.append(["Total:",
                 convertSize(total_diskspace_total),
                 convertSize(total_diskspace_free),
                 convertSize(total_memory_total),
                 convertSize(total_memory_free),
                 "%s%%" % (total_cpu_usage / len(recs))
                ])
            
        clear_cmd_response = os.system(osclearcmd)
        
        print_table(data)

def run_server():
    server = UDPServer(('', server_port))
    asyncore.loop()

if __name__ == '__main__':
    clear_cmd_response = os.system(osclearcmd)

    t1 = threading.Thread(target=run_server)
    t2 = threading.Thread(target=print_report)

    t1.start()
    t2.start()

As promised, below is a picture of the inside of my main home automation controller. It consists of 8 Raspberry Pis that are all connected via a 10/100/1000 switch at the bottom and powered by a USB hub on the right. On the left is a touchscreen TFT display that is exposed thru the lid which allows me to monitor the Pis in the network all while they’re enclosed in a utility box.

Each Pi has a 32 GB SD card running Arch Linux and overclocked at 950MHz. Each Pi in this box is dedicated to a different zone of my house and is responsible for monitoring cameras & microphones in each of those zones for handling face & speech recognition.

The Pi at the top includes a WiFi dongle and is setup as a DHCP server to the other Pis and acts as their gateway to my primary network and the other devices in my home automation system. This Pi is also responsible for displaying the system vitals of the other Pis on the touchscreen TFT attached to the enclosure’s lid.

RPi Home Automation Controller3CLICK TO ENLARGE

Thank you for your interest in my site. If you find the information provided on this site useful, please consider making a donation to help continue development!

PayPal will open in a new tab.
$2.00
$5.00
Other

Related Posts

Leave a Reply