Geeking out w/ networkQuality

macOS Monterey has a new command line utility called “networkQuality.” Per the man page:

networkQuality allows for measuring the different aspects of Network Quality, including:

     Maximal capacity (often described as speed)

     The responsiveness of the connection. Responsiveness measures the quality of your network by the number of roundtrips completed per minute (RPM) under working conditions. See https://support.apple.com/kb/HT212313

     Other aspects of the connection that affect the quality of experience.

The best part of this tool (IMO) is that it measures the “Maximal capacity” or speed of my internet connection. I know there are other speed test tools available but I like that this one is built-in. As pointed out by Jeff Butts at macobserver.com, “networkQuality uses Apple’s CDN at https://mensura.cdn-apple.com/api/v1/gm/config as the target for its testing.” I’ve seen pretty big differences between using networkQuality and other web based speed testing sites; but, networkQuality seems to most closely match the speed results reported from my eero router.

Lately, I’ve been using GeekTool to add scripts that report the battery percentage of my connected bluetooth devices (AirPods Pro and my Apple Keyboard). I decided that my download speed would be a good addition. I wrote this small python script that parses the JSON output in Mbps and displays the result in the lower left corner of my screen. I have this geeklet set to run every 30min.

#!/usr/bin/python

import json
import subprocess

def mbps(speed):
    return int(round((speed / 1024 / 1024), 0))

# Args: c – outputs in JSON, s – tests download and upload separately
cmd = ["/usr/bin/networkQuality", "-c", "-s"]

response = json.loads(subprocess.run(cmd, capture_output=True, text=True).stdout)

# Download Speed in Mbps
dl_throughput = mbps(response.get("dl_throughput", 0))

# Upload Speed in Mbps (not used at the moment)
# ul_throughput = mbps(response.get("ul_throughput", 0))

print(dl_throughput)

Screenshot of my GeekTool geeklets. Left to right: left AirPod battery, right AirPod battery, keyboard battery, networkQuality download speed in Mbps

py-dep

Backstory

If you’ve read my post about the road to creating the py-acc module, you’ll know that while working for Simply Mac I made a Python module to help enroll devices with AppleCare+. Well, the need came up long ago to also be able to enroll customer’s devices purchased from us into the customer’s DEP account. This process was far more complex than getting things ready for AppleCare+ enrollments but we managed to get Apple’s sign-off. As before, while I’m not able to share the full code that made our application great, I can share a piece of it.

The Goods!

py-dep on GitHub is our Python module that interfaces with the DEP API to enroll customer devices into DEP. This one even includes objects to help structure your data in the proper format to be sent to Apple. My intent is to allow this to be used, scrutinized, and improved by the Apple Reseller community and Python developers in general.

Let me know what you think!

Access JSON String in Django Templates Like a Dictionary

One of the reasons I like to use JSONFields in my Django applications is that I can store an entire REST API request body and response body as a JSON object to be accessed like a dictionary later. I would even access it this way in templates to dynamically display data. It’s magical.

However, I’ve recently imported a bunch of data and the JSONField validation managed to import the API responses as strings instead of valid JSON. Why? I don’t know for sure yet but it bothers me.

So I wrote a quick template tag that will process the JSON string and return a dictionary-like object which allows me to parse data the same as before. Beautiful.

# custom_tags.py
import json

from django import template

register = template.Library()


@register.filter(name='jsonify')
def jsonify(data):
    if isinstance(data, dict):
        return data
    else:
        return json.loads(data)


This only requires me to change my template slightly. Here’s what it looked like prior to Django 2.2:

{% for call in api_calls %}
    {% if call.response.specificResponseKey %}
        <p>{{ call.response.specificResponseKey.anotherSpecificKey }}</p>
    {% endif %}
{% endfor %}

And after applying my new template tag:

{% load custom_tags %}

{% for call in api_calls %}
    {% with call.response|jsonify as response %}
        {% if response.specificResponseKey %}
            <p>{{ response.specificResponseKey.anotherSpecificKey }}</p>
        {% endif %}
    {% endwith %}
{% endfor %}

While I could find out why the JSONField didn’t translate the whole API response, which was in valid JSON format, I think this post was more about solving a specific problem in a forward thinking way. Should data be imported improperly again in a way I can’t anticipate, the templatetag will have my back.

Phonetic Passwords

Problem

Have you ever had to communicate a password with someone over the phone? Unfortunately, I have and I usually dread it. When I have to communicate passwords over the phone (thankfully not often) I will usually pull up a NATO phonetic alphabet so I don’t have a Brian Regan moment.

Idea

Today, I got to thinking that I could probably just write a script to process each character in a password string and output the phonetic names. Then I realized that someone has probably already done this. To Google I went and did indeed find someone who had written a script for this very thing. Brandon Amos wrote a small python script called phonetic.py that will spit out the phonetic names of characters in a string of text, no matter the size. Here’s an example:phonetic

New Problem

It’s not perfect for my needs as it doesn’t do any special treatments for numbers/special characters and doesn’t differentiate between capital and lowercase letters. See the treatment of ‘yY’ in the image below. phonetic_fail

Solution

So, I forked Brandon Amos’s repo and created a new file to handle capitals, name the ASCII characters found in good passwords, and even spell out the numbers. This may seem silly since you shouldn’t need to see the word for each number but I wanted this to be as uniform and fool-proof as possible. This is what we get running the same string as before through the new phonetic_password.py file.
phonetic_password

Get the Code

Here’s a direct link to the file: phonetic_password.py

P.S.

If you like the nice screenshots in this post, I made them with Carbon.