Skip to content

Commit

Permalink
Generate entities for new API (#149)
Browse files Browse the repository at this point in the history
* Bring back service call callback to Rx API

* Added generate entities in new API
  • Loading branch information
helto4real committed Jun 30, 2020
1 parent 5573e68 commit d9c2ec8
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 0 deletions.
1 change: 1 addition & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"HASS_HOST": "${localEnv:HASS_HOST}",
"HASS_PORT": "${localEnv:HASS_PORT}",
"HASS_LOGLEVEL": "${localEnv:HASS_LOGLEVEL}",
"HASS_GEN_ENTITIES": "${localEnv:HASS_GEN_ENTITIES}",
"HASS_DAEMONAPPFOLDER": "${localEnv:HASS_DAEMONAPPFOLDER}"
},
"postCreateCommand": "dotnet restore && .devcontainer/install_prettyprompt.sh",
Expand Down
35 changes: 35 additions & 0 deletions src/App/NetDaemon.App/Common/Reactive/RxEntity.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Reactive.Linq;

Expand Down Expand Up @@ -123,6 +124,40 @@ internal static string GetDomainFromEntity(string entity)
return entityParts[0];
}

/// <summary>
/// Calls a service using current entity id/s and the entity domain
/// </summary>
/// <param name="service">Name of the service to call</param>
/// <param name="data">Data to provide</param>
public void CallService(string service, dynamic? data = null)
{
if (_entityIds is null || _entityIds is object && _entityIds.Count() == 0)
return;

foreach (var entityId in _entityIds!)
{
var serviceData = new FluentExpandoObject();

if (data is ExpandoObject)
{
// Maske sure we make a copy since we reuse all info but entity id
serviceData.CopyFrom(data);
}
else if (data is object)
{
// It is initialized with anonmous type new {transitio=10} for example
var expObject = ((object)data).ToExpandoObject();
serviceData.CopyFrom(expObject);
}

var domain = GetDomainFromEntity(entityId);

serviceData["entity_id"] = entityId;

_daemonRxApp.CallService(domain, service, serviceData);
}
}

private void CallServiceOnEntity(string service, dynamic? attributes = null)
{
if (_entityIds is null || _entityIds is object && _entityIds.Count() == 0)
Expand Down
71 changes: 71 additions & 0 deletions src/DaemonRunner/DaemonRunner/Service/App/CodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,77 @@ public class CodeGenerator
return code.NormalizeWhitespace(indentation: " ", eol: "\n").ToFullString();
}

public string? GenerateCodeRx(string nameSpace, IEnumerable<string> entities)
{
var code = SyntaxFactory.CompilationUnit();

// Add Usings statements
code = code.AddUsings(SyntaxFactory.UsingDirective(SyntaxFactory.ParseName("JoySoftware.HomeAssistant.NetDaemon.Common.Reactive")));

// Add namespace
var namespaceDeclaration = SyntaxFactory.NamespaceDeclaration(SyntaxFactory.ParseName(nameSpace)).NormalizeWhitespace();

// Add support for extensions for entities
var extensionClass = SyntaxFactory.ClassDeclaration("GeneratedAppBase");

extensionClass = extensionClass.AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword));
extensionClass = extensionClass.AddBaseListTypes(
SyntaxFactory.SimpleBaseType(SyntaxFactory.ParseTypeName("NetDaemonRxApp")));

// Get all available domains, this is used to create the extensionmethods
var domains = GetDomainsFromEntities(entities);

foreach (var domain in domains)
{
if (_FluentApiMapper.ContainsKey(domain))
{
var camelCaseDomain = domain.ToCamelCase();
var property = $@"public {camelCaseDomain}Entities {camelCaseDomain} => new {camelCaseDomain}Entities(this);";
var propertyDeclaration = CSharpSyntaxTree.ParseText(property).GetRoot().ChildNodes().OfType<PropertyDeclarationSyntax>().FirstOrDefault();
extensionClass = extensionClass.AddMembers(propertyDeclaration);
}
}
namespaceDeclaration = namespaceDeclaration.AddMembers(extensionClass);

// Add the classes implementing the specific entities
foreach (var domain in GetDomainsFromEntities(entities))
{
if (_FluentApiMapper.ContainsKey(domain))
{
var classDeclaration = $@"public partial class {domain.ToCamelCase()}Entities
{{
private readonly NetDaemonRxApp _app;
public {domain.ToCamelCase()}Entities(NetDaemonRxApp app)
{{
_app = app;
}}
}}";
var entityClass = CSharpSyntaxTree.ParseText(classDeclaration).GetRoot().ChildNodes().OfType<ClassDeclarationSyntax>().FirstOrDefault();
foreach (var entity in entities.Where(n => n.StartsWith(domain)))
{

var name = entity[(entity.IndexOf(".") + 1)..];
// Quick check to make sure the name is a valid C# identifier. Should really check to make
// sure it doesn't collide with a reserved keyword as well.
if (!char.IsLetter(name[0]) && (name[0] != '_'))
{
name = "e_" + name;
}

var propertyCode = $@"public RxEntity {name.ToCamelCase()} => _app.Entity(""{entity}"");";
var propDeclaration = CSharpSyntaxTree.ParseText(propertyCode).GetRoot().ChildNodes().OfType<PropertyDeclarationSyntax>().FirstOrDefault();
entityClass = entityClass.AddMembers(propDeclaration);
}
namespaceDeclaration = namespaceDeclaration.AddMembers(entityClass);
}
}

code = code.AddMembers(namespaceDeclaration);

return code.NormalizeWhitespace(indentation: " ", eol: "\n").ToFullString();
}

/// <summary>
/// Returns a list of domains from all entities
/// </summary>
Expand Down
5 changes: 5 additions & 0 deletions src/DaemonRunner/DaemonRunner/Service/RunnerService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,11 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
_daemonHost.State.Select(n => n.EntityId).Distinct());

System.IO.File.WriteAllText(System.IO.Path.Combine(sourceFolder!, "_EntityExtensions.cs"), source);

var sourceRx = codeGen.GenerateCodeRx("Netdaemon.Generated.Reactive",
_daemonHost.State.Select(n => n.EntityId).Distinct());

System.IO.File.WriteAllText(System.IO.Path.Combine(sourceFolder!, "_EntityExtensionsRx.cs"), sourceRx);
}
}
await _daemonHost.Initialize().ConfigureAwait(false);
Expand Down

0 comments on commit d9c2ec8

Please sign in to comment.