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.
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.
-
Index 0 have the value 0 or 1 depending on wether the button is held down or not. When the state changes index 1 will always be 0, even if the knob is spinning while we push or release the button. A value other than 0 for index 1 while index 0 is 1 means the knob is being held down and turned at the same time.
-
Index 1 have a value corresponding to how far the knob has been turned since the last report. It is signed, positive numbers for turning right, negative for turning left. Spinning the knob as fast as I can I have observed values up to ±7 here. You do need to spin quite fast to get anything other than 1 though.
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)".
- Click + at the bottom to add a new trigger.
- Choose "Generic Device & Input Analyzer".
- Under the tab "Target Device", find the Griffin Powermate in the "See all connected HID Devices" dropdown. This will fill out all necessary values like Vendor and Product ID.
- Go to the "Analyzer" tab and paste the triggers we want to define in the "Provided Triggers" input box.
buttonpress
buttonrelease
left
leftpressed
right
rightpressed
- Then click the "Parse Device Input/Output" button. This will open a new window.
- Give the PowerMate a little spin. If everything is ok so far, you should see reports coming in. If not, try closing the window and open it again. I found it can sometimes be a little flaky.
- Click on the values in index 0 and index 1 in the report under "Current Input Data", to monitor them for changes. When turning or pushing the knob there will now be messages in "History Of Monitored Changes".
- Paste the following script in the provided space to the left.
// 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');
}
}
- Give the knob a turn again and check that things are written in the log.
- Close the window.
- Add more triggers with the + button, this time select the "Griffin Powermate"-triggers in the trigger selector, and add any actions you want to them.
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?