Skip to content

Electronics Time Updates: #157

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@ csharp_style_namespace_declarations = file_scoped:silent
csharp_style_prefer_method_group_conversion = true:silent
csharp_style_prefer_top_level_statements = true:silent
csharp_style_prefer_primary_constructors = true:suggestion
dotnet_diagnostic.SA1010.severity = none


[/src/*Controller.cs]
Expand Down
1 change: 1 addition & 0 deletions NuttyTree.NetDaemon.sln
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{1E435BC4
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{08A2828C-5FD1-4917-B92E-A65EB0BC182C}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
Directory.Build.props = Directory.Build.props
build\Dockerfile = build\Dockerfile
EndProjectSection
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ internal sealed class ElectronicsTimeApp : IDisposable

private readonly string? chrisUserId;

private readonly List<IDisposable> toDoListUpdateTriggers = new List<IDisposable>();
private readonly List<IDisposable> toDoListUpdateTriggers = [];

private readonly List<IDisposable> taskTriggers = new List<IDisposable>();
private readonly List<IDisposable> taskTriggers = [];

private readonly ITriggerableTask updateToDoListTask;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ namespace NuttyTree.NetDaemon.Application.ElectronicsTime.Options;

internal sealed class ElectronicsTimeOptions
{
public IList<RecurringToDoListItem> ToDoListItems { get; set; } = new List<RecurringToDoListItem>();
public IList<RecurringToDoListItem> ToDoListItems { get; set; } = [];

public IList<AllowedApplication> Applications { get; set; } = new List<AllowedApplication>();
public string AdminPassword { get; set; } = string.Empty;

public string WebhookId { get; set; } = string.Empty;

public IList<AllowedApplication> Applications { get; set; } = [];
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using Grpc.Core;
using FluentDateTime;
using Grpc.Core;
using Microsoft.Extensions.Options;
using NuttyTree.NetDaemon.Application.ElectronicsTime.Options;
using NuttyTree.NetDaemon.ExternalServices.HomeAssistantWebhook;
using NuttyTree.NetDaemon.Infrastructure.Extensions;
using NuttyTree.NetDaemon.Infrastructure.HomeAssistant;

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

private readonly IEntities homeAssistantEntities;

public ElectronicsTimeGrpcService(IOptionsMonitor<ElectronicsTimeOptions> options, IEntities homeAssistantEntities)
private readonly IHomeAssistantWebhookApi homeAssistantWebhook;

public ElectronicsTimeGrpcService(
IOptionsMonitor<ElectronicsTimeOptions> options,
IEntities homeAssistantEntities,
IHomeAssistantWebhookApi homeAssistantWebhook)
{
this.options = options;
this.homeAssistantEntities = homeAssistantEntities;
this.homeAssistantWebhook = homeAssistantWebhook;
}

public override async Task GetApplicationConfig(ApplicationConfigRequest request, IServerStreamWriter<ApplicationConfigResponse> responseStream, ServerCallContext context)
Expand All @@ -27,6 +35,7 @@ public override async Task GetApplicationConfig(ApplicationConfigRequest request
{
var response = new ApplicationConfigResponse
{
AdminPassword = options.CurrentValue.AdminPassword,
Applications =
{
options.CurrentValue.Applications.Select(a => new Application
Expand All @@ -51,10 +60,16 @@ public override async Task GetApplicationConfig(ApplicationConfigRequest request
public override async Task GetStatus(StatusRequest request, IServerStreamWriter<StatusResponse> responseStream, ServerCallContext context)
{
var updateStatusTrigger = new TaskCompletionSource();
using var timer = new Timer(_ => updateStatusTrigger.TrySetResult(), null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));
using var modeChange = homeAssistantEntities.InputSelect.MaysonElectronicsMode.StateChanges().Subscribe(_ => updateStatusTrigger.TrySetResult());
using var locationChange = homeAssistantEntities.DeviceTracker.PhoneMayson.StateChanges().Subscribe(_ => updateStatusTrigger.TrySetResult());
using var availableTimeChange = homeAssistantEntities.Sensor.MaysonAvailableTime.StateChanges().Subscribe(_ => updateStatusTrigger.TrySetResult());
using var tasksChange = homeAssistantEntities.Todo.Mayson.StateChanges().Subscribe(_ => updateStatusTrigger.TrySetResult());

while (!context.CancellationToken.IsCancellationRequested)
{
// We have to recreate the timer each time because the time to next daytime change can vary based on Daylight Saving Time
using var daytimeChange = new Timer(_ => updateStatusTrigger.TrySetResult(), null, GetTimeToNextDaytimeChange(), TimeSpan.MaxValue);

var response = new StatusResponse
{
Mode = homeAssistantEntities.InputSelect.MaysonElectronicsMode.EntityState.AsEnum<ElectronicsMode>() ?? ElectronicsMode.Restricted,
Expand All @@ -70,8 +85,37 @@ public override async Task GetStatus(StatusRequest request, IServerStreamWriter<
}
}

public override Task<DeviceStatusResponse> SendDeviceStatus(DeviceStatus request, ServerCallContext context)
public override async Task<DeviceStatusResponse> SendDeviceStatus(DeviceStatus request, ServerCallContext context)
{
await homeAssistantWebhook.CallWebhookAsync(
options.CurrentValue.WebhookId,
new
{
request.CurrentApp,
request.CurrentPipApp,
IsUsingTime = options.CurrentValue.Applications.Any(a => a.RequiresTime && (a.Name == request.CurrentApp || a.Name == request.CurrentPipApp)),
},
context.CancellationToken);

return new DeviceStatusResponse();
}

private TimeSpan GetTimeToNextDaytimeChange()
{
return Task.FromResult(new DeviceStatusResponse());
var now = DateTime.Now;

var morning = now.At(8, 0);
if (now <= morning)
{
return morning - now;
}

var evening = now.At(21, 0);
if (now <= evening)
{
return evening - now;
}

return morning.NextDay() - now;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ message ApplicationConfigRequest {
}

message ApplicationConfigResponse {
repeated Application applications = 1;
string adminPassword = 1;
repeated Application applications = 2;
}

message Application {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@
<ItemGroup>
<PackageReference Include="FluentDateTime" Version="3.0.0" />
<PackageReference Include="Grpc.AspNetCore" Version="2.65.0" />
<PackageReference Include="NetDaemon.AppModel" Version="24.28.1" />
<PackageReference Include="NetDaemon.Runtime" Version="24.28.1" />
<PackageReference Include="NetDaemon.Client" Version="24.28.1" />
<PackageReference Include="NetDaemon.Extensions.Scheduling" Version="24.28.1" />
<PackageReference Include="NetDaemon.Extensions.Logging" Version="24.28.1" />
<PackageReference Include="NetDaemon.Extensions.Tts" Version="24.28.1" />
<PackageReference Include="NetDaemon.AppModel" Version="24.35.1" />
<PackageReference Include="NetDaemon.Runtime" Version="24.35.1" />
<PackageReference Include="NetDaemon.Client" Version="24.35.1" />
<PackageReference Include="NetDaemon.Extensions.Scheduling" Version="24.35.1" />
<PackageReference Include="NetDaemon.Extensions.Logging" Version="24.35.1" />
<PackageReference Include="NetDaemon.Extensions.Tts" Version="24.35.1" />
<PackageReference Include="Net.Codecrete.QrCodeGenerator" Version="2.0.5" />
<PackageReference Include="System.IO.Abstractions" Version="21.0.29" />
<PackageReference Include="System.Reactive" Version="6.0.1" />
<PackageReference Include="System.Security.Cryptography.Pkcs" Version="8.0.0" />
<PackageReference Include="System.ServiceModel.Primitives" Version="8.0.0" />
<PackageReference Include="YamlDotNet" Version="16.0.0" />
<PackageReference Include="YamlDotNet" Version="16.1.0" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Refit;

namespace NuttyTree.NetDaemon.ExternalServices.HomeAssistantWebhook;

public interface IHomeAssistantWebhookApi
{
[Put("/api/webhook/{webhookId}")]
Task CallWebhookAsync(string webhookId, [Body] object data, CancellationToken cancellationToken = default);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using NetDaemon.Client.Settings;
using Refit;

namespace NuttyTree.NetDaemon.ExternalServices.HomeAssistantWebhook;

public static class IServiceCollectionExtensions
{
public static IServiceCollection AddHomeAssistantWebhooks(this IServiceCollection services)
{
services.AddRefitClient<IHomeAssistantWebhookApi>()
.AddDefaultRetryPolicy()
.ConfigureHttpClient((serviceProvider, client) =>
{
var settings = serviceProvider.GetRequiredService<IOptions<HomeAssistantSettings>>().Value;
client.BaseAddress = new UriBuilder(settings.Ssl ? "https" : "http", settings.Host, settings.Port).Uri;
});

return services;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.8" />
<PackageReference Include="NetDaemon.HassModel" Version="24.28.1" />
<PackageReference Include="NetDaemon.HassModel" Version="24.35.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.8">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
2 changes: 1 addition & 1 deletion src/NuttyTree.NetDaemon/NuttyTree.NetDaemon.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.7.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.7.3" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Bogus" Version="35.6.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageReference Include="Moq" Version="4.20.70" />
<PackageReference Include="Bogus" Version="35.6.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.0" />
<PackageReference Include="Moq" Version="4.20.71" />
<PackageReference Include="xunit" Version="2.9.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
Loading