In the documentation and in manually coded automations, I’d do something like this
- alias: 'Leave Home notification'
trigger:
- platform: zone
event: leave
zone: zone.home
entity_id: device_tracker.paulus
condition:
- condition: time
after: '20:00'
action:
- service: notify.notify
data:
message: 'Paulus left the house'
Using the UI editor to add a new automation/ script or editing an existing one, the keys would be resorted and everything becomes much more difficult to read - after all the action is not data but a service.
- alias: 'Leave Home notification'
trigger:
- entity_id: device_tracker.paulus
event: leave
platform: zone
zone: zone.home
condition:
- after: '20:00'
condition: time
action:
- data:
message: 'Paulus left the house'
service: notify.notify
Additionally, when using version control, the diffs become cluttered with resorting changes.
It’s probably impossible to get every key sorted right, but already keeping trigger, condition, and service first in the respective sections would be a big win in my mind
AFAIK they are storing this yaml in json. Since json is unordered collection it’s impossible to achieve what you ask for without splitting it to separate blocks and store as json array… which unlikely will happen.
Also this is the reason why comments are also not persisted.
BTW this is one of worst decisions made by devs recently IMO (transconverting between yaml and json)
Haven’t looked at the underlying storage but even if it’s processed as JSON, I guess the keys could be sorted using a custom order prior to saving as YAML?
I personally don’t care so much about the original order, I’m fine with the keys being resorted, as long as it is in a reasonable order.
This could be something like main key (e.g., trigger for trigger section, condition for condition section, and service for action section) or main keys (it could be several - my list may not be exhaustive) first, and then the rest in alphabetical order
Automation Editor stores automations in automations.yaml in YAML.
If it’s being converted to JSON for processing, it’s peculiarly selective about how it converts the JSON back to YAML: it doesn’t sort the trigger, condition, and action keys, only the keys they contain.
Interestingly, every online YAML to JSON converter (and the opposite direction) can perform the task without sorting the keys.
Maybe I’m wrong.
My answer is based on how it does work in case of lovelace (in GUI mode). Because OP describes very similar behaviour I thought it might be the same root cause.
Anything core brings in from the configs is parsed with pyYAML, which produces an OrderedDict upon parse (or an empty OrderedDict if the config file is empty). This applies to automations.yaml, configuration.yaml, secrets.yaml, scenes.yaml, and scripts.yaml (should they exist).
When writing the files back to the file system, the OrderedDict that was created during parsing is transformed back to YAML and then written out. That’s why automations get written in an ordered fashion.
AFAIK, none of these base configuration files gets parsed to JSON at all. I do remember that there was talk about moving over to JSON eventually, but I haven’t seen much movement towards that in the source files.
Similar to what? The OP is discussing the UI-based Automation Editor which stores everything it reads in sorted YAML format. So if you use it to open an unsorted YAML automation, it will save it as sorted YAML (and discard comments).
This is destructive behavior and means the Automation Editor should never be used to modify automations that were created in a text editor. However, by default,others is no safeguard in place to prevent it. Many people, including me, discover it empirically (try the Automation Editor then discover it has mangled all the automations created with a text editor).
The simplest way to prevent it is to separate the automations created via text editor from those created via the Automation Editor. The documentation describes how to do it and it involves creating a directory to hold one’s ‘manually created’ automations. Then you add an option to the config file to indicate where the ‘manual automations’ are located.
However, this only prevents damage to ‘manual automations’ and doesn’t address the issue of Automation Editor producing sorted YAML.
I’d like to learn more about this OrderedDict behaves because, as I mentioned previously, it’s rather specific about how what it does and does not ‘order’. Here’s a simple automation I just created using the Automation Editor (0.114.1):
- id: '1598274610865'
alias: Turn on the lights when the sun is set
description: ''
trigger:
- event: sunset
platform: sun
condition: []
action:
- device_id: cb08dbe923044ce59f4f90e013ff98b7
domain: light
entity_id: light.family_ceiling
type: turn_on
mode: single
The first-level keys are not ordered, only the second-level keys. If everything was sorted, it would look like this “dog’s breakfast”:
- action:
device_id: cb08dbe923044ce59f4f90e013ff98b7
domain: light
entity_id: light.family_ceiling
type: turn_on
alias: Turn on the lights when the sun is set
condition: []
description: ''
id: '1598274610865'
mode: single
trigger:
- event: sunset
platform: sun
This implies there is some selective mechanism available for sorting.
EDIT
OrderedDict
Return an instance of a dict subclass, supporting the usual dict methods. An OrderedDict is a dict that remembers the order that keys were first inserted. If a new entry overwrites an existing entry, the original insertion position is left unchanged. Deleting an entry and reinserting it will move it to the end.
Maybe I’m guilty of confirmation bias but that description suggests to me that OrderedDict isn’t responsible for sorting the keys.
You’re absolutely right. I haven’t directly used OrderedDict in a long time (I much prefer OmegaConf for all my dict management )
In researching a bit more, I’m wondering if they are sorting deeper in the code base as that would support your examples.
I’m pretty sure that there’s something more going on when the automation editor writes the file back based upon what you demonstrated. My thought is that they are parsing the config file upon load and then looping over it using something like for key, value in [dict] and using that same loop with an added .sort() for the child objects. So, the top level keys don’t get reordered, but the child items do.
I’ll dig deeper into the code base and see if I can find anything.
For reading/writing automations (with the Automation Editor).
If an automations.yaml file contains comments, writing to it with Automation Editor purges all the comments. Understandable, because JSON doesn’t support comments, but destructive behavior nonetheless.