Skip to content
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
2 changes: 2 additions & 0 deletions .github/workflows/push_nuget_manual.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,7 @@ jobs:
run: dotnet pack src/Extensions/NetDaemon.Extensions.Logging/NetDaemon.Extensions.Logging.csproj --configuration Release -p:PackageVersion=${{ github.event.inputs.tag }}
- name: 🎁 Pack TTS extensions
run: dotnet pack src/Extensions/NetDaemon.Extensions.Tts/NetDaemon.Extensions.Tts.csproj --configuration Release -p:PackageVersion=${{ github.event.inputs.tag }}
- name: 🎁 Pack Mqtt extensions
run: dotnet pack src/Extensions/NetDaemon.Extensions.MqttEntityManager/NetDaemon.Extensions.MqttEntityManager.csproj --configuration Release -p:PackageVersion=${{ github.event.inputs.tag }}
- name: 📨 Push to nuget
run: dotnet nuget push **/*.nupkg --api-key ${{secrets.NUGET_API_KEY}} --source https://api.nuget.org/v3/index.json --no-symbols true
2 changes: 2 additions & 0 deletions .github/workflows/tags_nuget.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,7 @@ jobs:
run: dotnet pack src/Extensions/NetDaemon.Extensions.Logging/NetDaemon.Extensions.Logging.csproj --configuration Release -p:PackageVersion=${{ steps.version.outputs.version }}
- name: 🎁 Pack TTS extensions
run: dotnet pack src/Extensions/NetDaemon.Extensions.Tts/NetDaemon.Extensions.Tts.csproj --configuration Release -p:PackageVersion=${{ steps.version.outputs.version }}
- name: 🎁 Pack Mqtt extensions
run: dotnet pack src/Extensions/NetDaemon.Extensions.MqttEntityManager/NetDaemon.Extensions.MqttEntityManager.csproj --configuration Release -p:PackageVersion=${{ steps.version.outputs.version }}
- name: 📨 Push to nuget
run: dotnet nuget push **/*.nupkg --api-key ${{secrets.NUGET_API_KEY}} --source https://api.nuget.org/v3/index.json --no-symbols true
23 changes: 19 additions & 4 deletions NetDaemon.sln
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,17 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetDaemon.Host.Default", "s
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Host", "Host", "{A6D03AB9-6C8E-42BE-ACF6-7FA6A1C539C2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetDaemon.Runtime.Tests", "src\Runtime\NetDaemon.Runtime.Tests\NetDaemon.Runtime.Tests.csproj", "{966C5143-7667-4E85-B7E3-336F7C28549F}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetDaemon.Runtime.Tests", "src\Runtime\NetDaemon.Runtime.Tests\NetDaemon.Runtime.Tests.csproj", "{966C5143-7667-4E85-B7E3-336F7C28549F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Debug", "Debug", "{E15D4280-7FFC-4F8B-9B8C-CF9AF2BF838C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DebugHost", "dev\DebugHost\DebugHost.csproj", "{898966EA-F814-4B7B-9A3D-5E78C38174B2}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DebugHost", "dev\DebugHost\DebugHost.csproj", "{898966EA-F814-4B7B-9A3D-5E78C38174B2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetDaemon.Extensions.Logging", "src\Extensions\NetDaemon.Extensions.Logging\NetDaemon.Extensions.Logging.csproj", "{00333EBA-DB52-4D56-ADF7-940FB533E530}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetDaemon.Extensions.Logging", "src\Extensions\NetDaemon.Extensions.Logging\NetDaemon.Extensions.Logging.csproj", "{00333EBA-DB52-4D56-ADF7-940FB533E530}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetDaemon.Extensions.Tts", "src\Extensions\NetDaemon.Extensions.Tts\NetDaemon.Extensions.Tts.csproj", "{F4B29B77-9B92-4037-A884-288CA5EF0B78}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetDaemon.Extensions.Tts", "src\Extensions\NetDaemon.Extensions.Tts\NetDaemon.Extensions.Tts.csproj", "{F4B29B77-9B92-4037-A884-288CA5EF0B78}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetDaemon.Extensions.MqttEntityManager", "src\Extensions\NetDaemon.Extensions.MqttEntityManager\NetDaemon.Extensions.MqttEntityManager.csproj", "{3EB8C461-C91E-4900-BFBD-0986CBBE87A6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -269,6 +271,18 @@ Global
{F4B29B77-9B92-4037-A884-288CA5EF0B78}.Release|x64.Build.0 = Release|Any CPU
{F4B29B77-9B92-4037-A884-288CA5EF0B78}.Release|x86.ActiveCfg = Release|Any CPU
{F4B29B77-9B92-4037-A884-288CA5EF0B78}.Release|x86.Build.0 = Release|Any CPU
{3EB8C461-C91E-4900-BFBD-0986CBBE87A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3EB8C461-C91E-4900-BFBD-0986CBBE87A6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3EB8C461-C91E-4900-BFBD-0986CBBE87A6}.Debug|x64.ActiveCfg = Debug|Any CPU
{3EB8C461-C91E-4900-BFBD-0986CBBE87A6}.Debug|x64.Build.0 = Debug|Any CPU
{3EB8C461-C91E-4900-BFBD-0986CBBE87A6}.Debug|x86.ActiveCfg = Debug|Any CPU
{3EB8C461-C91E-4900-BFBD-0986CBBE87A6}.Debug|x86.Build.0 = Debug|Any CPU
{3EB8C461-C91E-4900-BFBD-0986CBBE87A6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3EB8C461-C91E-4900-BFBD-0986CBBE87A6}.Release|Any CPU.Build.0 = Release|Any CPU
{3EB8C461-C91E-4900-BFBD-0986CBBE87A6}.Release|x64.ActiveCfg = Release|Any CPU
{3EB8C461-C91E-4900-BFBD-0986CBBE87A6}.Release|x64.Build.0 = Release|Any CPU
{3EB8C461-C91E-4900-BFBD-0986CBBE87A6}.Release|x86.ActiveCfg = Release|Any CPU
{3EB8C461-C91E-4900-BFBD-0986CBBE87A6}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -292,6 +306,7 @@ Global
{898966EA-F814-4B7B-9A3D-5E78C38174B2} = {E15D4280-7FFC-4F8B-9B8C-CF9AF2BF838C}
{00333EBA-DB52-4D56-ADF7-940FB533E530} = {DFF3E7AA-7A50-4A1E-B3F8-EC01531FB83D}
{F4B29B77-9B92-4037-A884-288CA5EF0B78} = {DFF3E7AA-7A50-4A1E-B3F8-EC01531FB83D}
{3EB8C461-C91E-4900-BFBD-0986CBBE87A6} = {DFF3E7AA-7A50-4A1E-B3F8-EC01531FB83D}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7C5FBB7F-654C-4CAC-964F-6D71AF3D62F8}
Expand Down
1 change: 1 addition & 0 deletions dev/DebugHost/DebugHost.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Extensions\NetDaemon.Extensions.Logging\NetDaemon.Extensions.Logging.csproj" />
<ProjectReference Include="..\..\src\Extensions\NetDaemon.Extensions.MqttEntityManager\NetDaemon.Extensions.MqttEntityManager.csproj" />
<ProjectReference Include="..\..\src\Extensions\NetDaemon.Extensions.Tts\NetDaemon.Extensions.Tts.csproj" />
<ProjectReference Include="..\..\src\Runtime\NetDaemon.Runtime\NetDaemon.Runtime.csproj" />
<ProjectReference Include="..\..\src\AppModel\NetDaemon.AppModel\NetDaemon.AppModel.csproj" />
Expand Down
35 changes: 19 additions & 16 deletions dev/DebugHost/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,35 @@
using NetDaemon.Runtime;
using NetDaemon.AppModel;
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
using NetDaemon.Extensions.Logging;
using NetDaemon.Extensions.Tts;
using NetDaemon.Extensions.MqttEntityManager;

#pragma warning disable CA1812

try
{
await Host.CreateDefaultBuilder(args)
.UseNetDaemonAppSettings()
.UseNetDaemonDefaultLogging()
.UseNetDaemonRuntime()
.UseNetDaemonTextToSpeech()
.ConfigureServices((_, services) =>
services
// change type of compilation here
// .AddAppsFromSource(true)
.AddAppsFromAssembly(Assembly.GetEntryAssembly()!)
// Remove this is you are not running the integration!
.AddNetDaemonStateManager()
)
.Build()
.RunAsync()
.ConfigureAwait(false);
.UseNetDaemonAppSettings()
.UseNetDaemonDefaultLogging()
.UseNetDaemonRuntime()
.UseNetDaemonTextToSpeech()
.UseNetDaemonMqttEntityManagement()
.ConfigureServices((_, services) =>
services
// change type of compilation here
// .AddAppsFromSource(true)
.AddAppsFromAssembly(Assembly.GetEntryAssembly()!)
// Remove this is you are not running the integration!
.AddNetDaemonStateManager()
)
.Build()
.RunAsync()
.ConfigureAwait(false);
}
catch (Exception e)
{
Console.WriteLine($"Failed to start host... {e}");
throw;
}
}
10 changes: 10 additions & 0 deletions dev/DebugHost/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"profiles": {
"DebugHost": {
"commandName": "Project",
"environmentVariables": {
"DOTNET_ENVIRONMENT": "Development"
}
}
}
}
63 changes: 63 additions & 0 deletions dev/DebugHost/apps/Extensions/MqttEntityManagerApp.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#region

using System;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using NetDaemon.AppModel;
using NetDaemon.Extensions.MqttEntityManager;
using NetDaemon.HassModel;

#endregion

namespace DebugHost.apps.Extensions;

[NetDaemonApp]
[Focus]
public class MqttEntityManagerApp : IAsyncInitializable
{
private readonly IHaContext _ha;
private readonly ILogger<MqttEntityManagerApp> _logger;
private readonly IMqttEntityManager _manager;

public MqttEntityManagerApp(IHaContext ha, ILogger<MqttEntityManagerApp> logger, IMqttEntityManager manager)
{
_ha = ha;
_logger = logger;
_manager = manager;
}

[SuppressMessage("Naming", "CA1727:Use PascalCase for named placeholders", Justification = "<Pending>")]
[SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "We need to log unexpected errors")]
public async Task InitializeAsync(CancellationToken cancellationToken)
{
try
{
_logger.LogInformation("Creating Entity {domain}.{entityId}", "binary_sensor", "manager_test");
await _manager.CreateAsync("binary_sensor", "manager_test", "motion", "Manager Test").ConfigureAwait(false);
// Using Delay to give Mqtt and HA enough time to process events.
// Only needed for the example as we immediately read the entity and it may not yet exist
await Task.Delay(250, cancellationToken).ConfigureAwait(false);

var entity = _ha.Entity("binary_sensor.manager_test");
_logger.LogInformation("Entity {domain}.{entityId} State: {state}", "binary_sensor", "manager_test", entity.State);

await _manager.UpdateAsync("binary_sensor", "manager_test", "ON", JsonSerializer.Serialize(new { attribute1 = "attr1" }))
.ConfigureAwait(false);
await Task.Delay(250, cancellationToken).ConfigureAwait(false);
_logger.LogInformation("Entity {domain}.{entityId} State: {state} Attributes: {attributes}",
"binary_sensor", "manager_test", entity.State, entity.Attributes);

await _manager.RemoveAsync("binary_sensor", "manager_test").ConfigureAwait(false);
await Task.Delay(250, cancellationToken).ConfigureAwait(false);
var removed = _ha.Entity("binary_sensor.manager_test").State == null;
_logger.LogInformation("Removed Entity: {removed}", removed);
}
catch (Exception e)
{
_logger.LogError(e, e.Message);
}
}
}
3 changes: 3 additions & 0 deletions dev/DebugHost/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,8 @@
"NetDaemon": {
"Admin": true,
"ApplicationConfigurationFolder": "./apps"
},
"Mqtt": {
"Host": "localhost"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#region

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using MQTTnet;

#endregion

namespace NetDaemon.Extensions.MqttEntityManager;

/// <summary>
/// DI setup for Mqtt Entity Manager
/// </summary>
public static class DependencyInjectionSetup
{
/// <summary>
/// Add support for managing entities via MQTT
/// </summary>
/// <param name="hostBuilder"></param>
/// <returns></returns>
public static IHostBuilder UseNetDaemonMqttEntityManagement(this IHostBuilder hostBuilder)
{
return hostBuilder.ConfigureServices((context, services) =>
{
services.AddSingleton<IMqttFactory, MqttFactory>();
services.AddSingleton<IMqttEntityManager, MqttEntityManager>();
services.AddTransient<IMessageSender, MessageSender>();
services.Configure<MqttConfiguration>(context.Configuration.GetSection("Mqtt"));
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace NetDaemon.Extensions.MqttEntityManager.Exceptions;

/// <summary>
/// MQTT connection failed
/// </summary>
public class MqttConnectionException : Exception
{
/// <summary>
/// MQTT connection failed
/// </summary>
/// <param name="msg"></param>
public MqttConnectionException(string msg) : base(msg)
{}

/// <summary>
/// MQTT connection failed
/// </summary>
/// <param name="msg"></param>
/// <param name="innerException"></param>
public MqttConnectionException(string msg, Exception innerException) : base(msg, innerException)
{}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace NetDaemon.Extensions.MqttEntityManager.Exceptions;

/// <summary>
/// Failed to publish a message to MQTT
/// </summary>
public class MqttPublishException : Exception
{
/// <summary>
/// Failed to publish a message to MQTT
/// </summary>
/// <param name="msg"></param>
public MqttPublishException(string msg) : base(msg)
{}

/// <summary>
/// Failed to publish a message to MQTT
/// </summary>
/// <param name="msg"></param>
/// <param name="innerException"></param>
public MqttPublishException(string msg, Exception innerException) : base(msg, innerException)
{}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace NetDaemon.Extensions.MqttEntityManager;

/// <summary>
/// Interface to send messages to MQTT
/// </summary>
internal interface IMessageSender
{
/// <summary>
/// Send a message for the given payload to the MQTT topic
/// </summary>
/// <param name="topic"></param>
/// <param name="payload"></param>
/// <param name="retain"></param>
/// <returns></returns>
Task SendMessageAsync(string topic, string payload, bool retain = false);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
namespace NetDaemon.Extensions.MqttEntityManager;

/// <summary>
/// Interface for managing entities via MQTT
/// </summary>
public interface IMqttEntityManager
{
/// <summary>
/// Create an entity in Home Assistant via MQTT
/// </summary>
Task CreateAsync(string domain, string entityId, string deviceClass, string name, bool persist = true);


/// <summary>
/// Remove an entity from Home Assistant
/// </summary>
Task RemoveAsync(string domain, string entityId);


/// <summary>
/// Update state and, optionally, attributes of an HA entity via MQTT
/// </summary>
Task UpdateAsync(string domain, string entityId, string state, string? attributes = null);
}
Loading