Skip to content

Commit

Permalink
Merge pull request #8 from timia2109/feature/prod-templates
Browse files Browse the repository at this point in the history
Feature/prod templates
  • Loading branch information
timia2109 authored Apr 8, 2024
2 parents 0ac479b + c373177 commit f9db9ed
Show file tree
Hide file tree
Showing 17 changed files with 200 additions and 72 deletions.
17 changes: 16 additions & 1 deletion HomeAssistant/HassTemplateExtender.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Globalization;
using DisplayUtil.Template;
using NetDaemon.HassModel;
using Scriban.Runtime;
Expand All @@ -14,6 +15,7 @@ public void Enrich(ScriptObject context, EnrichScope scope)
hassObject.Import("get_state", GetState);
hassObject.Import("get_attribute", GetAttribute);
hassObject.Import("get_float_state", GetFloatState);
hassObject.Import("get_datetime", GetDateTime);
context.Add("hass", hassObject);
}

Expand All @@ -39,8 +41,21 @@ private float GetFloatState(string entityId)
{
var state = GetState(entityId);
if (state == null) return 0f;
return TemplateContextProvider.ToFloat(state);
return UtilTemplateExtender.ToFloat(state);
}

private DateTime? GetDateTime(string entityId)
{
var state = GetState(entityId);
if (state is null) return null;

if (!DateTime.TryParseExact(state,
"yyyy-MM-dd HH:mm:ss",
CultureInfo.GetCultureInfo("de-DE"),
DateTimeStyles.None,
out var dt))
return null;

return dt;
}
}
10 changes: 10 additions & 0 deletions Layouting/ElementCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,16 @@ public ElementCollection Append(Element element)
return this;
}

/// <summary>
/// Add all Elements to this Collection
/// </summary>
/// <param name="elements">The elements</param>
public ElementCollection Append(IEnumerable<Element> elements)
{
Children.AddRange(elements);
return this;
}

