Skip to content

Commit 1e4dc65

Browse files
committed
Use complex return type from OpenRGB source
1 parent aef98cf commit 1e4dc65

File tree

9 files changed

+120
-48
lines changed

9 files changed

+120
-48
lines changed

AllMyLights.Test/Common/ColorConverterTest.cs

+10
Original file line numberDiff line numberDiff line change
@@ -120,5 +120,15 @@ public void Should_convert_to_BGR_decimal(string hex, int expectedBgr)
120120

121121
Assert.AreEqual(expectedBgr, color.ToBgrDecimal());
122122
}
123+
124+
125+
[Test]
126+
public void Should_convert_to_comma_separated_rgb_string()
127+
{
128+
var color = Color.FromArgb(10, 20, 30);
129+
var actual = color.ToCommaSeparatedRgbString();
130+
131+
Assert.AreEqual("10,20,30", actual);
132+
}
123133
}
124134
}

AllMyLights.Test/Connectors/OpenRGBSourceTest.cs

+12-8
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
14
using System.Reactive;
25
using AllMyLights.Connectors.Sources.OpenRGB;
36
using Microsoft.Reactive.Testing;
@@ -43,7 +46,7 @@ public void Should_emit_distinct_device_colors()
4346
var corsairH150i = new Device();
4447
corsairH150i.SetColors(red, green);
4548
corsairH150i.SetName("Corsair H150");
46-
49+
4750
var devices = new Device[] {
4851
corsairH150i
4952
};
@@ -79,21 +82,22 @@ public void Should_emit_distinct_device_colors()
7982
);
8083

8184
var actual = scheduler.Start(
82-
() => subject.Get(),
85+
() => subject.Get() as IObservable<Dictionary<string, DeviceState>>,
8386
created: 0,
8487
subscribed: 0,
8588
disposed: 100
8689
);
8790

8891

89-
string payload = $"{{\"Corsair H150\":{{\"Colors\":[\"#FF0000\",\"#00FF00\"]}}}}";
90-
string payloadUpdated = $"{{\"Corsair H150\":{{\"Colors\":[\"#00FF00\",\"#0000FF\"]}}}}";
91-
92-
var expected = new Recorded<Notification<object>>[] {
93-
OnNext(10, (object)payload),
94-
OnNext(30, (object)payloadUpdated)
92+
var deviceState = new DeviceState(new List<System.Drawing.Color> { red.ToSystemColor(), green.ToSystemColor() });
93+
var deviceStateUpdated = new DeviceState(new List<System.Drawing.Color> { green.ToSystemColor(), blue.ToSystemColor() });
94+
95+
var expected = new Recorded<Notification<Dictionary<string, DeviceState>>>[] {
96+
OnNext(10, (Dictionary<string, DeviceState> actual) => actual["Corsair H150"].Colors.SequenceEqual(deviceState.Colors) ),
97+
OnNext(30, (Dictionary<string, DeviceState> actual) => actual["Corsair H150"].Colors.SequenceEqual(deviceStateUpdated.Colors) ),
9598
};
9699

100+
97101
ReactiveAssert.AreElementsEqual(expected, actual.Messages);
98102
}
99103
}

AllMyLights.Test/Transformations/ExpressionTransformationTest.cs

+36
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
using System.Collections.Generic;
12
using System.Drawing;
23
using System.Reactive;
34
using System.Reactive.Linq;
45
using AllMyLights.Common;
6+
using AllMyLights.Connectors.Sources.OpenRGB;
57
using AllMyLights.Transformations;
68
using AllMyLights.Transformations.Expression;
79
using Microsoft.Reactive.Testing;
@@ -122,5 +124,39 @@ public void Should_not_break_for_invalid_input()
122124

