Skip to content

Commit 110920c

Browse files
committed
add brightness control
1 parent c3d66de commit 110920c

File tree

12 files changed

+247
-196
lines changed

12 files changed

+247
-196
lines changed

mediocre/Device.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@
1010
public static class Device {
1111
public static async Task<IEnumerable<YeelightAPI.Device>> All(string? filter) {
1212
DeviceLocator.MaxRetryCount = 3;
13-
return await DeviceLocator.DiscoverAsync();
13+
var devices = await DeviceLocator.DiscoverAsync();
14+
return filter != null
15+
? devices.Where(d => d.Name.ContainsI(filter) || d.Model.ToString().ContainsI(filter))
16+
: devices;
1417
}
1518

1619
public static async Task<IDeviceController> InitFirst(int port) {

mediocre/Program.cs

Lines changed: 10 additions & 184 deletions
Original file line numberDiff line numberDiff line change
@@ -1,187 +1,13 @@
1-
namespace Mediocre;
2-
3-
using System;
4-
using System.Diagnostics;
5-
using System.Drawing;
6-
using System.Linq;
7-
using System.Runtime.CompilerServices;
8-
using System.Threading.Tasks;
9-
10-
using CommandLine;
11-
using CommandLine.Text;
1+
using CommandLine;
122

3+
using Mediocre;
134
using Mediocre.CLI;
145

15-
public static class Program {
16-
public static async Task<int> Main(string[] args) => await new Parser()
17-
.ParseArguments<SyncOpts, PrintOpts, ReadOpts, ListOpts>(args)
18-
.MapResult(
19-
parsedSync: Sync,
20-
parsedPrint: Print,
21-
parsedRead: Read,
22-
parsedList: List,
23-
notParsed: Help);
24-
25-
/**
26-
* TODO:
27-
* - select sepcified device instead of first
28-
* - multi-device support
29-
* - select all devices by default
30-
* - subtract avg calc time from delay for more accurate fps
31-
*/
32-
private static async Task<int> Sync(SyncOpts opts) {
33-
Log.Verbose = opts.Verbose;
34-
Console.WriteLine(HeadingInfo.Default);
35-
Console.WriteLine();
36-
37-
var screenshot = Screenshot.FromScreenName(opts.Screen);
38-
Log.Dbg($"selected screen {screenshot.ScreenName}.");
39-
40-
var device = await Device.InitFirst(opts.Port);
41-
Log.Msg($"syncing average color of {screenshot.ScreenName} with {device}.");
42-
43-
Color? prevColor = null;
44-
var prevBright = 0;
45-
var delay = 1000 / opts.Fps;
46-
47-
while (true) {
48-
screenshot.Refresh();
49-
50-
var color = screenshot.GetAverageColor(opts.SampleStep);
51-
var bright = color.GetBrightness().Scale(1, 100);
52-
53-
if (color.R < 10 && color.G < 10 && color.B < 10)
54-
color = Color.Black;
55-
56-
if (color != prevColor) await device
57-
.SetRGBColor(color.R, color.G, color.B, opts.Smooth)
58-
.Log($"setting {color}.");
59-
60-
if (bright != prevBright) await device
61-
.SetBrightness(bright, opts.Smooth)
62-
.Log($"setting brightness {bright}.");
63-
64-
prevColor = color;
65-
prevBright = bright;
66-
67-
await Task.Delay(delay);
68-
}
69-
}
70-
71-
/**
72-
* TODO:
73-
* - subtract avg calc time from delay for more accurate fps
74-
* - configurable color format
75-
*/
76-
private static async Task<int> Print(PrintOpts opts) {
77-
var screen = Screenshot.FromScreenName(opts.Screen);
78-
79-
Color? prevColor = null;
80-
var delay = 1000 / opts.Fps;
81-
82-
while (true) {
83-
screen.Refresh();
84-
85-
var color = screen.GetAverageColor(opts.SampleStep);
86-
if (color != prevColor)
87-
Console.WriteLine(color.ToRgb());
88-
89-
prevColor = color;
90-
91-
await Task.Delay(delay);
92-
}
93-
}
94-
95-
/**
96-
* TODO:
97-
* - everything
98-
*/
99-
private static async Task<int> Read(ReadOpts opts) {
100-
Log.Verbose = opts.Verbose;
101-
Console.WriteLine(HeadingInfo.Default);
102-
Console.WriteLine();
103-
104-
var device = await Device.InitFirst(opts.Port);
105-
Log.Msg($"syncing stdin color stream with {device}.");
106-
107-
while (true) {
108-
var text = await Console.In.ReadLineAsync();
109-
Debug.Assert(text != null);
110-
var num = int.Parse(text);
111-
var color = num.ToRgb();
112-
var bright = color.GetBrightness().Scale(1, 100);
113-
114-
if (color.R < 10 && color.G < 10 && color.B < 10)
115-
color = Color.Black;
116-
117-
await device
118-
.SetRGBColor(color.R, color.G, color.B, opts.Smooth)
119-
.Log($"setting {color}.");
120-
121-
await device
122-
.SetBrightness(bright, opts.Smooth)
123-
.Log($"setting brightness {bright}.");
124-
}
125-
}
126-
127-
/**
128-
* TODO:
129-
* - filter devices by name
130-
*/
131-
private static Task<int> List(ListOpts opts) => opts.What switch {
132-
ListWhat.screens => ListScreens(opts.Filter),
133-
ListWhat.devices => ListDevices(opts.Filter),
134-
_ => throw new SwitchExpressionException(opts.What)
135-
};
136-
137-
private static Task<int> ListScreens(string? filter) {
138-
Console.WriteLine(HeadingInfo.Default);
139-
Console.WriteLine();
140-
141-
foreach (var screen in Screenshot.All(filter)) {
142-
using (ConsoleWith.FG(ConsoleColor.DarkYellow).When(screen.IsPrimary)) {
143-
Console.WriteLine(screen.ScreenName);
144-
Console.WriteLine();
145-
Console.WriteLine($" upper left: ({screen.Bounds.Top}, {screen.Bounds.Left})");
146-
Console.WriteLine($" width: {screen.Bounds.Width} px");
147-
Console.WriteLine($" height: {screen.Bounds.Height} px");
148-
Console.WriteLine();
149-
}
150-
}
151-
152-
return Task.FromResult(0);
153-
}
154-
155-
private static async Task<int> ListDevices(string? filter) {
156-
Console.WriteLine(HeadingInfo.Default);
157-
Console.WriteLine();
158-
159-
foreach (var device in await Device.All(filter)) {
160-
var props = device.Properties.Select(x => $"{x.Key} = {x.Value}").Order();
161-
var ops = device.SupportedOperations.Select(x => x.GetRealName()).Order();
162-
163-
Console.WriteLine(device);
164-
Console.WriteLine();
165-
Console.WriteLine($" id: {device.Id}");
166-
Console.WriteLine($" name: {device.Name}");
167-
Console.WriteLine($" model: {device.Model}");
168-
Console.WriteLine($" firmware: {device.FirmwareVersion}");
169-
Console.WriteLine($" hostname: {device.Hostname}");
170-
Console.WriteLine($" port: {device.Port}");
171-
Console.WriteLine($" properties: {props.Join("\n ")}");
172-
Console.WriteLine($" supported commands: {ops.Join("\n ")}");
173-
Console.WriteLine();
174-
}
175-
176-
return await Task.FromResult(0);
177-
}
178-
179-
private static Task<int> Help(NotParsed<object> result) {
180-
var help = HelpText.AutoBuild(result, helpText => helpText
181-
.With(ht => ht.Copyright = "")
182-
.With(ht => ht.AdditionalNewLineAfterOption = false)
183-
.With(ht => ht.AddEnumValuesToHelpText = true));
184-
Console.WriteLine(help);
185-
return Task.FromResult(1);
186-
}
187-
}
6+
await new Parser()
7+
.ParseArguments<SyncOpts, PrintOpts, ReadOpts, ListOpts>(args)
8+
.MapResult(
9+
parsedSync: Commands.Sync,
10+
parsedPrint: Commands.Print,
11+
parsedRead: Commands.Read,
12+
parsedList: Commands.List,
13+
notParsed: Commands.Help);

mediocre/Screenshot.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ public static Screenshot FromScreenName(string name) {
4040
.Where(s => s.DeviceName.ContainsI(name))
4141
.ToArray();
4242

43-
return screens.Length switch {
44-
1 => new(screens.Single()),
45-
0 => throw new InvalidOperationException($"No screen matching '{name}' found. Available screens: {Screen.AllScreens.Print()}"),
43+
return screens switch {
44+
[var s] => new(s),
45+
[] => throw new InvalidOperationException($"No screen matching '{name}' found. Available screens: {Screen.AllScreens.Print()}"),
4646
_ => throw new InvalidOperationException($"Multiple screens found for '{name}': {screens.Print()}")
4747
};
4848
}

mediocre/Util.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ public static Color ToRgb(this int n) => Color.FromArgb(
5353
green: (byte)(n >> 8),
5454
blue: (byte)n);
5555

56-
public static int Scale(this float x, int min, int max, int? factor = null)
57-
=> (int)Math.Round(Math.Clamp(x * (factor ?? max), min, max));
56+
public static int Scale(this float x, int min, int max)
57+
=> (int)Math.Round(Math.Clamp(x * max, min, max));
5858

5959
#region hack the real name of a supported device operation
6060

mediocre/cli/Help.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
namespace Mediocre.CLI;
2+
3+
using CommandLine;
4+
using CommandLine.Text;
5+
6+
using System;
7+
using System.Threading.Tasks;
8+
9+
public partial class Commands {
10+
public static Task<int> Help(NotParsed<object> result) {
11+
var help = HelpText.AutoBuild(result, helpText => helpText
12+
.With(ht => ht.Copyright = "")
13+
.With(ht => ht.AdditionalNewLineAfterOption = false)
14+
.With(ht => ht.AddEnumValuesToHelpText = true));
15+
Console.WriteLine(help);
16+
return Task.FromResult(1);
17+
}
18+
}

mediocre/cli/List.cs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
namespace Mediocre.CLI;
2+
3+
using CommandLine.Text;
4+
5+
using System;
6+
using System.Linq;
7+
using System.Runtime.CompilerServices;
8+
using System.Threading.Tasks;
9+
10+
public partial class Commands {
11+
public static Task<int> List(ListOpts opts) => opts.What switch {
12+
ListWhat.screens => ListScreens(opts.Filter),
13+
ListWhat.devices => ListDevices(opts.Filter),
14+
_ => throw new SwitchExpressionException(opts.What)
15+
};
16+
17+
private static Task<int> ListScreens(string? filter) {
18+
Console.WriteLine(HeadingInfo.Default);
19+
Console.WriteLine();
20+
21+
foreach (var screen in Screenshot.All(filter)) {
22+
using (ConsoleWith.FG(ConsoleColor.DarkYellow).When(screen.IsPrimary)) {
23+
Console.WriteLine(
24+
$"""
25+
{screen.ScreenName}
26+
27+
upper left: ({screen.Bounds.Top}, {screen.Bounds.Left})
28+
width: {screen.Bounds.Width} px
29+
height: {screen.Bounds.Height} px
30+
31+
""");
32+
}
33+
}
34+
35+
return Task.FromResult(0);
36+
}
37+
38+
private static async Task<int> ListDevices(string? filter) {
39+
Console.WriteLine(HeadingInfo.Default);
40+
Console.WriteLine();
41+
42+
foreach (var device in await Device.All(filter)) {
43+
var props = device.Properties.Select(x => $"{x.Key} = {x.Value}").Order();
44+
var ops = device.SupportedOperations.Select(x => x.GetRealName()).Order();
45+
46+
Console.WriteLine(
47+
$"""
48+
{device}
49+
50+
id: {device.Id}
51+
name: {device.Name}
52+
model: {device.Model}
53+
firmware: {device.FirmwareVersion}
54+
hostname: {device.Hostname}
55+
port: {device.Port}
56+
properties: {props.Join("\n ")}
57+
supported commands: {ops.Join("\n ")}
58+
59+
""");
60+
}
61+
62+
return await Task.FromResult(0);
63+
}
64+
}

mediocre/cli/ListOpts.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public readonly struct ListOpts(ListWhat what, string? filter = null) {
2121
MetaName = "filter",
2222
MetaValue = "STRING",
2323
Default = null,
24-
HelpText = "Optional filter. Only list items with STRING in their name.")]
24+
HelpText = "Optional filter. Only list items with STRING in their name or model.")]
2525
public string? Filter { get; } = filter;
2626

2727
[Usage(ApplicationAlias = "mediocre")]

mediocre/cli/Print.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
namespace Mediocre.CLI;
2+
3+
using System;
4+
using System.Drawing;
5+
using System.Threading.Tasks;
6+
7+
public partial class Commands {
8+
/**
9+
* TODO:
10+
* - subtract avg calc time from delay for more accurate fps
11+
* - configurable color format
12+
*/
13+
public static async Task<int> Print(PrintOpts opts) {
14+
var screen = Screenshot.FromScreenName(opts.Screen);
15+
16+
Color? prevColor = null;
17+
var delay = 1000 / opts.Fps;
18+
19+
while (true) {
20+
screen.Refresh();
21+
22+
var color = screen.GetAverageColor(opts.SampleStep);
23+
if (color != prevColor)
24+
Console.WriteLine(color.ToRgb());
25+
26+
prevColor = color;
27+
28+
await Task.Delay(delay);
29+
}
30+
}
31+
}

0 commit comments

Comments
 (0)