Pyscript vs AppDaemon vs YAML

So really interested in the collective view on the above ways of creating automations. Here is my progression -

  • I started with YAML, as I am sure most do. Its simple, but verbose to do even quite simple things.
  • I moved to node-red to create my more complex automations, especially interfacing with Google via nora, but I guess visual programming just isn’t my thing!
  • Looking for a more traditional programming environment I came across AppDaemon and pyscript. AppDaemon looked more complex to setup, so I am currently trying out pyscript. In the space of a few days I have moved many of my automations to it (even the most complex ones).

Obviously YAML is supported by core HA, and both node-red and pyscript are custom components. AppDaemon I think is classified as an add-on.

Here is an example pyscript automation to turn on/off an extractor fan based on CO and humidity levels, which is quite complex in YAML!

# Utility room extractor fan
@state_trigger("sensor.utility_room_multisensor_humidity_air")
@state_trigger("binary_sensor.utility_room_sensor_co_co_alarm")
@time_trigger("once(08:00)","once(22:00)")
def extractor_fan():
	if (binary_sensor.utility_room_sensor_co_co_alarm == 'on'):
		if (switch.utility_room_extractor_fan_switch_1 == "off"):
			switch.turn_on(entity_id="switch.utility_room_extractor_fan_switch_1")
	else:
		if (float(sensor.utility_room_multisensor_humidity_air)
			> float(sensor.hall_multisensor_humidity_air) + 10.0
			and is_time_between(time(8,0), time(22,0))):
			if (switch.utility_room_extractor_fan_switch_1 == "off"):
				switch.turn_on(entity_id="switch.utility_room_extractor_fan_switch_1")
		else:
			if (switch.utility_room_extractor_fan_switch_1 == "on"):
				switch.turn_off(entity_id="switch.utility_room_extractor_fan_switch_1")

Followed by a YAML version to do the same thing:

- id: '1666726828122'
  alias: Extractor fan
  description: ''
  trigger:
  - platform: state
    entity_id: sensor.utility_room_multisensor_humidity_air
  - platform: state
    entity_id:
    - binary_sensor.utility_room_sensor_co_co_alarm
  - platform: time
    at: '22:00:00'
  - platform: time
    at: 08:00:00
  condition: []
  action:
  - if:
    - condition: or
      conditions:
      - condition: state
        entity_id: binary_sensor.utility_room_sensor_co_co_alarm
        state: 'on'
      - condition: and
        conditions:
        - condition: numeric_state
          entity_id: sensor.utility_room_multisensor_humidity_air
          above: sensor.hall_multisensor_humidity_air
          value_template: '{{ float(state.state,0) - 10 }}'
        - condition: time
          after: 08:00:00
          before: '22:00:00'
    - condition: state
      entity_id: switch.utility_room_extractor_fan_switch_1
      state: 'off'
    then:
    - service: switch.turn_on
      data: {}
      target:
        entity_id: switch.utility_room_extractor_fan_switch_1
    else:
    - if:
      - condition: state
        entity_id: switch.utility_room_extractor_fan_switch_1
        state: 'on'
      then:
      - service: switch.turn_off
        data: {}
        target:
          entity_id: switch.utility_room_extractor_fan_switch_1
  mode: single

So where I have ended up currently:

  • If it can be done with a blueprint (e.g. motion->light on) then it stays in YAML
  • If it interfaces to Google, I use nora, so node-red
  • Everything else in pyscript

It seems surprising that more people aren’t using pyscript (judging by forum posts), but perhaps they are using AppDaemon already and I just haven’t got there yet :slight_smile:

4 Likes

Node RED and AppDaemon are both totally separate software that is capable of interfacing with HA. There is an addon available for both of them which pre-configures them to talk to HA. But they are developed and updated independently.

There is also a custom component available which this npm package can interface with to enhance its features. But its not required, it just expands the feature set of that NPM package to allow it to create entities and register webhooks in HA instead of only listening for events.

It seems like your main complaint with YAML is verbosity. Given that I would suggest starting with more of an apples to apples comparison. Your automation can be made a lot more concise with templates. Which seems fine to do if you’re going to compare it with python code as templates are basically just code as well:

