Using Mac Notification Center to Monitor Printer Supply Levels

It looks like the transition to HP for Samsung printers is complete. On a recent visit to the Samsung Printer Support page, every request was redirected to HP Technical Support. My visit was intended to update the Samsung software which had stopped working after upgrading to High Sierra. Instead I found myself pondering how to write my own application to monitor printer supply levels.

My Samsung C460 printer provides a web-based interface called SyncThru Web Service for administering the printer. For the sake of expediency, I selected Python for this script. While it is attached in its entirety, I am also going to post key sections necessary to run this.

For this script, the only configurable options are the URL to your Samsung SyncThru Web Services and the supply level to warn at. The check for supply levels is initiated when the following function is invoked:

def check_supply_status(host, level):
    r = requests.get(host + "/sws/app/information/supplies/supplies.json")

    json_text = StringIO.StringIO()

    for line in StringIO.StringIO(r.text):
        line = re.sub(r'(\w+)\ ?:', r'"\1":', line.strip())
        json_text.write(line)

    toner_json = json.loads(json_text.getvalue())
    toner_msg = ""

    for color in ["black", "cyan", "magenta", "yellow"]:

        toner_key = "toner_" + color

        if (toner_key in toner_json):

            toner_level = toner_json[toner_key]["remaining"]

            if int(toner_level) < int(level):
                toner_msg += color.title() + " @ " + str(toner_level) + "% "

    if toner_msg:
        alert(toner_msg)

The logic is to invoke the Python Requests library via requests.get() using a prefix specified by host together with the known location for the supply level information on this Samsung printer.

Normally the requests library works well and is able to parse results directly from JSON to a dictionary; however, the Samsung C460 has a malformed JSON response which makes it necessary to clean this prior to parsing - that is the reason for the re.sub() expression looping through each line of response.

The color loop checks for toner levels against colors and summarizes low toner levels into a message that can then go to the alert() function:

def alert(message):

    # load printer icon
    icon = NSImage.alloc().initWithContentsOfFile_("printer.png")

    # create notification
    notification = NSUserNotification.alloc().init()
    notification.setTitle_("Print Levels Alert")
    notification.setSubtitle_(message)
    notification.setContentImage_(icon)

    # create identifier
    id = "TONERATE_" + datetime.datetime.now().strftime("%Y%m%d")
    notification.setIdentifier_(id)

    notification.setSoundName_(NSUserNotificationDefaultSoundName)

    center = NSUserNotificationCenter.defaultUserNotificationCenter()
    center.deliverNotification_(notification)

Alert uses the Mac OS NSUserNotification API call to create a notification that appears in the Notification Center. Using a unique identifier prevents this from creating multiple notifications on the same date for the same low-toner message. Since this is a native Mac OS X call it prompts directly on-screen and integrates with the Notification Center.

Finally, all of this is tied together using a crontab entry:

*/5 * * * * cd /opt/tonerate/ && /usr/bin/python /opt/tonerate/tonerate.py -u http://10.0.0.17

This entry has the task running a check against the printer every 5 minutes, alerts appear in the notification center once the thresholds are met:

tonerate - source
Download the source from this post.