Skip to content

Commit

Permalink
Fixes and Removals
Browse files Browse the repository at this point in the history
Fixed some CloudDasClient methods not ensuring login
Removed Visualizer example as the local API is too slow for it to be viable
Added keypress hotspot example
Added more comments in a few places
Added / improved readme
Included package info in csproj for Nuget
  • Loading branch information
jmazouri committed Jul 19, 2018
1 parent a125835 commit b0ec691
Show file tree
Hide file tree
Showing 11 changed files with 177 additions and 93 deletions.
33 changes: 33 additions & 0 deletions LibSharpQ.Examples/Keypress.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using LibSharpQ.Models;

namespace LibSharpQ.Examples
{
public static class Keypress
{
public static async Task Execute(IDasClient client)
{
ConsoleKey key = ConsoleKey.A;
Console.WriteLine("Type keys in the console window and watch them glow!");
Console.WriteLine("Hit escape to quit");

while (key != ConsoleKey.Escape)
{
var input = Console.ReadKey();
key = input.Key;

if (key == ConsoleKey.Escape) { continue; }

char inputChar = Char.ToUpper(input.KeyChar);
var signal = new Signal("Hotspot", "KEY_" + inputChar, new Color(255, 0, 0));

var result = await client.SendSignal(signal);
await Task.Delay(1000);
await client.DeleteSignal(result.Id);
}
}
}
}
1 change: 0 additions & 1 deletion LibSharpQ.Examples/LibSharpQ.Examples.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="CSCore" Version="1.2.1.2" />
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.0-beta0004" />
</ItemGroup>

Expand Down
10 changes: 6 additions & 4 deletions LibSharpQ.Examples/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ static async Task PresentOptions()
Console.WriteLine("Select a demo: ");
Console.WriteLine("1. Rainbow F-Keys");
Console.WriteLine("2. Snake");
Console.WriteLine("3. Audio Visualizer");
Console.WriteLine("4. Image Loader");
Console.WriteLine("3. Image Loader");
Console.WriteLine("4. Keypress Hotspot");

Console.WriteLine();

Console.WriteLine("8. Clear All Signals");
Console.WriteLine("9. Quit");
Expand All @@ -47,10 +49,10 @@ static async Task PresentOptions()
await ChasingSnake.Execute(_client);
break;
case 3:
await Visualizer.Execute(_client);
await ImageLoader.Execute(_client);
break;
case 4:
await ImageLoader.Execute(_client);
await Keypress.Execute(_client);
break;
case 8:
await _client.DeleteAllSignals();
Expand Down
78 changes: 0 additions & 78 deletions LibSharpQ.Examples/Visualizer.cs

This file was deleted.

