Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Discussion: automation switches #120

Closed
dlashua opened this issue Dec 15, 2020 · 26 comments
Closed

Feature Discussion: automation switches #120

dlashua opened this issue Dec 15, 2020 · 26 comments

Comments

@dlashua
Copy link
Contributor

dlashua commented Dec 15, 2020

One nice feature about native Home Assistant automations is they all come with an "automation.whatever" entity that can be turned off or triggered manually (usually for testing). Pyscript doesn't have this so turning off an automation either means commenting it out or adding @state_active('input_boolean.my_automation == "on"') to the methods and then creating the input_boolean.

Is there any interest in letting pyscript do this for us, perhaps even on an "as requested" basis?

Example code:

@state_trigger('binary_sensor.living_motion == "on"')
@automation_switch('common_area_lights')
def living_on():
  light.living.turn_on()

@state_trigger('binary_sensor.kitchen_motion == "on"')
@automation_switch('common_area_lights')
def kitchen_on():
  light.kitchen.turn_on()

In this example, two methods use the same "automation_switch". Pyscript would create the switch on the first invocation, and realize it was already created on the second invocation and do nothing. If these methods are deleted, pyscript should realize there are no more methods that use this automation_switch and delete it from Home Assistant.

Additionally, each of these functions would have the equivalent of @state_active('switch.common_area_lights == "on"') attached to them. If the switch is off, they don't trigger. Even better would be to give the function the same treatment as a "filename comment out" so that the "shutdown" functions happen when turned off, and the "startup" functions happen when turned on.

Creating the switch in Home Assistant is the hardest part of the puzzle, likely, only because pyscript does nothing like it so far. We can't just state.set the switch entity because 1) a switch with that entity id might already exist and 2) that doesn't create all the home assistant hooks to listen for turn_off and turn_on service calls. So we have to use the switch platform to create the switch.

If we don't want to get into all the platform entity creation stuff, another option would be to provide (pyscript.automation_turn_on and pyscript.automation_turn_off services that take automation: common_area_lights as data (with possibly better names than I've come up with). This would make it really easy to turn on/off a pyscript automation from code/native automations, but a little more difficult to do it from the UI since users would have to use a button card (or something like it) to handle this instead of just adding the switch entity to a row. It's less nice, but MUCH easier since platform entities can be a bit cumbersome.

Thoughts?

This feature discussion brought to you by me playing "flashlight tag" in the dark with my kids the other day and realizing this was impossible since pyscript kept turning all my lights on. So I had to comment everything out, enjoy the game, and then turn everything back on. I would have still had to manually turn something off and then on again with the above in place, but I could have written a single pyscript to handle the on/off functionality (to be used then and any time again in the future) instead of having to find and edit the "state_active" bits of every applicable automation.

I really like the idea of each function classifying itself with the decorator. This gets really fancy when I can supply multiple names:

@automation_switch('common_area_lights', 'living_lights', 'lights')

Thus providing me with three switches, one to turn off all common_area light automations, one to turn off all living light automations, and one to turn off all light automations in the whole house. They end up working a bit like "tags" for the functions that the function authors can use as they see fit.

@wsw70
Copy link
Contributor

wsw70 commented Dec 16, 2020

Is there any interest in letting pyscript do this for us, perhaps even on an "as requested" basis?

I believe very much there is.

I will work around that in the HA frontend by setting an extra state that I set or unset in the UI (in a specific card), and test in my automation its state before going forward. Having that built-in would be awesome.

@wsw70
Copy link
Contributor

wsw70 commented Dec 16, 2020

This feature discussion brought to you by me playing "flashlight tag" in the dark with my kids the other day

For my curiosity (my kids are teens so I am not sure this is still relevant for me :)) - what is a flashlight tag game?

@dlashua
Copy link
Contributor Author

dlashua commented Dec 16, 2020

@wsw70 teens seem to enjoy it too. very young kids will need a buddy. basically.... turn off ALL the lights. Then play "hide and go seek" (except the hiding is different since you can hide in plain sight since it's dark). The "seeker" gets the only flashlight. If you get lit up by the flashlight, you're out.

@wsw70
Copy link
Contributor

wsw70 commented Dec 16, 2020

@dlashua oh that's great! I will actually use it as a game for my kids and their friends (probably somewhere outside) after we are free from COVID (in France we have a curfew starting at 20:00 and nobody meets noone anyway). Thanks for the idea!

@wsw70
Copy link
Contributor

wsw70 commented Dec 16, 2020

Is there a place where the current, loaded automations (functions) from pyscript are registered? A place that could be queried from within pyscript?

I just found the list of the files the automations are ran from (pyscript.list_global_ctx())

@dlashua
Copy link
Contributor Author

dlashua commented Dec 16, 2020

It depends on exactly what pieces you're looking for. These bits aren't designed for user interaction (i.e. you can break things if you mess around with it) but... you can get a list of all the names of all registered triggers, for instance, like this:

import custom_components.pyscript.global_ctx as global_ctx

@time_trigger('startup')
def test_startup():
    for gctx_name in global_ctx.GlobalContextMgr.contexts:
        gctx_obj = global_ctx.GlobalContextMgr.contexts[gctx_name]
        for one_trigger in gctx_obj.triggers:
            trig_obj = one_trigger.trigger
            if trig_obj is not None:
                log.info(trig_obj.name)

@wsw70
Copy link
Contributor

wsw70 commented Dec 20, 2020

I will work around that in the HA frontend by setting an extra state that I set or unset in the UI (in a specific card),

This ended up being more difficult than expected (for now :)). While I can manage states for automations (mostly thanks to @dlashua code) and display them nicely with https://github.com/thomasloven/lovelace-auto-entities in a dynamic way, this is just a display of their status.