123125
ReactiveAssert.AreElementsEqual(expected, actual.Messages);
124126
}
127+
128+
[Test]
129+
public void Should_allow_usage_of_color_related_extensions_methods()
130+
{
131+
var input = new Dictionary<string, DeviceState>() {
132+
{ "Copperhead", new DeviceState(new Color[]{ Color.Red }) }
133+
};
134+
var source = Observable.Return(input);
135+
var expressionExpectingColor = "value[\"Copperhead\"].Colors.Cast().First().ToCommaSeparatedRgbString()";
136+
var expectation = "255,0,0";
137+
138+
var options = new ExpressionTransformationOptions()
139+
{
140+
Expression = expressionExpectingColor
141+
};
142+
143+
var transformation = new ExpressionTransformation<string>(options);
144+
145+
var scheduler = new TestScheduler();
146+
147+
var actual = scheduler.Start(
148+
() => transformation.GetOperator()(source),
149+
created: 0,
150+
subscribed: 10,
151+
disposed: 100
152+
);
153+
154+
var expected = new Recorded<Notification<string>>[] {
155+
OnNext(10, expectation),
156+
OnCompleted<string>(10)
157+
};
158+
159+
ReactiveAssert.AreElementsEqual(expected, actual.Messages);
160+
}
125161
}
126162
}

AllMyLights/Common/ColorConverter.cs

+3
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,12 @@ public static int ToBgrDecimal(this Color color)
7070
}
7171

7272
public static OpenRGB.NET.Models.Color ToOpenRGBColor(this Color color) => new OpenRGB.NET.Models.Color(color.R, color.G, color.B);
73+
public static Color ToSystemColor(this OpenRGB.NET.Models.Color color) => Color.FromArgb(color.R, color.G, color.B);
7374

7475
public static string ToHexString(this Color c) => $"#{c.R:X2}{c.G:X2}{c.B:X2}";
7576

77+
public static string ToCommaSeparatedRgbString(this Color c) => $"{c.R},{c.G},{c.B}";
78+
7679
public static string ToHexString(this OpenRGB.NET.Models.Color c) => $"#{c.R:X2}{c.G:X2}{c.B:X2}";
7780

7881
private static void FromHex(string hex, out byte a, out byte r, out byte g, out byte b)

AllMyLights/Connectors/Sources/OpenRGB/DeviceState.cs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
using System.Collections.Generic;
2+
using System.Drawing;
23

34
namespace AllMyLights.Connectors.Sources.OpenRGB
45
{
56
public struct DeviceState
67
{
7-
public IEnumerable<string> Colors;
8+
public IEnumerable<Color> Colors;
89

9-
public DeviceState(IEnumerable<string> colors)
10+
public DeviceState(IEnumerable<Color> colors)
1011
{
1112
Colors = colors;
1213
}

AllMyLights/Connectors/Sources/OpenRGB/OpenRGBSource.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public class OpenRGBSource: Source
1616
protected override IObservable<object> Value { get; }
1717

1818
private IOpenRGBClient Client { get; }
19-
private readonly ReplaySubject<string> Subject = new ReplaySubject<string>(1);
19+
private readonly ReplaySubject<Dictionary<string, DeviceState>> Subject = new ReplaySubject<Dictionary<string, DeviceState>>(1);
2020

2121
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
2222

@@ -52,11 +52,11 @@ IObservable<long> pollingInterval
5252
{
5353
deviceStates.Add(it.Name, new DeviceState()
5454
{
55-
Colors = it.Colors.Select(color => color.ToHexString())
55+
Colors = it.Colors.Select(color => color.ToSystemColor())
5656
});
5757
});
5858

59-
Subject.OnNext(JsonConvert.SerializeObject(deviceStates));
59+
Subject.OnNext(deviceStates);
6060
});
6161
}
6262
}

AllMyLights/Transformations/Expression/ExpressionTransformation.cs

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
using System;
22
using System.Collections.Generic;
3-
using SystemColor = System.Drawing.Color;
3+
using System.Linq;
44
using System.Reactive.Linq;
55
using AllMyLights.Common;
66
using CodingSeb.ExpressionEvaluator;
77
using NLog;
8+
using SystemColor = System.Drawing.Color;
89

