feat(hass): setup netdaemon
All checks were successful
Discord / discord commits (push) Has been skipped

This commit is contained in:
matt1432 2024-10-05 12:38:13 -04:00
parent 291f42cf30
commit 82a05091a5
21 changed files with 572 additions and 0 deletions

View file

@ -55,5 +55,6 @@ in {
sshd.enable = true;
};
khepri.enable = true;
services.kmscon.enable = true;
}

View file

@ -4,6 +4,7 @@
./bluetooth.nix
./firmware.nix
./frontend.nix
./netdaemon
./spotify.nix
./timer.nix
];

View file

@ -0,0 +1 @@
use flake "$FLAKE#netdaemon"

View file

@ -0,0 +1,2 @@
obj
bin

View file

@ -0,0 +1,19 @@
namespace AppModel;
/// <summary>
/// Showcases how to instance apps with yaml and use automatic configuration population
/// </summary>
[NetDaemonApp]
public class HelloYamlApp
{
public HelloYamlApp(IHaContext ha, IAppConfig<HelloConfig> config)
{
ha.CallService("notify", "persistent_notification",
data: new {message = config.Value.HelloMessage, title = "Hello yaml app!"});
}
}
public class HelloConfig
{
public string? HelloMessage { get; set; }
}

View file

@ -0,0 +1,2 @@
AppModel.HelloConfig:
HelloMessage: Hello from yaml

View file

@ -0,0 +1,6 @@
// Common usings for NetDaemon apps
global using System;
global using System.Reactive.Linq;
global using Microsoft.Extensions.Logging;
global using NetDaemon.AppModel;
global using NetDaemon.HassModel;

View file

@ -0,0 +1,16 @@
// Use unique namespaces for your apps if you going to share with others to avoid
// conflicting names
namespace HassModel;
/// <summary>
/// Hello world showcase using the new HassModel API
/// </summary>
[NetDaemonApp]
public class HelloWorldApp
{
public HelloWorldApp(IHaContext ha)
{
ha.CallService("notify", "persistent_notification", data: new {message = "Notify me", title = "Hello world!"});
}
}

View file

@ -0,0 +1,17 @@
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"Microsoft": "Warning"
},
"ConsoleThemeType": "Ansi"
},
"NetDaemon": {
"ApplicationConfigurationFolder": "./apps"
},
"CodeGeneration": {
"Namespace": "HomeAssistantGenerated",
"OutputFile": "HomeAssistantGenerated.cs",
"UseAttributeBaseClasses" : "false"
}
}

View file

@ -0,0 +1,68 @@
{
config,
self,
pkgs,
...
}: let
inherit (config.sops) secrets;
compiled = pkgs.callPackage ./package.nix {};
in {
khepri.compositions."netdaemon" = {
networks.netdaemon = {external = true;};
services."netdaemon4" = {
image = import ./images/netdaemon.nix pkgs;
restart = "always";
environmentFiles = [secrets.netdaemon.path];
environment = {
HomeAssistant__Host = "homie.nelim.org";
HomeAssistant__Port = "443";
HomeAssistant__Ssl = "true";
NetDaemon__ApplicationAssembly = "netdaemon.dll";
Logging__LogLevel__Default = "Information"; # use Information/Debug/Trace/Warning/Error
TZ = "America/New_York";
};
volumes = ["${compiled}/lib/netdaemon-config:/data"];
networks = ["netdaemon"];
};
};
services.home-assistant = {
customComponents = builtins.attrValues {
inherit
(self.legacyPackages.${pkgs.system}.hass-components)
netdaemon
;
};
};
environment.systemPackages = [
(pkgs.writeShellApplication {
name = "updateNuDeps";
runtimeInputs = [pkgs.dotnet-sdk_8];
text = ''
# Update the codegen
dotnet tool update -g NetDaemon.HassModel.CodeGen
# Update all nugets to latest versions
regex='PackageReference Include="([^"]*)" Version="([^"]*)"'
find . -type f -name '*.csproj' | while read -r file; do
# Extract unique package names from the .csproj file
packages=$(grep -oP "$regex" "$file" | sed -E 's/.*Include="([^"]*)".*/\1/' | sort -u)
# Loop through each package and update
for package in $packages; do
echo -e "\033[35mUpdate $file package: $package\033[0m"
dotnet add "$file" package "$package"
done
done
${compiled.passthru.fetch-deps} .
'';
})
];
}

