2023-02-02

Touch of Power

If you are impatient and just want to get the Powermate working on your Mac, scroll down to the code

Our story so far

Back in 2001 or so, Griffin Technology released the PowerMate. It's basically just a jog wheel with a USB-connector, but it's also quite stylish, machined from a solid piece of steel aluminium with a slightly brushed finish. Inside the semi-translucent base sits a single blue LED—none of that RGB that is so popular these days—that can pulse smoothly to indicate things.

There was a bluetooth version released in 2014, but I never had that one.

The PowerMate is more or less just a glorified volume knob for your desktop, but it can be much more. As I recall, the software allowed you to map the rotating and pushing actions to anything you wanted, and you could use AppleScript to make it even more advanced.

Fast forward 20 odd years and that old software of course does not work any more. I believe there have been some developments, but I never found anything that seemed to work well.

But at it's core it's still just a USB low speed HID-device. It should be compatible with anything that can understand the simple values it sends.

Photo of the Griffin Powermate. The base is illuminated by a nice blue light.

The Better Tool

BetterTouchTool by folivora.AI GmbH is a wonderful little application for macOS. If there is an input devices on a mac, BTT can most likely do something with it. It does not do much at all right after you install it, it requires a lot of configuration, but that is also the apps main strength. It can really do more or less anything, and it has been constantly developed for many years now. It costs 10 dollar for two years of updates, or 22 dollar for lifetime, but it should probably cost a lot more than that.

Combining them

BTT version 4 was released a few days ago, with support for "Generic Devices". This immediately caught my attention. It allows you to look at the reports coming in from any HID-device on the system and use JavaScript to act on the raw bytes. It's still a bit rough around the edges, but it works. 😊

First thing I thought about was the PowerMate. I managed to find it in an old box, plugged it in to my M1 Mac Mini, followed the simple steps in the (for now) a bit limited documentation and boom. I got data coming in as I turned the knob.

The Powermate sends six bytes in every report, I do not know the mening of all of them, but the only ones we need to use are index 0 and 1.

Screenshot showing the six bytes as received by BetterTouchTool Analyzer

Spinning the knob at a steady pace will cause repeated identical reports with the same value for movement. Originally it was not possible to get these repeat messages to the script, but version 4.006 added a function that can be called to tell BTT we want the next report also, even if it's the same. This solved that problem. 😄

The code

To do this yourself with BTT 4.006, open the BTT configuration and choose "Generic Devices (work in progress)".

buttonpress
buttonrelease
left
leftpressed
right
rightpressed
// Input Analyser script for Griffin PowerMate
// Select index 0 and 1 in report 0 for monitoring

function analyzeDeviceInput(targetDevice, reportID, reportDataHex) {
    let reportBuffer = buffer.Buffer.from(reportDataHex, 'hex'),
        // Index 0 is button state. 1 = press, 0 = release.
        button = reportBuffer.readUInt8(0),
        // Index 1 is amount of movement since last report.
        // Signed value, positive for right, negative for left.
        // Spinning really fast I have observed a value up to +/- 7,
        // lets assume it will never be larger than 9.
        movement = reportBuffer.readInt8(1);

    if ( movement < 0 ) {
        if ( button == 0 ) {
            log('left ' + movement);
            // We should probably repeat the trigger "movement" times ...
            // but that would be too many triggers :)
            bttTriggerDeviceTrigger(targetDevice, 'left');
        } else {
            log('left ' + movement + ' pressed');
            bttTriggerDeviceTrigger(targetDevice, 'leftpressed');
        }
        // If we are spinning we want the next report even if it's the same
        bttGetNextEvenWithoutChange(targetDevice, reportID);
    }
    else if( movement > 0) {
        if ( button == 0 ) {
            log('right ' + movement);
            bttTriggerDeviceTrigger(targetDevice, 'right');
        } else {
            log('right ' + movement + ' pressed');
            bttTriggerDeviceTrigger(targetDevice, 'rightpressed');
        }
        bttGetNextEvenWithoutChange(targetDevice, reportID);
    }

    // When button state change index 1 is always 0, even if knob is spinning.
    else if ( button === 1 && movement === 0 ) {
        log('button press');
        bttTriggerDeviceTrigger(targetDevice, 'buttonpress');
    }
    else if ( button === 0 && movement === 0 ) {
        log('button release');
        bttTriggerDeviceTrigger(targetDevice, 'buttonrelease');
    }

}

Screenshot showing the triggers added to BetterTouchTool Analyzer

I have found that you sometimes need to restart BetterTouchTool for script changes to take affect in the actual actions, even if it works in the analyser window. Just select Restart in BTTs menu and it should be fine.

Please note that this only receives data from the Powermate. It does not control the LED, though that should be possible as soon as I figure out the values to send to the device.

Further developments

I am currently experimenting with storing a position value in a "global" variable, increasing and decreasing this value by the amount of movement in the reports. Then sending a trigger every time it has passed over an even 10 ticks. This allows you to make corse movement, which would be a lot better for some types of input. It's not quite finished yet, will post more later. I'm not sure if it's allowed to use a global variable like that, but it works in the Analyzer at least. Update: Andreas Hegenberg have confirmed that that global variables are fine to use.

Disclaimer

I am in no way affiliated or sponsored by neither folivora.AI GmbH nor Griffin Technology. I just enjoy their products. I do not make any claims of usability or correctness of any code or instructions released here. Code and instructions may contain bugs or be incorrect. Software might change in the future making this obsolete. You are free to use the code presented here any way you like. If you get this working yourself, why not Toot me on Mastodon @lardh@mastodon.social?