[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$f19tc3knwu1jsk":3},{"_id":4,"slug":5,"title":6,"subtitle":7,"kind":8,"cards":9,"tags":58,"categories":60,"source":62,"lang":65,"author":66,"audioState":69,"stats":70,"publishedAt":73,"renderer":74},"6abb988bca21c797c7e9d1e9","splitting-a-2000-line-automationsyaml-into-8-files-b5d5ad9d","Splitting a 2,000-Line automations.yaml into 8 Files","My automations.yaml had quietly grown into a 60 KB monster.","news",[10,13,18,23,28,33,38,43,48,53],{"headline":6,"body":11,"imageUrl":12,"sourceImageUrl":12},"My automations.yaml had quietly grown into a 60 KB monster. 2,144 lines. 63 automations stacked end to end in a single file, averaging about 34 lines each. Scrolling it was a chore, editing it made me nervous, and finding one particular heating automation meant a full-text search. The file worked, so there was never any pressure to touch it, and there was a good reason not to: when you refactor a live config you can silently drop the automation that keeps the heating from freezing or the alarm from missing a sensor.","https:\u002F\u002Fmedia2.dev.to\u002Fdynamic\u002Fimage\u002Fwidth=1200,height=627,fit=cover,gravity=auto,format=auto\u002Fhttps%3A%2F%2Fcdn.smartcms.ai%2Fcms-cloudapp-dev%2Fcover-splitting-home-assistant-automations-yaml.jpg",{"headline":14,"body":15,"imageUrl":16,"images":17},"So this is a small story about a","So this is a small story about a refactor I almost didn't do, and the one thing that made me trust it: I wrote a 40-line script to split the file, and then I wrote a second, longer script whose only job was to prove the first one hadn't lost anything. Why one file stops scaling","\u002Fapi\u002Fmedia\u002Fposts\u002Fsplitting-a-2000-line-automationsyaml-into-8-files-b5d5ad9d\u002F1.webp",{"local":16},{"headline":19,"body":20,"imageUrl":21,"images":22},"Home Assistant wires automations in through one line","Home Assistant wires automations in through one line in configuration.yaml: automation: !include automations.yaml. That single include is convenient while the file is small. With 63 automations in there, a few groups had formed without my planning them. Heating was by far the biggest concern — 21 automations, a third of the whole file, driving 11 thermostats with day and night modes and room-by-room overrides. Alarm was the next slab at 13. Then a cluster around the AC·THOR power diverter, a handful of camera and detection rules, time-based switching, system housekeeping, and a long tail of one-offs.","\u002Fapi\u002Fmedia\u002Fposts\u002Fsplitting-a-2000-line-automationsyaml-into-8-files-b5d5ad9d\u002F2.webp",{"local":21},{"headline":24,"body":25,"imageUrl":26,"images":27},"None of that structure was visible. It was","None of that structure was visible. It was just 2,144 lines in the order I'd happened to add each one. I wanted the heating rules in a heating file and the ability to open exactly the slice I was working on. A 40-line splitter that classifies by name","\u002Fapi\u002Fmedia\u002Fposts\u002Fsplitting-a-2000-line-automationsyaml-into-8-files-b5d5ad9d\u002F3.webp",{"local":26},{"headline":29,"body":30,"imageUrl":31,"images":32},"The splitter is deliberately boring. It's about 40","The splitter is deliberately boring. It's about 40 lines of pure standard-library Python — just yaml, os, and a defaultdict. It loads the YAML list, walks each automation, decides which bucket it belongs to, and dumps one file per bucket into an automations\u002F directory.","\u002Fapi\u002Fmedia\u002Fposts\u002Fsplitting-a-2000-line-automationsyaml-into-8-files-b5d5ad9d\u002F4.webp",{"local":31},{"headline":34,"body":35,"imageUrl":36,"images":37},"Here's the honest quirk: the classification isn't driven","Here's the honest quirk: the classification isn't driven by any tag or metadata field, because there isn't one. It's substring matching on the automation's German alias. If the alias contains \"Heizung\" it's heating; \"Alarm\" goes to alarm; \"AC Thor\" (in any of its hyphenated spellings) to ac_thor; camera and detection words to cameras; push and notification words to notifications; the time-control vocabulary to time_control; sync and reachability words to system; and everything the rules don't catch falls through to a misc bucket. So the classification depends entirely on how consistently I named things.","\u002Fapi\u002Fmedia\u002Fposts\u002Fsplitting-a-2000-line-automationsyaml-into-8-files-b5d5ad9d\u002F5.webp",{"local":36},{"headline":39,"body":40,"imageUrl":41,"images":42},"Two of the dump arguments are worth explaining","Two of the dump arguments are worth explaining. allow_unicode=True keeps the German umlauts intact instead of mangling them into escape sequences, so a name like \"Büro\" survives the round trip. And sort_keys=False preserves the original key order inside each automation — the trigger, condition and action stay in the order I wrote them, instead of getting alphabetised into nonsense. Eight buckets the data chose for itself","\u002Fapi\u002Fmedia\u002Fposts\u002Fsplitting-a-2000-line-automationsyaml-into-8-files-b5d5ad9d\u002F6.webp",{"local":41},{"headline":44,"body":45,"imageUrl":46,"images":47},"I didn't pick eight up front; I had","I didn't pick eight up front; I had half expected to hand-carve a dozen or so files. The committed splitter emits eight category files: heating, alarm, ac_thor, cameras, notifications, time_control, system, and misc. The distribution is lopsided: heating is 21 automations (33%), alarm is 13 (21%), AC·THOR is 5 (8%), and then it thins fast into pairs and singletons. By estimated size the heating file lands around 700 lines on its own, alarm around 440, cameras around 270, ac_thor around 170.","\u002Fapi\u002Fmedia\u002Fposts\u002Fsplitting-a-2000-line-automationsyaml-into-8-files-b5d5ad9d\u002F7.webp",{"local":46},{"headline":49,"body":50,"imageUrl":51,"images":52},"A 700-line heating file controlling 11 thermostats with","A 700-line heating file controlling 11 thermostats with near-identical day\u002Fnight\u002Fpresence logic is an obvious candidate for templating into a handful of parameterised scripts, and with it isolated I can see what that would look like. The AC·THOR file, by contrast, came out clean and self-contained: temperature monitoring, power management, and a bit of system detection, all in one place.","\u002Fapi\u002Fmedia\u002Fposts\u002Fsplitting-a-2000-line-automationsyaml-into-8-files-b5d5ad9d\u002F8.webp",{"local":51},{"headline":54,"body":55,"imageUrl":56,"images":57},"Before I changed a single line of configuration.yaml","Before I changed a single line of configuration.yaml, I wrote a second script — about 160 lines — whose entire purpose is to re-read the original file and every split file and assert the round trip is lossless. It runs five checks. One: the total automation count matches. Two: the set of unique aliases matches, with no automation missing and none invented. Three: any duplicate aliases are identical between original and split. Four: every automation id value matches as a set. Five: a per-alias deep dictionary comparison to catch silent content drift.","\u002Fapi\u002Fmedia\u002Fposts\u002Fsplitting-a-2000-line-automationsyaml-into-8-files-b5d5ad9d\u002F9.webp",{"local":56},[59],"dev",[61],"Technology",{"name":63,"url":64},"Dev.to","https:\u002F\u002Fdev.to\u002Fcloudapp_dev\u002Fsplitting-a-2000-line-automationsyaml-into-8-files-24cn","en",{"handle":67,"displayName":68},"spots","Spots","queued",{"views":71,"likes":72,"saves":72,"shares":72,"completions":72,"opens":72,"skips":72,"depthSum":72},3,0,"2026-09-29T10:52:59.175Z","local"]