6 changes: 3 additions & 3 deletions LibSharpQ.sln
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27703.2035
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibSharpQ", "LibSharpQ\LibSharpQ.csproj", "{02AB105B-D067-4578-8F37-F0856D31B5B4}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibSharpQ", "LibSharpQ\LibSharpQ.csproj", "{02AB105B-D067-4578-8F37-F0856D31B5B4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibSharpQ.Tests", "LibSharpQ.Tests\LibSharpQ.Tests.csproj", "{6D7DC3D3-1043-4E24-B242-79B57B9FBD7D}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibSharpQ.Tests", "LibSharpQ.Tests\LibSharpQ.Tests.csproj", "{6D7DC3D3-1043-4E24-B242-79B57B9FBD7D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibSharpQ.Examples", "LibSharpQ.Examples\LibSharpQ.Examples.csproj", "{D63A3689-40A3-42F4-9670-1D9F12E88503}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibSharpQ.Examples", "LibSharpQ.Examples\LibSharpQ.Examples.csproj", "{D63A3689-40A3-42F4-9670-1D9F12E88503}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down
11 changes: 8 additions & 3 deletions LibSharpQ/BaseDasClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,14 @@ public async Task DeleteSignal(int signalId)
await _client.SendAsync(msg).ConfigureAwait(false);
}

public Task DeleteSignal(Signal signal)
{
return DeleteSignal(signal.Id);
}

public abstract Task<IReadOnlyList<Signal>> GetSignals(bool retrieveAll = true);

public async Task<Signal> SendSignal(Signal signal)
public virtual async Task<Signal> SendSignal(Signal signal)
{
string serializedSignal = JsonConvert.SerializeObject(signal, new JsonSerializerSettings
{
Expand All @@ -59,12 +64,12 @@ public virtual async Task DeleteSignals(IEnumerable<int> signalIds)
await Task.WhenAll(signalIds.Select(id => DeleteSignal(id))).ConfigureAwait(false);
}

public Task DeleteSignals(IEnumerable<Signal> signals)
public virtual Task DeleteSignals(IEnumerable<Signal> signals)
{
return DeleteSignals(signals.Select(d=>d.Id));
}

public async Task DeleteAllSignals()
public virtual async Task DeleteAllSignals()
{
var signals = await GetSignals().ConfigureAwait(false);
await DeleteSignals(signals).ConfigureAwait(false);
Expand Down
30 changes: 30 additions & 0 deletions LibSharpQ/CloudDasClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ public Task<IReadOnlyList<Effect>> GetEffects(string pid = "DK5QPID")
/// <returns>A collection of signals that were previously sent</returns>
public override async Task<IReadOnlyList<Signal>> GetSignals(bool retrieveAll = true)
{
EnsureLoggedIn();

List<Signal> ret = new List<Signal>();
int page = 0;
bool hasMorePages = true;
Expand All @@ -114,5 +116,33 @@ public override async Task<IReadOnlyList<Signal>> GetSignals(bool retrieveAll =

return ret;
}

public override Task<Signal> SendSignal(Signal signal)
{
EnsureLoggedIn();

return base.SendSignal(signal);
}

public override Task DeleteAllSignals()
{
EnsureLoggedIn();

return base.DeleteAllSignals();
}

public override Task DeleteSignals(IEnumerable<int> signalIds)
{
EnsureLoggedIn();

return base.DeleteSignals(signalIds);
}

public override Task DeleteSignals(IEnumerable<Signal> signals)
{
EnsureLoggedIn();

return base.DeleteSignals(signals);
}
}
}
1 change: 0 additions & 1 deletion LibSharpQ/IDasClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ public interface IDasClient
/// <summary>
/// Deletes all signals currently active
/// </summary>

Task DeleteAllSignals();

/// <summary>
Expand Down
14 changes: 14 additions & 0 deletions LibSharpQ/LibSharpQ.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,20 @@

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<Version>0.1.0</Version>
<Authors>John Mazouri</Authors>
<Company />
<Product />
<Copyright>2017 John Mazouri</Copyright>
<Description>A client library for the Das Keyboard 5Q (and other cloud-enabled Das keyboards)</Description>
<PackageLicenseUrl>https://github.com/jmazouri/LibSharpQ/blob/master/LICENSE</PackageLicenseUrl>
<PackageProjectUrl>https://github.com/jmazouri/LibSharpQ</PackageProjectUrl>
<RepositoryUrl>https://github.com/jmazouri/LibSharpQ.git</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageTags>das daskeyboard 5q</PackageTags>
<AssemblyVersion>0.0.1.0</AssemblyVersion>
<FileVersion>0.0.1.0</FileVersion>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>

<ItemGroup>
Expand Down
23 changes: 21 additions & 2 deletions LibSharpQ/Models/Signal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,28 @@ public Signal(string name, string zoneId, string color)
Color = color;
}

public Signal(string name, string zoneId, Color color) : this(name, zoneId, color.HexCode) { }
public Signal(string name, (int x, int y) position, Color color) : this(name, position, color.HexCode) { }
/// <summary>
/// Create a signal with the specified parameters
/// </summary>
/// <param name="name">The name of the signal</param>
/// <param name="zoneId">The zone for the signal to appear</param>
/// <param name="color">The color for the signal. Will use the Name if not null, otherwise HexCode.</param>
public Signal(string name, string zoneId, Color color) : this(name, zoneId, color.Name ?? color.HexCode) { }

/// <summary>
/// Create a signal with the specified parameters
/// </summary>
/// <param name="name">The name of the signal</param>
/// <param name="position">The location for the signal to appear</param>
/// <param name="color">The color for the signal. Will use the Name if not null, otherwise HexCode.</param>
public Signal(string name, (int x, int y) position, Color color) : this(name, position, color.Name ?? color.HexCode) { }

/// <summary>
/// Create a signal with the specified parameters
/// </summary>
/// <param name="name">The name of the signal</param>
/// <param name="position">The location for the signal to appear</param>
/// <param name="color">The color for the signal. Should be a predefined color name, or hexcode.</param>
public Signal(string name, (int x, int y) position, string color) : this(name, $"{position.x},{position.y}", color) { }

[JsonConstructor]
Expand Down
63 changes: 62 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,63 @@
# LibSharpQ
A client library for the Das Keyboard 5Q (and other cloud-enabled Das keyboards)
A client library for the Das Keyboard 5Q (and other cloud-enabled Das keyboards).

# Installation
Install the NuGet package `LibSharpQ`, grab the `.nupkg` from the Releases page, or download and build yourself from this repository. Requires the newest version of Visual Studio and .NET Core 2.1 tooling.

# How to Use
This library includes two main "client" classes - `CloudDasClient` and `LocalDasClient`. The former is designed for use with the "cloud" Das Keyboard API, and the latter is for the local Das Keyboard API available via the Das Keyboard Q desktop software.

Both provide async-only APIs, implement `IDisposable`, and provide the option to inject your own `HttpClient` - for demos / basic applications, I recommend switching your C# language version to "latest minor" and using an `async Task Main()` - see the Examples project for, well, examples.

If you want information on the API itself, you can find the official documentation here: https://www.daskeyboard.io/q-api-doc/

Below is a list of all available methods.

---

# Cloud & Local APIs

## GetSignals(bool retrieveAll = true)
This method return an `IReadOnlyList<Signal>` of all the previously sent signals. Note that signals are not synced, so signals sent to the Cloud API will not be returned if this method is called on a `LocalDasClient` instance, or vice-versa.

The `retrieveAll` parameter, if set to false, will make this method only return the first page of results from the API. This parameter does nothing on a `LocalDasClient`, where there is no pagination on this endpoint.

## SendSignal(Signal signal)
This method will send a signal to the API. There are convenient constructor overloads for `Signal` that will ensure the required parameters are present - but you can override anything you'd like via the properties, like `Effect`, which is `"SET_COLOR"` by default, or Pid, which is `"DK5QPID"` by default.

For indexed location zones, there is an overload that allows you to pass a `ValueTuple(int x, int y)` for location, which will be formatted appropriately.

This method will return a new instance of `Signal` as per the API response, which will include the signal ID you need to delete it later. The `ZoneId` of this response should be in the same format it was sent. If you sent it with an indexed location, it will be available as a `(int x, int y)` via the `ZonePosition` property.

## DeleteSignal(int signalId)
## DeleteSignals(IEnumerable\<int\> signalIds)
## DeleteAllSignals()
These methods will delete the signal with the given id, the signal(s) with the given id(s), or all the signals, respectively.

The DeleteAllSignals() method follows the same rules as `GetSignals()` - if called on a `LocalDasClient`, it will *not* delete signals on the Cloud, and vice-versa. This method also has a different implementation for the `LocalDasClient` - there, it will delete signals one at a time, whereas it will try to delete them all at once for the `CloudDasClient`. This is due to a hard-crash bug with concurrent requests in the current version of the Das Keyboard software, and will be changed once that bug is fixed.

---

# Cloud API

Certain features are only available via the Cloud API - primarily the endpoints that return device information.

## Login(OAuthTokenRequest credentials)
This is required to be called before calling any other methods on the `CloudDasClient` instance. Pass your OAuth credentials as provided by Das - available on this page after logging in: https://q.daskeyboard.com/account

You will need to populate both the Client ID and Client Secret. I highly recommend storing these in a config file, and loading them at runtime for security purposes - especially if you are writing an application that will be shared with others, or made open-source.

## GetDevices()
This method returns an `IReadOnlyList<Device>` of devices registered & active on the logged-in account.

## GetDeviceDefinitions()
This method returns an `IReadOnlyList<DeviceDefinition>` of definitions for devices that the API supports. This includes the Das Keyboard 5Q, other cloud-enabled Das keyboards, and international layouts of those keyboards. Useful to retrieve layout information.

## GetPredefinedColors()
This method returns an `IReadOnlyList<Color>` of predefined colors available via the API. The resulting `Color` instances will have their `Name` properties populated, which can be used instead of hex codes when sending a signal - and if a `Color` instance is passed to the `Signal` constructor, `Name` will be used instead of `HexCode` if not null.

## GetZones(string pid = "DK5QPID")
This method will return an `IReadOnlyList<Zone>` all the zones defined for the provided product ID - default is the Das Keyboard 5Q's PID. The resulting `Zone` instances will have a linearly numbered Id that can be used as a `ZoneId` for sending Signals, the `Code` which can also be used, and a `Description` of the zone.

## GetEffects(string pid = "DK5QPID")
This method will return an `IReadOnlyList<Effect>` of available signal effects for the provided product ID - again defaulting to the Das Keyboard 5Q. The resulting `Effect` instances will have the `Code` that must be assigned to the `Signal.Effect` property when creating/sending Signals, and a user-friendly `Name`.

0 comments on commit b0ec691

Please sign in to comment.