C# for Home Assistant

That’s workable with multiple methods. But as seen in the attributes, my schedule differs for the weekend. A non-workday should also have the same schedule as the weekend. Thus the dilemma. The executed code is the same, so I’d prefer to keep it DRY, execution time differs only. That’s what I’m trying to do anyway. BTW a weekend is considered not a workday as well as holidays.

Ok i see. The only problem I have with using the Workday sensor is that I would have to implement logic that only applies if you are using that sensor.

How about a Schedule attribute you could inherit from and implement your own schedule logic.
Basically the scheduler would call a GetNextOccurence function and you could implement that the way you want to.

Sounds fine!

Man I know I’m throwing requests like crazy, but it’s only because I’m so stoked about this project.

It would be good to get some helper classes to handle timers. Right now I don’t see any way other than swallowing events (which is messy) to get a callback from a HASS Helper Timer.

Like timers in c#? Can you show me code?

I’ve worked the schedule and the timer thing (I’m a bit rusty in .NET) so nevermind, sorry.

Strange behavior I’m witnessing.
Within the the class in which the automation endpoints exist, I’m instantiating objects in the constructor and attempting to persist them across calls. But it appears that they’re being re-instantiated with each automation endpoint call, I can see the constructor being called each time. Can you explain? They must be dynamically created at runtime.

Because of this various variables will not persist unless they are abstracted to a static class.

Is there a way to determine which entity fired the automation if you use multiple ‘triggers’ in the same endpoint?

#1 There is now a way to create custom triggers and schedules: 4. Triggers · anhaehne/hhnl.HomeAssistantNet Wiki (github.com)
#2 Yes, the automation classes are transient, meaning they get newly created for each automation run. If you want to persist something between multiple runs you should create static variables or save them in Home Assistant.
#3 You can inject the current event. 7. Events · anhaehne/hhnl.HomeAssistantNet Wiki (github.com) Here you will get the source event as JsonElement.

PS: The newest version 0.8.0+ has a breaking change. RunOnStart is now an attribute and not part of the AutomationAttribute anymore. See: 4. Triggers · anhaehne/hhnl.HomeAssistantNet Wiki (github.com)

Also some namespaces have changed.

1 Like

Since the latest, I’ve patched up all the breaking changes, I can build local but it will not start or build on HASS. Looks like the generator might be twisted at the axel.


