Skip to content

Commit

Permalink
Refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
yannikHoeflich committed Sep 1, 2023
1 parent a9af68c commit 523d5d2
Show file tree
Hide file tree
Showing 31 changed files with 263 additions and 262 deletions.
38 changes: 19 additions & 19 deletions Tests/MatrixWeatherDisplay.UnitTests/ColorHelperTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,69 +10,69 @@

namespace MatrixWeatherDisplay.UnitTests;
public class ColorHelperTests {
private ColorHelper _colorHelper = new(new ConfigService());
private readonly ColorHelper _colorHelper = new(new ConfigService());
private Color _color;

[Fact]
public void Temperature() {
_color = _colorHelper.MapTemperature(-20);
_color = ColorHelper.MapTemperature(-20);
Assert.Equal(Color.FromRgb(0, 0, 255), _color);

_color = _colorHelper.MapTemperature(-10);
_color = ColorHelper.MapTemperature(-10);
Assert.Equal(Color.FromRgb(0, 0, 255), _color);

_color = _colorHelper.MapTemperature(45);
_color = ColorHelper.MapTemperature(45);
Assert.Equal(Color.FromRgb(255, 0, 0), _color);

_color = _colorHelper.MapTemperature(55);
_color = ColorHelper.MapTemperature(55);
Assert.Equal(Color.FromRgb(255, 0, 0), _color);
}

[Fact]
public void Hour() {
_color = _colorHelper.MapHour(0);
_color = ColorHelper.MapHour(0);
Assert.Equal(Color.FromRgb(0, 0, 255), _color);

_color = _colorHelper.MapHour(4);
_color = ColorHelper.MapHour(4);
Assert.Equal(Color.FromRgb(255, 0, 255), _color);

_color = _colorHelper.MapHour(8);
_color = ColorHelper.MapHour(8);
Assert.Equal(Color.FromRgb(255, 0, 0), _color);

_color = _colorHelper.MapHour(12);
_color = ColorHelper.MapHour(12);
Assert.Equal(Color.FromRgb(255, 255, 0), _color);

_color = _colorHelper.MapHour(16);
_color = ColorHelper.MapHour(16);
Assert.Equal(Color.FromRgb(0, 255, 0), _color);

_color = _colorHelper.MapHour(20);
_color = ColorHelper.MapHour(20);
Assert.Equal(Color.FromRgb(0, 255, 255), _color);

_color = _colorHelper.MapHour(24);
_color = ColorHelper.MapHour(24);
Assert.Equal(Color.FromRgb(0, 0, 255), _color);
}

[Fact]
public void Minute() {
_color = _colorHelper.MapMinute(0);
_color = ColorHelper.MapMinute(0);
Assert.Equal(Color.FromRgb(255, 0, 0), _color);

_color = _colorHelper.MapMinute(10);
_color = ColorHelper.MapMinute(10);
Assert.Equal(Color.FromRgb(255, 255, 0), _color);

_color = _colorHelper.MapMinute(20);
_color = ColorHelper.MapMinute(20);
Assert.Equal(Color.FromRgb(0, 255, 0), _color);

_color = _colorHelper.MapMinute(30);
_color = ColorHelper.MapMinute(30);
Assert.Equal(Color.FromRgb(0, 255, 255), _color);

_color = _colorHelper.MapMinute(40);
_color = ColorHelper.MapMinute(40);
Assert.Equal(Color.FromRgb(0, 0, 255), _color);

_color = _colorHelper.MapMinute(50);
_color = ColorHelper.MapMinute(50);
Assert.Equal(Color.FromRgb(255, 0, 255), _color);

_color = _colorHelper.MapMinute(60);
_color = ColorHelper.MapMinute(60);
Assert.Equal(Color.FromRgb(255, 0, 0), _color);
}
}
10 changes: 5 additions & 5 deletions Tests/MatrixWeatherDisplay.UnitTests/ImageHelperTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@