View file

@ -0,0 +1,304 @@
# This file was automatically generated by passthru.fetch-deps.
# Please dont edit it manually, your changes might get overwritten!
{fetchNuGet}: [
(fetchNuGet {
pname = "Cronos";
version = "0.8.4";
hash = "sha256-L9rLcqnQybPoJCcg60h49bjXfqEarM9SFHqOJUMvxz8=";
})
(fetchNuGet {
pname = "Microsoft.Extensions.Configuration";
version = "8.0.0";
hash = "sha256-9BPsASlxrV8ilmMCjdb3TiUcm5vFZxkBnAI/fNBSEyA=";
})
(fetchNuGet {
pname = "Microsoft.Extensions.Configuration.Abstractions";
version = "8.0.0";
hash = "sha256-4eBpDkf7MJozTZnOwQvwcfgRKQGcNXe0K/kF+h5Rl8o=";
})
(fetchNuGet {
pname = "Microsoft.Extensions.Configuration.Binder";
version = "8.0.0";
hash = "sha256-GanfInGzzoN2bKeNwON8/Hnamr6l7RTpYLA49CNXD9Q=";
})
(fetchNuGet {
pname = "Microsoft.Extensions.Configuration.Binder";
version = "8.0.2";
hash = "sha256-aGB0VuoC34YadAEqrwoaXLc5qla55pswDV2xLSmR7SE=";
})
(fetchNuGet {
pname = "Microsoft.Extensions.Configuration.CommandLine";
version = "8.0.0";
hash = "sha256-fmPC/o8S+weTtQJWykpnGHm6AKVU21xYE/CaHYU7zgg=";
})
(fetchNuGet {
pname = "Microsoft.Extensions.Configuration.EnvironmentVariables";
version = "8.0.0";
hash = "sha256-+bjFZvqCsMf2FRM2olqx/fub+QwfM1kBhjGVOT5HC48=";
})
(fetchNuGet {
pname = "Microsoft.Extensions.Configuration.FileExtensions";
version = "8.0.0";
hash = "sha256-BCxcjVP+kvrDDB0nzsFCJfU74UK4VBvct2JA4r+jNcs=";
})
(fetchNuGet {
pname = "Microsoft.Extensions.Configuration.Json";
version = "8.0.0";
hash = "sha256-Fi/ijcG5l0BOu7i96xHu96aN5/g7zO6SWQbTsI3Qetg=";
})
(fetchNuGet {
pname = "Microsoft.Extensions.Configuration.UserSecrets";
version = "8.0.0";
hash = "sha256-/yj5QaEzeRStvOFoBpPRPXlEehGtr2E6/rJb+OEPIK8=";
})
(fetchNuGet {
pname = "Microsoft.Extensions.DependencyInjection";
version = "8.0.0";
hash = "sha256-+qIDR8hRzreCHNEDtUcPfVHQdurzWPo/mqviCH78+EQ=";
})
(fetchNuGet {
pname = "Microsoft.Extensions.DependencyInjection.Abstractions";
version = "8.0.0";
hash = "sha256-75KzEGWjbRELczJpCiJub+ltNUMMbz5A/1KQU+5dgP8=";
})
(fetchNuGet {
pname = "Microsoft.Extensions.DependencyInjection.Abstractions";
version = "8.0.1";
hash = "sha256-lzTYLpRDAi3wW9uRrkTNJtMmaYdtGJJHdBLbUKu60PM=";
})
(fetchNuGet {
pname = "Microsoft.Extensions.DependencyModel";
version = "8.0.1";
hash = "sha256-m8daXRK1Qn9y2c8SmtWu9ysLHwFJtEWiUQoAnMalw7s=";
})
(fetchNuGet {
pname = "Microsoft.Extensions.Diagnostics";
version = "8.0.0";
hash = "sha256-fBLlb9xAfTgZb1cpBxFs/9eA+BlBvF8Xg0DMkBqdHD4=";
})
(fetchNuGet {
pname = "Microsoft.Extensions.Diagnostics.Abstractions";
version = "8.0.0";
hash = "sha256-USD5uZOaahMqi6u7owNWx/LR4EDrOwqPrAAim7iRpJY=";
})
(fetchNuGet {
pname = "Microsoft.Extensions.FileProviders.Abstractions";
version = "8.0.0";
hash = "sha256-uQSXmt47X2HGoVniavjLICbPtD2ReQOYQMgy3l0xuMU=";
})
(fetchNuGet {
pname = "Microsoft.Extensions.FileProviders.Physical";
version = "8.0.0";
hash = "sha256-29y5ZRQ1ZgzVOxHktYxyiH40kVgm5un2yTGdvuSWnRc=";
})
(fetchNuGet {
pname = "Microsoft.Extensions.FileSystemGlobbing";
version = "8.0.0";
hash = "sha256-+Oz41JR5jdcJlCJOSpQIL5OMBNi+1Hl2d0JUHfES7sU=";
})
(fetchNuGet {
pname = "Microsoft.Extensions.Hosting";
version = "8.0.0";
hash = "sha256-sKHa+w4/pMeQb5RRFqLtMTUJy5H6hSIGWchbH2pxSrg=";
})
(fetchNuGet {
pname = "Microsoft.Extensions.Hosting.Abstractions";
version = "8.0.0";
hash = "sha256-0JBx+wwt5p1SPfO4m49KxNOXPAzAU0A+8tEc/itvpQE=";
})
(fetchNuGet {
pname = "Microsoft.Extensions.Http";
version = "8.0.0";
hash = "sha256-UgljypOLld1lL7k7h1noazNzvyEHIJw+r+6uGzucFSY=";
})
(fetchNuGet {
pname = "Microsoft.Extensions.Logging";
version = "8.0.0";
hash = "sha256-Meh0Z0X7KyOEG4l0RWBcuHHihcABcvCyfUXgasmQ91o=";
})
(fetchNuGet {
pname = "Microsoft.Extensions.Logging.Abstractions";
version = "8.0.0";
hash = "sha256-Jmddjeg8U5S+iBTwRlVAVLeIHxc4yrrNgqVMOB7EjM4=";
})
(fetchNuGet {
pname = "Microsoft.Extensions.Logging.Abstractions";
version = "8.0.1";
hash = "sha256-TYce3qvMr92JbAZ62ATBsocaH0joJzw0px0tYGZ9N0U=";
})
(fetchNuGet {
pname = "Microsoft.Extensions.Logging.Configuration";
version = "8.0.0";
hash = "sha256-mzmstNsVjKT0EtQcdAukGRifD30T82BMGYlSu8k4K7U=";
})
(fetchNuGet {
pname = "Microsoft.Extensions.Logging.Console";
version = "8.0.0";
hash = "sha256-bdb9YWWVn//AeySp7se87/tCN2E7e8Gx2GPMw28cd9c=";
})
(fetchNuGet {
pname = "Microsoft.Extensions.Logging.Debug";
version = "8.0.0";
hash = "sha256-AJunzYBZM2wCg86hnPnMrBuWIIyW/4PnIVoDSU969cA=";
})
(fetchNuGet {
pname = "Microsoft.Extensions.Logging.EventLog";
version = "8.0.0";
hash = "sha256-vXBm4yhWGP4uow0CqstuqOkxO8yeZEM15JTTenjPbhc=";
})
(fetchNuGet {
pname = "Microsoft.Extensions.Logging.EventSource";
version = "8.0.0";
hash = "sha256-kaR7YOlq5s8W9nZDtH/lKtnfGbrgOuQY4DUPcA2lcj0=";
})
(fetchNuGet {
pname = "Microsoft.Extensions.Options";
version = "8.0.0";
hash = "sha256-n2m4JSegQKUTlOsKLZUUHHKMq926eJ0w9N9G+I3FoFw=";
})
(fetchNuGet {
pname = "Microsoft.Extensions.Options.ConfigurationExtensions";
version = "8.0.0";
hash = "sha256-A5Bbzw1kiNkgirk5x8kyxwg9lLTcSngojeD+ocpG1RI=";
})
(fetchNuGet {
pname = "Microsoft.Extensions.Primitives";
version = "8.0.0";
hash = "sha256-FU8qj3DR8bDdc1c+WeGZx/PCZeqqndweZM9epcpXjSo=";
})
(fetchNuGet {
pname = "NetDaemon.AppModel";
version = "24.37.1";
hash = "sha256-KQKTm0+4itReyulWfYMLKX1uXBv8tMNMxyI+TdOnK/s=";
})
(fetchNuGet {
pname = "NetDaemon.Client";
version = "24.37.1";
hash = "sha256-xxOsjKFtD0cSMOr7if+bRQq6y5yR7//FruIVMXSiEww=";
})
(fetchNuGet {
pname = "NetDaemon.Extensions.Logging";
version = "24.37.1";
hash = "sha256-JLDREBFhOOtveJu3JtwJR3ZIkQmrwMRrHt7mwmXy7dw=";
})
(fetchNuGet {
pname = "NetDaemon.Extensions.Scheduling";
version = "24.37.1";
hash = "sha256-f+IvbPAMfK4yA7bi56SI/+1hol/6oBbz6AMkJ2OCAOc=";
})
(fetchNuGet {
pname = "NetDaemon.Extensions.Tts";
version = "24.37.1";
hash = "sha256-R4bFaR2mUct39njcbK2m7xeuDIZeRqHdvsjp3hFBdfQ=";
})
(fetchNuGet {
pname = "NetDaemon.HassModel";
version = "24.37.1";
hash = "sha256-eIOk6/LImCTjTC4cwWBpATqxiQUQxbsRXAcR6Mz7LKs=";
})
(fetchNuGet {
pname = "NetDaemon.HassModel.CodeGen";
version = "24.37.0";
hash = "sha256-+YSo9/FkkDLfymWrzf4OjMwE31qjAbbFjmF7L5Aj2Bg=";
})
(fetchNuGet {
pname = "NetDaemon.HassModel.Integration";
version = "24.37.1";
hash = "sha256-6e7oQFRs15dT0+cQxgyQWwWgmHNdFzlCnyJzmfPe5b8=";
})
(fetchNuGet {
pname = "NetDaemon.Runtime";
version = "24.37.1";
hash = "sha256-GwMx6f+lIoM1OznORs0Wkoc6HLalILFK1OS6Vcz1BuI=";
})
(fetchNuGet {
pname = "Serilog";
version = "3.1.1";
hash = "sha256-L263y8jkn7dNFD2jAUK6mgvyRTqFe39i1tRhVZsNZTI=";
})
(fetchNuGet {
pname = "Serilog";
version = "4.0.0";
hash = "sha256-j8hQ5TdL1TjfdGiBO9PyHJFMMPvATHWN1dtrrUZZlNw=";
})
(fetchNuGet {
pname = "Serilog.AspNetCore";
version = "8.0.2";
hash = "sha256-cRZHG2bqrESOxPVxq2v+mHx+oZBzZEPksrleGVXO1p0=";
})
(fetchNuGet {
pname = "Serilog.Extensions.Hosting";
version = "8.0.0";
hash = "sha256-OEVkEQoONawJF+SXeyqqgU0OGp9ubtt9aXT+rC25j4E=";
})
(fetchNuGet {
pname = "Serilog.Extensions.Logging";
version = "8.0.0";
hash = "sha256-GoWxCpkdahMvYd7ZrhwBxxTyjHGcs9ENNHJCp0la6iA=";
})
(fetchNuGet {
pname = "Serilog.Formatting.Compact";
version = "2.0.0";
hash = "sha256-c3STGleyMijY4QnxPuAz/NkJs1r+TZAPjlmAKLF4+3g=";
})
(fetchNuGet {
pname = "Serilog.Settings.Configuration";
version = "8.0.2";
hash = "sha256-iHRQt6vDk85/6HpMXiJluAwhkjgwEnL3IKavfDgFX0k=";
})
(fetchNuGet {
pname = "Serilog.Sinks.Console";
version = "6.0.0";
hash = "sha256-QH8ykDkLssJ99Fgl+ZBFBr+RQRl0wRTkeccQuuGLyro=";
})
(fetchNuGet {
pname = "Serilog.Sinks.Debug";
version = "2.0.0";
hash = "sha256-/PLVAE33lTdUEXdahkI5ddFiGZufWnvfsOodQsFB8sQ=";
})
(fetchNuGet {
pname = "Serilog.Sinks.File";
version = "5.0.0";
hash = "sha256-GKy9hwOdlu2W0Rw8LiPyEwus+sDtSOTl8a5l9uqz+SQ=";
})
(fetchNuGet {
pname = "System.Diagnostics.DiagnosticSource";
version = "8.0.0";
hash = "sha256-+aODaDEQMqla5RYZeq0Lh66j+xkPYxykrVvSCmJQ+Vs=";
})
(fetchNuGet {
pname = "System.Diagnostics.EventLog";
version = "8.0.0";
hash = "sha256-rt8xc3kddpQY4HEdghlBeOK4gdw5yIj4mcZhAVtk2/Y=";
})
(fetchNuGet {
pname = "System.IO.Pipelines";
version = "8.0.0";
hash = "sha256-LdpB1s4vQzsOODaxiKstLks57X9DTD5D6cPx8DE1wwE=";
})
(fetchNuGet {
pname = "System.Reactive";
version = "6.0.1";
hash = "sha256-Lo5UMqp8DsbVSUxa2UpClR1GoYzqQQcSxkfyFqB/d4Q=";
})
(fetchNuGet {
pname = "System.Text.Encodings.Web";
version = "8.0.0";
hash = "sha256-IUQkQkV9po1LC0QsqrilqwNzPvnc+4eVvq+hCvq8fvE=";
})
(fetchNuGet {
pname = "System.Text.Json";
version = "8.0.0";
hash = "sha256-XFcCHMW1u2/WujlWNHaIWkbW1wn8W4kI0QdrwPtWmow=";
})
(fetchNuGet {
pname = "System.Text.Json";
version = "8.0.4";
hash = "sha256-g5oT7fbXxQ9Iah1nMCr4UUX/a2l+EVjJyTrw3FTbIaI=";
})
(fetchNuGet {
pname = "YamlDotNet";
version = "16.1.2";
hash = "sha256-J8fZ6rRFiNsAYDxHFskAjC2fP+K2XrewDs50jAKEWTY=";
})
]