Unhandled exception. System.ArgumentException: An item with the same key has already been added. Key: CS4HA.MasterBath.Occupancy
   at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior) in System.Private.CoreLib.dll:token 0x60062ce+0x1a0
   at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value) in System.Private.CoreLib.dll:token 0x60062c1+0x0
   at System.Linq.Enumerable.ToDictionary[TSource,TKey](IEnumerable`1 source, Func`2 keySelector, IEqualityComparer`1 comparer) in System.Linq.dll:token 0x600011d+0x75
   at hhnl.HomeAssistantNet.Automations.Automation.AutomationRegistry..ctor(IGeneratedMetaData generatedMetaData, IAutomationInfoProvider automationInfoProvider, Assembly assembly) in hhnl.HomeAssistantNet.Automations.dll:token 0x60000a2+0x5b
   at hhnl.HomeAssistantNet.Automations.Automation.AutomationStartup.<ConfigureServiceInternal>b__3_8(IServiceProvider s) in hhnl.HomeAssistantNet.Automations.dll:token 0x60000c3+0x0
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context) in Microsoft.Extensions.DependencyInjection.dll:token 0x600007e+0x0
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument) in Microsoft.Extensions.DependencyInjection.dll:token 0x6000091+0x33
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType) in Microsoft.Extensions.DependencyInjection.dll:token 0x6000079+0x59
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context) in Microsoft.Extensions.DependencyInjection.dll:token 0x6000077+0x0
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument) in Microsoft.Extensions.DependencyInjection.dll:token 0x6000090+0x4e
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context) in Microsoft.Extensions.DependencyInjection.dll:token 0x6000076+0x39
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument) in Microsoft.Extensions.DependencyInjection.dll:token 0x6000091+0x4f
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType) in Microsoft.Extensions.DependencyInjection.dll:token 0x6000079+0x59
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context) in Microsoft.Extensions.DependencyInjection.dll:token 0x6000077+0x0
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument) in Microsoft.Extensions.DependencyInjection.dll:token 0x6000090+0x4e
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope) in Microsoft.Extensions.DependencyInjection.dll:token 0x6000074+0x12
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope) in Microsoft.Extensions.DependencyInjection.dll:token 0x600016d+0x0
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope) in Microsoft.Extensions.DependencyInjection.dll:token 0x60000fd+0x3e
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType) in Microsoft.Extensions.DependencyInjection.dll:token 0x6000103+0xd
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType) in Microsoft.Extensions.DependencyInjection.Abstractions.dll:token 0x600007b+0x34
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider) in Microsoft.Extensions.DependencyInjection.Abstractions.dll:token 0x600007c+0xe
   at hhnl.HomeAssistantNet.Automations.Automation.AutomationStartup.<>c.<ConfigureServiceInternal>b__3_1(IServiceProvider s) in hhnl.HomeAssistantNet.Automations.dll:token 0x60001b8+0x0
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context) in Microsoft.Extensions.DependencyInjection.dll:token 0x600007e+0x0
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument) in Microsoft.Extensions.DependencyInjection.dll:token 0x6000091+0x33
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType) in Microsoft.Extensions.DependencyInjection.dll:token 0x6000079+0x59
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context) in Microsoft.Extensions.DependencyInjection.dll:token 0x6000077+0x0
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument) in Microsoft.Extensions.DependencyInjection.dll:token 0x6000090+0x4e
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitIEnumerable(IEnumerableCallSite enumerableCallSite, RuntimeResolverContext context) in Microsoft.Extensions.DependencyInjection.dll:token 0x600007d+0x14
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument) in Microsoft.Extensions.DependencyInjection.dll:token 0x6000091+0x41
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType) in Microsoft.Extensions.DependencyInjection.dll:token 0x6000079+0x59
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context) in Microsoft.Extensions.DependencyInjection.dll:token 0x6000077+0x0
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument) in Microsoft.Extensions.DependencyInjection.dll:token 0x6000090+0x4e
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope) in Microsoft.Extensions.DependencyInjection.dll:token 0x6000074+0x12
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope) in Microsoft.Extensions.DependencyInjection.dll:token 0x600016d+0x0
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope) in Microsoft.Extensions.DependencyInjection.dll:token 0x60000fd+0x3e
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType) in Microsoft.Extensions.DependencyInjection.dll:token 0x6000103+0xd
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider) in Microsoft.Extensions.DependencyInjection.Abstractions.dll:token 0x600007a+0xe
   at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken) in Microsoft.Extensions.Hosting.dll:token 0x6000041+0xc4
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token) in Microsoft.Extensions.Hosting.Abstractions.dll:token 0x600001d+0x93
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token) in Microsoft.Extensions.Hosting.Abstractions.dll:token 0x600001d+0x1be
   at CS4HA.Startup.<Main>(String[] args) in CS4HA.dll:token 0x600008f+0xc

I cleaned out the deploy folder and restarted, seems to be good.
As far as I can see, NoTrack is now missing.

This sounds amazing… like some I work in C# for a living and trying to understand template’ing an automation and along with YAMAL just is alien some how.

What been everyone’s experience been so far wit this add-on… I know its new///

-Aaron

I have been able to get everything working (Intellisense for entities, remote debugging, deployment) as expected and have converted all my existing automations. It is so nice being able to work in C# rather than the UI. Thanks Andre, I really hope this project stays afloat.

1 Like

Hey guys,

I’m new to HA, but a C# dev, so discover this addon with a lot of interest.
I’m trying to convert a little YAML script for a start, which works with a Hue light.

I just don’t figure how to change color on the light ?
The hue light is HomeAssistant.Lights._0x0017880100f56187
but this object does not seems to have any brightness_pct nor color attribute, can’t figure out to make this work.

Could you share your C# automations ? i’m quite sure it would help beginers like to me understand how this works.

Thanks !

You can call all services available in HA like this: 3. Calling services · anhaehne/hhnl.HomeAssistantNet Wiki (github.com)

You can look at service data here: Light - Home Assistant (home-assistant.io)

In your example it would probably be something like this:

public class Test
{
    private readonly IHomeAssistantClient _homeAssistantClient;

    public Test(IHomeAssistantClient homeAssistantClient)
    {
        _homeAssistantClient = homeAssistantClient;
    }

    // We use the NoTack attribute to not run this automation when the light changes.
    // Alternatively you can request the light entity in the constructor.
    public async Task MyAutomation([NoTrack]HomeAssistant.Lights._0x0017880100f56187 myLight)
    {
        // TODO: Add your logic here 
        await _homeAssistantClient.CallServiceAsync(domain: "light",
                service: "turn_on",
                targetId: myLight.UniqueId,
                serviceData: new
                {
                    brightness = 130,
                    rgb_color = new[] { 255, 0, 0 }
                });
    }

}

Hey Limeray ! First of all many many thanks for the awesome works :slight_smile:

Well my question is more “how should I know it’s a service I need to call ?”.
I now understand your exemple, but honestly I was not aware that to change the color (or brightness or whatever) I need to call the turn_on service.
I’m quite sure it’s related to the fact that I’m not familiar with HA !

Just looked at your second link, this IS the documentation I was missing. I’ll guess I have to search more in the HA docs to get my answer !

Regards,

Hello there !
It seems I’m having some issues with scripts that do not trigger by C# for HA. It’s based on HA automations that launch a script every morning :

- id: '1641585609160'
  alias: Bouchon
  description: ''
  trigger:
  - platform: time
    at: 07:50
  condition: []
  action:
  - service: script.waze
    data: {}
  mode: single

And then C# for HA has a dedicated classe :

 public WazeAutomations(ILogger<WazeAutomations> logger, 
            IHomeAssistantClient homeAssistantClient, 
            HomeAssistant.Lights.PhilipsLct0018761f500LevelLightColorOnOff hue, HomeAssistant.Sensors.Taf trajet)
        {
            _logger = logger;
            _homeAssistantClient = homeAssistantClient;
            _hue = new EasyLight(hue.UniqueId, homeAssistantClient);
            _trajet = trajet;
        }

        [Automation(reentryPolicy: ReentryPolicy.Discard)]
        public async Task WazeBouchonAutomation(CancellationToken ct, [Snapshot]HomeAssistant.Scripts.Waze waze)
        {
(...)
         }

The morning the automatiion is triggered by HA, but nothing in C# for HA (no trace for execution looking at the automation.

Rebuilding and deploy solved the issu. But yesterday the automation had never stop (I had to manually stop it, and now it appears as Cancelled). And this morning it does not trigget at all again

I was having absolutly no issue since february, my Ha is always up to date. Do you have any clue ?

Regards,

Sometimes automation get stuck in the running state but that isn’t impacting the automation. So the state says running but the automation has completed successfully. Can you add logging to your automation to see if the automation really compeletes? There is a wiki entry on github on how to setup the logging.

I do have logging but I’m also sure it has not completed because when the automation start a light is on and then it’s off at the end :slight_smile:
edit: or maybe the call for turning the light off did not work, and as the call was

await  _hue.TurnOffAsync();

it has waited ?

But my main concern is about the automation that does not trigger this morning, it should have!

this morning still no automation on C# for HA, even if the HA automation had triggered ?

Ok so, as last time, I had to rebuild&deploy on C# for HA for the automation to trigger again. I don’t changer anything else. It’s weird and a little bit concerning ?