From 2a30ab44298eeed63aa57a10d0bd4164d3ca4a24 Mon Sep 17 00:00:00 2001 From: Pavel Yadlouski Date: Thu, 20 Jul 2023 19:15:17 +0200 Subject: [PATCH 01/18] Add interfaces for service targets --- .../CodeGeneration/EntitiesGenerator.cs | 13 +- .../ExtensionMethodsGenerator.cs | 5 +- .../CodeGeneration/HelpersGenerator.cs | 25 ++++ .../NetDeamon.HassModel/Entities/Entity.cs | 2 +- .../Entities/Interfaces/IEntity.cs | 6 + .../Interfaces/ILightServiceTarget.cs | 9 ++ .../Entities/Interfaces/IOnOffTarget.cs | 119 ++++++++++++++++++ .../Entities/Interfaces/IServiceTarget.cs | 14 +++ .../Entities/Interfaces/ISwitchEntity.cs | 6 + 9 files changed, 192 insertions(+), 7 deletions(-) create mode 100644 src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IEntity.cs create mode 100644 src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ILightServiceTarget.cs create mode 100644 src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IOnOffTarget.cs create mode 100644 src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IServiceTarget.cs create mode 100644 src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ISwitchEntity.cs diff --git a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/EntitiesGenerator.cs b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/EntitiesGenerator.cs index e200dc1b6..483c2e081 100644 --- a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/EntitiesGenerator.cs +++ b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/EntitiesGenerator.cs @@ -18,15 +18,12 @@ public static IEnumerable Generate(IReadOnlyCollection< { yield return GenerateEntiesForDomainClass(domainMetadata.Key, domainMetadata); } - foreach (var domainMetadata in metaData) { yield return GenerateEntityType(domainMetadata); - yield return AttributeTypeGenerator.GenerateAttributeRecord(domainMetadata); } } - private static TypeDeclarationSyntax GenerateRootEntitiesInterface(IEnumerable domains) { var autoProperties = domains.Select(domain => @@ -79,13 +76,17 @@ private static MemberDeclarationSyntax GenerateEntityProperty(EntityMetaData ent /// private static MemberDeclarationSyntax GenerateEntityType(EntityDomainMetadata domainMetaData) { - string attributesGeneric = domainMetaData.AttributesClassName; + var attributesGeneric = domainMetaData.AttributesClassName; var baseType = domainMetaData.IsNumeric ? typeof(NumericEntity) : typeof(Entity); var entityStateType = domainMetaData.IsNumeric ? typeof(NumericEntityState) : typeof(EntityState); - var baseClass = $"{SimplifyTypeName(baseType)}<{domainMetaData.EntityClassName}, {SimplifyTypeName(entityStateType)}<{attributesGeneric}>, {attributesGeneric}>"; + if (HelpersGenerator.EntityInterfaces.TryGetValue(domainMetaData.Domain, out var @values)) + { + baseClass += $", {@values[HelpersGenerator.GenerationMode.Entity]}"; + } + var (className, variableName) = GetNames(); var classDeclaration = $$""" record {{domainMetaData.EntityClassName}} : {{baseClass}} @@ -95,6 +96,8 @@ record {{domainMetaData.EntityClassName}} : {{baseClass}} public {{domainMetaData.EntityClassName}}({{SimplifyTypeName(typeof(Entity))}} entity) : base(entity) {} + + // Here would be some wrappers around the entity extension methods } """; diff --git a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ExtensionMethodsGenerator.cs b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ExtensionMethodsGenerator.cs index 8a71b6a08..4dfc3ff47 100644 --- a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ExtensionMethodsGenerator.cs +++ b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ExtensionMethodsGenerator.cs @@ -1,3 +1,4 @@ +using NetDaemon.HassModel.CodeGenerator.CodeGeneration; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace NetDaemon.HassModel.CodeGenerator; @@ -59,7 +60,9 @@ private static IEnumerable GenerateExtensionMethodsForS private static IEnumerable GenerateExtensionMethodsForService(string domain, HassService service, string targetEntityDomain, ILookup entityClassNameByDomain) { - var entityTypeName = entityClassNameByDomain[targetEntityDomain].FirstOrDefault(); + var entityTypeName = HelpersGenerator.EntityInterfaces.GetValueOrDefault(targetEntityDomain)?.GetValueOrDefault(HelpersGenerator.GenerationMode.Entity) ?? + entityClassNameByDomain[targetEntityDomain].FirstOrDefault(); + if (entityTypeName == null) yield break; var serviceName = service.Service; diff --git a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/HelpersGenerator.cs b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/HelpersGenerator.cs index 8d16e50d2..fa6de9057 100644 --- a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/HelpersGenerator.cs +++ b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/HelpersGenerator.cs @@ -5,6 +5,31 @@ namespace NetDaemon.HassModel.CodeGenerator.CodeGeneration; internal static class HelpersGenerator { + + public enum GenerationMode + { + Entity, + Parameter + } + + public static readonly Dictionary> EntityInterfaces = new() + { + { + "light", + new Dictionary + { + { GenerationMode.Entity, "ILightEntity" }, + } + }, + { + "switch", + new Dictionary + { + { GenerationMode.Entity, "ISwitchEntity" }, + } + } + }; + public static IEnumerable Generate(IReadOnlyCollection domains, IEnumerable orderedServiceDomains) { var extensionClass = GenerateServiceCollectionExtension(domains, orderedServiceDomains); diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Entity.cs b/src/HassModel/NetDeamon.HassModel/Entities/Entity.cs index 5985ec259..b53c42532 100644 --- a/src/HassModel/NetDeamon.HassModel/Entities/Entity.cs +++ b/src/HassModel/NetDeamon.HassModel/Entities/Entity.cs @@ -1,7 +1,7 @@ namespace NetDaemon.HassModel.Entities; /// Represents a Home Assistant entity with its state, changes and services -public record Entity +public record Entity: IServiceTarget { /// /// The IHAContext diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IEntity.cs b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IEntity.cs new file mode 100644 index 000000000..9a6b6f5df --- /dev/null +++ b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IEntity.cs @@ -0,0 +1,6 @@ +namespace NetDaemon.HassModel.Entities; + +public interface IEntity +{ + +} \ No newline at end of file diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ILightServiceTarget.cs b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ILightServiceTarget.cs new file mode 100644 index 000000000..8f22e4e20 --- /dev/null +++ b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ILightServiceTarget.cs @@ -0,0 +1,9 @@ +namespace NetDaemon.HassModel.Entities; + +public interface ILightServiceTarget: IServiceTarget, IOnOffTarget //, IOnOffListTarget +{ +} + +public interface ILightEntity : ILightServiceTarget +{ +} \ No newline at end of file diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IOnOffTarget.cs b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IOnOffTarget.cs new file mode 100644 index 000000000..eb4e4bcec --- /dev/null +++ b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IOnOffTarget.cs @@ -0,0 +1,119 @@ +namespace NetDaemon.HassModel.Entities; + + + +/// +/// +/// +public interface IToggleParameters +{ +} + +/// +/// +/// +public interface ITurnOffParameters +{ +} + +public interface ITurnOnParameters +{ +} + + + +public interface IOnOffTarget +{ + // Virtual extension methods (aka default interface methods) + + public void Toggle() + { + throw new NotImplementedException(); + } + + public static void TurnOn() + { + throw new NotImplementedException(); + } + + public static void TurnOff() + { + throw new NotImplementedException(); + } + + ///Toggles one or more targets, from on to off, or, off to on, based on their current state. + public void Toggle(IToggleParameters data) + { + throw new NotImplementedException(); + } + + ///Toggles one or more targets, from on to off, or, off to on, based on their current state. + ///The LightEntity to call this service for + ///Duration it takes to get to next state. + ///Color for the light in RGB-format. eg: [255, 100, 100] + ///A human readable color name. + ///Color for the light in hue/sat format. Hue is 0-360 and Sat is 0-100. eg: [300, 70] + ///Color for the light in XY-format. eg: [0.52, 0.43] + ///Color temperature for the light in mireds. + ///Color temperature for the light in Kelvin. + ///Number indicating brightness, where 0 turns the light off, 1 is the minimum brightness and 255 is the maximum brightness supported by the light. + ///Number indicating percentage of full brightness, where 0 turns the light off, 1 is the minimum brightness and 100 is the maximum brightness supported by the light. + ///Set the light to white mode. + ///Name of a light profile to use. eg: relax + ///If the light should flash. + ///Light effect. + public static void Toggle(long? transition = null, object? rgbColor = null, object? colorName = null, object? hsColor = null, object? xyColor = null, object? colorTemp = null, long? kelvin = null, long? brightness = null, long? brightnessPct = null, object? white = null, string? profile = null, object? flash = null, string? effect = null) + { + throw new NotImplementedException(); + } + + ///Turns off one or more targets. + public static void TurnOff(ITurnOffParameters data) + { + throw new NotImplementedException(); + } + + ///Turns off one or more targets. + ///The LightEntity to call this service for + ///Duration it takes to get to next state. + ///If the light should flash. + public static void TurnOff(long? transition = null, object? flash = null) + { + throw new NotImplementedException(); + } + + ///Turn on one or more targets and adjust properties of the light, even when they are turned on already. + public void TurnOn(ITurnOnParameters data) + { + throw new NotImplementedException(); + } + + ///Turn on one or more targets and adjust properties of the light, even when they are turned on already. + ///The LightEntity to call this service for + ///Duration it takes to get to next state. + ///The color for the light (based on RGB - red, green, blue). + ///A list containing four integers between 0 and 255 representing the RGBW (red, green, blue, white) color for the light. eg: [255, 100, 100, 50] + ///A list containing five integers between 0 and 255 representing the RGBWW (red, green, blue, cold white, warm white) color for the light. eg: [255, 100, 100, 50, 70] + ///A human readable color name. + ///Color for the light in hue/sat format. Hue is 0-360 and Sat is 0-100. eg: [300, 70] + ///Color for the light in XY-format. eg: [0.52, 0.43] + ///Color temperature for the light in mireds. + ///Color temperature for the light in Kelvin. + ///Number indicating brightness, where 0 turns the light off, 1 is the minimum brightness and 255 is the maximum brightness supported by the light. + ///Number indicating percentage of full brightness, where 0 turns the light off, 1 is the minimum brightness and 100 is the maximum brightness supported by the light. + ///Change brightness by an amount. + ///Change brightness by a percentage. + ///Set the light to white mode. + ///Name of a light profile to use. eg: relax + ///If the light should flash. + ///Light effect. + public static void TurnOn(long? transition = null, object? rgbColor = null, object? rgbwColor = null, object? rgbwwColor = null, object? colorName = null, object? hsColor = null, object? xyColor = null, object? colorTemp = null, long? kelvin = null, long? brightness = null, long? brightnessPct = null, long? brightnessStep = null, long? brightnessStepPct = null, object? white = null, string? profile = null, object? flash = null, string? effect = null) + { + throw new NotImplementedException(); + } +} + +public interface IOnOffListTarget: IEnumerable +{ + +} \ No newline at end of file diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IServiceTarget.cs b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IServiceTarget.cs new file mode 100644 index 000000000..3af8161e7 --- /dev/null +++ b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IServiceTarget.cs @@ -0,0 +1,14 @@ +namespace NetDaemon.HassModel.Entities; + +/// +/// +/// +public interface IServiceTarget: IEntity +{ + /// + /// Base interface for all service targets such as entities, rooms, areas. + /// + /// + /// + public void CallService(string service, object? data = null); +} diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ISwitchEntity.cs b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ISwitchEntity.cs new file mode 100644 index 000000000..7e4a55070 --- /dev/null +++ b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ISwitchEntity.cs @@ -0,0 +1,6 @@ +namespace NetDaemon.HassModel.Entities; + +public interface ISwitchEntity: IOnOffTarget, IServiceTarget +{ + +} \ No newline at end of file From e95a87069cdb462fd78db12c06b597ab5f7d4b22 Mon Sep 17 00:00:00 2001 From: Pavel Yadlouski Date: Thu, 20 Jul 2023 19:43:12 +0200 Subject: [PATCH 02/18] Fix types in Enumerable extension methods --- .../Entities/EnumerableEntityExtensions.cs | 6 +++--- .../NetDeamon.HassModel/Entities/Interfaces/IEntity.cs | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/HassModel/NetDeamon.HassModel/Entities/EnumerableEntityExtensions.cs b/src/HassModel/NetDeamon.HassModel/Entities/EnumerableEntityExtensions.cs index 894f2eefd..ae6f87159 100644 --- a/src/HassModel/NetDeamon.HassModel/Entities/EnumerableEntityExtensions.cs +++ b/src/HassModel/NetDeamon.HassModel/Entities/EnumerableEntityExtensions.cs @@ -17,7 +17,7 @@ public static class EnumerableEntityExtensions /// .Subscribe(e => HandleBrightnessOverHalf()); /// /// - public static IObservable StateAllChanges(this IEnumerable entities) => + public static IObservable StateAllChanges(this IEnumerable entities) => entities.Select(t => t.StateAllChanges()).Merge(); /// @@ -31,7 +31,7 @@ public static IObservable StateAllChanges(this IEnumerable /// .Subscribe(e => e.Entity.TurnOff()); /// /// - public static IObservable StateChanges(this IEnumerable entities) => + public static IObservable StateChanges(this IEnumerable entities) => entities.StateAllChanges().StateChangesOnly(); /// @@ -75,7 +75,7 @@ public static IObservable> StateChangesIEnumerable of Entities for which to call the service /// Name of the service to call. If the Domain of the service is the same as the domain of the Entities it can be omitted /// Data to provide - public static void CallService(this IEnumerable entities, string service, object? data = null) + public static void CallService(this IEnumerable entities, string service, object? data = null) { ArgumentNullException.ThrowIfNull(service); diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IEntity.cs b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IEntity.cs index 9a6b6f5df..5728322d6 100644 --- a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IEntity.cs +++ b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IEntity.cs @@ -2,5 +2,9 @@ namespace NetDaemon.HassModel.Entities; public interface IEntity { + public string EntityId { get; } + public IHaContext? HaContext { get; } + + public IObservable StateAllChanges(); } \ No newline at end of file From d34f8e0de65b9ac9a939472cecb59ff9190556e1 Mon Sep 17 00:00:00 2001 From: Pavel Yadlouski Date: Thu, 20 Jul 2023 20:47:53 +0200 Subject: [PATCH 03/18] Add testing projects --- src/debug/MyLibrary/MyLibrary.csproj | 13 +++++ src/debug/MyLibrary/MyLibraryClass.cs | 18 +++++++ src/debug/MyNDApp/.gitignore | 8 +++ src/debug/MyNDApp/MyNDApp.csproj | 52 +++++++++++++++++++ .../MyInterfaceAutomation/InterfaceUsage.cs | 22 ++++++++ src/debug/MyNDApp/program.cs | 35 +++++++++++++ 6 files changed, 148 insertions(+) create mode 100644 src/debug/MyLibrary/MyLibrary.csproj create mode 100644 src/debug/MyLibrary/MyLibraryClass.cs create mode 100644 src/debug/MyNDApp/.gitignore create mode 100644 src/debug/MyNDApp/MyNDApp.csproj create mode 100644 src/debug/MyNDApp/apps/HassModel/MyInterfaceAutomation/InterfaceUsage.cs create mode 100644 src/debug/MyNDApp/program.cs diff --git a/src/debug/MyLibrary/MyLibrary.csproj b/src/debug/MyLibrary/MyLibrary.csproj new file mode 100644 index 000000000..62d184b2f --- /dev/null +++ b/src/debug/MyLibrary/MyLibrary.csproj @@ -0,0 +1,13 @@ + + + + net7.0 + enable + enable + + + + + + + diff --git a/src/debug/MyLibrary/MyLibraryClass.cs b/src/debug/MyLibrary/MyLibraryClass.cs new file mode 100644 index 000000000..8451b2969 --- /dev/null +++ b/src/debug/MyLibrary/MyLibraryClass.cs @@ -0,0 +1,18 @@ +using NetDaemon.HassModel.Entities; + +namespace MyLibrary; + +public class MyLibraryClass +{ + public IOnOffTarget Target; + + public MyLibraryClass(ILightServiceTarget target) + { + Target = target; + } + + public void ToogleTarget() + { + Target.Toggle(); + } +} \ No newline at end of file diff --git a/src/debug/MyNDApp/.gitignore b/src/debug/MyNDApp/.gitignore new file mode 100644 index 000000000..d209ae50d --- /dev/null +++ b/src/debug/MyNDApp/.gitignore @@ -0,0 +1,8 @@ +obj +bin +appsettings.Development.json +.vs +*.gen +.idea +#appsettings.json +#HomeAssistantGenerated.cs \ No newline at end of file diff --git a/src/debug/MyNDApp/MyNDApp.csproj b/src/debug/MyNDApp/MyNDApp.csproj new file mode 100644 index 000000000..ed005da15 --- /dev/null +++ b/src/debug/MyNDApp/MyNDApp.csproj @@ -0,0 +1,52 @@ + + + + Exe + net7.0 + 11.0 + enable + Debug + + + + Always + + + Always + + + Always + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/debug/MyNDApp/apps/HassModel/MyInterfaceAutomation/InterfaceUsage.cs b/src/debug/MyNDApp/apps/HassModel/MyInterfaceAutomation/InterfaceUsage.cs new file mode 100644 index 000000000..7148d4e20 --- /dev/null +++ b/src/debug/MyNDApp/apps/HassModel/MyInterfaceAutomation/InterfaceUsage.cs @@ -0,0 +1,22 @@ +using System.Threading; +using HomeAssistantGenerated; +using MyLibrary; + +namespace Debug.apps.HassModel.MyInterfaceAutomation; + +[NetDaemonApp] +[Focus] +public class InterfaceUsage +{ + public InterfaceUsage(IHaContext haContext, ILogger logger) + { + var entities = new Entities(haContext); + var myLibraryClass = new MyLibraryClass(entities.Light.SonoffLed); + + while (true) + { + myLibraryClass.ToogleTarget(); + Thread.Sleep(1000); + } + } +} \ No newline at end of file diff --git a/src/debug/MyNDApp/program.cs b/src/debug/MyNDApp/program.cs new file mode 100644 index 000000000..5fb2a0a69 --- /dev/null +++ b/src/debug/MyNDApp/program.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using HomeAssistantGenerated; +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 + +#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; +} From b64ce0e43925127fd9c3e561fc1c97cf97e87a42 Mon Sep 17 00:00:00 2001 From: Pavel Yadlouski Date: Fri, 21 Jul 2023 22:03:11 +0200 Subject: [PATCH 04/18] Add usage of IEnumirable of entities --- .../Entities/Interfaces/ILightServiceTarget.cs | 2 +- .../Entities/Interfaces/IOnOffTarget.cs | 14 +++++++++++--- src/debug/MyLibrary/MyLibraryClass.cs | 13 ++++++++++--- .../MyInterfaceAutomation/InterfaceUsage.cs | 8 +++++--- 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ILightServiceTarget.cs b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ILightServiceTarget.cs index 8f22e4e20..e23d53435 100644 --- a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ILightServiceTarget.cs +++ b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ILightServiceTarget.cs @@ -1,6 +1,6 @@ namespace NetDaemon.HassModel.Entities; -public interface ILightServiceTarget: IServiceTarget, IOnOffTarget //, IOnOffListTarget +public interface ILightServiceTarget: IServiceTarget, IOnOffTarget { } diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IOnOffTarget.cs b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IOnOffTarget.cs index eb4e4bcec..db163b05d 100644 --- a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IOnOffTarget.cs +++ b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IOnOffTarget.cs @@ -31,12 +31,17 @@ public void Toggle() throw new NotImplementedException(); } - public static void TurnOn() + public void TurnOn() { throw new NotImplementedException(); } - public static void TurnOff() + public void TurnOff() + { + throw new NotImplementedException(); + } + + public void Toggle(IEnumerable targets) { throw new NotImplementedException(); } @@ -115,5 +120,8 @@ public static void TurnOn(long? transition = null, object? rgbColor = null, obje public interface IOnOffListTarget: IEnumerable { - + public void Toggle() + { + throw new NotImplementedException(); + } } \ No newline at end of file diff --git a/src/debug/MyLibrary/MyLibraryClass.cs b/src/debug/MyLibrary/MyLibraryClass.cs index 8451b2969..fc2608481 100644 --- a/src/debug/MyLibrary/MyLibraryClass.cs +++ b/src/debug/MyLibrary/MyLibraryClass.cs @@ -4,15 +4,22 @@ namespace MyLibrary; public class MyLibraryClass { - public IOnOffTarget Target; + public ILightEntity Target; + public IEnumerable TargetList; - public MyLibraryClass(ILightServiceTarget target) + public MyLibraryClass(ILightEntity target, IEnumerable lights) { Target = target; + TargetList = lights; } public void ToogleTarget() { Target.Toggle(); } -} \ No newline at end of file + + public void ToogleTargetList() + { + Target.Toggle(TargetList); + } +} diff --git a/src/debug/MyNDApp/apps/HassModel/MyInterfaceAutomation/InterfaceUsage.cs b/src/debug/MyNDApp/apps/HassModel/MyInterfaceAutomation/InterfaceUsage.cs index 7148d4e20..313a66220 100644 --- a/src/debug/MyNDApp/apps/HassModel/MyInterfaceAutomation/InterfaceUsage.cs +++ b/src/debug/MyNDApp/apps/HassModel/MyInterfaceAutomation/InterfaceUsage.cs @@ -1,6 +1,8 @@ +using System.Collections.Generic; using System.Threading; using HomeAssistantGenerated; using MyLibrary; +using NetDaemon.HassModel.Entities; namespace Debug.apps.HassModel.MyInterfaceAutomation; @@ -11,11 +13,11 @@ public class InterfaceUsage public InterfaceUsage(IHaContext haContext, ILogger logger) { var entities = new Entities(haContext); - var myLibraryClass = new MyLibraryClass(entities.Light.SonoffLed); - + IEnumerable lights = new[] { entities.Light.LivingRoom, entities.Light.SonoffLed }; + var myLibraryClass = new MyLibraryClass(entities.Light.SonoffLed, lights); while (true) { - myLibraryClass.ToogleTarget(); + myLibraryClass.ToogleTargetList(); Thread.Sleep(1000); } } From eaed11de10131870c219917bc6200580040a591f Mon Sep 17 00:00:00 2001 From: Pavel Yadlouski Date: Sat, 22 Jul 2023 11:07:43 +0200 Subject: [PATCH 05/18] Add part of generated code to the library --- .../LightEntityExtensionMethods.cs | 40 +++++++++++++++++++ src/debug/MyLibrary/MyLibraryClass.cs | 1 + 2 files changed, 41 insertions(+) create mode 100644 src/debug/MyLibrary/InternalHomeAssistantGenerated/LightEntityExtensionMethods.cs diff --git a/src/debug/MyLibrary/InternalHomeAssistantGenerated/LightEntityExtensionMethods.cs b/src/debug/MyLibrary/InternalHomeAssistantGenerated/LightEntityExtensionMethods.cs new file mode 100644 index 000000000..66f69e964 --- /dev/null +++ b/src/debug/MyLibrary/InternalHomeAssistantGenerated/LightEntityExtensionMethods.cs @@ -0,0 +1,40 @@ +using NetDaemon.HassModel.Entities; + +namespace MyLibrary.InternalHomeAssistantGenerated; + +public static class LightEntityExtensionMethods +{ + public static void Toggle(this ILightEntity target, IToggleParameters data) + { + target.CallService("toggle", data); + } + + public static void Toggle(this IEnumerable target, IToggleParameters data) + { + target.CallService("toggle", data); + } + + ///Turns off one or more lights. + public static void TurnOff(this ILightEntity target, ITurnOffParameters data) + { + target.CallService("turn_off", data); + } + + ///Turns off one or more lights. + public static void TurnOff(this IEnumerable target, ITurnOffParameters data) + { + target.CallService("turn_off", data); + } + + ///Turn on one or more lights and adjust properties of the light, even when they are turned on already. + public static void TurnOn(this ILightEntity target, ITurnOnParameters data) + { + target.CallService("turn_on", data); + } + + ///Turn on one or more lights and adjust properties of the light, even when they are turned on already. + public static void TurnOn(this IEnumerable target, ITurnOnParameters data) + { + target.CallService("turn_on", data); + } +} \ No newline at end of file diff --git a/src/debug/MyLibrary/MyLibraryClass.cs b/src/debug/MyLibrary/MyLibraryClass.cs index fc2608481..5930f735e 100644 --- a/src/debug/MyLibrary/MyLibraryClass.cs +++ b/src/debug/MyLibrary/MyLibraryClass.cs @@ -1,4 +1,5 @@ using NetDaemon.HassModel.Entities; +using MyLibrary.InternalHomeAssistantGenerated; namespace MyLibrary; From c7d8371f938a9a1de6ef3404c9a28be49d16472b Mon Sep 17 00:00:00 2001 From: Pavel Yadlouski Date: Sat, 22 Jul 2023 17:26:27 +0200 Subject: [PATCH 06/18] Add extension method to the library --- .../LightEntityExtensionMethods.cs | 5 +++-- src/debug/MyLibrary/MyLibraryClass.cs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/debug/MyLibrary/InternalHomeAssistantGenerated/LightEntityExtensionMethods.cs b/src/debug/MyLibrary/InternalHomeAssistantGenerated/LightEntityExtensionMethods.cs index 66f69e964..e19943dac 100644 --- a/src/debug/MyLibrary/InternalHomeAssistantGenerated/LightEntityExtensionMethods.cs +++ b/src/debug/MyLibrary/InternalHomeAssistantGenerated/LightEntityExtensionMethods.cs @@ -1,11 +1,12 @@ using NetDaemon.HassModel.Entities; -namespace MyLibrary.InternalHomeAssistantGenerated; +namespace MyLibrary; public static class LightEntityExtensionMethods { public static void Toggle(this ILightEntity target, IToggleParameters data) - { + { + Console.WriteLine("Toggle"); target.CallService("toggle", data); } diff --git a/src/debug/MyLibrary/MyLibraryClass.cs b/src/debug/MyLibrary/MyLibraryClass.cs index 5930f735e..409be065e 100644 --- a/src/debug/MyLibrary/MyLibraryClass.cs +++ b/src/debug/MyLibrary/MyLibraryClass.cs @@ -1,5 +1,5 @@ using NetDaemon.HassModel.Entities; -using MyLibrary.InternalHomeAssistantGenerated; + namespace MyLibrary; From 1dc6634b446d96ab5e6006f9257cba9edb813410 Mon Sep 17 00:00:00 2001 From: Pavel Yadlouski Date: Sat, 22 Jul 2023 18:23:09 +0200 Subject: [PATCH 07/18] Add dummy docs --- .../Entities/Interfaces/IEntity.cs | 13 +++++++ .../Interfaces/ILightServiceTarget.cs | 6 ++++ .../Entities/Interfaces/IOnOffTarget.cs | 36 ++++++++++++------- .../Entities/Interfaces/ISwitchEntity.cs | 3 ++ 4 files changed, 46 insertions(+), 12 deletions(-) diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IEntity.cs b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IEntity.cs index 5728322d6..072f5eb28 100644 --- a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IEntity.cs +++ b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IEntity.cs @@ -1,10 +1,23 @@ namespace NetDaemon.HassModel.Entities; +/// +/// Base interface for all entities in NetDaemon +/// public interface IEntity { + /// + /// + /// public string EntityId { get; } + /// + /// + /// public IHaContext? HaContext { get; } + /// + /// + /// + /// public IObservable StateAllChanges(); } \ No newline at end of file diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ILightServiceTarget.cs b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ILightServiceTarget.cs index e23d53435..9d81c573c 100644 --- a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ILightServiceTarget.cs +++ b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ILightServiceTarget.cs @@ -1,9 +1,15 @@ namespace NetDaemon.HassModel.Entities; +/// +/// +/// public interface ILightServiceTarget: IServiceTarget, IOnOffTarget { } +/// +/// +/// public interface ILightEntity : ILightServiceTarget { } \ No newline at end of file diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IOnOffTarget.cs b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IOnOffTarget.cs index db163b05d..11cfdb458 100644 --- a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IOnOffTarget.cs +++ b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IOnOffTarget.cs @@ -1,6 +1,6 @@ namespace NetDaemon.HassModel.Entities; - +#pragma warning disable CA1040 /// /// @@ -16,31 +16,54 @@ public interface ITurnOffParameters { } +/// +/// +/// public interface ITurnOnParameters { } +/// +/// Base interface for togglebal targets +/// public interface IOnOffTarget { // Virtual extension methods (aka default interface methods) + /// + /// + /// + /// public void Toggle() { throw new NotImplementedException(); } + /// + /// + /// + /// public void TurnOn() { throw new NotImplementedException(); } + /// + /// + /// + /// public void TurnOff() { throw new NotImplementedException(); } + /// + /// + /// + /// + /// public void Toggle(IEnumerable targets) { throw new NotImplementedException(); @@ -53,7 +76,6 @@ public void Toggle(IToggleParameters data) } ///Toggles one or more targets, from on to off, or, off to on, based on their current state. - ///The LightEntity to call this service for ///Duration it takes to get to next state. ///Color for the light in RGB-format. eg: [255, 100, 100] ///A human readable color name. @@ -79,7 +101,6 @@ public static void TurnOff(ITurnOffParameters data) } ///Turns off one or more targets. - ///The LightEntity to call this service for ///Duration it takes to get to next state. ///If the light should flash. public static void TurnOff(long? transition = null, object? flash = null) @@ -94,7 +115,6 @@ public void TurnOn(ITurnOnParameters data) } ///Turn on one or more targets and adjust properties of the light, even when they are turned on already. - ///The LightEntity to call this service for ///Duration it takes to get to next state. ///The color for the light (based on RGB - red, green, blue). ///A list containing four integers between 0 and 255 representing the RGBW (red, green, blue, white) color for the light. eg: [255, 100, 100, 50] @@ -117,11 +137,3 @@ public static void TurnOn(long? transition = null, object? rgbColor = null, obje throw new NotImplementedException(); } } - -public interface IOnOffListTarget: IEnumerable -{ - public void Toggle() - { - throw new NotImplementedException(); - } -} \ No newline at end of file diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ISwitchEntity.cs b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ISwitchEntity.cs index 7e4a55070..f2383eb29 100644 --- a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ISwitchEntity.cs +++ b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ISwitchEntity.cs @@ -1,5 +1,8 @@ namespace NetDaemon.HassModel.Entities; +/// +/// +/// public interface ISwitchEntity: IOnOffTarget, IServiceTarget { From 51f446dbd09dfb0a27ff951b72ab29841f1f13a1 Mon Sep 17 00:00:00 2001 From: Pavel Yadlouski Date: Mon, 24 Jul 2023 00:57:39 +0200 Subject: [PATCH 08/18] Refactored interfaces for entities --- .../NetDeamon.HassModel/Entities/Entity.cs | 2 +- .../Entities/EnumerableEntityExtensions.cs | 6 +- .../{IServiceTarget.cs => IEntityTarget.cs} | 2 +- .../Entities/Interfaces/ILightEntityTarget.cs | 88 +++++++++++++++ .../Interfaces/ILightServiceTarget.cs | 15 --- .../Entities/Interfaces/IOnOffTarget.cs | 102 +++--------------- .../Entities/Interfaces/ISwitchEntity.cs | 2 +- .../MyInterfaceAutomation/InterfaceUsage.cs | 6 +- 8 files changed, 112 insertions(+), 111 deletions(-) rename src/HassModel/NetDeamon.HassModel/Entities/Interfaces/{IServiceTarget.cs => IEntityTarget.cs} (89%) create mode 100644 src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ILightEntityTarget.cs delete mode 100644 src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ILightServiceTarget.cs diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Entity.cs b/src/HassModel/NetDeamon.HassModel/Entities/Entity.cs index b53c42532..bad30ee4f 100644 --- a/src/HassModel/NetDeamon.HassModel/Entities/Entity.cs +++ b/src/HassModel/NetDeamon.HassModel/Entities/Entity.cs @@ -1,7 +1,7 @@ namespace NetDaemon.HassModel.Entities; /// Represents a Home Assistant entity with its state, changes and services -public record Entity: IServiceTarget +public record Entity: IEntityTarget { /// /// The IHAContext diff --git a/src/HassModel/NetDeamon.HassModel/Entities/EnumerableEntityExtensions.cs b/src/HassModel/NetDeamon.HassModel/Entities/EnumerableEntityExtensions.cs index ae6f87159..fcb96400b 100644 --- a/src/HassModel/NetDeamon.HassModel/Entities/EnumerableEntityExtensions.cs +++ b/src/HassModel/NetDeamon.HassModel/Entities/EnumerableEntityExtensions.cs @@ -17,7 +17,7 @@ public static class EnumerableEntityExtensions /// .Subscribe(e => HandleBrightnessOverHalf()); /// /// - public static IObservable StateAllChanges(this IEnumerable entities) => + public static IObservable StateAllChanges(this IEnumerable entities) => entities.Select(t => t.StateAllChanges()).Merge(); /// @@ -31,7 +31,7 @@ public static IObservable StateAllChanges(this IEnumerable /// - public static IObservable StateChanges(this IEnumerable entities) => + public static IObservable StateChanges(this IEnumerable entities) => entities.StateAllChanges().StateChangesOnly(); /// @@ -75,7 +75,7 @@ public static IObservable> StateChangesIEnumerable of Entities for which to call the service /// Name of the service to call. If the Domain of the service is the same as the domain of the Entities it can be omitted /// Data to provide - public static void CallService(this IEnumerable entities, string service, object? data = null) + public static void CallService(this IEnumerable entities, string service, object? data = null) { ArgumentNullException.ThrowIfNull(service); diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IServiceTarget.cs b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IEntityTarget.cs similarity index 89% rename from src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IServiceTarget.cs rename to src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IEntityTarget.cs index 3af8161e7..981bd7ea9 100644 --- a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IServiceTarget.cs +++ b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IEntityTarget.cs @@ -3,7 +3,7 @@ namespace NetDaemon.HassModel.Entities; /// /// /// -public interface IServiceTarget: IEntity +public interface IEntityTarget: IEntity { /// /// Base interface for all service targets such as entities, rooms, areas. diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ILightEntityTarget.cs b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ILightEntityTarget.cs new file mode 100644 index 000000000..46fe91f90 --- /dev/null +++ b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ILightEntityTarget.cs @@ -0,0 +1,88 @@ +namespace NetDaemon.HassModel.Entities; + +/// +/// +/// +public interface ILightEntityTarget: IOnOffTarget +{ +} + +/// +/// +/// +public interface ILightEntity : ILightEntityTarget +{ + /// + /// Default implementation of Toggle method + /// + public new void Toggle() + { + CallService("light.toggle"); + } + + /// + /// Default implementation of TurnOn method + /// + public new void TurnOn() + { + CallService("light.turn_on"); + } + + /// + /// Default implementation of TurnOff method + /// + public new void TurnOff() + { + CallService("light.turn_off"); + } + + ///Toggles one or more targets, from on to off, or, off to on, based on their current state. + ///Duration it takes to get to next state. + ///Color for the light in RGB-format. eg: [255, 100, 100] + ///A human readable color name. + ///Color for the light in hue/sat format. Hue is 0-360 and Sat is 0-100. eg: [300, 70] + ///Color for the light in XY-format. eg: [0.52, 0.43] + ///Color temperature for the light in mireds. + ///Color temperature for the light in Kelvin. + ///Number indicating brightness, where 0 turns the light off, 1 is the minimum brightness and 255 is the maximum brightness supported by the light. + ///Number indicating percentage of full brightness, where 0 turns the light off, 1 is the minimum brightness and 100 is the maximum brightness supported by the light. + ///Set the light to white mode. + ///Name of a light profile to use. eg: relax + ///If the light should flash. + ///Light effect. + public void Toggle(long? transition = null, object? rgbColor = null, object? colorName = null, object? hsColor = null, object? xyColor = null, object? colorTemp = null, long? kelvin = null, long? brightness = null, long? brightnessPct = null, object? white = null, string? profile = null, object? flash = null, string? effect = null) + { + throw new NotImplementedException(); + } + + ///Turns off one or more targets. + ///Duration it takes to get to next state. + ///If the light should flash. + public void TurnOff(long? transition = null, object? flash = null) + { + throw new NotImplementedException(); + } + + ///Turn on one or more targets and adjust properties of the light, even when they are turned on already. + ///Duration it takes to get to next state. + ///The color for the light (based on RGB - red, green, blue). + ///A list containing four integers between 0 and 255 representing the RGBW (red, green, blue, white) color for the light. eg: [255, 100, 100, 50] + ///A list containing five integers between 0 and 255 representing the RGBWW (red, green, blue, cold white, warm white) color for the light. eg: [255, 100, 100, 50, 70] + ///A human readable color name. + ///Color for the light in hue/sat format. Hue is 0-360 and Sat is 0-100. eg: [300, 70] + ///Color for the light in XY-format. eg: [0.52, 0.43] + ///Color temperature for the light in mireds. + ///Color temperature for the light in Kelvin. + ///Number indicating brightness, where 0 turns the light off, 1 is the minimum brightness and 255 is the maximum brightness supported by the light. + ///Number indicating percentage of full brightness, where 0 turns the light off, 1 is the minimum brightness and 100 is the maximum brightness supported by the light. + ///Change brightness by an amount. + ///Change brightness by a percentage. + ///Set the light to white mode. + ///Name of a light profile to use. eg: relax + ///If the light should flash. + ///Light effect. + public void TurnOn(long? transition = null, object? rgbColor = null, object? rgbwColor = null, object? rgbwwColor = null, object? colorName = null, object? hsColor = null, object? xyColor = null, object? colorTemp = null, long? kelvin = null, long? brightness = null, long? brightnessPct = null, long? brightnessStep = null, long? brightnessStepPct = null, object? white = null, string? profile = null, object? flash = null, string? effect = null) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ILightServiceTarget.cs b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ILightServiceTarget.cs deleted file mode 100644 index 9d81c573c..000000000 --- a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ILightServiceTarget.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace NetDaemon.HassModel.Entities; - -/// -/// -/// -public interface ILightServiceTarget: IServiceTarget, IOnOffTarget -{ -} - -/// -/// -/// -public interface ILightEntity : ILightServiceTarget -{ -} \ No newline at end of file diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IOnOffTarget.cs b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IOnOffTarget.cs index 11cfdb458..54cb8482c 100644 --- a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IOnOffTarget.cs +++ b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IOnOffTarget.cs @@ -1,34 +1,10 @@ namespace NetDaemon.HassModel.Entities; -#pragma warning disable CA1040 - -/// -/// -/// -public interface IToggleParameters -{ -} - -/// -/// -/// -public interface ITurnOffParameters -{ -} - -/// -/// -/// -public interface ITurnOnParameters -{ -} - - /// /// Base interface for togglebal targets /// -public interface IOnOffTarget +public interface IOnOffTarget: IEntityTarget { // Virtual extension methods (aka default interface methods) @@ -38,7 +14,7 @@ public interface IOnOffTarget /// public void Toggle() { - throw new NotImplementedException(); + CallService("toggle"); } /// @@ -64,75 +40,27 @@ public void TurnOff() /// /// /// - public void Toggle(IEnumerable targets) + public void Toggle(IEnumerable targets) { throw new NotImplementedException(); } - ///Toggles one or more targets, from on to off, or, off to on, based on their current state. - public void Toggle(IToggleParameters data) - { - throw new NotImplementedException(); - } - - ///Toggles one or more targets, from on to off, or, off to on, based on their current state. - ///Duration it takes to get to next state. - ///Color for the light in RGB-format. eg: [255, 100, 100] - ///A human readable color name. - ///Color for the light in hue/sat format. Hue is 0-360 and Sat is 0-100. eg: [300, 70] - ///Color for the light in XY-format. eg: [0.52, 0.43] - ///Color temperature for the light in mireds. - ///Color temperature for the light in Kelvin. - ///Number indicating brightness, where 0 turns the light off, 1 is the minimum brightness and 255 is the maximum brightness supported by the light. - ///Number indicating percentage of full brightness, where 0 turns the light off, 1 is the minimum brightness and 100 is the maximum brightness supported by the light. - ///Set the light to white mode. - ///Name of a light profile to use. eg: relax - ///If the light should flash. - ///Light effect. - public static void Toggle(long? transition = null, object? rgbColor = null, object? colorName = null, object? hsColor = null, object? xyColor = null, object? colorTemp = null, long? kelvin = null, long? brightness = null, long? brightnessPct = null, object? white = null, string? profile = null, object? flash = null, string? effect = null) - { - throw new NotImplementedException(); - } - - ///Turns off one or more targets. - public static void TurnOff(ITurnOffParameters data) - { - throw new NotImplementedException(); - } - - ///Turns off one or more targets. - ///Duration it takes to get to next state. - ///If the light should flash. - public static void TurnOff(long? transition = null, object? flash = null) + /// + /// + /// + /// + /// + public void TurnOn(IEnumerable targets) { throw new NotImplementedException(); } - ///Turn on one or more targets and adjust properties of the light, even when they are turned on already. - public void TurnOn(ITurnOnParameters data) - { - throw new NotImplementedException(); - } - - ///Turn on one or more targets and adjust properties of the light, even when they are turned on already. - ///Duration it takes to get to next state. - ///The color for the light (based on RGB - red, green, blue). - ///A list containing four integers between 0 and 255 representing the RGBW (red, green, blue, white) color for the light. eg: [255, 100, 100, 50] - ///A list containing five integers between 0 and 255 representing the RGBWW (red, green, blue, cold white, warm white) color for the light. eg: [255, 100, 100, 50, 70] - ///A human readable color name. - ///Color for the light in hue/sat format. Hue is 0-360 and Sat is 0-100. eg: [300, 70] - ///Color for the light in XY-format. eg: [0.52, 0.43] - ///Color temperature for the light in mireds. - ///Color temperature for the light in Kelvin. - ///Number indicating brightness, where 0 turns the light off, 1 is the minimum brightness and 255 is the maximum brightness supported by the light. - ///Number indicating percentage of full brightness, where 0 turns the light off, 1 is the minimum brightness and 100 is the maximum brightness supported by the light. - ///Change brightness by an amount. - ///Change brightness by a percentage. - ///Set the light to white mode. - ///Name of a light profile to use. eg: relax - ///If the light should flash. - ///Light effect. - public static void TurnOn(long? transition = null, object? rgbColor = null, object? rgbwColor = null, object? rgbwwColor = null, object? colorName = null, object? hsColor = null, object? xyColor = null, object? colorTemp = null, long? kelvin = null, long? brightness = null, long? brightnessPct = null, long? brightnessStep = null, long? brightnessStepPct = null, object? white = null, string? profile = null, object? flash = null, string? effect = null) + /// + /// + /// + /// + /// + public void TurnOff(IEnumerable targets) { throw new NotImplementedException(); } diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ISwitchEntity.cs b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ISwitchEntity.cs index f2383eb29..840e222b3 100644 --- a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ISwitchEntity.cs +++ b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ISwitchEntity.cs @@ -3,7 +3,7 @@ namespace NetDaemon.HassModel.Entities; /// /// /// -public interface ISwitchEntity: IOnOffTarget, IServiceTarget +public interface ISwitchEntity: IOnOffTarget, IEntityTarget { } \ No newline at end of file diff --git a/src/debug/MyNDApp/apps/HassModel/MyInterfaceAutomation/InterfaceUsage.cs b/src/debug/MyNDApp/apps/HassModel/MyInterfaceAutomation/InterfaceUsage.cs index 313a66220..f237b8ea2 100644 --- a/src/debug/MyNDApp/apps/HassModel/MyInterfaceAutomation/InterfaceUsage.cs +++ b/src/debug/MyNDApp/apps/HassModel/MyInterfaceAutomation/InterfaceUsage.cs @@ -14,10 +14,10 @@ public InterfaceUsage(IHaContext haContext, ILogger logger) { var entities = new Entities(haContext); IEnumerable lights = new[] { entities.Light.LivingRoom, entities.Light.SonoffLed }; - var myLibraryClass = new MyLibraryClass(entities.Light.SonoffLed, lights); - while (true) + var myLibraryClass = new MyLibraryClass(entities.Light.LivingRoom, lights, logger); + for (var i = 0; i < 4; i++) { - myLibraryClass.ToogleTargetList(); + myLibraryClass.ToogleTarget(); Thread.Sleep(1000); } } From 2e0aac121140b87ec6201eb3cc26ec80785b1b87 Mon Sep 17 00:00:00 2001 From: Pavel Yadlouski Date: Sat, 29 Jul 2023 14:05:14 +0200 Subject: [PATCH 09/18] Clean interfaces from redundant function definitions --- .../Entities/Interfaces/ILightEntityTarget.cs | 72 ------------------- .../Entities/Interfaces/IOnOffTarget.cs | 57 --------------- .../Entities/Interfaces/ISwitchEntity.cs | 2 +- 3 files changed, 1 insertion(+), 130 deletions(-) diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ILightEntityTarget.cs b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ILightEntityTarget.cs index 46fe91f90..d9762c077 100644 --- a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ILightEntityTarget.cs +++ b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ILightEntityTarget.cs @@ -12,77 +12,5 @@ public interface ILightEntityTarget: IOnOffTarget /// public interface ILightEntity : ILightEntityTarget { - /// - /// Default implementation of Toggle method - /// - public new void Toggle() - { - CallService("light.toggle"); - } - /// - /// Default implementation of TurnOn method - /// - public new void TurnOn() - { - CallService("light.turn_on"); - } - - /// - /// Default implementation of TurnOff method - /// - public new void TurnOff() - { - CallService("light.turn_off"); - } - - ///Toggles one or more targets, from on to off, or, off to on, based on their current state. - ///Duration it takes to get to next state. - ///Color for the light in RGB-format. eg: [255, 100, 100] - ///A human readable color name. - ///Color for the light in hue/sat format. Hue is 0-360 and Sat is 0-100. eg: [300, 70] - ///Color for the light in XY-format. eg: [0.52, 0.43] - ///Color temperature for the light in mireds. - ///Color temperature for the light in Kelvin. - ///Number indicating brightness, where 0 turns the light off, 1 is the minimum brightness and 255 is the maximum brightness supported by the light. - ///Number indicating percentage of full brightness, where 0 turns the light off, 1 is the minimum brightness and 100 is the maximum brightness supported by the light. - ///Set the light to white mode. - ///Name of a light profile to use. eg: relax - ///If the light should flash. - ///Light effect. - public void Toggle(long? transition = null, object? rgbColor = null, object? colorName = null, object? hsColor = null, object? xyColor = null, object? colorTemp = null, long? kelvin = null, long? brightness = null, long? brightnessPct = null, object? white = null, string? profile = null, object? flash = null, string? effect = null) - { - throw new NotImplementedException(); - } - - ///Turns off one or more targets. - ///Duration it takes to get to next state. - ///If the light should flash. - public void TurnOff(long? transition = null, object? flash = null) - { - throw new NotImplementedException(); - } - - ///Turn on one or more targets and adjust properties of the light, even when they are turned on already. - ///Duration it takes to get to next state. - ///The color for the light (based on RGB - red, green, blue). - ///A list containing four integers between 0 and 255 representing the RGBW (red, green, blue, white) color for the light. eg: [255, 100, 100, 50] - ///A list containing five integers between 0 and 255 representing the RGBWW (red, green, blue, cold white, warm white) color for the light. eg: [255, 100, 100, 50, 70] - ///A human readable color name. - ///Color for the light in hue/sat format. Hue is 0-360 and Sat is 0-100. eg: [300, 70] - ///Color for the light in XY-format. eg: [0.52, 0.43] - ///Color temperature for the light in mireds. - ///Color temperature for the light in Kelvin. - ///Number indicating brightness, where 0 turns the light off, 1 is the minimum brightness and 255 is the maximum brightness supported by the light. - ///Number indicating percentage of full brightness, where 0 turns the light off, 1 is the minimum brightness and 100 is the maximum brightness supported by the light. - ///Change brightness by an amount. - ///Change brightness by a percentage. - ///Set the light to white mode. - ///Name of a light profile to use. eg: relax - ///If the light should flash. - ///Light effect. - public void TurnOn(long? transition = null, object? rgbColor = null, object? rgbwColor = null, object? rgbwwColor = null, object? colorName = null, object? hsColor = null, object? xyColor = null, object? colorTemp = null, long? kelvin = null, long? brightness = null, long? brightnessPct = null, long? brightnessStep = null, long? brightnessStepPct = null, object? white = null, string? profile = null, object? flash = null, string? effect = null) - { - throw new NotImplementedException(); - } } \ No newline at end of file diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IOnOffTarget.cs b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IOnOffTarget.cs index 54cb8482c..9382f8012 100644 --- a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IOnOffTarget.cs +++ b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IOnOffTarget.cs @@ -6,62 +6,5 @@ namespace NetDaemon.HassModel.Entities; /// public interface IOnOffTarget: IEntityTarget { - // Virtual extension methods (aka default interface methods) - - /// - /// - /// - /// - public void Toggle() - { - CallService("toggle"); - } - - /// - /// - /// - /// - public void TurnOn() - { - throw new NotImplementedException(); - } - - /// - /// - /// - /// - public void TurnOff() - { - throw new NotImplementedException(); - } - - /// - /// - /// - /// - /// - public void Toggle(IEnumerable targets) - { - throw new NotImplementedException(); - } - - /// - /// - /// - /// - /// - public void TurnOn(IEnumerable targets) - { - throw new NotImplementedException(); - } - /// - /// - /// - /// - /// - public void TurnOff(IEnumerable targets) - { - throw new NotImplementedException(); - } } diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ISwitchEntity.cs b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ISwitchEntity.cs index 840e222b3..f5dd0f37c 100644 --- a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ISwitchEntity.cs +++ b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ISwitchEntity.cs @@ -3,7 +3,7 @@ namespace NetDaemon.HassModel.Entities; /// /// /// -public interface ISwitchEntity: IOnOffTarget, IEntityTarget +public interface ISwitchEntity: IOnOffTarget { } \ No newline at end of file From 18406711f777ffa74cc189cf4825cb2d681ae4a8 Mon Sep 17 00:00:00 2001 From: Pavel Yadlouski Date: Sun, 30 Jul 2023 11:47:41 +0200 Subject: [PATCH 10/18] Add dynamic resolution of the interfaces name for the entity --- .../CodeGeneration/EntitiesGenerator.cs | 13 +++--- .../ExtensionMethodsGenerator.cs | 5 +-- .../CodeGeneration/HelpersGenerator.cs | 43 ++++--------------- .../Interfaces/IBinarySensorEntity.cs | 10 +++++ 4 files changed, 29 insertions(+), 42 deletions(-) create mode 100644 src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IBinarySensorEntity.cs diff --git a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/EntitiesGenerator.cs b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/EntitiesGenerator.cs index 483c2e081..b5e3fd473 100644 --- a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/EntitiesGenerator.cs +++ b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/EntitiesGenerator.cs @@ -1,6 +1,7 @@ using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; using Microsoft.CodeAnalysis.CSharp; using NetDaemon.HassModel.CodeGenerator.CodeGeneration; +using NetDaemon.HassModel.Entities; namespace NetDaemon.HassModel.CodeGenerator; @@ -80,11 +81,15 @@ private static MemberDeclarationSyntax GenerateEntityType(EntityDomainMetadata d var baseType = domainMetaData.IsNumeric ? typeof(NumericEntity) : typeof(Entity); var entityStateType = domainMetaData.IsNumeric ? typeof(NumericEntityState) : typeof(EntityState); - var baseClass = $"{SimplifyTypeName(baseType)}<{domainMetaData.EntityClassName}, {SimplifyTypeName(entityStateType)}<{attributesGeneric}>, {attributesGeneric}>"; + var baseClass = $"{SimplifyTypeName(baseType)}<{domainMetaData .EntityClassName}, {SimplifyTypeName(entityStateType)}<{attributesGeneric}>, {attributesGeneric}>"; - if (HelpersGenerator.EntityInterfaces.TryGetValue(domainMetaData.Domain, out var @values)) + var result = Array.Find(typeof(IEntityTarget).Assembly + .GetTypes(), + t => t.IsInterface && t.Name.Equals($"I{domainMetaData.EntityClassName}", StringComparison.Ordinal) + ); + if (result is not null) { - baseClass += $", {@values[HelpersGenerator.GenerationMode.Entity]}"; + baseClass += $", {result.Name}"; } var (className, variableName) = GetNames(); @@ -96,8 +101,6 @@ record {{domainMetaData.EntityClassName}} : {{baseClass}} public {{domainMetaData.EntityClassName}}({{SimplifyTypeName(typeof(Entity))}} entity) : base(entity) {} - - // Here would be some wrappers around the entity extension methods } """; diff --git a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ExtensionMethodsGenerator.cs b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ExtensionMethodsGenerator.cs index 4dfc3ff47..48a8f0aba 100644 --- a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ExtensionMethodsGenerator.cs +++ b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ExtensionMethodsGenerator.cs @@ -60,11 +60,10 @@ private static IEnumerable GenerateExtensionMethodsForS private static IEnumerable GenerateExtensionMethodsForService(string domain, HassService service, string targetEntityDomain, ILookup entityClassNameByDomain) { - var entityTypeName = HelpersGenerator.EntityInterfaces.GetValueOrDefault(targetEntityDomain)?.GetValueOrDefault(HelpersGenerator.GenerationMode.Entity) ?? - entityClassNameByDomain[targetEntityDomain].FirstOrDefault(); + var entityTypeName = entityClassNameByDomain[targetEntityDomain].FirstOrDefault(); if (entityTypeName == null) yield break; - + var serviceName = service.Service; var serviceArguments = ServiceArguments.Create(domain, service); var enumerableTargetTypeName = $"IEnumerable<{entityTypeName}>"; diff --git a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/HelpersGenerator.cs b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/HelpersGenerator.cs index fa6de9057..4faa74e54 100644 --- a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/HelpersGenerator.cs +++ b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/HelpersGenerator.cs @@ -5,31 +5,6 @@ namespace NetDaemon.HassModel.CodeGenerator.CodeGeneration; internal static class HelpersGenerator { - - public enum GenerationMode - { - Entity, - Parameter - } - - public static readonly Dictionary> EntityInterfaces = new() - { - { - "light", - new Dictionary - { - { GenerationMode.Entity, "ILightEntity" }, - } - }, - { - "switch", - new Dictionary - { - { GenerationMode.Entity, "ISwitchEntity" }, - } - } - }; - public static IEnumerable Generate(IReadOnlyCollection domains, IEnumerable orderedServiceDomains) { var extensionClass = GenerateServiceCollectionExtension(domains, orderedServiceDomains); @@ -58,15 +33,15 @@ private static ClassDeclarationSyntax GenerateServiceCollectionExtension(IReadOn /// Generates the AddHomeAssistantGenerated method /// // - // public static IServiceCollection AddGeneratedCode(this IServiceCollection serviceCollection) - // { - // serviceCollection.AddTransient(); - // serviceCollection.AddTransient(); - // serviceCollection.AddTransient(); - // serviceCollection.AddTransient(); - // serviceCollection.AddTransient(); - // return serviceCollection; - // } + // public static IServiceCollection AddGeneratedCode(this IServiceCollection serviceCollection) + // { + // serviceCollection.AddTransient(); + // serviceCollection.AddTransient(); + // serviceCollection.AddTransient(); + // serviceCollection.AddTransient(); + // serviceCollection.AddTransient(); + // return serviceCollection; + // } private static MethodDeclarationSyntax BuildAddHomeAssistantGenerated(IEnumerable domains, IEnumerable orderedServiceDomains) { diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IBinarySensorEntity.cs b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IBinarySensorEntity.cs new file mode 100644 index 000000000..553b1013a --- /dev/null +++ b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IBinarySensorEntity.cs @@ -0,0 +1,10 @@ +namespace NetDaemon.HassModel.Entities; + + +/// +/// Interface for entity type binary_sensor +/// +public interface IBinarySensorEntity: IEntity +{ + +} \ No newline at end of file From 5eeef5f1573ac01941c164b454b6e15e3efc83ef Mon Sep 17 00:00:00 2001 From: Pavel Yadlouski Date: Sun, 6 Aug 2023 09:23:06 +0200 Subject: [PATCH 11/18] Remove IEntity interface --- .../Interfaces/IBinarySensorEntity.cs | 2 +- .../Entities/Interfaces/IEntity.cs | 23 ------------------- .../Entities/Interfaces/IEntityTarget.cs | 17 +++++++++++++- 3 files changed, 17 insertions(+), 25 deletions(-) delete mode 100644 src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IEntity.cs diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IBinarySensorEntity.cs b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IBinarySensorEntity.cs index 553b1013a..ab8c3e129 100644 --- a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IBinarySensorEntity.cs +++ b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IBinarySensorEntity.cs @@ -4,7 +4,7 @@ namespace NetDaemon.HassModel.Entities; /// /// Interface for entity type binary_sensor /// -public interface IBinarySensorEntity: IEntity +public interface IBinarySensorEntity: IEntityTarget { } \ No newline at end of file diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IEntity.cs b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IEntity.cs deleted file mode 100644 index 072f5eb28..000000000 --- a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IEntity.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace NetDaemon.HassModel.Entities; - -/// -/// Base interface for all entities in NetDaemon -/// -public interface IEntity -{ - /// - /// - /// - public string EntityId { get; } - - /// - /// - /// - public IHaContext? HaContext { get; } - - /// - /// - /// - /// - public IObservable StateAllChanges(); -} \ No newline at end of file diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IEntityTarget.cs b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IEntityTarget.cs index 981bd7ea9..14be1ac21 100644 --- a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IEntityTarget.cs +++ b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IEntityTarget.cs @@ -3,7 +3,7 @@ namespace NetDaemon.HassModel.Entities; /// /// /// -public interface IEntityTarget: IEntity +public interface IEntityTarget { /// /// Base interface for all service targets such as entities, rooms, areas. @@ -11,4 +11,19 @@ public interface IEntityTarget: IEntity /// /// public void CallService(string service, object? data = null); + /// + /// + /// + public string EntityId { get; } + + /// + /// + /// + public IHaContext? HaContext { get; } + + /// + /// + /// + /// + public IObservable StateAllChanges(); } From 059ce5bfcdd7674ee3c1fdd81c8614148a143857 Mon Sep 17 00:00:00 2001 From: Frank Bakker Date: Mon, 14 Aug 2023 23:19:40 +0200 Subject: [PATCH 12/18] Refactored --- NetDaemon.sln | 30 ++ .../CodeGeneration/EntitiesGenerator.cs | 25 +- .../ExtensionMethodsGenerator.cs | 1 - .../CodeGenerationSettings.cs | 2 +- .../EntityMetaData/EntityDomainMetadata.cs | 3 + .../NetDaemon.HassModel.CodeGenerator.csproj | 1 - .../NetDeamon.HassModel/Entities/Entity.cs | 26 +- .../Entities/EntityExtensions.cs | 18 + .../Entities/EnumerableEntityExtensions.cs | 6 +- .../Interfaces/IBinarySensorEntity.cs | 10 - .../Entities/Interfaces/IEntityTarget.cs | 29 -- .../Entities/Interfaces/ILightEntityTarget.cs | 16 - .../Entities/Interfaces/IOnOffTarget.cs | 10 - .../Entities/Interfaces/ISwitchEntity.cs | 9 - .../LightEntityExtensionMethods.cs | 337 +++++++++++++++++- src/debug/MyLibrary/MyLibraryClass.cs | 37 +- .../MyInterfaceAutomation/InterfaceUsage.cs | 22 +- src/debug/MyNDApp/program.cs | 5 +- 18 files changed, 456 insertions(+), 131 deletions(-) delete mode 100644 src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IBinarySensorEntity.cs delete mode 100644 src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IEntityTarget.cs delete mode 100644 src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ILightEntityTarget.cs delete mode 100644 src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IOnOffTarget.cs delete mode 100644 src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ISwitchEntity.cs diff --git a/NetDaemon.sln b/NetDaemon.sln index cb0001245..208bfbcac 100644 --- a/NetDaemon.sln +++ b/NetDaemon.sln @@ -57,6 +57,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DebugWebHost", "src\debug\D EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetDaemon.Tests.Integration", "tests\Integration\NetDaemon.Tests.Integration\NetDaemon.Tests.Integration.csproj", "{9B6A778A-A2D6-43A6-9FED-8D5B2BC18514}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyLibrary", "src\debug\MyLibrary\MyLibrary.csproj", "{CF7273C1-A4FE-4598-9C99-D746CE279A32}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyNDApp", "src\debug\MyNDApp\MyNDApp.csproj", "{FEE1EA29-4609-4200-A92C-C61ECB7A3D0B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -307,6 +311,30 @@ Global {9B6A778A-A2D6-43A6-9FED-8D5B2BC18514}.Release|x64.Build.0 = Release|Any CPU {9B6A778A-A2D6-43A6-9FED-8D5B2BC18514}.Release|x86.ActiveCfg = Release|Any CPU {9B6A778A-A2D6-43A6-9FED-8D5B2BC18514}.Release|x86.Build.0 = Release|Any CPU + {CF7273C1-A4FE-4598-9C99-D746CE279A32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CF7273C1-A4FE-4598-9C99-D746CE279A32}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CF7273C1-A4FE-4598-9C99-D746CE279A32}.Debug|x64.ActiveCfg = Debug|Any CPU + {CF7273C1-A4FE-4598-9C99-D746CE279A32}.Debug|x64.Build.0 = Debug|Any CPU + {CF7273C1-A4FE-4598-9C99-D746CE279A32}.Debug|x86.ActiveCfg = Debug|Any CPU + {CF7273C1-A4FE-4598-9C99-D746CE279A32}.Debug|x86.Build.0 = Debug|Any CPU + {CF7273C1-A4FE-4598-9C99-D746CE279A32}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CF7273C1-A4FE-4598-9C99-D746CE279A32}.Release|Any CPU.Build.0 = Release|Any CPU + {CF7273C1-A4FE-4598-9C99-D746CE279A32}.Release|x64.ActiveCfg = Release|Any CPU + {CF7273C1-A4FE-4598-9C99-D746CE279A32}.Release|x64.Build.0 = Release|Any CPU + {CF7273C1-A4FE-4598-9C99-D746CE279A32}.Release|x86.ActiveCfg = Release|Any CPU + {CF7273C1-A4FE-4598-9C99-D746CE279A32}.Release|x86.Build.0 = Release|Any CPU + {FEE1EA29-4609-4200-A92C-C61ECB7A3D0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FEE1EA29-4609-4200-A92C-C61ECB7A3D0B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FEE1EA29-4609-4200-A92C-C61ECB7A3D0B}.Debug|x64.ActiveCfg = Debug|Any CPU + {FEE1EA29-4609-4200-A92C-C61ECB7A3D0B}.Debug|x64.Build.0 = Debug|Any CPU + {FEE1EA29-4609-4200-A92C-C61ECB7A3D0B}.Debug|x86.ActiveCfg = Debug|Any CPU + {FEE1EA29-4609-4200-A92C-C61ECB7A3D0B}.Debug|x86.Build.0 = Debug|Any CPU + {FEE1EA29-4609-4200-A92C-C61ECB7A3D0B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FEE1EA29-4609-4200-A92C-C61ECB7A3D0B}.Release|Any CPU.Build.0 = Release|Any CPU + {FEE1EA29-4609-4200-A92C-C61ECB7A3D0B}.Release|x64.ActiveCfg = Release|Any CPU + {FEE1EA29-4609-4200-A92C-C61ECB7A3D0B}.Release|x64.Build.0 = Release|Any CPU + {FEE1EA29-4609-4200-A92C-C61ECB7A3D0B}.Release|x86.ActiveCfg = Release|Any CPU + {FEE1EA29-4609-4200-A92C-C61ECB7A3D0B}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -331,6 +359,8 @@ Global {F4B29B77-9B92-4037-A884-288CA5EF0B78} = {DFF3E7AA-7A50-4A1E-B3F8-EC01531FB83D} {3EB8C461-C91E-4900-BFBD-0986CBBE87A6} = {DFF3E7AA-7A50-4A1E-B3F8-EC01531FB83D} {AEBC7828-7C19-4A86-B6E2-58B5171347B1} = {E15D4280-7FFC-4F8B-9B8C-CF9AF2BF838C} + {CF7273C1-A4FE-4598-9C99-D746CE279A32} = {E15D4280-7FFC-4F8B-9B8C-CF9AF2BF838C} + {FEE1EA29-4609-4200-A92C-C61ECB7A3D0B} = {E15D4280-7FFC-4F8B-9B8C-CF9AF2BF838C} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {7C5FBB7F-654C-4CAC-964F-6D71AF3D62F8} diff --git a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/EntitiesGenerator.cs b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/EntitiesGenerator.cs index b5e3fd473..bb0121b32 100644 --- a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/EntitiesGenerator.cs +++ b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/EntitiesGenerator.cs @@ -1,7 +1,6 @@ using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; using Microsoft.CodeAnalysis.CSharp; using NetDaemon.HassModel.CodeGenerator.CodeGeneration; -using NetDaemon.HassModel.Entities; namespace NetDaemon.HassModel.CodeGenerator; @@ -72,6 +71,12 @@ private static MemberDeclarationSyntax GenerateEntityProperty(EntityMetaData ent .WithSummaryComment(entity.friendlyName); } + private static readonly HashSet CoreInterfaces = + typeof(IEntityCore).Assembly.GetTypes() + .Where(t => t.IsInterface && t.IsAssignableTo(typeof(IEntityCore))) + .Select(t => t.Name) + .ToHashSet(); + /// /// Generates a record derived from Entity like ClimateEntity or SensorEntity for a specific set of entities /// @@ -83,24 +88,20 @@ private static MemberDeclarationSyntax GenerateEntityType(EntityDomainMetadata d var entityStateType = domainMetaData.IsNumeric ? typeof(NumericEntityState) : typeof(EntityState); var baseClass = $"{SimplifyTypeName(baseType)}<{domainMetaData .EntityClassName}, {SimplifyTypeName(entityStateType)}<{attributesGeneric}>, {attributesGeneric}>"; - var result = Array.Find(typeof(IEntityTarget).Assembly - .GetTypes(), - t => t.IsInterface && t.Name.Equals($"I{domainMetaData.EntityClassName}", StringComparison.Ordinal) - ); - if (result is not null) + if (CoreInterfaces.Contains(domainMetaData.CoreInterfaceName)) { - baseClass += $", {result.Name}"; + baseClass += $", {domainMetaData.CoreInterfaceName}"; } - + var (className, variableName) = GetNames(); var classDeclaration = $$""" record {{domainMetaData.EntityClassName}} : {{baseClass}} { - public {{domainMetaData.EntityClassName}}({{className}} {{variableName}}, string entityId) : base({{variableName}}, entityId) - {} + public {{domainMetaData.EntityClassName}}({{className}} {{variableName}}, string entityId) : base({{variableName}}, entityId) + {} - public {{domainMetaData.EntityClassName}}({{SimplifyTypeName(typeof(Entity))}} entity) : base(entity) - {} + public {{domainMetaData.EntityClassName}}({{SimplifyTypeName(typeof(IEntityCore))}} entity) : base(entity) + {} } """; diff --git a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ExtensionMethodsGenerator.cs b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ExtensionMethodsGenerator.cs index 48a8f0aba..b39e69f98 100644 --- a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ExtensionMethodsGenerator.cs +++ b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ExtensionMethodsGenerator.cs @@ -1,4 +1,3 @@ -using NetDaemon.HassModel.CodeGenerator.CodeGeneration; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace NetDaemon.HassModel.CodeGenerator; diff --git a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGenerationSettings.cs b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGenerationSettings.cs index 321a8ddd2..b0d61bde7 100644 --- a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGenerationSettings.cs +++ b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGenerationSettings.cs @@ -1,6 +1,6 @@ namespace NetDaemon.HassModel.CodeGenerator; -public record CodeGenerationSettings +record CodeGenerationSettings { public string OutputFile { get; init; } = "HomeAssistantGenerated.cs"; public string OutputFolder { get; init; } = "NetDaemonCodegen"; diff --git a/src/HassModel/NetDaemon.HassModel.CodeGenerator/MetaData/EntityMetaData/EntityDomainMetadata.cs b/src/HassModel/NetDaemon.HassModel.CodeGenerator/MetaData/EntityMetaData/EntityDomainMetadata.cs index 2decf71f9..191893a6d 100644 --- a/src/HassModel/NetDaemon.HassModel.CodeGenerator/MetaData/EntityMetaData/EntityDomainMetadata.cs +++ b/src/HassModel/NetDaemon.HassModel.CodeGenerator/MetaData/EntityMetaData/EntityDomainMetadata.cs @@ -23,6 +23,9 @@ IReadOnlyList Attributes [JsonIgnore] public string EntityClassName => $"{prefixedDomain}Entity".ToValidCSharpPascalCase(); + [JsonIgnore] + public string CoreInterfaceName => $"I{Domain.ToValidCSharpPascalCase()}EntityCore"; + [JsonIgnore] public string AttributesClassName => $"{prefixedDomain}Attributes".ToValidCSharpPascalCase(); diff --git a/src/HassModel/NetDaemon.HassModel.CodeGenerator/NetDaemon.HassModel.CodeGenerator.csproj b/src/HassModel/NetDaemon.HassModel.CodeGenerator/NetDaemon.HassModel.CodeGenerator.csproj index acc39370e..db8cae98f 100644 --- a/src/HassModel/NetDaemon.HassModel.CodeGenerator/NetDaemon.HassModel.CodeGenerator.csproj +++ b/src/HassModel/NetDaemon.HassModel.CodeGenerator/NetDaemon.HassModel.CodeGenerator.csproj @@ -18,7 +18,6 @@ Please advice this is still in beta Home Assistant - True diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Entity.cs b/src/HassModel/NetDeamon.HassModel/Entities/Entity.cs index bad30ee4f..0eb40c8e0 100644 --- a/src/HassModel/NetDeamon.HassModel/Entities/Entity.cs +++ b/src/HassModel/NetDeamon.HassModel/Entities/Entity.cs @@ -1,7 +1,7 @@ namespace NetDaemon.HassModel.Entities; /// Represents a Home Assistant entity with its state, changes and services -public record Entity: IEntityTarget +public record Entity : IEntityCore { /// /// The IHAContext @@ -23,6 +23,14 @@ public Entity(IHaContext haContext, string entityId) HaContext = haContext; EntityId = entityId; } + + /// Copy constructor from IEntityCore + public Entity(IEntityCore entity) + { + ArgumentNullException.ThrowIfNull(entity); + HaContext = entity.HaContext; + EntityId = entity.EntityId; + } /// /// Area name of entity @@ -78,13 +86,7 @@ public virtual IObservable StateChanges() => /// Data to provide public virtual void CallService(string service, object? data = null) { - ArgumentNullException.ThrowIfNull(service, nameof(service)); - - var (serviceDomain, serviceName) = service.SplitAtDot(); - - serviceDomain ??= EntityId.SplitAtDot().Left ?? throw new InvalidOperationException("EntityId must be formatted 'domain.name'"); - - HaContext.CallService(serviceDomain, serviceName, ServiceTarget.FromEntity(EntityId), data); + EntityExtensions.CallService(this, service, data); } } @@ -94,8 +96,8 @@ public abstract record Entity : Entity where TEntityState : EntityState where TAttributes : class { - /// Copy constructor from Base type - protected Entity(Entity entity) : base(entity) + /// Copy constructor from IEntityCore + protected Entity(IEntityCore entity) : base(entity) { } /// Constructor from haContext and entityId @@ -126,8 +128,8 @@ public record Entity : Entity, EntityStateCopy constructor from Base type - public Entity(Entity entity) : base(entity) { } + /// Copy constructor from IEntityCore + public Entity(IEntityCore entity) : base(entity) { } /// Constructor from haContext and entityId public Entity(IHaContext haContext, string entityId) : base(haContext, entityId) { } diff --git a/src/HassModel/NetDeamon.HassModel/Entities/EntityExtensions.cs b/src/HassModel/NetDeamon.HassModel/Entities/EntityExtensions.cs index 9f91bf18d..c1179619a 100644 --- a/src/HassModel/NetDeamon.HassModel/Entities/EntityExtensions.cs +++ b/src/HassModel/NetDeamon.HassModel/Entities/EntityExtensions.cs @@ -56,4 +56,22 @@ public static NumericEntity WithAttributesAs(this Nume internal static IObservable StateChangesOnly(this IObservable changes) where T : StateChange => changes.Where(c => c.New?.State != c.Old?.State); + + /// + /// Calls a service using this entity as the target + /// + /// The Entity to call the service for + /// Name of the service to call. If the Domain of the service is the same as the domain of the Entity it can be omitted + /// Data to provide + public static void CallService(this IEntityCore entity, string service, object? data = null) + { + ArgumentNullException.ThrowIfNull(entity); + ArgumentNullException.ThrowIfNull(service); + + var (serviceDomain, serviceName) = service.SplitAtDot(); + + serviceDomain ??= entity.EntityId.SplitAtDot().Left ?? throw new InvalidOperationException("EntityId must be formatted 'domain.name'"); + + entity.HaContext.CallService(serviceDomain, serviceName, ServiceTarget.FromEntity(entity.EntityId), data); + } } diff --git a/src/HassModel/NetDeamon.HassModel/Entities/EnumerableEntityExtensions.cs b/src/HassModel/NetDeamon.HassModel/Entities/EnumerableEntityExtensions.cs index fcb96400b..735fa10b4 100644 --- a/src/HassModel/NetDeamon.HassModel/Entities/EnumerableEntityExtensions.cs +++ b/src/HassModel/NetDeamon.HassModel/Entities/EnumerableEntityExtensions.cs @@ -17,7 +17,7 @@ public static class EnumerableEntityExtensions /// .Subscribe(e => HandleBrightnessOverHalf()); /// /// - public static IObservable StateAllChanges(this IEnumerable entities) => + public static IObservable StateAllChanges(this IEnumerable entities) => entities.Select(t => t.StateAllChanges()).Merge(); /// @@ -31,7 +31,7 @@ public static IObservable StateAllChanges(this IEnumerable /// - public static IObservable StateChanges(this IEnumerable entities) => + public static IObservable StateChanges(this IEnumerable entities) => entities.StateAllChanges().StateChangesOnly(); /// @@ -75,7 +75,7 @@ public static IObservable> StateChangesIEnumerable of Entities for which to call the service /// Name of the service to call. If the Domain of the service is the same as the domain of the Entities it can be omitted /// Data to provide - public static void CallService(this IEnumerable entities, string service, object? data = null) + public static void CallService(this IEnumerable entities, string service, object? data = null) { ArgumentNullException.ThrowIfNull(service); diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IBinarySensorEntity.cs b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IBinarySensorEntity.cs deleted file mode 100644 index ab8c3e129..000000000 --- a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IBinarySensorEntity.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace NetDaemon.HassModel.Entities; - - -/// -/// Interface for entity type binary_sensor -/// -public interface IBinarySensorEntity: IEntityTarget -{ - -} \ No newline at end of file diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IEntityTarget.cs b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IEntityTarget.cs deleted file mode 100644 index 14be1ac21..000000000 --- a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IEntityTarget.cs +++ /dev/null @@ -1,29 +0,0 @@ -namespace NetDaemon.HassModel.Entities; - -/// -/// -/// -public interface IEntityTarget -{ - /// - /// Base interface for all service targets such as entities, rooms, areas. - /// - /// - /// - public void CallService(string service, object? data = null); - /// - /// - /// - public string EntityId { get; } - - /// - /// - /// - public IHaContext? HaContext { get; } - - /// - /// - /// - /// - public IObservable StateAllChanges(); -} diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ILightEntityTarget.cs b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ILightEntityTarget.cs deleted file mode 100644 index d9762c077..000000000 --- a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ILightEntityTarget.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace NetDaemon.HassModel.Entities; - -/// -/// -/// -public interface ILightEntityTarget: IOnOffTarget -{ -} - -/// -/// -/// -public interface ILightEntity : ILightEntityTarget -{ - -} \ No newline at end of file diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IOnOffTarget.cs b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IOnOffTarget.cs deleted file mode 100644 index 9382f8012..000000000 --- a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/IOnOffTarget.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace NetDaemon.HassModel.Entities; - - -/// -/// Base interface for togglebal targets -/// -public interface IOnOffTarget: IEntityTarget -{ - -} diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ISwitchEntity.cs b/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ISwitchEntity.cs deleted file mode 100644 index f5dd0f37c..000000000 --- a/src/HassModel/NetDeamon.HassModel/Entities/Interfaces/ISwitchEntity.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace NetDaemon.HassModel.Entities; - -/// -/// -/// -public interface ISwitchEntity: IOnOffTarget -{ - -} \ No newline at end of file diff --git a/src/debug/MyLibrary/InternalHomeAssistantGenerated/LightEntityExtensionMethods.cs b/src/debug/MyLibrary/InternalHomeAssistantGenerated/LightEntityExtensionMethods.cs index e19943dac..c8e8fbec6 100644 --- a/src/debug/MyLibrary/InternalHomeAssistantGenerated/LightEntityExtensionMethods.cs +++ b/src/debug/MyLibrary/InternalHomeAssistantGenerated/LightEntityExtensionMethods.cs @@ -1,41 +1,358 @@ +using System.Text.Json.Serialization; +using NetDaemon.HassModel; using NetDaemon.HassModel.Entities; namespace MyLibrary; +public partial record LightEntity : Entity, LightAttributes>, ILightEntityCore +{ + public LightEntity(IHaContext haContext, string entityId) : base(haContext, entityId) + { + } + + public LightEntity(IEntityCore entity) : base(entity) + { + } +} + +public partial record LightAttributes +{ + [JsonPropertyName("min_color_temp_kelvin")] + public double? MinColorTempKelvin { get; init; } + + [JsonPropertyName("max_color_temp_kelvin")] + public double? MaxColorTempKelvin { get; init; } + + [JsonPropertyName("color_temp_kelvin")] + public double? ColorTempKelvin { get; init; } + + [JsonPropertyName("off_with_transition")] + public bool? OffWithTransition { get; init; } + + [JsonPropertyName("off_brightness")] + public double? OffBrightness { get; init; } + + [JsonPropertyName("restored")] + public bool? Restored { get; init; } + + [JsonPropertyName("supported_color_modes")] + public IReadOnlyList? SupportedColorModes { get; init; } + + [JsonPropertyName("friendly_name")] + public string? FriendlyName { get; init; } + + [JsonPropertyName("supported_features")] + public double? SupportedFeatures { get; init; } + + [JsonPropertyName("min_mireds")] + public double? MinMireds { get; init; } + + [JsonPropertyName("max_mireds")] + public double? MaxMireds { get; init; } + + [JsonPropertyName("effect_list")] + public IReadOnlyList? EffectList { get; init; } + + [JsonPropertyName("entity_id")] + public IReadOnlyList? EntityId { get; init; } + + [JsonPropertyName("icon")] + public string? Icon { get; init; } + + [JsonPropertyName("color_mode")] + public string? ColorMode { get; init; } + + [JsonPropertyName("brightness")] + public double? Brightness { get; init; } + + [JsonPropertyName("color_temp")] + public double? ColorTemp { get; init; } + + [JsonPropertyName("hs_color")] + public IReadOnlyList? HsColor { get; init; } + + [JsonPropertyName("rgb_color")] + public IReadOnlyList? RgbColor { get; init; } + + [JsonPropertyName("xy_color")] + public IReadOnlyList? XyColor { get; init; } +} + + +public partial record LightToggleParameters +{ + ///Duration it takes to get to next state. + [JsonPropertyName("transition")] + public long? Transition { get; init; } + + ///Color for the light in RGB-format. eg: [255, 100, 100] + [JsonPropertyName("rgb_color")] + public object? RgbColor { get; init; } + + ///A human readable color name. + [JsonPropertyName("color_name")] + public object? ColorName { get; init; } + + ///Color for the light in hue/sat format. Hue is 0-360 and Sat is 0-100. eg: [300, 70] + [JsonPropertyName("hs_color")] + public object? HsColor { get; init; } + + ///Color for the light in XY-format. eg: [0.52, 0.43] + [JsonPropertyName("xy_color")] + public object? XyColor { get; init; } + + ///Color temperature for the light in mireds. + [JsonPropertyName("color_temp")] + public object? ColorTemp { get; init; } + + ///Color temperature for the light in Kelvin. + [JsonPropertyName("kelvin")] + public long? Kelvin { get; init; } + + ///Number indicating brightness, where 0 turns the light off, 1 is the minimum brightness and 255 is the maximum brightness supported by the light. + [JsonPropertyName("brightness")] + public long? Brightness { get; init; } + + ///Number indicating percentage of full brightness, where 0 turns the light off, 1 is the minimum brightness and 100 is the maximum brightness supported by the light. + [JsonPropertyName("brightness_pct")] + public long? BrightnessPct { get; init; } + + ///Name of a light profile to use. eg: relax + [JsonPropertyName("profile")] + public string? Profile { get; init; } + + ///If the light should flash. + [JsonPropertyName("flash")] + public object? Flash { get; init; } + + ///Light effect. + [JsonPropertyName("effect")] + public string? Effect { get; init; } +} + +public partial record LightTurnOffParameters +{ + ///Duration it takes to get to next state. + [JsonPropertyName("transition")] + public long? Transition { get; init; } + + ///If the light should flash. + [JsonPropertyName("flash")] + public object? Flash { get; init; } +} + +public partial record LightTurnOnParameters +{ + ///Duration it takes to get to next state. + [JsonPropertyName("transition")] + public long? Transition { get; init; } + + ///The color for the light (based on RGB - red, green, blue). + [JsonPropertyName("rgb_color")] + public object? RgbColor { get; init; } + + ///A list containing four integers between 0 and 255 representing the RGBW (red, green, blue, white) color for the light. eg: [255, 100, 100, 50] + [JsonPropertyName("rgbw_color")] + public object? RgbwColor { get; init; } + + ///A list containing five integers between 0 and 255 representing the RGBWW (red, green, blue, cold white, warm white) color for the light. eg: [255, 100, 100, 50, 70] + [JsonPropertyName("rgbww_color")] + public object? RgbwwColor { get; init; } + + ///A human readable color name. + [JsonPropertyName("color_name")] + public object? ColorName { get; init; } + + ///Color for the light in hue/sat format. Hue is 0-360 and Sat is 0-100. eg: [300, 70] + [JsonPropertyName("hs_color")] + public object? HsColor { get; init; } + + ///Color for the light in XY-format. eg: [0.52, 0.43] + [JsonPropertyName("xy_color")] + public object? XyColor { get; init; } + + ///Color temperature for the light in mireds. + [JsonPropertyName("color_temp")] + public object? ColorTemp { get; init; } + + ///Color temperature for the light in Kelvin. + [JsonPropertyName("kelvin")] + public long? Kelvin { get; init; } + + ///Number indicating brightness, where 0 turns the light off, 1 is the minimum brightness and 255 is the maximum brightness supported by the light. + [JsonPropertyName("brightness")] + public long? Brightness { get; init; } + + ///Number indicating percentage of full brightness, where 0 turns the light off, 1 is the minimum brightness and 100 is the maximum brightness supported by the light. + [JsonPropertyName("brightness_pct")] + public long? BrightnessPct { get; init; } + + ///Change brightness by an amount. + [JsonPropertyName("brightness_step")] + public long? BrightnessStep { get; init; } + + ///Change brightness by a percentage. + [JsonPropertyName("brightness_step_pct")] + public long? BrightnessStepPct { get; init; } + + ///Set the light to white mode and change its brightness, where 0 turns the light off, 1 is the minimum brightness and 255 is the maximum brightness supported by the light. + [JsonPropertyName("white")] + public long? White { get; init; } + + ///Name of a light profile to use. eg: relax + [JsonPropertyName("profile")] + public string? Profile { get; init; } + + ///If the light should flash. + [JsonPropertyName("flash")] + public object? Flash { get; init; } + + ///Light effect. + [JsonPropertyName("effect")] + public string? Effect { get; init; } +} + + public static class LightEntityExtensionMethods { - public static void Toggle(this ILightEntity target, IToggleParameters data) - { - Console.WriteLine("Toggle"); + ///Toggles one or more lights, from on to off, or, off to on, based on their current state. + public static void Toggle(this ILightEntityCore target, LightToggleParameters data) + { target.CallService("toggle", data); } - public static void Toggle(this IEnumerable target, IToggleParameters data) + ///Toggles one or more lights, from on to off, or, off to on, based on their current state. + public static void Toggle(this IEnumerable target, LightToggleParameters data) { target.CallService("toggle", data); } - + + ///Toggles one or more lights, from on to off, or, off to on, based on their current state. + ///The ILightEntity to call this service for + ///Duration it takes to get to next state. + ///Color for the light in RGB-format. eg: [255, 100, 100] + ///A human readable color name. + ///Color for the light in hue/sat format. Hue is 0-360 and Sat is 0-100. eg: [300, 70] + ///Color for the light in XY-format. eg: [0.52, 0.43] + ///Color temperature for the light in mireds. + ///Color temperature for the light in Kelvin. + ///Number indicating brightness, where 0 turns the light off, 1 is the minimum brightness and 255 is the maximum brightness supported by the light. + ///Number indicating percentage of full brightness, where 0 turns the light off, 1 is the minimum brightness and 100 is the maximum brightness supported by the light. + ///Name of a light profile to use. eg: relax + ///If the light should flash. + ///Light effect. + public static void Toggle(this ILightEntityCore target, long? transition = null, object? rgbColor = null, object? colorName = null, object? hsColor = null, object? xyColor = null, object? colorTemp = null, long? kelvin = null, long? brightness = null, long? brightnessPct = null, string? profile = null, object? flash = null, string? effect = null) + { + target.CallService("toggle", new LightToggleParameters { Transition = transition, RgbColor = rgbColor, ColorName = colorName, HsColor = hsColor, XyColor = xyColor, ColorTemp = colorTemp, Kelvin = kelvin, Brightness = brightness, BrightnessPct = brightnessPct, Profile = profile, Flash = flash, Effect = effect }); + } + + ///Toggles one or more lights, from on to off, or, off to on, based on their current state. + ///The IEnumerable<ILightEntity> to call this service for + ///Duration it takes to get to next state. + ///Color for the light in RGB-format. eg: [255, 100, 100] + ///A human readable color name. + ///Color for the light in hue/sat format. Hue is 0-360 and Sat is 0-100. eg: [300, 70] + ///Color for the light in XY-format. eg: [0.52, 0.43] + ///Color temperature for the light in mireds. + ///Color temperature for the light in Kelvin. + ///Number indicating brightness, where 0 turns the light off, 1 is the minimum brightness and 255 is the maximum brightness supported by the light. + ///Number indicating percentage of full brightness, where 0 turns the light off, 1 is the minimum brightness and 100 is the maximum brightness supported by the light. + ///Name of a light profile to use. eg: relax + ///If the light should flash. + ///Light effect. + public static void Toggle(this IEnumerable target, long? transition = null, object? rgbColor = null, object? colorName = null, object? hsColor = null, object? xyColor = null, object? colorTemp = null, long? kelvin = null, long? brightness = null, long? brightnessPct = null, string? profile = null, object? flash = null, string? effect = null) + { + target.CallService("toggle", new LightToggleParameters { Transition = transition, RgbColor = rgbColor, ColorName = colorName, HsColor = hsColor, XyColor = xyColor, ColorTemp = colorTemp, Kelvin = kelvin, Brightness = brightness, BrightnessPct = brightnessPct, Profile = profile, Flash = flash, Effect = effect }); + } + ///Turns off one or more lights. - public static void TurnOff(this ILightEntity target, ITurnOffParameters data) + public static void TurnOff(this ILightEntityCore target, LightTurnOffParameters data) { target.CallService("turn_off", data); } ///Turns off one or more lights. - public static void TurnOff(this IEnumerable target, ITurnOffParameters data) + public static void TurnOff(this IEnumerable target, LightTurnOffParameters data) { target.CallService("turn_off", data); } + ///Turns off one or more lights. + ///The ILightEntity to call this service for + ///Duration it takes to get to next state. + ///If the light should flash. + public static void TurnOff(this ILightEntityCore target, long? transition = null, object? flash = null) + { + target.CallService("turn_off", new LightTurnOffParameters { Transition = transition, Flash = flash }); + } + + ///Turns off one or more lights. + ///The IEnumerable<ILightEntity> to call this service for + ///Duration it takes to get to next state. + ///If the light should flash. + public static void TurnOff(this IEnumerable target, long? transition = null, object? flash = null) + { + target.CallService("turn_off", new LightTurnOffParameters { Transition = transition, Flash = flash }); + } + ///Turn on one or more lights and adjust properties of the light, even when they are turned on already. - public static void TurnOn(this ILightEntity target, ITurnOnParameters data) + public static void TurnOn(this ILightEntityCore target, LightTurnOnParameters data) { target.CallService("turn_on", data); } ///Turn on one or more lights and adjust properties of the light, even when they are turned on already. - public static void TurnOn(this IEnumerable target, ITurnOnParameters data) + public static void TurnOn(this IEnumerable target, LightTurnOnParameters data) { target.CallService("turn_on", data); } -} \ No newline at end of file + + ///Turn on one or more lights and adjust properties of the light, even when they are turned on already. + ///The ILightEntity to call this service for + ///Duration it takes to get to next state. + ///The color for the light (based on RGB - red, green, blue). + ///A list containing four integers between 0 and 255 representing the RGBW (red, green, blue, white) color for the light. eg: [255, 100, 100, 50] + ///A list containing five integers between 0 and 255 representing the RGBWW (red, green, blue, cold white, warm white) color for the light. eg: [255, 100, 100, 50, 70] + ///A human readable color name. + ///Color for the light in hue/sat format. Hue is 0-360 and Sat is 0-100. eg: [300, 70] + ///Color for the light in XY-format. eg: [0.52, 0.43] + ///Color temperature for the light in mireds. + ///Color temperature for the light in Kelvin. + ///Number indicating brightness, where 0 turns the light off, 1 is the minimum brightness and 255 is the maximum brightness supported by the light. + ///Number indicating percentage of full brightness, where 0 turns the light off, 1 is the minimum brightness and 100 is the maximum brightness supported by the light. + ///Change brightness by an amount. + ///Change brightness by a percentage. + ///Set the light to white mode and change its brightness, where 0 turns the light off, 1 is the minimum brightness and 255 is the maximum brightness supported by the light. + ///Name of a light profile to use. eg: relax + ///If the light should flash. + ///Light effect. + public static void TurnOn(this ILightEntityCore target, long? transition = null, object? rgbColor = null, object? rgbwColor = null, object? rgbwwColor = null, object? colorName = null, object? hsColor = null, object? xyColor = null, object? colorTemp = null, long? kelvin = null, long? brightness = null, long? brightnessPct = null, long? brightnessStep = null, long? brightnessStepPct = null, long? white = null, string? profile = null, object? flash = null, string? effect = null) + { + target.CallService("turn_on", new LightTurnOnParameters { Transition = transition, RgbColor = rgbColor, RgbwColor = rgbwColor, RgbwwColor = rgbwwColor, ColorName = colorName, HsColor = hsColor, XyColor = xyColor, ColorTemp = colorTemp, Kelvin = kelvin, Brightness = brightness, BrightnessPct = brightnessPct, BrightnessStep = brightnessStep, BrightnessStepPct = brightnessStepPct, White = white, Profile = profile, Flash = flash, Effect = effect }); + } + + ///Turn on one or more lights and adjust properties of the light, even when they are turned on already. + ///The IEnumerable<ILightEntity> to call this service for + ///Duration it takes to get to next state. + ///The color for the light (based on RGB - red, green, blue). + ///A list containing four integers between 0 and 255 representing the RGBW (red, green, blue, white) color for the light. eg: [255, 100, 100, 50] + ///A list containing five integers between 0 and 255 representing the RGBWW (red, green, blue, cold white, warm white) color for the light. eg: [255, 100, 100, 50, 70] + ///A human readable color name. + ///Color for the light in hue/sat format. Hue is 0-360 and Sat is 0-100. eg: [300, 70] + ///Color for the light in XY-format. eg: [0.52, 0.43] + ///Color temperature for the light in mireds. + ///Color temperature for the light in Kelvin. + ///Number indicating brightness, where 0 turns the light off, 1 is the minimum brightness and 255 is the maximum brightness supported by the light. + ///Number indicating percentage of full brightness, where 0 turns the light off, 1 is the minimum brightness and 100 is the maximum brightness supported by the light. + ///Change brightness by an amount. + ///Change brightness by a percentage. + ///Set the light to white mode and change its brightness, where 0 turns the light off, 1 is the minimum brightness and 255 is the maximum brightness supported by the light. + ///Name of a light profile to use. eg: relax + ///If the light should flash. + ///Light effect. + public static void TurnOn(this IEnumerable target, long? transition = null, object? rgbColor = null, object? rgbwColor = null, object? rgbwwColor = null, object? colorName = null, object? hsColor = null, object? xyColor = null, object? colorTemp = null, long? kelvin = null, long? brightness = null, long? brightnessPct = null, long? brightnessStep = null, long? brightnessStepPct = null, long? white = null, string? profile = null, object? flash = null, string? effect = null) + { + target.CallService("turn_on", new LightTurnOnParameters { Transition = transition, RgbColor = rgbColor, RgbwColor = rgbwColor, RgbwwColor = rgbwwColor, ColorName = colorName, HsColor = hsColor, XyColor = xyColor, ColorTemp = colorTemp, Kelvin = kelvin, Brightness = brightness, BrightnessPct = brightnessPct, BrightnessStep = brightnessStep, BrightnessStepPct = brightnessStepPct, White = white, Profile = profile, Flash = flash, Effect = effect }); + } +} + diff --git a/src/debug/MyLibrary/MyLibraryClass.cs b/src/debug/MyLibrary/MyLibraryClass.cs index 409be065e..5cc703765 100644 --- a/src/debug/MyLibrary/MyLibraryClass.cs +++ b/src/debug/MyLibrary/MyLibraryClass.cs @@ -5,22 +5,45 @@ namespace MyLibrary; public class MyLibraryClass { - public ILightEntity Target; - public IEnumerable TargetList; + public LightEntity Target; + public IEnumerable TargetList; - public MyLibraryClass(ILightEntity target, IEnumerable lights) + public MyLibraryClass(ILightEntityCore target, IEnumerable lights) { - Target = target; + Target = new LightEntity(target); TargetList = lights; } - public void ToogleTarget() + public void ToggleTarget() { Target.Toggle(); } - public void ToogleTargetList() + + public void Increment() + { + var current = (long)(Target.Attributes?.Brightness ?? 0); + var newBrightness = current + 10; + if (newBrightness <= 256) + { + Target.TurnOn(brightness: newBrightness); + } + else + { + Target.TurnOff(); + } + } + + + public void ToggleTargetList() { - Target.Toggle(TargetList); + TargetList.Toggle(); } + + + public void HalfBrightness() + { + TargetList.TurnOn(brightnessPct: 50); + } + } diff --git a/src/debug/MyNDApp/apps/HassModel/MyInterfaceAutomation/InterfaceUsage.cs b/src/debug/MyNDApp/apps/HassModel/MyInterfaceAutomation/InterfaceUsage.cs index f237b8ea2..b69269de6 100644 --- a/src/debug/MyNDApp/apps/HassModel/MyInterfaceAutomation/InterfaceUsage.cs +++ b/src/debug/MyNDApp/apps/HassModel/MyInterfaceAutomation/InterfaceUsage.cs @@ -1,7 +1,11 @@ +using System; using System.Collections.Generic; -using System.Threading; +using System.Reactive.Concurrency; using HomeAssistantGenerated; +using Microsoft.Extensions.Logging; using MyLibrary; +using NetDaemon.AppModel; +using NetDaemon.HassModel; using NetDaemon.HassModel.Entities; namespace Debug.apps.HassModel.MyInterfaceAutomation; @@ -10,15 +14,15 @@ namespace Debug.apps.HassModel.MyInterfaceAutomation; [Focus] public class InterfaceUsage { - public InterfaceUsage(IHaContext haContext, ILogger logger) + public InterfaceUsage(IHaContext haContext, ILogger logger, IScheduler scheduler) { var entities = new Entities(haContext); - IEnumerable lights = new[] { entities.Light.LivingRoom, entities.Light.SonoffLed }; - var myLibraryClass = new MyLibraryClass(entities.Light.LivingRoom, lights, logger); - for (var i = 0; i < 4; i++) - { - myLibraryClass.ToogleTarget(); - Thread.Sleep(1000); - } + IEnumerable lights = new[] { entities.Light.Zolder, entities.Light.LampenEettafel }; + + + // pass generated types to the library using the commonly known interfaces + var myLibraryClass = new MyLibraryClass(entities.Light.Zolder, lights); + + scheduler.SchedulePeriodic(TimeSpan.FromSeconds(1), () => myLibraryClass.Increment()); } } \ No newline at end of file diff --git a/src/debug/MyNDApp/program.cs b/src/debug/MyNDApp/program.cs index 5fb2a0a69..b0944576d 100644 --- a/src/debug/MyNDApp/program.cs +++ b/src/debug/MyNDApp/program.cs @@ -1,10 +1,13 @@ +using System; using System.Reflection; using HomeAssistantGenerated; using Microsoft.Extensions.Hosting; +using NetDaemon.AppModel; using NetDaemon.Extensions.Logging; using NetDaemon.Extensions.Scheduler; using NetDaemon.Extensions.Tts; using NetDaemon.Runtime; + // Add next line if using code generator #pragma warning disable CA1812 @@ -32,4 +35,4 @@ await Host.CreateDefaultBuilder(args) { Console.WriteLine($"Failed to start host... {e}"); throw; -} +} \ No newline at end of file From 3ab1ee2b6e6a6b5ab793bf4d74a7206648072bdf Mon Sep 17 00:00:00 2001 From: Frank Bakker Date: Mon, 14 Aug 2023 23:35:26 +0200 Subject: [PATCH 13/18] forgotten to add --- .../Entities/Core/CoreInterfaces.cs | 13 +++++++++++++ .../Entities/Core/IEntityCore.cs | 17 +++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 src/HassModel/NetDeamon.HassModel/Entities/Core/CoreInterfaces.cs create mode 100644 src/HassModel/NetDeamon.HassModel/Entities/Core/IEntityCore.cs diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Core/CoreInterfaces.cs b/src/HassModel/NetDeamon.HassModel/Entities/Core/CoreInterfaces.cs new file mode 100644 index 000000000..3a6c187d1 --- /dev/null +++ b/src/HassModel/NetDeamon.HassModel/Entities/Core/CoreInterfaces.cs @@ -0,0 +1,13 @@ +namespace NetDaemon.HassModel.Entities; + +// These 'Core' interfaces serve as common types between 3rd party libraries and classes that are generated by the end +// user using nd-codegen + +/// Common interface for switch entities +public interface ISwitchEntityCore: IEntityCore { } + +/// Common interface for light entities +public interface ILightEntityCore: IEntityCore { } + +/// Common interface for binary_sensor entities +public interface IBinarySensorEntityCore: IEntityCore { } \ No newline at end of file diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Core/IEntityCore.cs b/src/HassModel/NetDeamon.HassModel/Entities/Core/IEntityCore.cs new file mode 100644 index 000000000..cc3c74a04 --- /dev/null +++ b/src/HassModel/NetDeamon.HassModel/Entities/Core/IEntityCore.cs @@ -0,0 +1,17 @@ +namespace NetDaemon.HassModel.Entities; + +/// +/// Core interface for any entity +/// +public interface IEntityCore +{ + /// + /// The IHAContext + /// + public IHaContext HaContext { get; } + + /// + /// Entity id being handled by this entity + /// + public string EntityId { get; } +} \ No newline at end of file From 39e45333ec819dda9281e0deaa24a7d51efddf51 Mon Sep 17 00:00:00 2001 From: Frank Bakker Date: Mon, 14 Aug 2023 23:46:22 +0200 Subject: [PATCH 14/18] Fix ctors of NumericEntity --- src/HassModel/NetDeamon.HassModel/Entities/NumericEntity.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/HassModel/NetDeamon.HassModel/Entities/NumericEntity.cs b/src/HassModel/NetDeamon.HassModel/Entities/NumericEntity.cs index bcb57b313..87dd4ccd6 100644 --- a/src/HassModel/NetDeamon.HassModel/Entities/NumericEntity.cs +++ b/src/HassModel/NetDeamon.HassModel/Entities/NumericEntity.cs @@ -6,7 +6,7 @@ public record NumericEntity : Entity { /// Copy constructor from base class - public NumericEntity(Entity entity) : base(entity) { } + public NumericEntity(IEntityCore entity) : base(entity) { } /// Constructor from haContext and entityId public NumericEntity(IHaContext haContext, string entityId) : base(haContext, entityId) { } @@ -36,7 +36,7 @@ public record NumericEntity : EntityCopy constructor from base class - public NumericEntity(Entity entity) : base(entity) { } + public NumericEntity(IEntityCore entity) : base(entity) { } /// Constructor from haContext and entityId public NumericEntity(IHaContext haContext, string entityId) : base(haContext, entityId) { } From 6256634fc1527e1faf6ab2ffe62a78a9d316a8f1 Mon Sep 17 00:00:00 2001 From: Pavel Yadlouski Date: Tue, 15 Aug 2023 12:46:22 +0200 Subject: [PATCH 15/18] Add common domain interfaces --- .../Entities/Core/CoreInterfaces.cs | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Core/CoreInterfaces.cs b/src/HassModel/NetDeamon.HassModel/Entities/Core/CoreInterfaces.cs index 3a6c187d1..7687e45e9 100644 --- a/src/HassModel/NetDeamon.HassModel/Entities/Core/CoreInterfaces.cs +++ b/src/HassModel/NetDeamon.HassModel/Entities/Core/CoreInterfaces.cs @@ -10,4 +10,40 @@ public interface ISwitchEntityCore: IEntityCore { } public interface ILightEntityCore: IEntityCore { } /// Common interface for binary_sensor entities -public interface IBinarySensorEntityCore: IEntityCore { } \ No newline at end of file +public interface IBinarySensorEntityCore: IEntityCore { } + +/// Common interface for person entities +public interface IPersonEntityCore: IEntityCore { } + +/// Common interface for zone entities +public interface IZoneEntityCore: IEntityCore { } + +/// Common interface for sun entities +public interface ISunEntityCore: IEntityCore { } + +/// Common interface for input_button entities +public interface IInputButtonEntityCore: IEntityCore { } + +/// Common interface for sensor entities +public interface ISensorEntityCore: IEntityCore { } + +/// Common interface for weather entities +public interface IWeatherEntityCore: IEntityCore { } + +/// Common interface for device_tracker entities +public interface IDeviceTrackerEntityCore: IEntityCore { } + +/// Common interface for media_player entities +public interface IMediaPlayerEntityCore: IEntityCore { } + +/// Common interface for button entities +public interface IButtonEntityCore: IEntityCore { } + +/// Common interface for camera entities +public interface INumberEntityCore: IEntityCore { } + +/// Common interface for select entities +public interface ISelectEntityCore: IEntityCore { } + +/// Common interface for automation entities +public interface IAutomationEntityCore: IEntityCore { } \ No newline at end of file From 8c21af307cb67886309648fc19bd7d853badd4fa Mon Sep 17 00:00:00 2001 From: Frank Bakker Date: Tue, 15 Aug 2023 23:23:57 +0200 Subject: [PATCH 16/18] Make extension methods target core interfaces when available, + add some tests --- .../CodeGeneration/EntitiesGenerator.cs | 13 ++++-------- .../ExtensionMethodsGenerator.cs | 2 +- .../EntityMetaData/EntityDomainMetadata.cs | 20 +++++++++++++++++-- .../CodeGenerator/CodeGeneratorTest.cs | 4 ++++ .../CodeGenerator/ServicesGeneratorTest.cs | 10 +++++++--- 5 files changed, 34 insertions(+), 15 deletions(-) diff --git a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/EntitiesGenerator.cs b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/EntitiesGenerator.cs index bb0121b32..3c788bdb1 100644 --- a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/EntitiesGenerator.cs +++ b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/EntitiesGenerator.cs @@ -71,12 +71,6 @@ private static MemberDeclarationSyntax GenerateEntityProperty(EntityMetaData ent .WithSummaryComment(entity.friendlyName); } - private static readonly HashSet CoreInterfaces = - typeof(IEntityCore).Assembly.GetTypes() - .Where(t => t.IsInterface && t.IsAssignableTo(typeof(IEntityCore))) - .Select(t => t.Name) - .ToHashSet(); - /// /// Generates a record derived from Entity like ClimateEntity or SensorEntity for a specific set of entities /// @@ -86,11 +80,12 @@ private static MemberDeclarationSyntax GenerateEntityType(EntityDomainMetadata d var baseType = domainMetaData.IsNumeric ? typeof(NumericEntity) : typeof(Entity); var entityStateType = domainMetaData.IsNumeric ? typeof(NumericEntityState) : typeof(EntityState); - var baseClass = $"{SimplifyTypeName(baseType)}<{domainMetaData .EntityClassName}, {SimplifyTypeName(entityStateType)}<{attributesGeneric}>, {attributesGeneric}>"; + var baseClass = $"{SimplifyTypeName(baseType)}<{domainMetaData.EntityClassName}, {SimplifyTypeName(entityStateType)}<{attributesGeneric}>, {attributesGeneric}>"; - if (CoreInterfaces.Contains(domainMetaData.CoreInterfaceName)) + var coreinterface = domainMetaData.CoreInterfaceName; + if (coreinterface != null) { - baseClass += $", {domainMetaData.CoreInterfaceName}"; + baseClass += $", {coreinterface}"; } var (className, variableName) = GetNames(); diff --git a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ExtensionMethodsGenerator.cs b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ExtensionMethodsGenerator.cs index b39e69f98..324816a9d 100644 --- a/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ExtensionMethodsGenerator.cs +++ b/src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ExtensionMethodsGenerator.cs @@ -27,7 +27,7 @@ internal static class ExtensionMethodsGenerator { public static IEnumerable Generate(IEnumerable serviceDomains, IReadOnlyCollection entityDomains) { - var entityClassNameByDomain = entityDomains.ToLookup(e => e.Domain, e => e.EntityClassName); + var entityClassNameByDomain = entityDomains.ToLookup(e => e.Domain, e => e.CoreInterfaceName ?? e.EntityClassName); return serviceDomains .Select(sd => GenerateDomainExtensionClass(sd, entityClassNameByDomain)) diff --git a/src/HassModel/NetDaemon.HassModel.CodeGenerator/MetaData/EntityMetaData/EntityDomainMetadata.cs b/src/HassModel/NetDaemon.HassModel.CodeGenerator/MetaData/EntityMetaData/EntityDomainMetadata.cs index 191893a6d..c6ccd00e3 100644 --- a/src/HassModel/NetDaemon.HassModel.CodeGenerator/MetaData/EntityMetaData/EntityDomainMetadata.cs +++ b/src/HassModel/NetDaemon.HassModel.CodeGenerator/MetaData/EntityMetaData/EntityDomainMetadata.cs @@ -18,14 +18,30 @@ record EntityDomainMetadata( IReadOnlyList Attributes ) { + private static readonly HashSet CoreInterfaces = + typeof(IEntityCore).Assembly.GetTypes() + .Where(t => t.IsInterface && t.IsAssignableTo(typeof(IEntityCore))) + .Select(t => t.Name) + .ToHashSet(); + private readonly string prefixedDomain = (IsNumeric && EntityIdHelper.MixedDomains.Contains(Domain) ? "numeric_" : "") + Domain; [JsonIgnore] public string EntityClassName => $"{prefixedDomain}Entity".ToValidCSharpPascalCase(); + /// + /// Returns the name of the corresponding Core Interface if it exists, or null if it does not + /// [JsonIgnore] - public string CoreInterfaceName => $"I{Domain.ToValidCSharpPascalCase()}EntityCore"; - + public string? CoreInterfaceName + { + get + { + var name = $"I{Domain.ToValidCSharpPascalCase()}EntityCore"; + return CoreInterfaces.Contains(name) ? name : null; + } + } + [JsonIgnore] public string AttributesClassName => $"{prefixedDomain}Attributes".ToValidCSharpPascalCase(); diff --git a/src/HassModel/NetDaemon.HassModel.Tests/CodeGenerator/CodeGeneratorTest.cs b/src/HassModel/NetDaemon.HassModel.Tests/CodeGenerator/CodeGeneratorTest.cs index d13c7c831..129ff5799 100644 --- a/src/HassModel/NetDaemon.HassModel.Tests/CodeGenerator/CodeGeneratorTest.cs +++ b/src/HassModel/NetDaemon.HassModel.Tests/CodeGenerator/CodeGeneratorTest.cs @@ -52,6 +52,10 @@ public void Run(IHaContext ha) LightEntity light2 = entities.Light.Light2; SwitchEntity switch1 = entities.Switch.Switch1; SwitchEntity switch2 = entities.Switch.Switch2; + + // Now check if the entity classes implement the core interfaces + ILightEntityCore lightAsCore = entities.Light.Light1; + ISwitchEntityCore switch1AsCore = entities.Switch.Switch1; } } """; diff --git a/src/HassModel/NetDaemon.HassModel.Tests/CodeGenerator/ServicesGeneratorTest.cs b/src/HassModel/NetDaemon.HassModel.Tests/CodeGenerator/ServicesGeneratorTest.cs index a782444e0..f6b2ed900 100644 --- a/src/HassModel/NetDaemon.HassModel.Tests/CodeGenerator/ServicesGeneratorTest.cs +++ b/src/HassModel/NetDaemon.HassModel.Tests/CodeGenerator/ServicesGeneratorTest.cs @@ -63,12 +63,17 @@ public void Run(IHaContext ha) s.Light.TurnOff(new ServiceTarget()); - var light = new RootNameSpace.LightEntity(ha, "light.testLight"); - + LightEntity light = new RootNameSpace.LightEntity(ha, "light.testLight"); light.TurnOn(); light.TurnOn(transition: 12, brightness: 324.5f); light.TurnOn(new (){ Transition = 12L, Brightness = 12.3f }); light.TurnOff(); + + ILightEntityCore lightCore = light; + lightCore.TurnOn(); + lightCore.TurnOn(transition: 12, brightness: 324.5f); + lightCore.TurnOn(new (){ Transition = 12L, Brightness = 12.3f }); + lightCore.TurnOff(); } } """; @@ -179,7 +184,6 @@ public void Run(Entities entities, Services services) CodeGenTestHelper.AssertCodeCompiles(code.ToString(), appCode); } - [Fact] public void TestServiceWithKeyWordFieldName_ParamEscaped() { From da0d483f09b512042d7e395e69595d3ac47d2351 Mon Sep 17 00:00:00 2001 From: Frank Bakker Date: Wed, 16 Aug 2023 00:08:58 +0200 Subject: [PATCH 17/18] Add All core interfaces --- .../Entities/Core/CoreInterfaces.cs | 119 +++++++++++++----- 1 file changed, 89 insertions(+), 30 deletions(-) diff --git a/src/HassModel/NetDeamon.HassModel/Entities/Core/CoreInterfaces.cs b/src/HassModel/NetDeamon.HassModel/Entities/Core/CoreInterfaces.cs index 7687e45e9..b8a464454 100644 --- a/src/HassModel/NetDeamon.HassModel/Entities/Core/CoreInterfaces.cs +++ b/src/HassModel/NetDeamon.HassModel/Entities/Core/CoreInterfaces.cs @@ -3,47 +3,106 @@ namespace NetDaemon.HassModel.Entities; // These 'Core' interfaces serve as common types between 3rd party libraries and classes that are generated by the end // user using nd-codegen -/// Common interface for switch entities -public interface ISwitchEntityCore: IEntityCore { } +/// Core interface for automation entities +public interface IAutomationEntityCore: IEntityCore {} -/// Common interface for light entities -public interface ILightEntityCore: IEntityCore { } +/// Core interface for binary_sensor entities +public interface IBinarySensorEntityCore: IEntityCore {} -/// Common interface for binary_sensor entities -public interface IBinarySensorEntityCore: IEntityCore { } +/// Core interface for button entities +public interface IButtonEntityCore: IEntityCore {} -/// Common interface for person entities -public interface IPersonEntityCore: IEntityCore { } +/// Core interface for calendar entities +public interface ICalendarEntityCore: IEntityCore {} -/// Common interface for zone entities -public interface IZoneEntityCore: IEntityCore { } +/// Core interface for camera entities +public interface ICameraEntityCore: IEntityCore {} -/// Common interface for sun entities -public interface ISunEntityCore: IEntityCore { } +/// Core interface for climate entities +public interface IClimateEntityCore: IEntityCore {} -/// Common interface for input_button entities -public interface IInputButtonEntityCore: IEntityCore { } +/// Core interface for cover entities +public interface ICoverEntityCore: IEntityCore {} -/// Common interface for sensor entities -public interface ISensorEntityCore: IEntityCore { } +/// Core interface for device_tracker entities +public interface IDeviceTrackerEntityCore: IEntityCore {} -/// Common interface for weather entities -public interface IWeatherEntityCore: IEntityCore { } +/// Core interface for group entities +public interface IGroupEntityCore: IEntityCore {} -/// Common interface for device_tracker entities -public interface IDeviceTrackerEntityCore: IEntityCore { } +/// Core interface for input_boolean entities +public interface IInputBooleanEntityCore: IEntityCore {} -/// Common interface for media_player entities -public interface IMediaPlayerEntityCore: IEntityCore { } +/// Core interface for input_button entities +public interface IInputButtonEntityCore: IEntityCore {} -/// Common interface for button entities -public interface IButtonEntityCore: IEntityCore { } +/// Core interface for input_datetime entities +public interface IInputDatetimeEntityCore: IEntityCore {} -/// Common interface for camera entities -public interface INumberEntityCore: IEntityCore { } +/// Core interface for input_number entities +public interface IInputNumberEntityCore: IEntityCore {} + +/// Core interface for input_select entities +public interface IInputSelectEntityCore: IEntityCore {} + +/// Core interface for input_text entities +public interface IInputTextEntityCore: IEntityCore {} + +/// Core interface for light entities +public interface ILightEntityCore: IEntityCore {} + +/// Core interface for lock entities +public interface ILockEntityCore: IEntityCore {} + +/// Core interface for media_player entities +public interface IMediaPlayerEntityCore: IEntityCore {} + +/// Core interface for number entities +public interface INumberEntityCore: IEntityCore {} + +/// Core interface for person entities +public interface IPersonEntityCore: IEntityCore {} + +/// Core interface for proximity entities +public interface IProximityEntityCore: IEntityCore {} + +/// Core interface for remote entities +public interface IRemoteEntityCore: IEntityCore {} + +/// Core interface for scene entities +public interface ISceneEntityCore: IEntityCore {} + +/// Core interface for schedule entities +public interface IScheduleEntityCore: IEntityCore {} + +/// Core interface for script entities +public interface IScriptEntityCore: IEntityCore {} + +/// Core interface for select entities +public interface ISelectEntityCore: IEntityCore {} + +/// Core interface for sensor entities +public interface ISensorEntityCore: IEntityCore {} + +/// Core interface for sun entities +public interface ISunEntityCore: IEntityCore {} + +/// Core interface for switch entities +public interface ISwitchEntityCore: IEntityCore {} + +/// Core interface for timer entities +public interface ITimerEntityCore: IEntityCore {} + +/// Core interface for update entities +public interface IUpdateEntityCore: IEntityCore {} + +/// Core interface for vacuum entities +public interface IVacuumEntityCore: IEntityCore {} + +/// Core interface for weather entities +public interface IWeatherEntityCore: IEntityCore {} + +/// Core interface for zone entities +public interface IZoneEntityCore: IEntityCore {} -/// Common interface for select entities -public interface ISelectEntityCore: IEntityCore { } -/// Common interface for automation entities -public interface IAutomationEntityCore: IEntityCore { } \ No newline at end of file From 1ff3acb5d02430e7adbef10db053d7edab65f5a7 Mon Sep 17 00:00:00 2001 From: Frank Bakker Date: Wed, 16 Aug 2023 00:09:24 +0200 Subject: [PATCH 18/18] Add dummy HomeAssistantGenerated.cs --- src/debug/MyNDApp/HomeAssistantGenerated.cs | 136 ++++++++++++++++++ .../MyInterfaceAutomation/InterfaceUsage.cs | 2 +- src/debug/MyNDApp/program.cs | 2 +- 3 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 src/debug/MyNDApp/HomeAssistantGenerated.cs diff --git a/src/debug/MyNDApp/HomeAssistantGenerated.cs b/src/debug/MyNDApp/HomeAssistantGenerated.cs new file mode 100644 index 000000000..c872b256d --- /dev/null +++ b/src/debug/MyNDApp/HomeAssistantGenerated.cs @@ -0,0 +1,136 @@ +//------------------------------------------------------------------------------ +// +// Generated using NetDaemon CodeGenerator nd-codegen v23.32.0.0 +// At: 2023-08-13T22:55:56.3430066+02:00 +// +// *** Make sure the version of the codegen tool and your nugets Joysoftware.NetDaemon.* have the same version.*** +// You can use following command to keep it up to date with the latest version: +// dotnet tool update JoySoftware.NetDaemon.HassModel.CodeGen +// +// To update this file with latest entities run this command in your project directory: +// dotnet tool run nd-codegen +// +// In the template projects we provided a convenience powershell script that will update +// the codegen and nugets to latest versions update_all_dependencies.ps1. +// +// For more information: https://netdaemon.xyz/docs/v3/hass_model/hass_model_codegen +// For more information about NetDaemon: https://netdaemon.xyz/ +// +//------------------------------------------------------------------------------ +#nullable enable +using System; +using System.Collections.Generic; +using Microsoft.Extensions.DependencyInjection; +using System.Text.Json.Serialization; +using NetDaemon.HassModel; +using NetDaemon.HassModel.Entities; +using NetDaemon.HassModel.Entities.Core; + +namespace HomeAssistantGenerated; + +public partial class Entities +{ + private readonly IHaContext _haContext; + public Entities(IHaContext haContext) + { + _haContext = haContext; + } + + public LightEntities Light => new(_haContext); +} + + +public partial class LightEntities +{ + private readonly IHaContext _haContext; + public LightEntities(IHaContext haContext) + { + _haContext = haContext; + } + + ///Woonkamer + public LightEntity Woonkamer => new(_haContext, "light.woonkamer"); + ///Alles Beneden + ///Zolder + public LightEntity Zolder => new(_haContext, "light.zolder"); +} + +public partial record LightEntity : Entity, LightAttributes>, ILightEntityCore +{ + public LightEntity(IHaContext haContext, string entityId) : base(haContext, entityId) + { + } + + public LightEntity(Entity entity) : base(entity) + { + } +} + +public partial record LightAttributes +{ + [JsonPropertyName("min_color_temp_kelvin")] + public double? MinColorTempKelvin { get; init; } + + [JsonPropertyName("max_color_temp_kelvin")] + public double? MaxColorTempKelvin { get; init; } + + [JsonPropertyName("color_temp_kelvin")] + public double? ColorTempKelvin { get; init; } + + [JsonPropertyName("off_with_transition")] + public bool? OffWithTransition { get; init; } + + [JsonPropertyName("off_brightness")] + public double? OffBrightness { get; init; } + + [JsonPropertyName("restored")] + public bool? Restored { get; init; } + + [JsonPropertyName("supported_color_modes")] + public IReadOnlyList? SupportedColorModes { get; init; } + + [JsonPropertyName("friendly_name")] + public string? FriendlyName { get; init; } + + [JsonPropertyName("supported_features")] + public double? SupportedFeatures { get; init; } + + [JsonPropertyName("min_mireds")] + public double? MinMireds { get; init; } + + [JsonPropertyName("max_mireds")] + public double? MaxMireds { get; init; } + + [JsonPropertyName("effect_list")] + public IReadOnlyList? EffectList { get; init; } + + [JsonPropertyName("entity_id")] + public IReadOnlyList? EntityId { get; init; } + + [JsonPropertyName("icon")] + public string? Icon { get; init; } + + [JsonPropertyName("color_mode")] + public string? ColorMode { get; init; } + + [JsonPropertyName("brightness")] + public double? Brightness { get; init; } + + [JsonPropertyName("color_temp")] + public double? ColorTemp { get; init; } + + [JsonPropertyName("hs_color")] + public IReadOnlyList? HsColor { get; init; } + + [JsonPropertyName("rgb_color")] + public IReadOnlyList? RgbColor { get; init; } + + [JsonPropertyName("xy_color")] + public IReadOnlyList? XyColor { get; init; } +} + + + + + + diff --git a/src/debug/MyNDApp/apps/HassModel/MyInterfaceAutomation/InterfaceUsage.cs b/src/debug/MyNDApp/apps/HassModel/MyInterfaceAutomation/InterfaceUsage.cs index b69269de6..aa599b3ac 100644 --- a/src/debug/MyNDApp/apps/HassModel/MyInterfaceAutomation/InterfaceUsage.cs +++ b/src/debug/MyNDApp/apps/HassModel/MyInterfaceAutomation/InterfaceUsage.cs @@ -17,7 +17,7 @@ public class InterfaceUsage public InterfaceUsage(IHaContext haContext, ILogger logger, IScheduler scheduler) { var entities = new Entities(haContext); - IEnumerable lights = new[] { entities.Light.Zolder, entities.Light.LampenEettafel }; + IEnumerable lights = new[] { entities.Light.Zolder, entities.Light.Woonkamer }; // pass generated types to the library using the commonly known interfaces diff --git a/src/debug/MyNDApp/program.cs b/src/debug/MyNDApp/program.cs index b0944576d..3835e285c 100644 --- a/src/debug/MyNDApp/program.cs +++ b/src/debug/MyNDApp/program.cs @@ -25,7 +25,7 @@ await Host.CreateDefaultBuilder(args) .AddNetDaemonStateManager() .AddNetDaemonScheduler() // Add next line if using code generator - .AddHomeAssistantGenerated() + //.AddHomeAssistantGenerated() ) .Build() .RunAsync()