About 113 kWh (155w) for me. I have 2 Intel NUC type devices, with two drive enclosures. Plus my networking equipment which include POE cameras.
First thought is VPN port issue. I recall changing from Mullvad to ProtonVPN because Mullvad wasn't' doing the port forwarding correctly... or so says the robot.
Gosh look at that skinny noodle.
I have and use pass for system secrets but for service where I'm logging in via the browser, I prefer KeePass.
I built myself a 'new masked email' workflow. I copy and paste the site url into the form and click create. It generates my random masked email, generates a strong password, prompts me for my keepass password then saves all the things and copies the generated password to the clipboard. Here are some screenshots. I did a test entry to demonstrate for you.
![Dark-themed web form titled "New masked email". The intro line reads "Mint a per-site alias at [redacted domain] and save a login to KeePass." Below it are a "Domain or URL" field with the placeholder "amazon.com · https://infosec.pub/", a "KeePass master password" field with the placeholder "used once, never stored" and the note "Used in memory to open the synced database, then discarded. Never written to disk or logs.", and a teal "Generate & save" button.](https://infosec.pub/pictrs/image/f97152b2-5fe3-4919-a381-847f464c91d8.png)
New form.
![The same form after a test run for google.com. A green check reads "Saved to KeePass · Logins / google.com (qvkk8729)". Below it are the generated email "google.qvkk8729@[redacted domain]" and a random 30-character password, each with a copy button, the URL "https://google.com/", and a "Mint another" link.](https://infosec.pub/pictrs/image/924cc668-a1db-4095-88d8-69452b456b89.png)
I type in my KeePass password and I get this screen while the entry is automatically saved to KeePass.
This all runs on an Intel NUC in my office and is accessible over my local network.
Uptime Kuma
Welp. My Forgejo instance got popped with an RCE two days ago by CVE-2026-60004. Luckily, I noticed the following morning and had the day free to figure out what happened. Let's dive in!
As a homelab enthusiast, I found this a very interesting post. Here are my take aways from the post that I'm implementing myself:
- Miner detection. I've updated monitoring rules to now watch the CPU on my hosts. If the same thing happened to me I would not have been alerted at all as I'm doing simple up / down monitoring. Fixed.
- Access logging. I turned on access logging for my homelab Caddy instances.
- Log retention. I have increased the amount and retention of my logging. The hope is this will help me reconstruct what happened after a breach.
- Logs offsite. The VPS access logs now ride along with the normal backup process, which runs hourly. The homelab side still only gets caught by the weekly VM backup, so that's next.
- Closed an open signup. My webtrees instance (genealogy) had self registration enabled, which is the same door this guy got hit through. Oops. Fixed.
- Built a tool.
log-inventory.sh, so "could I actually reconstruct what happened" is a command I run instead of a thing I assume.
It's a system76 Launch Heavy. It's expensive but it's the best keyboard I've ever owned.
Polly is helping out at work today. She usually likes to spend her day outside but it's supposed to be hot today!
I have one of the nabu casa voice devices. When I first got it, I experimented with it and I found it wasn't as nice as an Apple HomePod Mini. Which is fine but I was mostly irritated that I couldn't set my own wake word. It has like 3 you can choose from but I want a custom one. I want to be able to say 'hey robot' to wake it up.
But to your point, it acts just like the other voice assistant devices. The speaker isn't for music but it's fine. I'd probably want to plug it into some sort of powered speaker if I was using it full time. I need to come back to it and run try to use it.
Really all we do with our HomePods is set timers and to control basic things liek turning the lights off and on or closing/opening the curtains.
The moment I can say 'hey robot, set a timer for 5 minutes' or 'hey robot, open the curtains' is the moment i buy enough to replace all the Apple HomePods.
I feel the aquarium hobby is a retro hobby. Sure, the lights and filters have got much more expensive, and now rimless tanks are popular online, but the standard size tanks like the 40 breeder and the 75 gallon are the same footprint from decades past.
What can I automate? Can I improve monitoring and alerting? There are some off-the-shelf options like Neptune Systems Apex, but what could a person do with Home Assistant? That's what I'm trying to figure out.
Hardware
My home automation platform of choice is Home Assistant. This runs bare metal on a little mini PC NUC with the following specs:
- System76 Meerkat (Intel NUC10i3FNB board)
- Intel Core i3-10110U @ 2.10GHz, 4 threads
- 16 GB RAM
- 228 GB disk
- Home Assistant OS
- Zigbee: ZBT-2 and ZHA
- Z-Wave: ZWA-2 and Z-Wave JS
To enable all the automations I'm writing about here, each aquarium gets these smart devices. When relevant, I will call out the specific bit of aquarium gear I picked for how I need it to work with Home Assistant.
- Power Strip: Zooz Zen20 Power Strip. This has 5 regular plugs and 2 USB plugs, all of which can be individually controlled. This runs on my Z-Wave network. Each aquarium gets one.
- Temperature Sensor: Apollo TEMP-1 Temperature Sensor. This allows me to get the temperature into Home Assistant; it runs on ESPHome and connects via Wi-Fi. If aquariums are close enough together, a single sensor can have multiple probes.
- Water Leak Sensor: Zooz Water Leak Sensor. At least one goes into each plant saucer/catch tray that I use with my canister filters.
- Smart Button: Aqara Mini Switch. I can use these buttons at the tanks to trigger automations without having to fish out my phone. Single press, double press and long press are all available to do things like toggle the lights or activate maintenance mode.
- Automatic Feeder: Avast Labs Plank MINI. These feeders have no built-in schedules or batteries and that's what I like. When there's power to the unit, the corkscrew turns, dispensing food. To stop dispensing, turn off the power.
- Heater: Bulk Reef Supply Titanium Heater Element. These do not have built-in thermostats and plug directly into the Zen20. When the plug is powered on, it heats. To stop the heat, turn off the power. Easy peasy. The smallest these go are 100W and it's what I use in my 20 gallon long aquariums. In the 75 gallon display tank, I use two 200W heaters.
- Filters: Eheim Classic Canister Filter & Aquarium Co-Op Coarse Sponge Filter. I like having both a canister and sponge filter in my tanks. If my canister is clogged and I don't notice, the sponge can carry things until I do. In the event of a power outage, I can run the air pump for the sponge filters off a battery pack for a good long time. Finally, having a seeded sponge filter at all times is nice for quickly spinning up a new tank.
- Air Pump: Eheim Air. This pump has been the quietest in my experience.
- Lights: Hygger HG999. This is just a budget light but it's a good price and my plants seem happy. Works fine powering it off and on from the power plug.

Aquarium 2! This is my "shrimp tank", which I put white cloud mountain minnows with. I'm rehoming the shrimpies and the minnows into a hillstream tank which is cycling now! (Richmond, VA · August 2026)
Lighting
Probably one of the easiest and most forgiving things to automate is the lighting schedule. I use Hygger HG999 lights with my tanks and they're fine for the price. If I plug the light into a smart plug, then it's easy to set a simple schedule to turn the lights on and off. The HG999 does have its own little controller, but it restores its previous state on power restore. So I just turn it on for the first time, set the brightness I want, and control it with Home Assistant via the smart plug.
Helpers
- Lights On Time: Date and/or time. Time only. Example: 7:30 a.m.
- Lights Off Time: Date and/or time. Time only. Example: 4:30 p.m.
- Lights On: Template binary sensor. It converts Lights On Time/Lights Off Time into an on/off state that then drives the automations. Example: On
Automations
Each tank gets two automations for lighting.
- Lights On: When the Lights On template binary sensor turns On, this fires and turns the lights on.
- Lights Off: This is the off version! When the Lights On template binary sensor turns Off, this fires and turns the lights off.
Dashboard
The dashboard gives me exactly one control for the lighting.

I have controls on each tank dashboard to do a manual feed, to adjust when the feed happens, a feeder master switch and the feed seconds.
Improvements
I plan to add a WLED light strip to each tank. The Hygger lights have morning, evening and night modes, which basically set the colors at a dim level. It's really more aesthetic, but I would like to be able to replicate that with my setup because I think it's cool. Plus, it seems the sudden on of the main light startles the fish, so I'd like to ramp up in the morning and ramp down in the evenings.

Tina! (Richmond, VA · August 2026)
Feeding
Feeding the fish is one of my favorite things about fish keeping. So why then would I want to automate it? Well, mostly to see if I can. But secondarily, it means I don't have to feed the fish every day if I don't want. I let the autofeeders dispense the dry pellets and I will supplement with frozen treats when I'm in the mood. Plus, if I automate the feeding like this, then I don't need to recruit anyone to come feed the fish while I'm away.
I knew I wanted to use automatic feeders with my fish. In my research, most hobbyists seemed to dismiss the idea as pointless and maybe even dangerous. Most of the anecdotes I saw were people using cheap barrel feeders like the Eheim Autofeeder while they were away, coming back to dead fish because the feeder dumped too much food into the aquarium.
Naively undeterred, I started experimenting with what was actually possible. I did try the cheap barrel feeders and yeah, they're not great. The dispensing bit is clunky and not very precise, plus there's no way to have a fasting day schedule with the barrel feeders I tried (Eheim and Aquarium Co-Op). That's where Home Assistant and the Avast Labs Plank MINI come in. This is a dumb feeder. If I plug it up, it runs the motor that spins the auger to dispense food. I then power off the plug to stop it. Hell yeah.
It actually took me a long time to find this feeder because I didn't know what to type into the search bar. Avast makes a regular-sized Plank, which is expensive. The mini is also expensive compared to the battery powered barrel feeders but I just squint my eyes and hit the buy button. Buy once, cry once, I always say.
This automation could be dangerous for my fishy friends so I spent a fair amount of time thinking through the edge cases and how this could fail. Accidentally dumping the full canister of food into the tank because a run got stuck would be a critical incident. Let's try not to do that.
The other failure mode is less critical. That's the feeder not dispensing food when I think it is, so I've also built some automations and monitors to try to catch this failure.
Helpers
- Feeding Enabled: Toggle. This allows me to arm and disarm the automatic schedule, should I for some reason want to turn off the automatic feeder without having to go around disabling automations. Example: On
- Feed Time: Date and/or time. This is when the food drops. Example: 7:45 a.m.
- Feeder Seconds: Number. This is the number of seconds the motor should run. I ran a few test runs of the feeder to see how much it dispensed and I continue to tweak this as needed. Example: 35
- Feeder Active: Toggle. The automations and scripts set this helper during legitimate feeding paths. Example: Off
- Last Verified Feed: Date and/or time. I use this helper to work out whether a scheduled feed actually happened. Example: August 24, 2026 at 7:45 a.m.
Automations
- Feed: The Feed Time helper triggers this automation. When the time arrives, it toggles the Feeder Active helper on, powers the feeder on, and the auger starts to dispense food. It waits the number of seconds I set in Feeder Seconds, then it powers the feeder off and toggles the Feeder Active helper off.
- Cutoff: This automation monitors for every edge case that I could think of that would cause an outlet to be on when it shouldn't be, then turns off the feeder and sends out all the alerts to all the places. There are three triggers:
- Overrun: If the outlet has been on past the max feed window, then this trigger executes. The max feed window is a hard-coded value of 120 seconds.
- Unexpected on: This trigger fires if the outlet came on with no feed running. A ghost Z-Wave command, a hand tapping the strip, a stale state restore. This branch only works because the automation switches the Feeder Active toggle helper on during a real feeding session. So the condition boils down to this: the plug on the feeder is powered on and the Feeder Active toggle helper is off.
- Startup recovery: This trigger fires if the outlet was already on when Home Assistant booted, which probably means HA rebooted mid-feed.
- Feed Verify: This runs a few seconds into a feed and checks the outlet is actually drawing current. If it is, it stamps Last Verified Feed. A relay can report a perfectly clean feed into a dead outlet and this is the automation that catches it.
- Feed Watchdog: This runs 15 minutes after the feed was due and alerts me if nothing stamped Last Verified Feed today. This one is for a feed that never ran at all.
Dashboard

I have controls on each tank dashboard to do a manual feed, to adjust when the feed happens, a feeder master switch and the feed seconds.
Heaters
Aquarium heaters are notoriously unreliable. The general advice on them is that they're so unreliable that fish keepers should replace theirs proactively, every 2 or 3 years. The main thing is the cheaply made thermostats on the heaters can fail in the on position, cooking all the fish in the tank. Or the glass can break, causing an electrocution risk.
Sources:
- Aquarium Heater Failures: How to Protect Your Reef Tank from Disaster
- 14.8. Aquarium Heaters
- Heaters – The Ticking Timebomb in Every Tank
Hobbyists recommend using a separate controller, like an INKBIRD. Then I'd just turn the thermostat up on the aquarium heater and let the INKBIRD control the temp. The INKBIRD is higher quality, one presumes, so is less likely to catastrophically fail. Instead of an INKBIRD, I decided to use Home Assistant as my controller.
To run the heaters, I use the Zooz Zen20 Power Strip, Apollo TEMP-1 Temperature Sensor, and the Bulk Reef Supply Titanium Heater Element. I'm choosing the BRS heater because it does not have a built-in thermostat. I power on its plug to run the heater and I turn off its plug to turn off the heater.
I've seen people say to get a standard aquarium heater and to set the temp a few degrees above the target so the external controller can drive the heater, but if the controller fails in some way, then the built-in thermostat can be the backstop. I reject that because if I don't trust the thermostat enough to run the heater, why would I trust it to be the backstop?
This is the most dangerous automation. A heater stuck in the on position can kill the fish in hours, so I've really spent a lot of time and energy to ensure I've accounted for the failure modes and edge cases that could cause the automations to fail. So far so good.

A male pearl gourami in the 75 gallon tank downstairs. (Richmond, VA · August 2026)
Helpers
If I were building this today, I'd just use the Generic Thermostat integration but I built this before I knew about the integration. There's little value that I can see to migrate to the integration so I'm just going to keep using my hand rolled solution.
- Set Point: Number. This is the target temperature of the aquarium. Example: 78
- Hysteresis: Number. I didn't know what this meant before working on this project but hysteresis is the gap you deliberately leave between the point where something switches on and the point where it switches off, so it doesn't flap back and forth every time the measurement wobbles across a single number. If I set the hysteresis at 1, then at 77.5, the heater turns on. At 78.5 it turns off. Hysteresis is basically the band of the swing. Example: 1
- Call For Heat: Template binary sensor. It reads the temperature probe, then compares against the Set Point and half the Hysteresis, then returns true or false depending on the target temperature and the actual temperature. It also reads its own current state, which is what creates the band: once it's on it stays on until the top of the band, and once it's off it stays off until the bottom. If the sensor is not returning a value, say the probe got unplugged, then it falls back to false so a heater can't get stuck on.
- Maintenance Mode: Toggle. Every tank gets a helper that allows me to put the tank into maintenance mode. This stops the filters and disables the heater so it's not running during a water change. It also holds off the temperature alerts, the sensor offline alert and the filter watchdog, because none of those are news while I've got my hands in the tank. Example: Off
- Temp Offset Alert: Number. This is the maximum amount of temperature swing, compared to Set Point, allowed before the system starts alerting. Example: 3
Automations
I use several classes of automations to run the heaters and verify everything is working correctly.
- Heater On: There are three triggers for this automation. When Call For Heat flips to true, when Home Assistant restarts, and when Maintenance Mode turns off. This automation is gated on Call For Heat, so when Home Assistant restarts, if Call For Heat is off then nothing happens. It's also gated on Maintenance Mode. If it's on, then do nothing because I'm doing a dang water change.
- Heater Off: There are also three triggers for this automation. When Call For Heat flips to false, when Maintenance Mode turns on and when Home Assistant restarts. Both Heater On and Heater Off fire on a reboot, so this one also carries the appropriate conditions to let the correct mode win.
- Low Temperature Alert: This triggers when a tank has drifted below setpoint by more than the alert offset.
- High Temperature Alert: This triggers when a tank has drifted above setpoint by more than the alert offset.
- Heater Stuck On: This triggers if the relay reads off while the heater outlet is still drawing over 20W. This is a critical automation and I've experienced this exact condition.
- Temperature Sensor Offline: This triggers if the temperature sensor is offline for more than five minutes.
Dashboard

The dashboard for aquarium 1. At the bottom are the controls and dials for the temperature automations and helpers.
Leak detection
I have no idea if canister filters are more prone to leaking than hang-on-back filters, but if one of mine springs a leak, I'd like to know it. So at a minimum, each of my tanks gets a Zooz Water Leak Sensor that goes into the leak tray of each filter. I have a holding/QT tank that uses an undergravel filter and a hang-on-back. For that one, I put the leak sensor right under the hang-on-back in case it overflows.
I treat leak detection alerts as critical, so they play no matter the time of day or night.
Helpers
- Leak Detected: Toggle. When a leak sensor detects water, the automation toggles this On.
- Leak Detected Time: Date and/or time. This records the date and time of an active leak.
Automations
- Leak Alert: This automation fires when a leak sensor detects water. It repeats every 5 minutes while the probe reads wet, capped at 12 passes, so an unanswered leak nags for an hour and then stops. Each pass plays a prerecorded clip at full volume and sends a high-priority push alert to my phone.
- Leak Latch: This automation fires when a leak sensor detects water. It turns on the Leak Detected helper and sets the Leak Detected Time helper. I do this so a leak detection must be manually cleared.
- Leak Reset: This is actually a script, but it's what resets the Leak Detected and Leak Detected Time helpers. I clear the leak from the dashboard.
Dashboard

I show the leak status in several places in the UI. Here on the fish dashboard, plus the alert dashboard and each individual tank dashboard.
Alerts
Since Home Assistant is running important life support for my fishy companions, I've put a fair amount of thought into making my alerting system as robust as possible.
Everything related to life support gets both a voice announcement played loudly over our house speakers and a high-priority alert sent to my phone, with no consideration for hour of the day. If I have a water leak, then yes I want to be woken up so I can deal with it.
I prefer the Nabu Casa voices over the Piper voices, so I do use a cloud-based service for my TTS. What happens if there's a critical alert during an internet outage? The alert fails is what! To mitigate that, I made prerecorded announcements with the Nabu Casa voices, then I just cast the announcement over my local network to my media devices, no internet required.

Super Red Bristlenose in the 75 gallon display tank downstairs. (Richmond, VA · August 2026)
Conclusion
So what can I automate and monitor? A fair amount, but nothing really groundbreaking, it turns out. I'm happiest with my solution for the automatic feeders. All the rest of it is mostly just nice-to-haves.
When I first started, I thought I might be able to monitor my water parameters like pH, ammonia, nitrites and nitrates, but that still doesn't seem possible. I was hoping for some probes, connected via ESPHome and reporting to Home Assistant. Alas, I use the API Master Test Kit like everyone else.
I think dosing would be trivial if I had the right type of doser, like this BRS model or even an Apollo PUMP-1 Fluid Pump for close to half the price because both work from just being powered on or off from the switch. I just manually dose my tanks weekly, plus I run low-tech tanks, so it's not strictly necessary.
I run my aquariums like a fleet and I use blueprints because if I need to adjust something, I don't want to make the same adjustment six different times. I've tried to create a system that I can replicate and stamp down when I add a new tank. Get the tank and hardware, run the onboarding script and boom, I have a tank!
Are you in the fish keeping hobby? If yes, I'd be curious how you do it. Are you strictly old school or do you have some automations? I'd be interested in hearing.
She was labeled as a female koi alien betta.
I'm not exactly sure. I'm pretty new to scuds and got this bag of bugs thing from Phillip Fish Works. I'm fine with Tina picking them off but I hope the colony survives and Tina has some enrichment from hunting the little critters.
I moved Tina from the big community tank downstairs up to her very own 10 gallon tank. She was being harassed by the big male pearl gourami. So far, she's been exploring her tank and picking off scuds.
No. I do not use Google devices to call HA scripts/scenes. I play TTS announcements over my local network to the nest minis. The devices have physical switches on them to disable the mics and I have turned them all off.
Google nest minis.
I'm a big Home Assistant fan and power user. It's the home automation platform of choice in our house and I've added many devices and automations, sometimes to the chagrin of Rachelle.
We also have five cats so it only makes sense to use some automations to help manage all the cat chores.

Top row: Lily and Mac. Second row: Linus, Lennie and Polly.
The dashboard
To help me stay organized and visualize all the cat automations and functionality, I've created a cats dashboard. Let's walk through the dashboard, and I'll explain as we go.

Cat door
Our cats are indoor/outdoor cats and we have a SureFlap Microchip Cat Flap. This thing talks to a little Sure Petcare hub in our living room, and that hub is what connects to Home Assistant. It's Cloud Polling, which isn't the best but when I was shopping, I couldn't find one with better local connectivity.
It allows us to use Home Assistant to lock the door when needed so the cats can't go out. Home Assistant does this on a schedule. It's open during the day but prevents the goblins from leaving after sunset.

We have a little Unifi G3 Instant camera pointed at the cat door so we can see who's coming and going and fiddling around at the door.
All of our cats have a microchip and it uses this chip ID to only allow our cats in. That means no neighborhood cats or raccoons can use the door, thank you please. We also get presence reporting so we can generally see who's in, who's out and when they transitioned.
Automatic feeders
We have Aqara Smart Pet Feeders that we use to dispense breakfast and snacks. They're zigbee devices so they connect directly to Home Assistant and are fully local. No Aqara app needed for any part of it. These are pretty basic devices and I wish it could alert us on food level but alas, they simply dispense. The automatic feeders hit at 6 a.m., a time I set from a tile on the dashboard rather than hardcoding it. Cats go scattering every which way to get their spot at a feeder.
Litter boxes
We have two Litter Robot 4s we purchased used from Facebook Marketplace. They're Cloud Push, which means the internet has to be up for these to work correctly with Home Assistant (or I presume the Whisker app). This thing allows us to unlock a couple of fun automations.
Voice announcements when a Litter Robot is full
When a litter box is full, Home Assistant announces it over the speakers: "The black litter robot is full and needs to be emptied." Then when we're up there, we pull the bag of dirty litter and reset it. If it needs a top off, we do that too. With two litter boxes and five cats, we can go a few days before one of them needs to be emptied! Not bad.
Send the robot vacuum after a cat has used the robot litter box
This is probably one of my favorite automations. Home Assistant can detect when a cat uses a litter box, which allows us to trigger automations to send the Roomba to spot clean the litter box area. We gate when the vacuum can run as we don't want the thing running during the middle of the night if a cat goes to the bathroom.

Lennie is an especially messy litter box user so this has been a great automation.
Helpers and trackers
So there are several helpers and trackers we use to keep up with everyone's different dates and things and such.
- Flea collar: We use Seresto flea collars and they need to be replaced about every 8 months. I set up a helper to track this so it announces it in the good morning announcement message when it's due.
- Age: Based on their birthday!
- With Us: Based on their gotcha date!
- Yearly Vaccines: I've not built this yet but I plan to also track when each cat received their vaccinations so I can remember when it's time to reschedule.

Improvements
Cat door
I purchased the wrong cat door. When we first purchased it, we had Oliver and he was a bigger boy and I was skeptical he could fit through the smaller door. The problem is the larger door is all or nothing: locked or unlocked, for everybody. The smaller flap they sell can be set per cat. That would have been helpful in the past when someone was sick or wasn't confident using the cat door yet and we were going to be away. We could restrict the kitten or the sick kitty while letting the rest come and go as usual.
Automatic feeders
I wish the Aqara feeders reported food levels instead of just dispensing. I also wish the automatic feeders were the chip variety and allowed us to restrict certain feeders to only certain cats. Linus likes to go around and finish off everyone else's bowls.
Water fountains
We purchased an AquaPurr fountain but have never fully installed it. We had it in one of the bathrooms but disconnected it. My plan is to move it into the guest bathroom then hopefully we can stop fiddling with these little plastic filter ones. This thing doesn't connect to anything but it would be super nice to eliminate the water fountain clean chore.
Conclusion
So that's it! Thanks for reading this. Do you have any smart home automations that you especially like?
Look at this sweet boy. Say hi to Lennie!
I think white cloud mountain minnows are underrated. I really like this little things y'all.
A smart thermostat was one of the first connected devices I purchased when I started building our smart home. I wanted automatic presence detection so the thermostat could set an away mode when we leave and "we're home" mode without us having to do anything. Never mind the fact that Rachelle and I both work from home and are both homebodies. On the rare occasion that we're both away from home, the house knows it, automatically! ;)
Throughout the year, I'd find myself fiddling with the set points though. 68°F (20°C) in February feels different than 68°F in August. So twice a year, as the seasons started to tip over into warmer or colder weather, I'd change the upper and lower bounds.
It feels weird to run the AC in winter or the heat in summer. We sleep with the thermostat set at 65°F (18°C). Our preference for day time temp is 68°F to 72°F (20°C to 22°C). So when we wake up, and toggle sleep mode off in Home Assistant, the thermostat sets itself to the day time values and turns on the heat to raise the temp from 65 to 68; even in summer. That bothers me. I'd rather the thermostat just set the lowest temp to 68 and allow the house temp to naturally rise.
Plus, I have all these damn sensors in the house, outside the house, and a weather forecast available. I feel like I have all the inputs needed to make some data-driven decisions.

My climate dashboard.
Goal
My goal was to stop running heat on summer mornings and AC on winter evenings. The set points stay fixed. What changes is the HVAC mode: heat-only, cool-only, or both.
Data
For Home Assistant to pick the right mode, it needs to know what's going on outside, so I made a couple of template sensors.
Outdoor Blend
It all comes down to one template sensor: sensor.outdoor_temp_blend. It's the average of three numbers: the current outdoor temperature, today's forecast high, and today's forecast low. The result tells me what kind of day this is rather than what the temperature is right this minute. That blend feeds sensor.thermostat_season, which labels the day heating, cooling or shoulder-season. The season is what picks the HVAC mode.
Why average instead of just reading the current outdoor temp? A 50°F dawn before a 75°F afternoon shouldn't kick the heater on for an hour at sunrise. The blend flattens out the time-of-day swings so the thermostat isn't reacting to a number that's about to change anyway.
- sensor:
- name: "Outdoor Temp Blend"
unique_id: outdoor_temp_blend
device_class: temperature
unit_of_measurement: "°F"
state_class: measurement
availability: >-
{{ state_attr('weather.forecast_12_grimmauld_place', 'temperature') is not none
and states('sensor.today_forecast_high') | float(none) is not none
and states('sensor.today_forecast_low') | float(none) is not none }}
state: >-
{% set current = state_attr('weather.forecast_12_grimmauld_place', 'temperature') | float %}
{% set high = states('sensor.today_forecast_high') | float %}
{% set low = states('sensor.today_forecast_low') | float %}
{{ ((current + high + low) / 3) | round(1) }}
Thermostat Season
sensor.thermostat_season reads the outdoor blend and labels the day as one of three states:
coolonce blend reaches 68°F, holds until blend drops below 65°Fheatonce blend falls to 55°F, holds until blend rises above 58°Fheat_coolfor everything in between
The mode scripts (thermostat_active_mode, thermostat_sleep_mode, thermostat_away_mode) read this sensor to decide whether the thermostat should run cooling only, heating only, or both with a deadband.
That 3°F gap on each side is on purpose. Without it, a blend hovering right at 68°F would flip the HVAC mode every time the value bounced from 67.9 to 68.1 across forecast updates. The hysteresis means the season has to meaningfully change before the mode does. Once it decides it's summer, it doesn't second-guess itself over one cool morning.
- sensor:
- name: "Thermostat Season"
unique_id: thermostat_season
icon: >-
{% set s = this.state %}
{% if s == 'cool' %}mdi:snowflake
{% elif s == 'heat' %}mdi:fire
{% else %}mdi:swap-vertical{% endif %}
availability: >-
{{ states('sensor.outdoor_temp_blend') | float(none) is not none }}
state: >-
{% set blend = states('sensor.outdoor_temp_blend') | float %}
{% set prev = this.state if this.state in ['heat','cool','heat_cool'] else 'heat_cool' %}
{% if prev == 'cool' %}
{# stay in cool until blend drops below 65 #}
{{ 'heat_cool' if blend < 65 else 'cool' }}
{% elif prev == 'heat' %}
{# stay in heat until blend rises above 58 #}
{{ 'heat_cool' if blend > 58 else 'heat' }}
{% else %}
{# in heat_cool, transition based on outer thresholds #}
{% if blend >= 68 %}cool
{% elif blend <= 55 %}heat
{% else %}heat_cool
{% endif %}
{% endif %}
Helpers
I built some helpers that allow me to easily set the temperature range. They're just input_number helpers, one pair per mode: day, night and away. The scripts below read them by name, so when I nudge the day time high from 72 to 71 on my dashboard, that's the number the thermostat gets the next time anything runs.

Putting it all together now
Three scripts do the actual work: thermostat_active_mode, thermostat_sleep_mode and thermostat_away_mode. They're deliberately dumb. Each one reads sensor.thermostat_season, picks a branch, and writes to the thermostat. That's the whole job. None of them know a thing about the weather.
Here's the day time one. I trimmed a couple of housekeeping steps off the end (it also flips some booleans and sets the fan mode) to keep the important part visible:
thermostat_active_mode:
alias: Thermostat active mode
sequence:
- choose:
- conditions:
- condition: state
entity_id: sensor.thermostat_season
state: cool
sequence:
- action: climate.set_temperature
target:
entity_id: climate.t6_pro_z_wave_programmable_thermostat
data:
hvac_mode: cool
temperature: "{{ states('input_number.thermostat_day_temp_high') | float }}"
- conditions:
- condition: state
entity_id: sensor.thermostat_season
state: heat
sequence:
- action: climate.set_temperature
target:
entity_id: climate.t6_pro_z_wave_programmable_thermostat
data:
hvac_mode: heat
temperature: "{{ states('input_number.thermostat_day_temp_low') | float }}"
default:
- action: climate.set_temperature
target:
entity_id: climate.t6_pro_z_wave_programmable_thermostat
data:
hvac_mode: heat_cool
target_temp_high: "{{ states('input_number.thermostat_day_temp_high') | float }}"
target_temp_low: "{{ states('input_number.thermostat_day_temp_low') | float }}"
mode: single
In cool season the script sets hvac_mode: cool and one number, the day time high. That's it. No lower bound anywhere in that call, so nothing can ask for heat. Winter is the same trick backwards, hvac_mode: heat and just the day time low. Only the shoulder season sends both numbers as a deadband, which is what I had before.
Sleep and away are the same shape. They just read their own pair of helpers.
What calls the scripts
Mostly, nothing new. My wake, sleep and away automations already called these three scripts, because that's how the house has worked for a while now. They picked up the season awareness for free. I didn't have to touch a single one of them. So that's cool.
The one thing I did have to add is an automation for when the season itself changes:
- id: thermostat_reevaluate_on_season_change
alias: Thermostat, re-evaluate on season change
triggers:
- trigger: state
entity_id: sensor.thermostat_season
to:
- heat
- cool
- heat_cool
conditions:
- condition: template
value_template: >-
{{ trigger.from_state is not none
and trigger.from_state.state in ['heat','cool','heat_cool'] }}
actions:
- choose:
- conditions:
- condition: state
entity_id: input_boolean.thermostat_away_mode
state: "on"
sequence:
- action: script.thermostat_away_mode
- conditions:
- condition: state
entity_id: input_boolean.thermostat_night_mode
state: "on"
sequence:
- action: script.thermostat_sleep_mode
- conditions:
- condition: state
entity_id: input_boolean.thermostat_day_mode
state: "on"
sequence:
- action: script.thermostat_active_mode
mode: single
Without it, a season flip in the middle of a Tuesday afternoon would just sit there. Nothing would be calling a script until bedtime. This one re-runs whichever mode is already active so the thermostat catches up.
The condition looks fussier than it needs to be. It's there because the season sensor drops to unavailable for a split second now and then, usually when the weather integration hiccups or Home Assistant restarts. Without the guard, every one of those blips would re-fire the thermostat. I went back through the last couple of weeks of history and it happened 16 times. So, worth having.
Conclusion
So, back to the thing that bugged me. Summer morning, house is sitting at 65, I toggle sleep mode off. The season is cool, so the script sends cool-only at 72 and there's no lower bound for the furnace to chase. The house drifts up to 68 on its own, for free, the way it would have anyway if I'd just left it alone.
I pulled the history to make sure I wasn't fooling myself. Over the last twelve days there were 13 mornings where the house was sitting at exactly 65°F when we got up, and the furnace ran for zero minutes. Under the old setup that's 13 mornings of running heat in the middle of summer.
I should say though, it's August. The heat branch has never actually fired for real. I've read it a dozen times and I think it's right. Ask me again in December.
I'm not an HVAC guy and there's almost certainly a smarter way to do this. What's your approach? Does your thermostat know what time of year it is, or do you fiddle with it twice a year like I used to?
A few weeks ago, the Canadian wildfire haze reached Central Virginia, where I live, and we noticed it as a haziness in the air. Well, I have an AirGradient Open Air (model O-1PST) outdoor sensor and two AirGradient ONE units (model I-9PSL) indoor sensors. I'm a data-driven person, and I was instantly curious how this was showing up to the sensors in Home Assistant.
Here's what it looked like in the sensor logs:

Hourly mean PM2.5, 17-18 July 2026, central Virginia. The shaded band spans the two indoor sensors; the dashed line is the EPA 24-hour "unhealthy for sensitive groups" breakpoint (35.4 µg/m³).
The signal was unmistakable. Outside, PM2.5 peaked at 164 µg/m³, against a normal range of 7 to 15 for that sensor. Inside, both sensors traced the same curve at about a quarter the height, topping out near 38.
What I didn't expect was the timing. Outside peaked at 9 a.m., but inside didn't level off until noon. And the house was slower to clear than the air outside was. At the worst of it, inside was running about a fifth of outside. The next morning, as the outdoor numbers dropped away, inside was still sitting at a third of them.
Here are some of my automation ideas based on this event:
- I have a morning automation that fires at 7 a.m. It basically just gives the current weather conditions, the daily forecast, if any litter robots need to be emptied, etc. I can add an air quality alert to this announcement if it's outside of the 'good' range.
- I can also use the same sensor data to trigger ad hoc voice announcements and alerts.
- I built a Corsi-Rosenthal Box a couple years ago, but Rachelle really didn't like it because it's ugly. I think I will resurrect one anyway. I still have the fan, and I've already purchased new MERV filters for it. Wildfires are the exact use case for these box fan filters, so I intend to use one! When the indoor sensors cross my clean-air threshold, I can build automations to run the filter.
- Of course, I'll need automations and sensors to track how long the fan filter has run so we can have some idea on when to change the filters out.
Did you detect the wildfires where you live? Do you have any smart home automations about air quality?
Y'all! I have a dang flower in one of my 20 longs. I'm shocked. This tank is running fine. Animals seems healthy but I'm not really doing anything special. This makes me feel like this tank is exactly dialed in though if this plant is so happy it wants to flower! I think it's some sort of Buce but I've bought many randoms from /r/AquaSwap.
Originally posted on my site: https://michaelharley.net/photos/2026/07/27/
Linus did so well at the vet yesterday! They said he needs to lose some weight but who doesn't?! Not pictured: Polly who was huddled in the corner who also got a clean bill of health but does not like new people, places or things.
Originally posted on my site: https://michaelharley.net/photos/2026/07/25/