PowerMate 1.1.0
dotnet add package PowerMate --version 1.1.0
NuGet\Install-Package PowerMate -Version 1.1.0
<PackageReference Include="PowerMate" Version="1.1.0" />
paket add PowerMate --version 1.1.0
#r "nuget: PowerMate, 1.1.0"
// Install PowerMate as a Cake Addin #addin nuget:?package=PowerMate&version=1.1.0 // Install PowerMate as a Cake Tool #tool nuget:?package=PowerMate&version=1.1.0
PowerMate
Receive events and control the light on a Griffin PowerMate USB device
Quick Start
dotnet install PowerMate
using PowerMate;
using IPowerMateClient powerMate = new PowerMateClient();
powerMate.LightBrightness = 255;
powerMate.InputReceived += (_, input) => {
switch (input) {
case { IsPressed: true, RotationDirection: RotationDirection.None }:
Console.WriteLine("PowerMate was pressed");
break;
case { RotationDirection: RotationDirection.Clockwise }:
Console.WriteLine($"PowerMate was rotated clockwise {input.RotationDistance:N0} increment(s)");
break;
case { RotationDirection: RotationDirection.Counterclockwise }:
Console.WriteLine($"PowerMate was rotated counterclockwise {input.RotationDistance:N0} increment(s)");
break;
default:
break;
}
};
Prerequisites
- A Griffin PowerMate
- ✅ The USB version is supported
- ❌ The Bluetooth version is not supported
- Any Microsoft .NET runtime that supports .NET Standard 2.0 or later
- A supported operating system
- ✅ Windows
- verified on 10 22H2 x64
- verified on 11 22H2 x64
- ✅ MacOS
- verified on 12.6 x64
- ❌ Linux is not supported
- on Fedora 37, Debian 11, Raspbian 11, and openSUSE 15, the PowerMate is never detected by HIDSharp, even though it appears with
lsusb
- on Fedora 37, Debian 11, Raspbian 11, and openSUSE 15, the PowerMate is never detected by HIDSharp, even though it appears with
- ✅ Windows
Installation
You can install this library into your project from NuGet Gallery:
dotnet add package PowerMate
Install-Package PowerMate
- Go to Project › Manage NuGet Packages in Visual Studio and search for
PowerMate
Usage
Construct a new instance of the
PowerMateClient
class.using IPowerMateClient powerMate = new PowerMateClient();
You should dispose of instances when you're done with them by calling
Dispose()
, or with ausing
statement or declaration.Now you can listen for
InputReceived
events from the client.powerMate.InputReceived += (_, input) => Console.WriteLine($"Received PowerMate event: {input}");
Connections
This library will automatically try to connect to one of the PowerMate devices that are plugged into your computer. If no device is connected, it will automatically wait until one appears and then connect to it. If a device disconnects, this library will reconnect automatically when one reappears.
If multiple PowerMate devices are present simultaneously, this library will pick one of them arbitrarily and use it until it disconnects.
The connection state is exposed by the bool IsConnected
property, and changes to this state are emitted by the IsConnectedChanged
event.
Console.WriteLine(powerMate.IsConnected
? "Listening for movements from PowerMate."
: "Waiting for a PowerMate to be connected.");
powerMate.IsConnectedChanged += (_, isConnected) => Console.WriteLine(isConnected
? "Reconnected to a PowerMate."
: "Disconnected from the PowerMate, attempting reconnection...");
Notifications
InputReceived
event
Fired whenever the PowerMate knob is rotated, pressed, or released.
powerMate.InputReceived += (_, input) => Console.WriteLine($"Received PowerMate event: {input}");
The event argument is a PowerMateInput
struct with the following fields.
Field name | Type | Example values | Description |
---|---|---|---|
IsPressed |
bool |
true false |
true if the knob is being held down, or false if it is up. Pressing and releasing the knob will generate two events, with true and false in order. Will also be true when the knob is rotated while being held down. |
RotationDirection |
enum |
None Clockwise Counterclockwise |
The direction the knob is being rotated when viewed from above, or None if it is not being rotated. |
RotationDistance |
uint |
0 1 2 |
How far, in arbitrary angular units, the knob was rotated since the last update. When you rotate the knob slowly, you will receive multiple events, each with this set to 1 . As you rotate it faster, updates are batched and this number increases to 2 or more. The highest value I have seen is 8 . This is always non-negative, regardless of the rotation direction; use RotationDirection to determine the direction. If the knob is pressed without being rotated, this is 0 . |
IsConnectedChanged
event
Fired whenever the connection state of the PowerMate changes. Not fired when constructing or disposing the PowerMateClient
instance.
The event argument is a bool
which is true
when a PowerMate has reconnected, or false
when it has disconnected.
To get the value of this state at any time, read the IsConnected
property on the IPowerMateClient
instance.
powerMate.IsConnectedChanged += (_, isConnected) => Console.WriteLine(isConnected
? "Reconnected to a PowerMate."
: "Disconnected from the PowerMate, attempting reconnection...");
Light Control
By default, the blue/cyan LED in the base of the PowerMate lights up when it's plugged in. You can change the intensity of the light, make it pulse at different frequencies, or turn it off entirely by setting the following properties. The values that you set are retained across reconnections.
LightBrightness
property
A writable byte
property with valid values in the range [0, 255]. 0
represents off, and 255
is the brightest.
The default value is 80
, which matches the brightness the device uses when no program has instructed it to change its brightness since it has been plugged in.
Changes to LightBrightness
will not take effect while the LED is pulsing with a LightAnimation
of Pulsing
.
powerMate.LightBrightness = 0;
powerMate.LightAnimation = LightAnimation.Solid;
powerMate.LightBrightness = 255;
powerMate.LightAnimation = LightAnimation.Solid;
LightAnimation
property
A writable enum
property that controls how the light is animated. Available values are
Solid
(default) — the light shines at a constant brightness, controlled byLightBrightness
Pulsing
— the light raises and lowers its brightness to the highest and lowest levels in a cyclical animation, with the frequency controlled byLightPulseSpeed
SolidWhileAwakeAndPulsingDuringComputerStandby
— while the computer to which the device is connected is awake, the light shines at a constant brightness (controlled byLightBrightness
), but while the computer is asleep, the light displays the pulsing animation (with the frequency controlled byLightPulseSpeed
)
powerMate.LightPulseSpeed = 12;
powerMate.LightAnimation = LightAnimation.Pulsing;
LightPulseSpeed
property
A writable int
property with valid values in the range [0, 24]. Values outside that range are clamped. The default value is 12
.
This property controls how fast the light pulses when LightAnimation
is set to Pulsing
or SolidWhileAwakeAndPulsingDuringComputerStandby
. The slowest pulse speed, 0
, is about 0.03443 Hz, or a 29.04 sec period. The fastest pulse speed, 24
, is about 15.63 Hz, or a 64 ms period.
powerMate.LightPulseSpeed = 12;
powerMate.LightAnimation = LightAnimation.Pulsing;
PowerMate light state loss on resume
When the computer goes into standby mode and then resumes, the PowerMate loses all of its state and resets its settings to their default values, erasing your light control changes. There are two techniques to fix this, and you should use both of them.
Automatically reapply settings on stale input
Each time the PowerMate device sends an input to the computer, such as a knob turn or press, it also sends the current state of the lights. This library checks that device state and compares it to the values you set using LightBrightness
, LightAnimation
, and LightPulseSpeed
. If any of them differ, it will automatically send the correct values to the PowerMate. You don't have to do anything to enable this behavior.
Manually reapply settings on resume
Unfortunately, the user is likely to see the incorrect light state before they send an input with the PowerMate: it will be wrong as soon as the computer resumes, and they may not need to touch the PowerMate until much later.
To fix this, your program should also wait for the computer to resume from standby, and when it does, force this library to resend all of the light control property values to the device by calling SetAllFeaturesIfStale()
.
To detect when a Windows computer resumes from standby, a successful strategy is to listen for event ID 107 from the Kernel-Power source in the System log.
using IStandbyListener standbyListener = new EventLogStandbyListener();
standbyListener.Resumed += (_, _) => powerMate.SetAllFeaturesIfStale();
⛔ You should not listen for SystemEvents.PowerModeChanged
events because they are unreliable and do not get sent about 5% of the time.
Demos
Simple demo
This console program just prints out each event it receives from the PowerMate.
> Demo-x64.exe
Listening for PowerMate events
Received event from PowerMate: Turning clockwise 1 increment while not pressed
Received event from PowerMate: Turning clockwise 1 increment while not pressed
Received event from PowerMate: Turning clockwise 1 increment while not pressed
^C
Volume control
This background program increases and decreases the output volume of the default Windows audio output device when you turn the PowerMate knob clockwise and counterclockwise. It also toggles the output mute when you press the knob.
PowerMateVolume.exe
By default, it increments and decrements the volume by 1 percentage point for each rotation event. You can customize this amount by passing a different percentage as a command-line argument, such as ½ or 2 percentage points:
PowerMateVolume.exe 0.005
PowerMateVolume.exe 0.02
Acknowledgements
Luke Ma for giving me a PowerMate as a Christmas gift in 2013. Thanks Luke!
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- HidClient (>= 1.0.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
1.1.0 | 250 | 8/1/2023 |
1.0.0 | 249 | 2/25/2023 |
0.0.1-SNAPSHOT2 | 141 | 2/18/2023 |
0.0.1-SNAPSHOT1 | 150 | 2/16/2023 |