View file

@ -0,0 +1,8 @@
pkgs:
pkgs.dockerTools.pullImage rec {
imageName = "netdaemon/netdaemon4";
imageDigest = "sha256:2ccb8dce2a7a5bba14bd90030640f09a91adccb472e16168ad06ae1f752430ae";
sha256 = "1qj2yrbhcr162ikfv3jbh4qvb17p7vzxva5z3r5vhhimayr24dn4";
finalImageName = imageName;
finalImageTag = "24.37.1";
}

View file

@ -0,0 +1,37 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<LangVersion>12.0</LangVersion>
<Nullable>enable</Nullable>
<RootNamespace>netdaemon</RootNamespace>
</PropertyGroup>
<ItemGroup>
<None Update="$(MSBuildProjectDir)appsettings.Development.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>
<None Update="$(MSBuildProjectDir)appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="$(MSBuildProjectDir)**\*.yaml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</None>
</ItemGroup>
<Target Name="AfterPublishMessage" AfterTargets="Publish">
<Message Text="Publish done! Copy all content in directory: $(PublishDir) to the `/config/netdaemon4' folder for add-on or your custom folder to deploy." Importance="high" />
</Target>
<ItemGroup>
<PackageReference Include="NetDaemon.AppModel" Version="24.37.1" />
<PackageReference Include="NetDaemon.Runtime" Version="24.37.1" />
<PackageReference Include="NetDaemon.HassModel" Version="24.37.1" />
<PackageReference Include="NetDaemon.Client" Version="24.37.1" />
<PackageReference Include="NetDaemon.Extensions.Scheduling" Version="24.37.1" />
<PackageReference Include="NetDaemon.Extensions.Logging" Version="24.37.1" />
<PackageReference Include="NetDaemon.Extensions.Tts" Version="24.37.1" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,22 @@
{
buildDotnetModule,
dotnetCorePackages,
}:
buildDotnetModule {
pname = "netdaemon-config";
version = "0.0.0";
src =
builtins.filterSource
(file: type:
(type != "directory")
|| (baseNameOf file != "default.nix" && baseNameOf file != "package.nix"))
./.;
projectFile = "netdaemon.csproj";
nugetDeps = ./deps.nix;
dotnet-sdk = dotnetCorePackages.sdk_8_0;
dotnet-runtime = dotnetCorePackages.runtime_8_0;
executables = [];
}

