~/blog/home-energy/solar-gateway-wifi-channel.md
My solar gateway went offline every night at 3 AM, and it was a Wi-Fi channel
// tl;dr
My Enphase Envoy dropped off Home Assistant around 03:01 six nights running. UniFi's scheduled channel optimization moved the radio and the Envoy never rejoined. I turned channel optimization off, and in the six nights after, it didn't happen once.
My Enphase Envoy dropped off Home Assistant every night. Not some nights. Six out of six.
It went unavailable at 03:01 or 03:02 and stayed that way for 156 to 223 minutes. Then it came back by itself like nothing had happened.
I lost hours blaming the wrong things. The cause was in the network.
What I chased first
Everything I suspected was on the Home Assistant side. The Enphase integration. A recent firmware update on the gateway. The custom component I'd installed through HACS.
Each one had a plausible story. None of them explained it.
What I should have looked at sooner was the clock. Flaky hardware doesn't fail inside the same two minutes every night. Something on a schedule does.
What UniFi was doing at 3 AM
On my setup, UniFi's channel optimization, which Ubiquiti calls Channel AI, ran on a schedule at 3 AM. It looks at the RF around each access point and moves radios to better channels. A sensible job for the middle of the night.
Once I lined the outages up against the rest of the wireless clients, it was obvious. At 03:05 every other client either showed nothing or dropped for a minute at most. All of them rejoined on their own.
The Envoy didn't. It's a wireless client, and when the channel changed under it, it never re-associated. It just sat there until it happened to reconnect hours later.
So the optimizer wasn't broken. Ubiquiti says the changes go out without impacting active clients, and for nearly everything I have, that held. One device couldn't cope.
Turning channel optimization off
I disabled it on 2026-09-11.
Then I watched. From 09-12 through 09-17 there wasn't a single outage around 03:00. What's left are occasional blips of about 3.6 minutes at 23:05. They recover by themselves, so I've left them alone.
I don't mind losing the automatic channel tuning. A solar gateway that reports through the night is worth more to me than whatever small gain the optimizer was finding.
If it comes back, I have a fallback in mind that I haven't built: an automation that notices the Envoy went unavailable and kicks it back onto the network. The UniFi integration in Home Assistant has a unifi.reconnect_client action for wireless clients, so I'd try that first. If that isn't enough, the integration also has a per-client block switch (the client has to be added in the integration options). Blocking and then unblocking forces a rejoin.
How sure I am
Measured: the outage start times, the durations, six out of six nights, the short blips on other clients at 03:05, and six clean nights after the change. Seen in September 2026.
Likely but unproven: that the Envoy specifically can't re-associate after a channel change. I'm inferring that from the timing and from the fix working. I haven't tested whether the reconnect action would bring it back.
How I measured it, and three traps
I pulled the outage times out of Home Assistant instead of eyeballing graphs. Three things nearly gave me wrong numbers.
The history API gives you one day unless you ask for more. If you call /api/history/period without end_time, the window ends one day after the start. Ask for the last seven days that way and you get the first day back, with no error.
Hourly statistics hide how long an outage lasted. The hour where an outage starts or ends still gets a mean, built from whatever minutes had data. Outages look shorter than they were. For durations I only trust the raw state changes.
Daily statistics include today. On my install, recorder/statistics_during_period with period: "day" also returned the bucket containing end_time, which is today's partial day. Filter rows by bucket start, or every per-day average comes out wrong.
One bit of good news. The Envoy's lifetime counters keep counting through an outage, so the missed energy lands in the recovery hour. Totals over a window survive the dropouts. The split between days only breaks if an outage crosses local midnight, and none of these did.
What I'd tell myself
The timing was the clue, and I had it on night one. I should have gone looking for anything on the network that runs on a schedule before I touched the integration. I didn't get there until night six.
$ ./ask --help
Stuck on something similar? Ask below and I'll try to help you work through it. It helps to include:
- --running hardware, OS, versions
- --tried what you've already tried
- --error the exact message, word for word
Comments are public, so leave out passwords, keys and public IP addresses.