Digistump Oak-Based System Monitor

Let’s take this part by part and work our way through the whole stack. I’ll start with the monitored PC side, and then work my way through to the code that executes in the browser.

Monitored PC Code

The monitored PC’s code has the following tasks:

  • Collect performance information
  • Report performance information to the Pro Micro via USB
  • Accept input from the Pro Micro via USB

The USB tasks are simplified by the Pro Micro’s USB support. We can use the USB serial port on the Pro Micro to send the performance info, and the keyboard interface makes accepting input a snap. So that simplifies these requirements down to “get current state of machine” and “write to a serial port.”

I decided to use Python for this, since it’s an easy language to write, I know it well, and there are tons of libraries for doing common tasks. It’s also cross platform, which means that although I’m writing this for Windows, porting it to a Linux or OSX system should be easy.


The two packages I pulled in are:

  • psutil for the performance monitoring functions
  • pyserial for writing to the serial port

Here’s the critical loop of the code, but the whole thing is up on GitHub:

def run(self):
    # the first time, this does nothing
    report_end = bytearray(1)

        if(self.ser == None):
            if(self.ser == None):
        report_dict = {}

        # get the timestamp
        report_dict['t'] = time.strftime("%Y-%m-%d %H:%M:%S")

        # Get CPU usage
        cpu_pct = psutil.cpu_percent(percpu=True)
        report_dict['c'] = []
        for i in range(len(cpu_pct)):

        # Get memory usage
        mem = psutil.virtual_memory()
        report_dict['m'] = {'t':mem.total, 'a':mem.available}

        # Get disk usage
        diskparts = psutil.disk_partitions()
        report_dict['d'] = []
        #print diskparts
        for part in diskparts:
            if os.name == 'nt':
                if 'cdrom' in part.opts or part.fstype == '':
                    # skip optical drives on windows
            usage = psutil.disk_usage(part.mountpoint)
            report_dict['d'].append({'m':part.mountpoint, 't':usage.total, 'u':usage.used})

        # Serialize to JSON
        report = json.dumps(report_dict)
        print report
        # Write to the serial port
        except serial.SerialException:
            print("Can't write to serial port, trying to reopen...")


As you can see, most of the loop is fetching the current statistics from psutil’s functions, and then I create a Python dict out of these values. The dict has entries for the current time (‘t’), the current CPU usage, per core (‘c’), memory stats (‘m’), and disk utilization (‘d’).

Design Decision From there, I decided to convert this dict to text using JSON. JSON is a great text format for data like this, and the fact that it’s natively supported in JavaScript will save us some pain later when I want to parse it for the browser. With the data pre-formatted, I can just funnel it through the system without having to parse it again. That will save CPU time and keep the complexity of the later code to a minimum. JSON has a bit of overhead – though far less than XML – but in my testing it wasn’t significant enough to really matter.

One thing I’d like to add to this is a tray icon or something similar. Right now it just runs in a terminal/DOS prompt. There’s an example of making a Python script with a tray icon which is cross platform, over on Stack Exchange.

Next: Pro Micro & Oak Firmware

Prev Page 3 of 5 Next