View file

@ -0,0 +1,35 @@
using System.Reflection;
using Microsoft.Extensions.Hosting;
using NetDaemon.Extensions.Logging;
using NetDaemon.Extensions.Scheduler;
using NetDaemon.Extensions.Tts;
using NetDaemon.Runtime;
// Add next line if using code generator
//using HomeAssistantGenerated;
#pragma warning disable CA1812
try
{
await Host.CreateDefaultBuilder(args)
.UseNetDaemonAppSettings()
.UseNetDaemonDefaultLogging()
.UseNetDaemonRuntime()
.UseNetDaemonTextToSpeech()
.ConfigureServices((_, services) =>
services
.AddAppsFromAssembly(Assembly.GetExecutingAssembly())
.AddNetDaemonStateManager()
.AddNetDaemonScheduler()
// Add next line if using code generator
// .AddHomeAssistantGenerated()
)
.Build()
.RunAsync()
.ConfigureAwait(false);
}
catch (Exception e)
{
Console.WriteLine($"Failed to start host... {e}");
throw;
}

Binary file not shown.

BIN
flake.nix

Binary file not shown.

View file

@ -196,6 +196,11 @@ let
owner = "make-all";
repo = "tuya-local";
}
{
name = "netdaemon-src";
owner = "net-daemon";
repo = "integration";
}
{
name = "spotifyplus-src";
owner = "thlucas1";

View file

@ -4,6 +4,7 @@ pkgs.lib.makeScope pkgs.newScope (hass: let
hass.callPackage file (inputs // extraArgs // {});
in {
extended-ollama-conversation = buildHassComponent ./extended-ollama-conversation {};
netdaemon = buildHassComponent ./netdaemon {};
spotifyplus = import ./spotifyplus ({inherit buildHassComponent;} // inputs);
tuya-local = buildHassComponent ./tuya-local {};
})

View file

@ -0,0 +1,21 @@
{
netdaemon-src,
buildHomeAssistantComponent,
python3Packages,
...
}: let
inherit (builtins) fromJSON readFile;
manifest = fromJSON (readFile "${netdaemon-src}/custom_components/netdaemon/manifest.json");
in
buildHomeAssistantComponent {
owner = "net-daemon";
inherit (manifest) domain version;
src = netdaemon-src;
propagatedBuildInputs = with python3Packages; [
awesomeversion
];
}

View file

@ -157,6 +157,12 @@
];
};
netdaemon = pkgs.mkShell {
packages = [
pkgs.dotnet-sdk_8
];
};
node = pkgs.mkShell {
packages =
(builtins.attrValues {