910
namespace AllMyLights.Transformations.Expression
1011
{
@@ -24,6 +25,8 @@ public class ExpressionTransformation<T>: ITransformation<T> where T: class
2425
public ExpressionTransformation(ExpressionTransformationOptions options)
2526
{
2627
Expression = options.Expression;
28+
Evaluator.StaticTypesForExtensionsMethods.Add(typeof(ColorConverter));
29+
Evaluator.StaticTypesForExtensionsMethods.Add(typeof(Enumerable));
2730
}
2831

2932
public Func<IObservable<object>, IObservable<T>> GetOperator()
@@ -34,7 +37,12 @@ public Func<IObservable<object>, IObservable<T>> GetOperator()
3437
{
3538
try
3639
{
37-
var value = input is Ref<SystemColor> ? (input as Ref<SystemColor>).Value : input;
40+
var value = input switch
41+
{
42+
Ref<SystemColor> r => r.Value,
43+
_ => input
44+
};
45+
3846
Evaluator.Variables["value"] = value;
3947

4048
Logger.Debug($"Expression received value {value}");

AllMyLights/allmylightsrc.json

+11
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,17 @@
1717
"ChannelLayout": "_RGB"
1818
}
1919
]
20+
},
21+
{
22+
"Type": "OpenRGB",
23+
"Server": "192.168.178.120",
24+
"Port": 6742,
25+
"Transformations": [
26+
{
27+
"Type": "Expression",
28+
"Expression": "value[\"Corsair H150i PRO RGB\"].Colors.Cast().First().ToCommaSeparatedRgbString()"
29+
}
30+
]
2031
}
2132
],
2233
"Sinks": [

README.md

+32-33
Original file line numberDiff line numberDiff line change
@@ -190,19 +190,19 @@ that topic.
190190

191191
```json5
192192
{
193-
"Type" : "Mqtt",
194-
"Server": "192.168.1.20",
195-
"Port": 1883,
196-
"Topics": {
197-
// optional command topic that is used to request the current color on startup
198-
"Command": "cmnd/sonoff-1144-dimmer-5/color",
199-
"Result": "stat/sonoff-1144-dimmer-5/RESULT"
200-
},
201-
// transformations are applied in order on any received message
202-
"Transformations": [
203-
// ... see section transformations for options
204-
]
205-
}
193+
"Type" : "Mqtt",
194+
"Server": "192.168.1.20",
195+
"Port": 1883,
196+
"Topics": {
197+
// optional command topic that is used to request the current color on startup
198+
"Command": "cmnd/sonoff-1144-dimmer-5/color",
199+
"Result": "stat/sonoff-1144-dimmer-5/RESULT"
200+
},
201+
// transformations are applied in order on any received message
202+
"Transformations": [
203+
// ... see section transformations for options
204+
]
205+
}
206206
```
207207

208208

@@ -212,36 +212,35 @@ a json that contains the colors per device if any device state changed.
212212

213213
```json5
214214
{
215-
"Type" : "OpenRGB",
216-
"Server": "127.0.0.1",
217-
"Port": 6742,
218-
// controls how often OpenRGB is asked for changes, default is 1000ms
219-
"PollingInterval": 1000,
220-
// transformations are applied in order on any received message
221-
"Transformations": [
222-
// ... see section transformations for options
223-
]
224-
}
215+
"Type" : "OpenRGB",
216+
"Server": "127.0.0.1",
217+
"Port": 6742,
218+
// controls how often OpenRGB is asked for changes, default is 1000ms
219+
"PollingInterval": 1000,
220+
// transformations are applied in order on any received message
221+
"Transformations": [
222+
// ... see section transformations for options
223+
]
224+
}
225225
```
226226

227-
The returned json looks as follows, where for each LED on your device
228-
one color is returned:
227+
The produced value is of type `Dictionary<string, DeviceState>()` where the
228+
key is the name of your OpenRGB device and `DeviceState` is a struct that
229+
has the following properties:
229230

230-
```json5
231+
```csharp
232+
public struct DeviceState
231233
{
232-
"Corsair H150": {
233-
"Colors": [ "#FF0000", "#00FF00" ]
234-
}
234+
public IEnumerable<Color> Colors;
235235
}
236236
```
237237

238-
To extract a single color value from that payload, you could use a
239-
[`JsonPath`](#jsonpath) transformation such as
238+
To extract values from it, use the [`Expression`](#expression) transformation such as
240239

241240
```json5
242241
{
243-
"Type": "JsonPath",
244-
"Expression": "$['Corsair H150i PRO RGB'].Colors[0]"
242+
"Type": "Expression",
243+
"Expression": "value[\"Corsair H150i PRO RGB\"].Colors.Cast().First().ToCommaSeparatedRgbString()"
245244
}
246245
```
247246

0 commit comments

Comments
 (0)