namespace MatrixWeatherDisplay.UnitTests;
public class ImageHelperTests {
Image<Rgb24> _image;
Random _random = new Random(420);
readonly Image<Rgb24> _image;
readonly Random _random = new(420);

public ImageHelperTests() {
_image = new Image<Rgb24>(16, 16);
Expand All @@ -29,13 +29,13 @@ public ImageHelperTests() {
[Fact]
public void SetColor() {
var color = Color.FromRgb(255, 0, 0);
var testPixelColor = color.ToPixel<Rgb24>();
var testPixelBlack = Color.Black.ToPixel<Rgb24>();
Rgb24 testPixelColor = color.ToPixel<Rgb24>();
Rgb24 testPixelBlack = Color.Black.ToPixel<Rgb24>();
ImageHelper.SetColor(_image, color);

for (int y = 0; y < _image.Height; y++) {
for (int x = 0; x < _image.Width; x++) {
var pixel = _image[x, y];
Rgb24 pixel = _image[x, y];
if(pixel != testPixelColor && pixel != testPixelBlack) {
Assert.Fail($"Each pixel must be either {color} or black");
}
Expand Down
16 changes: 7 additions & 9 deletions src/MatrixWeatherDisplay/Data/Converter/ColorHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,28 @@ public class ColorHelper: IInitializable {

public ConfigLayout ConfigLayout { get; } = new() {
ConfigName = s_configName,
Keys = new ConfigKey[] { }
Keys = Array.Empty<ConfigKey>()
};
public ColorHelper(ConfigService configService) {
_configService = configService;
}

public InitResult Init() {
RawConfig? config = _configService.GetConfig(s_configName);
if(config is null) {
return InitResult.NoConfig();
}

return InitResult.Success;
return config is not null
? InitResult.Success
: InitResult.NoConfig();
}


public Color MapTemperature(int temperature)
public static Color MapTemperature(int temperature)
=> MapColor(temperature, -10, 45, 240, 0);


public Color MapHour(double hours)
public static Color MapHour(double hours)
=> MapColor(hours, 0, 24, 240, 240 + 360);

public Color MapMinute(double minutes)
public static Color MapMinute(double minutes)
=> MapColor(minutes, 0, 60, 0, 360);


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

namespace MatrixWeatherDisplay.DependencyInjection;
public partial class DisplayApplication {
private static async Task<bool> ShouldScreenGeneratorSkipAsync(InternetService? internetService, IScreenGenerator? screenGenerator)
private static async Task<bool> ShouldScreenGeneratorSkipAsync(InternetService? internetService, [NotNullWhen(false)] IScreenGenerator? screenGenerator)
=> screenGenerator is null ||
screenGenerator.ScreenTime <= TimeSpan.Zero ||
!screenGenerator.IsEnabled ||
Expand All @@ -22,71 +22,20 @@ private static async Task<bool> ShouldScreenGeneratorSkipAsync(InternetService?
private static async Task<bool> HasInternetErrorAsync(IScreenGenerator screenGenerator, InternetService? internetService) {
return internetService is not null &&
screenGenerator.RequiresInternet &&
!await internetService.HasInternetConnection();
!await internetService.HasInternetConnectionAsync();
}

private async Task<bool> LogIfSkippedLastAsync(int skips, IScreenGenerator? screenGenerator) {
if (skips > 0) {
_logger.LogDebug("Skipping screen '{screenName}'", screenGenerator?.GetType().Name);
_logger?.LogDebug("Skipping screen '{screenName}'", screenGenerator?.GetType().Name);
}

if (skips > ScreenGenerators.ScreenGeneratorCount) {
_logger.LogInformation("Skipped all screen generators, waiting 30 Seconds to retry");
_logger?.LogInformation("Skipped all screen generators, waiting 30 Seconds to retry");
await Extensions.SleepAsync(TimeSpan.FromSeconds(30), () => !_shouldRun);
return true;
}

return false;
}


private bool HandleInitResult(IInitializable service, InitResult result) => HandleInitResult(GetName(service), result);
private bool HandleInitResult(IAsyncInitializable service, InitResult result) => HandleInitResult(GetName(service), result);

private bool HandleInitResult(string name, InitResult result) {
if (result == InitResult.Success) {
return false;
}

if (result.ResultType == InitResultType.Warning) {
_logger.LogInformation("Warning initializing {serviceName}: {message}", name, result.Message.GetText(LanguageCode.EN));
return false;
}
if (result.ResultType == InitResultType.Error) {
_logger.LogWarning("Error initializing {serviceName}: {message}", name, result.Message.GetText(LanguageCode.EN));
return false;
}

if (result.ResultType == InitResultType.Critical) {
_logger.LogCritical("Critical error initializing {serviceName}: {message}", name, result.Message.GetText(LanguageCode.EN));
_logger.LogCritical("Stopping!");
_ = StopAsync();
return true;
}

_logger.LogInformation("Unknown result from initializing {serviceName}: {message}", name, result.Message.GetText(LanguageCode.EN));
return false;
}

private string GetName(IAsyncInitializable service) {
return TryGetNameFromConfig(service.ConfigLayout, out string? name)
? name
: service.GetType().Name;
}

private string GetName(IInitializable service) {
return TryGetNameFromConfig(service.ConfigLayout, out string? name)
? name
: service.GetType().Name;
}

private bool TryGetNameFromConfig(ConfigLayout configLayout, [NotNullWhen(true)] out string? name) {
if(configLayout is not null && !string.IsNullOrWhiteSpace(configLayout.ConfigName)) {
name = configLayout.ConfigName;
return true;
}

name = null;
return false;
}
}
62 changes: 24 additions & 38 deletions src/MatrixWeatherDisplay/DependencyInjection/DisplayApplication.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System.Xml.Serialization;
using System.Data.SqlTypes;
using System.Xml.Serialization;

using MatrixWeatherDisplay.Data;
using MatrixWeatherDisplay.DependencyInjection.Helper;
using MatrixWeatherDisplay.DependencyInjection.ScreenGeneratorCollections;
using MatrixWeatherDisplay.Screens;
using MatrixWeatherDisplay.Services;
Expand All @@ -23,7 +25,7 @@ public partial class DisplayApplication {
internal ServiceDescriptor[]? Initializables { get; init; }
internal ServiceDescriptor[]? AsyncInitializables { get; init; }

private ILogger _logger;
private ILogger? _logger;

private bool _running = false;
private bool _shouldRun = false;
Expand All @@ -42,56 +44,40 @@ internal DisplayApplication(IServiceProvider services, IScreenGeneratorProvider
/// <returns>true if the code flow should be continued, false if a critical error accured and the program should not be started.</returns>
/// <exception cref="InvalidOperationException"></exception>
public async Task<bool> InitDefaultServicesAsync() {
ConfigService configService = Services.GetService<ConfigService>() ?? throw new InvalidOperationException("The service 'ConfigService' has to be registered");
if (Initializables is null || AsyncInitializables is null) {
_logger?.LogCritical("The display application didn't get information about services to initialize.");
return false;
}

IEnumerable<IInitializable> initializables = Initializables.Select(x => x.GetService(Services)).OfType<IInitializable>().ToArray();
IEnumerable<IAsyncInitializable> asyncInitializables = AsyncInitializables.Select(x => x.GetService(Services)).OfType<IAsyncInitializable>().ToArray();
var serviceInitializer = new ServiceInitializer(Services, Initializables, AsyncInitializables);

var configLayouts = initializables.Select(x => x.ConfigLayout).Concat(
asyncInitializables.Select(x => x.ConfigLayout))
.Where(x => x != ConfigLayout.Empty && x.Keys.Length > 0)
.DistinctBy(x => x.Keys)
.ToList();
IReadOnlyCollection<ConfigLayout> configLayouts = serviceInitializer.GetConfigLayouts();

ConfigService configService = Services.GetService<ConfigService>() ?? throw new InvalidOperationException("The service 'ConfigService' has to be registered");
await configService.InitAsync(configLayouts);

ILogger<DisplayApplication>? newLogger = Services.GetService<ILogger<DisplayApplication>>();
if (newLogger is not null) {
_logger = newLogger;
serviceInitializer.Logger = _logger;
}

BrightnessService autoBrightnessService = Services.GetService<BrightnessService>() ?? throw new InvalidOperationException("The Service of type 'AutoBrightnessService' must be registered");
RedManager = new RedSettings(autoBrightnessService);

if (Initializables is not null) {
foreach (IInitializable service in initializables) {
InitResult result = service.Init();
if(HandleInitResult(service, result)) {
return false;
}
}
}

if (AsyncInitializables is not null) {
foreach (IAsyncInitializable service in asyncInitializables) {
InitResult result = await service.InitAsync();
if (HandleInitResult(service, result)) {
return false;
}
}
}

bool result = await serviceInitializer.InitAllAsync();
await configService.SaveAsync();
return true;
return result;
}

public async Task RunAsync() {
if (_running) {
_logger.LogInformation("Already running");
_logger?.LogInformation("Already running");
return;
}

_logger.LogInformation("Starting up");
_logger?.LogInformation("Starting up");

_running = true;
_shouldRun = true;
Expand Down Expand Up @@ -122,9 +108,9 @@ private async Task ShowNextScreenAndWaitAsync(DeviceService deviceService, Inter
}

private async Task SendScreenAsync(DeviceService deviceService, ByteScreen screen) {
_logger.LogTrace("sending gif");
_logger?.LogTrace("sending gif");
await deviceService.SendGifAsync(screen.Image);
_logger.LogTrace("waiting {screen time}ms", screen.ScreenTime.TotalMilliseconds);
_logger?.LogTrace("waiting {screen time}ms", screen.ScreenTime.TotalMilliseconds);
SetWaitUntil(screen.ScreenTime);
}

Expand All @@ -137,7 +123,7 @@ private async Task SendScreenAsync(DeviceService deviceService, ByteScreen scree
}

screenGenerator = ScreenGenerators.GetNextScreenGenerator();
_logger.LogTrace("Trying to show '{screen}'", screenGenerator?.Name);
_logger?.LogTrace("Trying to show '{screen}'", screenGenerator?.Name);

if (await ShouldScreenGeneratorSkipAsync(internetService, screenGenerator)) {
skips++;
Expand All @@ -151,7 +137,7 @@ private async Task SendScreenAsync(DeviceService deviceService, ByteScreen scree
Screen rawScreen = await screenGenerator.GenerateImageAsync();
screen = await ByteScreen.FromScreenAsync(rawScreen, turnRed);
} catch (Exception ex) {
_logger.LogError("Error creating next screen {ex}", ex);
_logger?.LogError("Error creating next screen {ex}", ex);
screen = null;
}

Expand All @@ -167,15 +153,15 @@ private async Task SendScreenAsync(DeviceService deviceService, ByteScreen scree
}

public async Task StopAsync() {
_logger.LogInformation($"Stopping");
_logger?.LogInformation($"Stopping");
_shouldRun = false;

await Extensions.SleepAsync(TimeSpan.FromSeconds(1), () => !_running);

if (_running) {
_logger.LogError($"Didn't stop after 1 Seconds.");
_logger.LogError($"Probably stuck in a task or already stopped because of an error!");
_logger.LogError($"Pretending to be stopped!");
_logger?.LogError($"Didn't stop after 1 Seconds.");
_logger?.LogError($"Probably stuck in a task or already stopped because of an error!");
_logger?.LogError($"Pretending to be stopped!");
_running = false;
}
}
Expand Down
Loading

0 comments on commit 523d5d2

Please sign in to comment.