-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3 from timia2109/feature/mqtt
Feature/mqtt
- Loading branch information
Showing
10 changed files
with
429 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
using SkiaSharp; | ||
|
||
namespace DisplayUtil.MqttExport; | ||
|
||
/// <summary> | ||
/// Responsible to render the Bitmap to the two color stream | ||
/// </summary> | ||
public static class BinaryImageStreamCreator | ||
{ | ||
|
||
public static byte[] GetImageStream(SKBitmap bitmap) | ||
{ | ||
var pixelWriter = new PixelWriter(); | ||
|
||
var width = bitmap.Width; | ||
var height = bitmap.Height; | ||
|
||
// The stream is width -> height | ||
for (var y = 1; y <= height; y++) | ||
{ | ||
for (var x = 1; x <= width; x++) | ||
{ | ||
var pixel = bitmap.GetPixel(x, y); | ||
pixelWriter.WritePixel(pixel); | ||
} | ||
} | ||
|
||
return pixelWriter.ToArray(); | ||
} | ||
|
||
private class PixelWriter | ||
{ | ||
public void WritePixel(SKColor color) | ||
{ | ||
var luma = 0.2126 * color.Red | ||
+ 0.7152 * color.Green | ||
+ 0.0722 * color.Blue; | ||
|
||
WriteBit(luma < 40); | ||
} | ||
|
||
private readonly MemoryStream _stream; | ||
private byte _currentByte; | ||
private int _bitsFilled; | ||
|
||
public PixelWriter() | ||
{ | ||
_stream = new MemoryStream(); | ||
_currentByte = 0; | ||
_bitsFilled = 0; | ||
} | ||
|
||
public void WriteBit(bool bit) | ||
{ | ||
// Shift the current byte to the left by 1 and add the new bit on the end. | ||
_currentByte = (byte)((_currentByte << 1) | (bit ? 1 : 0)); | ||
_bitsFilled++; | ||
|
||
// If the current byte is full (contains 8 bits), write it to the stream. | ||
if (_bitsFilled == 8) | ||
{ | ||
_stream.WriteByte(_currentByte); | ||
// Reset for the next byte. | ||
_currentByte = 0; | ||
_bitsFilled = 0; | ||
} | ||
} | ||
|
||
public byte[] ToArray() | ||
{ | ||
// If there are any bits that haven't been written yet because they didn't make up a full byte, | ||
// write them now. This will effectively pad the last byte with zeroes if it's not full. | ||
if (_bitsFilled > 0) | ||
{ | ||
_currentByte = (byte)(_currentByte << (8 - _bitsFilled)); | ||
_stream.WriteByte(_currentByte); | ||
_currentByte = 0; | ||
_bitsFilled = 0; | ||
} | ||
|
||
return _stream.ToArray(); | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
using System.Diagnostics; | ||
using DisplayUtil.Scenes; | ||
|
||
namespace DisplayUtil.MqttExport; | ||
|
||
/// <summary> | ||
/// Responsible to provide the images in a form for the ESP. | ||
/// Scoped | ||
/// </summary> | ||
public partial class EspImageProvider( | ||
ILogger<MqttExporter> logger, | ||
ScreenRepository screenRepository | ||
) | ||
{ | ||
private readonly ILogger _logger = logger; | ||
|
||
/// <summary> | ||
/// Gets the image as plain true / false Bytes | ||
/// </summary> | ||
/// <param name="providerId">Id of the provider</param> | ||
/// <returns>Byte Array</returns> | ||
public async Task<byte[]> GetAsPlainBytesAsync(string providerId) | ||
{ | ||
var stopwatch = new Stopwatch(); | ||
LogRender(providerId); | ||
stopwatch.Start(); | ||
|
||
//Render | ||
using var image = await screenRepository.GetImageAsync(providerId); | ||
stopwatch.Stop(); | ||
var elapsed = stopwatch.ElapsedMilliseconds; | ||
LogRenderTime(elapsed); | ||
|
||
var binaryData = BinaryImageStreamCreator.GetImageStream(image); | ||
LogPlainBytes(binaryData.Length); | ||
return binaryData; | ||
} | ||
|
||
/// <summary> | ||
/// Gets the Image as RunLength Compressed | ||
/// </summary> | ||
/// <param name="providerId">Id of the provider</param> | ||
/// <returns>Compressed Data</returns> | ||
public async Task<byte[]> GetAsRunLengthAsync(string providerId) | ||
{ | ||
var plainBytes = await GetAsPlainBytesAsync(providerId); | ||
|
||
var runLengthEncoder = new RunLengthCompressor(); | ||
var compressedData = runLengthEncoder.WriteStream(plainBytes); | ||
|
||
var compressedPercent = compressedData.Length / (float)plainBytes.Length; | ||
LogCompressedBytes( | ||
compressedData.Length, | ||
Math.Round((1 - compressedPercent) * 100, 2) | ||
); | ||
|
||
return compressedData; | ||
} | ||
|
||
|
||
[LoggerMessage(LogLevel.Information, "Render screen {providerId}")] | ||
private partial void LogRender(string providerId); | ||
|
||
[LoggerMessage(LogLevel.Information, "Rendering took {time} ms")] | ||
private partial void LogRenderTime(long time); | ||
|
||
[LoggerMessage(LogLevel.Information, "Plain binary takes {bytes} bytes")] | ||
private partial void LogPlainBytes(int bytes); | ||
|
||
[LoggerMessage(LogLevel.Information, "Compressing takes {bytes} bytes ({percent} % less)")] | ||
private partial void LogCompressedBytes(int bytes, double percent); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
using Microsoft.Extensions.Options; | ||
using MQTTnet.Client; | ||
using MQTTnet.Protocol; | ||
|
||
namespace DisplayUtil.MqttExport; | ||
|
||
/// <summary> | ||
/// Responsible to export the Image to Mqtt | ||
/// </summary> | ||
public partial class ExportingMqttClient( | ||
IMqttClient client, | ||
MqttClientOptions clientOptions, | ||
IOptions<MqttSettings> settings, | ||
ILogger<ExportingMqttClient> logger | ||
) | ||
{ | ||
|
||
private readonly ILogger _logger = logger; | ||
|
||
private async Task EnsureConnectedAsync() | ||
{ | ||
if (!client.IsConnected) | ||
{ | ||
LogConnecting(); | ||
await client.ConnectAsync(clientOptions); | ||
} | ||
} | ||
|
||
public async Task SendAsync(byte[] data) | ||
{ | ||
await EnsureConnectedAsync(); | ||
|
||
await client.PublishBinaryAsync( | ||
settings.Value.Topic | ||
?? throw new ArgumentNullException(nameof(settings.Value.Topic)), | ||
data, | ||
MqttQualityOfServiceLevel.AtLeastOnce | ||
); | ||
} | ||
|
||
[LoggerMessage(LogLevel.Information, "Connecting to Mqtt Server")] | ||
private partial void LogConnecting(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
using System.Diagnostics; | ||
using DisplayUtil.Scenes; | ||
using MQTTnet.Client; | ||
|
||
namespace DisplayUtil.MqttExport; | ||
|
||
/// <summary> | ||
/// Responsible to export the image to Mqtt. | ||
/// Scoped | ||
/// </summary> | ||
public class MqttExporter( | ||
EspImageProvider espImageProvider, | ||
ExportingMqttClient exportingMqttClient | ||
) | ||
{ | ||
public async Task ExportScreenToMqtt(string providerId) | ||
{ | ||
var data = await espImageProvider.GetAsRunLengthAsync(providerId); | ||
await exportingMqttClient.SendAsync(data); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
using System.Security.Cryptography.X509Certificates; | ||
using MQTTnet; | ||
using MQTTnet.Client; | ||
|
||
namespace DisplayUtil.MqttExport; | ||
|
||
public static class MqttInitExtension | ||
{ | ||
public static IHostApplicationBuilder AddMqttWriter(this IHostApplicationBuilder builder) | ||
{ | ||
builder.Services.Configure<MqttSettings>( | ||
builder.Configuration.GetSection("Mqtt")); | ||
|
||
if (!CreateMqttClient(builder)) | ||
{ | ||
return builder; | ||
} | ||
|
||
return builder; | ||
} | ||
|
||
private static bool CreateMqttClient(IHostApplicationBuilder builder) | ||
{ | ||
var settings = builder.Configuration.GetSection("Mqtt") | ||
.Get<MqttSettings>(); | ||
|
||
if (settings is null || settings.Uri is null) | ||
return false; | ||
|
||
var factory = new MqttFactory(); | ||
|
||
var client = factory.CreateMqttClient(); | ||
|
||
var clientOptions = new MqttClientOptionsBuilder() | ||
.WithTcpServer(settings.Uri) | ||
.WithClientId("displayutil_" + builder.Environment.EnvironmentName) | ||
.WithCredentials(settings.User, settings.Password) | ||
.Build(); | ||
|
||
if (client is null || clientOptions is null) | ||
throw new Exception("Error creating MQTT instances"); | ||
|
||
builder.Services | ||
.AddSingleton(client) | ||
.AddSingleton(clientOptions) | ||
.AddSingleton<ExportingMqttClient>() | ||
.AddScoped<EspImageProvider>() | ||
.AddScoped<MqttExporter>(); | ||
|
||
return true; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
namespace DisplayUtil.MqttExport; | ||
|
||
public record MqttSettings | ||
{ | ||
public string? Uri { get; init; } | ||
public string? User { get; init; } | ||
public string? Password { get; init; } | ||
public string? Topic { get; init; } | ||
public string? ScreenDetectTemplate { get; init; } | ||
} |
Oops, something went wrong.