- id: '1666726828122'
  alias: Extractor fan
  trigger:
  - platform: state
    entity_id:
      - sensor.utility_room_multisensor_humidity_air
      - binary_sensor.utility_room_sensor_co_co_alarm
  - platform: template
    value_template: "{{ now().hour in [22, 8] }}"
  action:
    choose:
      - conditions: >-
          {{ is_state('switch.utility_room_extractor_fan_switch_1', 'off') 
            and (is_state('binary_sensor.utility_room_sensor_co_co_alarm', 'on')
              or today_at('08:00') <= now() and now() <= today_at('22:00')
                and (states('sensor.utility_room_multisensor_humidity_air') | float(0) - 10)
                      > states('sensor.hall_multisensor_humidity_air') | float(0)
            ) }}
        sequence:
          service: switch.turn_on
          target: &extractor-fan-switch
            entity_id: switch.utility_room_extractor_fan_switch_1
      - conditions: "{{ is_state('switch.utility_room_extractor_fan_switch_1', 'on') }}"
        sequence:
          service: switch.turn_off
          target: *extractor-fan-switch

Personally I would probably break up that giant conditions template a bit using the and/or shorthand form shown in here. But since you want concise and comparing to code, one big template it is.

The YAML generated by the UI editor is extraordinarily verbose. Comparing that in this context isn’t really a good comparison. The UI editor puts the YAML in a file you aren’t supposed to edit by hand. It makes no attempt to reduce verbosity or increase readability of the YAML like a human would if they were writing it themselves.

No, the most popular alternative to HA is definitely node RED. I mean truth be told its tricky to get metrics on the popularity of pyscript since people just clone it to use it but I would agree with your assessment based on discourse of the forum as well as the HA discord. Also activity in the pyscript repo compared to activity in the AppDaemon addon repo and the NodeRED addon repo

For AppDaemon and Node RED since they are available as addons we also have better metrics. Everyone must pull the image for an addon to use it and github container registry shows us how many times an image it hosts has been pulled - AppDaemon and NodeRED. Note that those links are to the overview page for their packages, click into the package for each architecture and see pulls of the latest version. That’s a fairly accurate metric since almost everyone that uses those pulls the image for their architecture. It doesn’t account for users on a docker container install that pull the AppDaemon/NodeRED public image and then configure it like the addon themselves but its still reasonably accurate.

Also for NodeRED in particular Node-RED is pretty active and there’s often questions in other sections too where the user is actually using Node RED and just calling it an automation.

While there are lots of people who prefer something that more like code, my impression is that the majority would prefer to configure stuff in a UI. Whether that is NR or HA. It’s hard to put a metric on that but I think the Month of "What the heck?!" this year provides a pretty good picture of this. Most of the top voted items are about changes people want in the UI. Compared to Month of "What the heck?!" (2020) where there was significantly more YAML/backend things in the top voted items.

2 Likes

Kinda in the same boat here. I want my automations in actual code. I really dislike YAML and Jinja and visual programing ala Node Red is not my thing either. So I switched to pyscript a while ago.

Technically I’m happy with it. But there’s always this nagging feeling that being a custom component with no ‘official’ support from the HA team, there’s always the risk that the project may be abandonned by its sole (afaik) developer and stop working after a HA update.

Ideally I would like to completely separate automation logic from HA. Everything im my home is MQTT based, so an external automation engine could handle this on its own. I have to look into AppDaemon.

4 Likes

Thanks for the insight into which automation systems are in use - most helpful. At the moment I am using all of them with the exception of AppDaemon! They all have their strengths and weaknesses.

I guess my issue with YAML is not simply verbosity but also readability/maintainability. I do appreciate your rewrite of the example I gave, although it does remind me slightly of my days with sed and awk. I’ll be honest when I say I am glad they are behind me now :smile:

At the moment, the advantages of pyscript outweigh the risk of the project being abandoned, and who knows, maybe something like pyscript will be adopted into HA core in the future.

I thought you hated python? Use netdaemon instead, you can basically get the same functionality. The support looks constant and the devs seem really nice.

I’ve used appdeamon and I left for a number of reasons:

  1. The automation engine ends up being more verbose than yaml or a custom integration. I took 8-10 200+ line appdaemon apps and turned them into HA scripts & custom integrations and ultimately reduced my overhead. Keep in mind that you have to use jinja, automation variables, and yaml anchors in order to achieve this with parallel automations & scripts. My custom integrations had the same or less yaml configuration, but half the code because you can directly create entities instead of using work arounds like firing events or MQTT discovery.
  2. You can’t create entities (this might have changed)
  3. You still need to use yaml as a configuration and it’s not any less verbose than using variables in a HA yaml automation.
  4. You can’t debug without creating log files. (this might have changed). With HA automations, you have traces and your variables are listed at each step. Very easy to debug without needing to log everything. In python, in order to attach to a process, the debug library needs to be loaded into the language. I don’t believe that’s done, so you can’t attach to the process at all.