image

Adding a switch at the place where on is apparently requires https://www.home-assistant.io/integrations/switch.template/, which in turn probably means that the templates need to be hardcoded in a file (which is directly in conflict with the dynamic nature).

I will think about that a bit more.

@raman325
Copy link
Contributor

Instead of creating a switch, I would suggest we create something similar to either

This will give us the flexibility to define services that make sense for pyscript and we can add states and attributes that can provide extra information, such as what is requested in #130

@dlashua
Copy link
Contributor Author

dlashua commented Dec 31, 2020

@raman325 not a bad idea at all. Thanks!

@raman325
Copy link
Contributor

I'd be happy to take a crack at this unless you already have thoughts on how to do it. I stumbled on this because of a recent need for such an entity 🙂

@dlashua
Copy link
Contributor Author

dlashua commented Jan 1, 2021

@raman325 Take a look at PR #129 because it's part of the way there. Then, add comments/codes to that?

@raman325
Copy link
Contributor

raman325 commented Jan 2, 2021

#129 is for user defined entities whereas I understand this to be about providing entities automatically for each pyscript service/automation. If you agree, then where do you see the intersection? I imagine that implement this feature, we'd have to create entities while loading contexts from files.

@dlashua
Copy link
Contributor Author

dlashua commented Jan 2, 2021

This is about handling them somewhat automatically, though there would still be a decorator to request the behavior, I imagine.

However, they both require the entity platforms to be handled on the Home Assistant side. So, while they are not the same thing, the code behind them is similar and related.

@raman325
Copy link
Contributor

raman325 commented Jan 2, 2021

The way I envisioned this, there would be an entity for every automation, service, or app that pyscript is aware of (I see this use case as very similar to the automation and script platforms). I don't see the harm in providing this by default, so no decorator would be required. Is there a problem you are trying to solve in using a decorator that I am missing?

The work you are doing in #129 is related in that in both cases, we are trying to create entities, but the difference is that you are using existing platforms in that PR (switches, sensors, etc.), whereas here we'd be defining our own EntityComponent. I don't think the code will end up being all that related, but happy to be proven wrong. Perhaps since you have made progress on #129 already, we should wait to see what comes out of that and then we can decide how to address this one.

@dlashua
Copy link
Contributor Author

dlashua commented Jan 2, 2021

I don't have a problem with having every Pyscript Trigger create an "automation" automatically by default. Using the decorator allowed it to have more features. For example, with Native Home Assistant Automations, many people have 2 automations for a motion activated light: one to turn it on when there is motion, and another to turn it off when the motion stops. Yes, this can be done in one automation and that is true in Pyscript as well, but the point is, there are two "automations" that are working toward the same goal. The advantage to using the decorator is that if I use the same "id" on the decorator for both triggers, then the two triggers/automations can be linked together and controlled with the same Toggle. So, if I want to turn off the motion activated lights in my living room, I only hav to turn off ONE thing... instead of two.

So that's an advantage. But, as you mentioned, the disadvantage is now the user has to ask for the functionality instead of it being automatiic. I'm sure there's a way to do both.

However, more to the point, I tried, just now, to create a proof of concept for this, but it seems Home Assistant doesn't allow the "Automation" platform to be extended the way "Switch" can be. It seems this is also true for "Script". So, if we make it a "Switch", I can still show this proof of concept. But, If we want it to be an Automation (which, I agree, is better) then it is indeed different than #129 and you should take a crack at it. I'd like to see how that's done.

@wsw70
Copy link
Contributor

wsw70 commented Jan 2, 2021

But, as you mentioned, the disadvantage is now the user has to ask for the functionality instead of it being automatic. I'm sure there's a way to do both.

As a side comment: pyscript means code anyway. It is not like the HA automations which you build through a click-next procedure.

So having a tighter control over what is exposed is in my opinion a plus. This is only one extra line that works fine with the stack of @decorators one will have anyway.

@raman325
Copy link
Contributor

raman325 commented Jan 2, 2021

