Disclaimer

This is my response to a ridiculous problem that has plagued Macs for almost a decade. My solution to it is also ridiculous. It uses a Raspberry Pi, so at the time of writing (2022), it’s also expensive. This is not a practical solution to anything. If you’re not interested in the backstory of my woes, skip to the technical bits

My Sob Story

I daily drive an M1 Max Macbook Pro which moves between a work desk, and a battlestation/hackerspace desk. On the latter, I have 3 identical 28” displays (left, center, right), and the Macbook itself open for a total of 4 displays.

The DeskMuch screen. Such productive.

The left is connected to a Caldigit TS4 dock via USB-C/HDMI cable.
The center is connected to the TS4 via DisplayPort cable.
The right is connected directly to the Macbook via USB-C/HDMI cable.

The SetupAgain, but more powerpointy

When I plug in at this desk, there’s a 50/50 chance that the left and right displays will be swapped logically (How the Macbook has them arranged). I’ve done some testing with this to see if the order things are plugged in/ports used makes a difference - it doesn’t.

It takes a few seconds to pull up the display settings and swap them back, but multiple times per day - that gets annoying. I want something automatic. Here’s what I tried:

DisplayPlacer

DisplayPlacer is a tool which lets you dictate the arrangement and orientation of your displays by executing a shell command, which means it can be automated.

Running displayplacer list returns a command that can then be executed to set the display configuration to exactly as it is now. It looks like this:

displayplacer 
	"id:37D8832A-2D66-02CA-B9F7-8F30A301B230 res:1512x982 hz:120 color_depth:8 scaling:on origin:(0,0) degree:0" 
	"id:4F1F039B-22A7-7D04-0857-D6964E3302DB res:2560x1440 hz:144 color_depth:7 scaling:off origin:(-7680,-458) degree:0" 
	"id:FAA2B035-24B7-4190-9DE9-0966D8C1CFC8 res:2560x1440 hz:144 color_depth:7 scaling:off origin:(-2560,-458) degree:0" 
	"id:4F1F039B-22A7-7D04-9894-1410B1601597 res:2560x1440 hz:144 color_depth:7 scaling:off origin:(-5120,-458) degree:0"

Running this command at any point should reset the displays into this exact configuration. But the next time the displays were swapped, I ran the command and… nothing happened. Rerunning displayplacer list resulted in the exact same output as before.

Wat.

Lunar

Lunar is an app for mac that allows you to control monitor settings directly from the computer without having to deal with the OSD. Among the many features it offers, it has a remote server option that you can install on a Raspberry Pi. You then plug this Pi into an unused input on the display you want to control, and it sends commands via the network to the Pi, which then controls the monitor. I don’t fully understand the intended use case for this, but the ability to remotely send commands to a monitor seemed promising.

If I can get it working with one display, use it to change the brightness (or any setting) to a specific value, then check that value using the local controls, I’m in business… or so I thought. It seems like Lunar is limited by the same issue DisplayPlacer is: the Macbook is inconsistently identifying the displays. This issue runs deep.

The Problem

Displays share information about their properties (Max resolution, bitrate, refresh rate, etc) with the computer they’re attached to using Extended Display Identification Data (EDID). Included in this data is the display serial number - which should be a globally unique identifier.

The Macbook (and most computers) stores contexts for different sets of displays, which basically maps the configurations to use with a specific combination of displays. It becomes apparent, once you have multiple monitors of the same model, that the Macbook isn’t actually using this serial number to internally identify displays within these contexts. As far as I can tell, it just sees that a certain number of displays of a particular model are connected, then randomly maps these to the displays in the context without checking the serial number.

Digging into things a bit more, it turns out that this specific problem isn’t just with M1s - this has been an issue for a long time.

For me, the left and right monitors are swapping, but never the center. The center is connected via DisplayPort, while the left and right are connected via HDMI. I moved inputs around a bit to see if it made a difference, and it did. 2 identical monitors using different inputs never swapped - only when they used the same input. Each of my displays have 2 HDMIs and a DisplayPort, so 2 will always use the same input…

The “Solution”

Code

Scripts, KM Macro, and Pi camera bracket STL are all here

Hardware

To fix this, I need to be able to make a change to a specific logical display, then confirm that action occurred on a physical display. Coming up short on better ideas, I pointed my webcam at the screen. If I can place an image at a specific logical position on the screen, then see it on the camera, it means the displays are in the right order, otherwise left and right need to switch.

The CameraTaking a picture of the screen seems like something you’d expect from elderly, tech-illiterate relatives, but here we are.

Surprisingly, this worked really well. Here’s what’s going on:

  • A Keyboard Maestro macro is executed when the TS4 dock is connected that

    • Waits 30 seconds (to make sure monitors are detected and awake, this is monitor specific)
    • Opens the preview of a blue square image file, resizes it, and positions it at the bottom-left corner of the left-most logical display
    • Fires off an ssh command to the Pi, telling it to run a script
  • The script on the Pi

    • Takes a photo with the camera, which is aimed at the bottom-left corner of the left-most physical display
    • Crops it down to a small sample area closest to the camera (which will have more consistent color)
    • Determines if that sample is the blue square (Using OpenCV and Numpy)
    • Outputs FOUND or NOT FOUND to the console, which gets returned to Keyboard Maestro
  • If NOT FOUND is returned, Keyboard Maestro runs a script locally that

    • Gets the current orientation of the monitors from DisplayPlacer
    • Swaps the left and right displays using DisplayPlacer

I originally tried this without the pi, having all the code running directly from the Macbook. When disconnecting and reconnecting my Macbook to the dock, the index numbers of the webcams (needed for opencv) would randomly change.

The irony is pain.

Taking into account how long my monitors take to wake from sleep, there’s a ~30 second delay from dock connection to script execution, which itself takes another ~20 seconds to return a result. It’s cumbersome af but it does work.

The webcam tripod just sitting on my desk wasn’t going to fly long term. I swapped it out for a Raspberry Pi camera module and printed a basic angled bracket to mount it to the bottom of the monitor. I’m still tweaking things, but I’ll eventually mount this Pi to the back of the monitor for a cleaner look.

The Mount Heavy Duty Mounting Implementation

Final Thoughts

This project was done out of irritation and spite. It’s a ridiculous solution to a stupid problem that isn’t particularly niche. The fact that it’s still an issue is inexcusable.