There’s only one benefit that I see over the built in automation engine at this point, and that’s dynamically creating a listener to perform a set of actions that can be canceled. You can’t cancel parallel instances of scripts in HA’s automation engine without some magic and it ends up being extremely verbose. HA’s automation engine could get past this if it allowed you to create scripts on the fly (Like you can with scenes). If you use a custom integration, you can get past that. The HA API is better than appdaemon IMO and you can make a reload function that’s built directly into the UI’s yaml page.

Just looking at netdaemon, it seems like it has the same problems I just listed aside from debugging bullet. Except it allows invalid yaml… not sure if that’s a typo in the documentation or what.

I’ve only read about pyscript, but it does look more appealing than appdaemon.

EDIT: In regards to OPs comments on readability, appdeamon is not any better than HA’s yaml automation. I’d argue that its less readable as you now need to understand callbacks and to some extent, threading. Pyscript looks far superior in this category.

1 Like

I have to say that I was surprised by pyscript’s simplicity. I run HA Core, and all it took was to install the custom component, restart HA and then save my first test.py file in the pyscript folder. The automations were automatically reloaded and running.

Within in a few hours I was able to recreate a pretty complex automation for my central heating, that was previously in node-red, and would have been huge if I tried it in YAML. It ended up being concise, and easily maintained. There’s a lot to like, but one weakness I have found so far - no easy option to trigger if something has been in a state for a period of time. I believe that it is on the to-do list.

You can probably get around that by creating a HA automation that fires an event for the time being.

alias: fire event for xyz
trigger:
- platform: state
  entity_id: sensor.xyz
  to: some state
  for:
    minutes: 5
action:
- event: minute_event
  event_data:
    entity: "{{ trigger.entity_id }}"
    state: "{{ trigger.to_state.state }}"

Then make a pyscript that works off that event. There’s about 1000 different ways to get around that, depends on what you’re looking to achieve.

1 Like

Thanks, that’s a great idea.

Unfortunately there aren’t any real alternatives to using Python in the HA ecosystem, so I have to put up with it if I want to get anything done on my side.

NetDaemon, while very inteteresting, is far from being production ready. V3 has been in permanent beta for as long as I have known it, the docs even warn from possible breaking changes (very prominently).

For anyone reading this post and concerned about this point - turns out that I just needed to read the pyscript manual a little more. There is a simple solution with the state_hold parameter of a trigger funtion:

# Turn garage lights off after 20 minutes
@state_trigger("light.garage == 'on'", state_hold=1200)
def garage_lights_timer_off():
    light.turn_off(entity_id="light.garage")

Couldn’t be easier!

Thank you all, I’ve learned a lot from this thread so far.

Does HassPY fit into this discussion?

I just noticed the logo on the slide for the State of the Open Home. I haven’t found much about it yet, but I’m guessing we may hear today that it is becoming a Nabu Casa project.

If this is the correct project looks like it might be a PyScript competitor?

HassPY doesn’t look like much has happened in the last 2 years, and the logo that you mention is for Rhasspy, the voice assistant, which is more of a Google,Alexa competitor. I’ll be interested to see what they have to say about that this afternoon, but a different topic entirely.

Clearly I needed more coffee before posting this morning, but that stylized R in the that logo is pretty easy to miss.

1 Like

I’m in the same boat as adwuk. Totally impressed with the simplicity and power of pyscript. Combined with jupyter complex code has never been easier to develop for HA.

However. I find pyscript somewhat limited in terms of functionality and repeatability which is super annoying. I have a few functions that just does not want to work consistently with pyscript. They sometimes work and other times throw errors even though the code never changed.
I know pyscript is not pure python but it’s really tricky to find out what works and what doesn’t when the results aren’t consistent. Not sure if this is partially a jupyter issue but I can’t really tell from my testing either. In my experience the differences between pyscript and python seems a lot bigger than the documentation states but I might be misunderstanding something.

I’m interested to hear what sort of things lead to instability. My pyscript automations have been solid as a rock. I only use Jupyter to test them, and then they are transferred to a .py file in the pyscript directory. Admittedly, I’m not using any major external libraries yet.

Since my last post I have discovered the @pyscript_compile possibility which actually solved most of my problems. I also understand the “memory” of the jupyter scope better which also caused me some issues befoe. E.g. “old” data remaining in dicts or other variables would sometimes mess up my results of not declared/refreshed properly before using them.

All in all I’m extremely happy with pyscript at this point. So much quicker and easier to write a script than messing with helper variables, horrible templates and strange naming conventions in automations.

1 Like