Two things:

  1. I would not recommend we extend the automation platform even if we could, because among other things, that will be confusing, and pyscript has different functionality than the automation platform does. Instead, we should create and use the pyscript platform and define entities that represent the various pyscript automations, services, and apps there.
  2. Your use case of having two automations that are more or less tied together is a good one. Instead of solving this with decorators, I would propose that we solve this by creating entities at the file/app level and entities at the individual service/automation level. So, in my case, I have a file called climate.py which holds automations related to the climate in my system (let's call them auto1 and auto2). We could essentially create three entities, one called pyscript.climate, and the other two called pyscript.climate.auto1 and pyscript.climate.auto2 (I have to check whether we can namespace this way or if we have to use underscores). This would allow users to turn on and off auto1 and auto2 individually, but they can also turn off the whole file (we can take a similar approach for apps). The file/app becomes the common ID and we no longer need a decorator.

@dlashua
Copy link
Contributor Author

dlashua commented Jan 3, 2021

We already create and use the pyscript platform. Unfortunately, I don't believe it's possible for a custom_component to indicate UI display for entities. So, I don't think we can get a toggle switch to show up on a pyscript.whatever entity. If this isn't true, I'd love to see any documentation you can link to to show how it's done. But, even then, I don't think it's possible to display a different UI for different entities in the same domain, and since pyscript is already being used for persistent storage needs and simple sensor needs, I'm not sure we should create a large breaking change by turning that over to automation switches.

Some "automations" are used more than once. Like this:

rt = []
def light_on_30_secs(light_entity):
  @state_trigger('{light_entity} == "on"')
  def turn_off():
    task.sleep(30)
    light.turn_off(entity_id=light_entity)

  rt.append(turn_off)

light_on_30_seconds('light.living')
light_on_30_seconds('light.kitchen')

In the above case, turning off the "filename.light_on_30_secs.turn_off` automation would turn off both the living and the kitchen, when that may not be what the user wants.

On top of that, with switches at the file, and function level, we have to deal with things like... what happens if I turn off the file level automation, but then turn on a function automation in that file.

And, though it doesn't effect this since we can just underscores, but, no, Home Assistant entity_ids can only have one "." between the domain and entity. No other "." are allowed.

I like the idea of being able to turn off an entire file/app. And we already have this with the "commented out filename" feature craig added, so the means to do so is already there. But I still think manually selected automation names that can be attached to more than one trigger function will provide the most flexibility and the least amount of "well, that's not what I expected to happen".

@raman325
Copy link
Contributor

raman325 commented Jan 3, 2021

What entities already exist in the pyscript domain? I haven't seen them personally.

Assuming ^ is true I don't see any breaking change here. Existing services can still exist within the pyscript domain but we'd introduce new services for the entities that represent the function and its action (turn on, turn off, run, etc). Your example can be resolved by providing two entities, one for each entity ID which we should be able to detect within pyscript

@dlashua
Copy link
Contributor Author

dlashua commented Jan 3, 2021

The entities that exist are user created. We have state.persist for persisting the data across a restart.

Adding services isn't the problem. The problem is, (and I'd love to be wrong about this), is that making an entity called pyscript.my_automation and making a service called pyscript.turn_on that takes an entity_id of pyscript.my_automation doesn't give that entity a Toggle Switch in the UI. To my knowledge, there is no way to give an entity of pyscript.my_automation a Toggle Switch in the UI without a custom card. Installing a companion card to go along with pyscript isn't a big deal except, that card would have to be indicated manually every time it needs to be used. It wouldn't show up in "more info" or in "dev tools" or on the default dashboard if you've not customized lovelace in anyway.

I understand what you're saying. And I agree, if it is possible to do it that way, that would be better. I just don't think that it's possible (without modifications to Home Assistant Core). So, if possible, send a PR or link to another custom_component that shows a toggle UI on a custom domain entity.

@raman325
Copy link
Contributor

raman325 commented Jan 3, 2021

you are right - I consulted with the FE experts in #devs_frontend and from a UI perspective we'd want to use existing domains. So I retract my previous statement about not using existing domains. Maybe we should try using automation for automations/files/apps, and script for services. I have to dig in further to these entity types to see if they make sense for our use cases.

@dlashua
Copy link
Contributor Author

dlashua commented Jan 3, 2021

Please do. From what I can see, those platforms cannot be extended by custom components. But, it might just be that it needs to be done in a different way that I'm not familiar with.

@raman325
Copy link
Contributor

raman325 commented Jan 6, 2021

Alright so I've made progress on this. Thus far I have created automation entities for automations/files/apps - I don't know that we need entities for services unless we have a way of tracking when an automation/service is running which I haven't tackled yet. I need to do a little more work to make sure the turning on and off actions of the files vs automations work logically with each other.

master...raman325:automation_entities

This is all pretty messy, it would be easier if it was easier to track the internals of each automation/file as it gets parsed in to pyscript. But it's progress!

@dlashua
Copy link
Contributor Author

dlashua commented Jan 6, 2021

So THAT'S how you make Entities in the automation Domain. Very interesting.

@cazador481
Copy link

A slightly different take would be to use MQTT autodiscovery to create a switch for the automation.

@dlashua
Copy link
Contributor Author

dlashua commented Jan 29, 2021

@cazador481 this would work. However, it would also add the requirement that the user run MQTT, add a bit of delay to the process, and be, in general, more complex. Since we have access to native Home Assistant entities inside a custom_component, we may as well use them. This is a nice work around for apps like AppDaemon and NodeRed, though, since they are not embedded in Home Assistant like Pyscript is.

@dlashua dlashua closed this as completed Feb 10, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants