Skip to content

Commit c4b819e

Browse files
authored
Electronics TIme Updates: (#157)
* Send admin password from config to client * Only trigger status updates to the client if something changes * Send client status to Home Assistant * Misc code cleanup * Update NuGet's
1 parent ebdbe26 commit c4b819e

File tree

12 files changed

+104
-22
lines changed

12 files changed

+104
-22
lines changed

.editorconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ csharp_style_namespace_declarations = file_scoped:silent
315315
csharp_style_prefer_method_group_conversion = true:silent
316316
csharp_style_prefer_top_level_statements = true:silent
317317
csharp_style_prefer_primary_constructors = true:suggestion
318+
dotnet_diagnostic.SA1010.severity = none
318319

319320

320321
[/src/*Controller.cs]

NuttyTree.NetDaemon.sln

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{1E435BC4
99
EndProject
1010
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{08A2828C-5FD1-4917-B92E-A65EB0BC182C}"
1111
ProjectSection(SolutionItems) = preProject
12+
.editorconfig = .editorconfig
1213
Directory.Build.props = Directory.Build.props
1314
build\Dockerfile = build\Dockerfile
1415
EndProjectSection

src/NuttyTree.NetDaemon.Application/ElectronicsTime/ElectronicsTimeApp.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ internal sealed class ElectronicsTimeApp : IDisposable
3636

3737
private readonly string? chrisUserId;
3838

39-
private readonly List<IDisposable> toDoListUpdateTriggers = new List<IDisposable>();
39+
private readonly List<IDisposable> toDoListUpdateTriggers = [];
4040

41-
private readonly List<IDisposable> taskTriggers = new List<IDisposable>();
41+
private readonly List<IDisposable> taskTriggers = [];
4242

4343
private readonly ITriggerableTask updateToDoListTask;
4444

src/NuttyTree.NetDaemon.Application/ElectronicsTime/Options/ElectronicsTimeOptions.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ namespace NuttyTree.NetDaemon.Application.ElectronicsTime.Options;
44

55
internal sealed class ElectronicsTimeOptions
66
{
7-
public IList<RecurringToDoListItem> ToDoListItems { get; set; } = new List<RecurringToDoListItem>();
7+
public IList<RecurringToDoListItem> ToDoListItems { get; set; } = [];
88

9-
public IList<AllowedApplication> Applications { get; set; } = new List<AllowedApplication>();
9+
public string AdminPassword { get; set; } = string.Empty;
10+
11+
public string WebhookId { get; set; } = string.Empty;
12+
13+
public IList<AllowedApplication> Applications { get; set; } = [];
1014
}

src/NuttyTree.NetDaemon.Application/ElectronicsTime/gRPC/ElectronicsTimeGrpcService.cs

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
using Grpc.Core;
1+
using FluentDateTime;
2+
using Grpc.Core;
23
using Microsoft.Extensions.Options;
34
using NuttyTree.NetDaemon.Application.ElectronicsTime.Options;
5+
using NuttyTree.NetDaemon.ExternalServices.HomeAssistantWebhook;
46
using NuttyTree.NetDaemon.Infrastructure.Extensions;
57
using NuttyTree.NetDaemon.Infrastructure.HomeAssistant;
68

@@ -12,10 +14,16 @@ internal sealed class ElectronicsTimeGrpcService : ElectronicsTimeGrpc.Electroni
1214

1315
private readonly IEntities homeAssistantEntities;
1416

15-
public ElectronicsTimeGrpcService(IOptionsMonitor<ElectronicsTimeOptions> options, IEntities homeAssistantEntities)
17+
private readonly IHomeAssistantWebhookApi homeAssistantWebhook;
18+
19+
public ElectronicsTimeGrpcService(
20+
IOptionsMonitor<ElectronicsTimeOptions> options,
21+
IEntities homeAssistantEntities,
22+
IHomeAssistantWebhookApi homeAssistantWebhook)
1623
{
1724
this.options = options;
1825
this.homeAssistantEntities = homeAssistantEntities;
26+
this.homeAssistantWebhook = homeAssistantWebhook;
1927
}
2028

2129
public override async Task GetApplicationConfig(ApplicationConfigRequest request, IServerStreamWriter<ApplicationConfigResponse> responseStream, ServerCallContext context)
@@ -27,6 +35,7 @@ public override async Task GetApplicationConfig(ApplicationConfigRequest request
2735
{
2836
var response = new ApplicationConfigResponse
2937
{
38+
AdminPassword = options.CurrentValue.AdminPassword,
3039
Applications =
3140
{
3241
options.CurrentValue.Applications.Select(a => new Application
@@ -51,10 +60,16 @@ public override async Task GetApplicationConfig(ApplicationConfigRequest request
5160
public override async Task GetStatus(StatusRequest request, IServerStreamWriter<StatusResponse> responseStream, ServerCallContext context)
5261
{
5362
var updateStatusTrigger = new TaskCompletionSource();
54-
using var timer = new Timer(_ => updateStatusTrigger.TrySetResult(), null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));
63+
using var modeChange = homeAssistantEntities.InputSelect.MaysonElectronicsMode.StateChanges().Subscribe(_ => updateStatusTrigger.TrySetResult());
64+
using var locationChange = homeAssistantEntities.DeviceTracker.PhoneMayson.StateChanges().Subscribe(_ => updateStatusTrigger.TrySetResult());
65+
using var availableTimeChange = homeAssistantEntities.Sensor.MaysonAvailableTime.StateChanges().Subscribe(_ => updateStatusTrigger.TrySetResult());
66+
using var tasksChange = homeAssistantEntities.Todo.Mayson.StateChanges().Subscribe(_ => updateStatusTrigger.TrySetResult());
5567

5668
while (!context.CancellationToken.IsCancellationRequested)
5769
{
70+
// We have to recreate the timer each time because the time to next daytime change can vary based on Daylight Saving Time
71+
using var daytimeChange = new Timer(_ => updateStatusTrigger.TrySetResult(), null, GetTimeToNextDaytimeChange(), TimeSpan.MaxValue);
72+
5873
var response = new StatusResponse
5974
{
6075
Mode = homeAssistantEntities.InputSelect.MaysonElectronicsMode.EntityState.AsEnum<ElectronicsMode>() ?? ElectronicsMode.Restricted,
@@ -70,8 +85,37 @@ public override async Task GetStatus(StatusRequest request, IServerStreamWriter<
7085
}
7186
}
7287

73-
public override Task<DeviceStatusResponse> SendDeviceStatus(DeviceStatus request, ServerCallContext context)
88+
public override async Task<DeviceStatusResponse> SendDeviceStatus(DeviceStatus request, ServerCallContext context)
89+
{
90+
await homeAssistantWebhook.CallWebhookAsync(
91+
options.CurrentValue.WebhookId,
92+
new
93+
{
94+
request.CurrentApp,
95+
request.CurrentPipApp,
96+
IsUsingTime = options.CurrentValue.Applications.Any(a => a.RequiresTime && (a.Name == request.CurrentApp || a.Name == request.CurrentPipApp)),
97+
},
98+
context.CancellationToken);
99+
100+
return new DeviceStatusResponse();
101+
}
102+
103+
private TimeSpan GetTimeToNextDaytimeChange()
74104
{
75-
return Task.FromResult(new DeviceStatusResponse());
105+
var now = DateTime.Now;
106+
107+
var morning = now.At(8, 0);
108+
if (now <= morning)
109+
{
110+
return morning - now;
111+
}
112+
113+
var evening = now.At(21, 0);
114+
if (now <= evening)
115+
{
116+
return evening - now;
117+
}
118+
119+
return morning.NextDay() - now;
76120
}
77121
}

src/NuttyTree.NetDaemon.Application/ElectronicsTime/gRPC/electronics_time.proto

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ message ApplicationConfigRequest {
1414
}
1515

1616
message ApplicationConfigResponse {
17-
repeated Application applications = 1;
17+
string adminPassword = 1;
18+
repeated Application applications = 2;
1819
}
1920

2021
message Application {

src/NuttyTree.NetDaemon.Application/NuttyTree.NetDaemon.Application.csproj

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,18 @@
99
<ItemGroup>
1010
<PackageReference Include="FluentDateTime" Version="3.0.0" />
1111
<PackageReference Include="Grpc.AspNetCore" Version="2.65.0" />
12-
<PackageReference Include="NetDaemon.AppModel" Version="24.28.1" />
13-
<PackageReference Include="NetDaemon.Runtime" Version="24.28.1" />
14-
<PackageReference Include="NetDaemon.Client" Version="24.28.1" />
15-
<PackageReference Include="NetDaemon.Extensions.Scheduling" Version="24.28.1" />
16-
<PackageReference Include="NetDaemon.Extensions.Logging" Version="24.28.1" />
17-
<PackageReference Include="NetDaemon.Extensions.Tts" Version="24.28.1" />
12+
<PackageReference Include="NetDaemon.AppModel" Version="24.35.1" />
13+
<PackageReference Include="NetDaemon.Runtime" Version="24.35.1" />
14+
<PackageReference Include="NetDaemon.Client" Version="24.35.1" />
15+
<PackageReference Include="NetDaemon.Extensions.Scheduling" Version="24.35.1" />
16+
<PackageReference Include="NetDaemon.Extensions.Logging" Version="24.35.1" />
17+
<PackageReference Include="NetDaemon.Extensions.Tts" Version="24.35.1" />
1818
<PackageReference Include="Net.Codecrete.QrCodeGenerator" Version="2.0.5" />
1919
<PackageReference Include="System.IO.Abstractions" Version="21.0.29" />
2020
<PackageReference Include="System.Reactive" Version="6.0.1" />
2121
<PackageReference Include="System.Security.Cryptography.Pkcs" Version="8.0.0" />
2222
<PackageReference Include="System.ServiceModel.Primitives" Version="8.0.0" />
23-
<PackageReference Include="YamlDotNet" Version="16.0.0" />
23+
<PackageReference Include="YamlDotNet" Version="16.1.0" />
2424
</ItemGroup>
2525

2626
<ItemGroup>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using Refit;
2+
3+
namespace NuttyTree.NetDaemon.ExternalServices.HomeAssistantWebhook;
4+
5+
public interface IHomeAssistantWebhookApi
6+
{
7+
[Put("/api/webhook/{webhookId}")]
8+
Task CallWebhookAsync(string webhookId, [Body] object data, CancellationToken cancellationToken = default);
9+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using Microsoft.Extensions.DependencyInjection;
2+
using Microsoft.Extensions.Options;
3+
using NetDaemon.Client.Settings;
4+
using Refit;
5+
6+
namespace NuttyTree.NetDaemon.ExternalServices.HomeAssistantWebhook;
7+
8+
public static class IServiceCollectionExtensions
9+
{
10+
public static IServiceCollection AddHomeAssistantWebhooks(this IServiceCollection services)
11+
{
12+
services.AddRefitClient<IHomeAssistantWebhookApi>()
13+
.AddDefaultRetryPolicy()
14+
.ConfigureHttpClient((serviceProvider, client) =>
15+
{
16+
var settings = serviceProvider.GetRequiredService<IOptions<HomeAssistantSettings>>().Value;
17+
client.BaseAddress = new UriBuilder(settings.Ssl ? "https" : "http", settings.Host, settings.Port).Uri;
18+
});
19+
20+
return services;
21+
}
22+
}

src/NuttyTree.NetDaemon.Infrastructure/NuttyTree.NetDaemon.Infrastructure.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
<ItemGroup>
1010
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.8" />
11-
<PackageReference Include="NetDaemon.HassModel" Version="24.28.1" />
11+
<PackageReference Include="NetDaemon.HassModel" Version="24.35.1" />
1212
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.8">
1313
<PrivateAssets>all</PrivateAssets>
1414
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

src/NuttyTree.NetDaemon/NuttyTree.NetDaemon.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
<ItemGroup>
1111
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
12-
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.7.0" />
12+
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.7.3" />
1313
</ItemGroup>
1414

1515
<ItemGroup>

tests/NuttyTree.NetDaemon.Application.UnitTests/NuttyTree.NetDaemon.Application.UnitTests.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
</PropertyGroup>
77

88
<ItemGroup>
9-
<PackageReference Include="Bogus" Version="35.6.0" />
10-
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
11-
<PackageReference Include="Moq" Version="4.20.70" />
9+
<PackageReference Include="Bogus" Version="35.6.1" />
10+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.0" />
11+
<PackageReference Include="Moq" Version="4.20.71" />
1212
<PackageReference Include="xunit" Version="2.9.0" />
1313
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
1414
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

0 commit comments

Comments
 (0)