protected override SKSize CalculateSize(DrawContext drawContext)
{
var childContext = BuildChildDrawContext(drawContext);
Expand Down
4 changes: 4 additions & 0 deletions MqttExport/MqttExportJob.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.Extensions.Options;
using NetDaemon.HassModel;

namespace DisplayUtil.MqttExport;

Expand All @@ -7,10 +8,13 @@ public class MqttExportJob(
IOptions<MqttSettings> optionsSnapshot
) : IHostedService
{
private static readonly TimeSpan InitTimeout = TimeSpan.FromSeconds(5);
private CancellationTokenSource? _cancellationTokenSource;

private async Task RunAsync(CancellationToken cancellation)
{
await Task.Delay(InitTimeout);

while (!cancellation.IsCancellationRequested)
{
await using (var scope = scopeFactory.CreateAsyncScope())
Expand Down
44 changes: 5 additions & 39 deletions MqttExport/MqttExporter.cs
Original file line number Diff line number Diff line change
@@ -1,63 +1,29 @@
using System.Diagnostics;
using DisplayUtil.EspUtilities;
using DisplayUtil.Scenes;
using Microsoft.Extensions.Options;
using MQTTnet.Client;

namespace DisplayUtil.MqttExport;

/// <summary>
/// Responsible to export the image to Mqtt.
/// Scoped
/// </summary>
public class MqttExporter(
ExportingMqttClient exportingMqttClient,
IOptions<MqttSettings> options
ExportingMqttClient exportingMqttClient
)
{
public Task ExportUriToMqtt(string providerId)
{
var settings = options.Value;

var query = providerId.IndexOf('?');
var providerPath = query == -1
? providerId
: providerId[0..(query - 1)];

var uriBuilder = new UriBuilder
{
Port = 80,
Scheme = "http",
Host = settings.ServerHostName,
Path = EspUtilitiesInitExtension.CompressedImageRoute
};

uriBuilder.Path = EspUtilitiesInitExtension.CompressedImageRoute
.Replace("{providerId}", providerPath);

if (query != -1)
uriBuilder.Query = providerId[query..];

return SubmitAsync(uriBuilder.Uri);
}

public virtual async Task SubmitAsync(Uri uri)
public virtual async Task PublishUriToMqttAsync(Uri uri)
{
await exportingMqttClient.SendAsync(uri.ToString());
}
}

internal partial class CachedMqttExporter(
ExportingMqttClient exportingMqttClient,
IOptions<MqttSettings> options,
ILogger<CachedMqttExporter> logger)
: MqttExporter(exportingMqttClient, options)
: MqttExporter(exportingMqttClient)
{
private readonly ILogger _logger = logger;

private Uri? _lastSubmission;

public override Task SubmitAsync(Uri uri)
public override Task PublishUriToMqttAsync(Uri uri)
{
if (_lastSubmission == uri)
{
Expand All @@ -67,7 +33,7 @@ public override Task SubmitAsync(Uri uri)

LogSubmitting(uri);
_lastSubmission = uri;
return base.SubmitAsync(uri);
return base.PublishUriToMqttAsync(uri);
}

[LoggerMessage(LogLevel.Debug, "Skipping resubmission of {uri}")]
Expand Down
19 changes: 19 additions & 0 deletions MqttExport/MqttInitExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,23 @@ MqttSettings settings

return true;
}

public static WebApplication UseMqttWriter(this WebApplication app)
{
if (app.Services.GetService<MqttExporter>() is null) return app;

app.MapGet("/mqtt/uri", async (MqttUrlRenderer renderer) =>
{
return Results.Ok(await renderer.GetMqttTemplateUriAsync());
})
.WithName("Get MQTT URI")
.WithOpenApi();

app.MapGet("/mqtt/template", async (MqttUrlRenderer renderer)
=> Results.Ok(await renderer.GetMqttTemplateAsync()))
.WithName("Get MQTT Template")
.WithOpenApi();

return app;
}
}
45 changes: 39 additions & 6 deletions MqttExport/MqttUrlRenderer.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using DisplayUtil.EspUtilities;
using DisplayUtil.Template;
using Microsoft.Extensions.Options;

Expand All @@ -9,19 +10,51 @@ public class MqttUrlRenderer(
IOptionsSnapshot<MqttSettings> options
)
{
public async Task<Uri> GetMqttTemplateUriAsync()
{
var providerId = await GetMqttTemplateAsync();

/// <summary>
/// Exports the Uri to MQTT
/// </summary>
/// <returns>Task</returns>
public async Task RenderUrlAndPublish()
var settings = options.Value;

var query = providerId.IndexOf('?');
var providerPath = query == -1
? providerId
: providerId[0..query];

var uriBuilder = new UriBuilder
{
Port = 80,
Scheme = "http",
Host = settings.ServerHostName,
Path = EspUtilitiesInitExtension.CompressedImageRoute
};

uriBuilder.Path = EspUtilitiesInitExtension.CompressedImageRoute
.Replace("{providerId}", providerPath);

if (query != -1)
uriBuilder.Query = providerId[query..];

return uriBuilder.Uri;
}

public async Task<string> GetMqttTemplateAsync()
{
var template = options.Value.ScreenDetectTemplate!;

var result = await renderer.RenderAsync(template,
EnrichScope.TemplateProvider);

await exporter.ExportUriToMqtt(result);
return result.Trim();
}

/// <summary>
/// Exports the Uri to MQTT
/// </summary>
/// <returns>Task</returns>
public async Task RenderUrlAndPublish()
{
await exporter.PublishUriToMqttAsync(await GetMqttTemplateUriAsync());
}

}
6 changes: 4 additions & 2 deletions Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
.AddSingleton<TemplateLoader>();

builder.Services.AddScoped<TemplateRenderer>()
.AddScoped<TemplateContextProvider>();
.AddScoped<TemplateContextProvider>()
.AddSingleton<ITemplateExtender, UtilTemplateExtender>();

builder.Services.AddTransient<FaIconDrawer>();

Expand All @@ -48,7 +49,8 @@
.WithName("Preview Image")
.WithOpenApi();

app.UseEspUtilities();
app.UseEspUtilities()
.UseMqttWriter();
app.UseStaticFiles();

app.Run();
12 changes: 6 additions & 6 deletions Resources/screens/_icon_data.sbntxt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{{ func icon_data(sIconName, sText) }}
{{ if (sText | string.strip | string.size ) > 0}}
<HBox Gap="2">
<Icon IconName="{{sIconName}}" />
<Text Content="{{sText}}" />
</HBox>
{{ end }}
{{ if (sText | string.strip | string.size ) > 0}}
<HBox Gap="2">
<Icon IconName="{{sIconName}}" />
<Text Content="{{sText | html.escape}}" />
</HBox>
{{ end }}
{{ end }}
5 changes: 3 additions & 2 deletions Resources/screens/_media_player.sbntxt
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,15 @@
{{ if state == "playing"
media_position = hass.get_attribute sPlayer "media_position" | to_float
media_duration = hass.get_attribute sPlayer "media_duration" | to_float
media_duration_ts = timespan.from_seconds media_duration
media_updated = hass.get_attribute sPlayer "media_position_updated_at" | date.parse

media_start = media_updated | date.add_seconds (-media_position)
media_end = media_start | date.add_seconds media_duration
}}
<Flexbox>
<Text Content="{{ media_updated | date.to_string "%T" }}" />
<Text Content="{{ media_end | date.to_string "%T" }}" />
{{ icon_data "timer" (timespan.to_string media_duration_ts "c") }}
{{ icon_data "clock" (media_end | date.to_string "%T") }}
</Flexbox>
{{ else if state == "paused"
icon_data "pause" " -&gt; Pausiert &lt;- "
Expand Down
20 changes: 20 additions & 0 deletions Resources/screens/_timer.sbntxt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{{ func timer() }}
{{
start_time = hass.get_datetime "input_datetime.googletimerstart"
end_time = hass.get_datetime "input_datetime.googletimerover"
timer_text = hass.get_state "input_text.countdown_text"
}}

{{ if start_time.year < 2000
ret 0
end}}

<VBox Gap="5">
<Text Content="{{ timer_text | html.escape }}" />
{{ icon_data "hourglass-start" (start_time | date.to_string "%T") }}
{{ icon_data "hourglass-end" (end_time | date.to_string "%T") }}
</VBox>

{{ ret 1 }}

{{ end }}
8 changes: 8 additions & 0 deletions Resources/screens/export_screen.sbntxt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{{
state = hass.get_state "sensor.wohnzimmer_display_mode"
}}
{{ if state == "Normal" }}
main?version={{ date.to_string date.now "%s" }}
{{ else }}
{{ state | string.downcase }}
{{ end }}
12 changes: 12 additions & 0 deletions Resources/screens/idle.sbntxt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Screen Height="800" Width="480">
<Defaults TextSize="40" IconHeight="40" />

<Flexbox Direction="Vertical" AlignItems="Center">
<Margin All="15" />

<Icon IconName="person-circle-question" Height="200" />
<Text Content="Niemand da!" Font="ProductSansBold" Size="40" />
<Text Content="Der Bildschirm ist aus" />
</Flexbox>

</Screen>
16 changes: 11 additions & 5 deletions Resources/screens/main.sbntxt
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
{{
include "_media_player"
include "_icon_data"
include "_timer"

items = 0

media_players = [
"media_player.buro",
Expand Down Expand Up @@ -31,19 +34,22 @@
<Border Bottom="2" />
</Flexbox>

<Flexbox AlignItems="Center">
<Flexbox>
{{ icon_data "couch" (hass.get_float_state "sensor.smart_hygrometer_0998_temperature" | math.round 2) + " °C"}}
{{ icon_data "cloud-sun" (hass.get_float_state "sensor.hue_outdoor_motion_sensor_1_temperature" | math.round 2) + " °C"}}
</Flexbox>

<Flexbox>
{{ icon_data "dumbbell" (hass.get_state "sensor.fitx_auslastung") + "%" }}
</Flexbox>

</VBox>

{{ for player in media_players
media_player player
end
}}
items += media_player player
end }}

<Text Content="Placeholder" />
{{ items += timer }}

<Margin All="1" />
</Flexbox>
Expand Down
12 changes: 12 additions & 0 deletions Resources/screens/night.sbntxt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Screen Height="800" Width="480">
<Defaults TextSize="40" IconHeight="40" />

<Flexbox Direction="Vertical" AlignItems="Center">
<Margin All="15" />

<Icon IconName="house-night" Height="200" />
<Text Content="Nachtmodus aktiv!" Font="ProductSansBold" Size="40" />
<Text Content="Der Bildschirm ist aus" />
</Flexbox>

</Screen>
Loading

0 comments on commit f9db9ed

Please sign in to comment.