There are some issues with LIFX lights reliability that can be fixed on home routers by using Open Source firmware such as OpenWrt.
As I've recently observed on my network, the LIFX bulbs often don't respond to the AP frequently enough to avoid being disassociated for inactivity (see notes later about ap_max_inactivity
and max_listen_interval
). Another issue common to OpenWrt or any Linux-based router that uses hostapd
is that disassoc_low_ack=1
is the default setting unless you turn it off explicitly with disassoc_low_ack=0
.
The comments in the default example hostapd.conf
explain what this setting does:
# Disassociate stations based on excessive transmission failures or other
# indications of connection loss. This depends on the driver capabilities and
# may not be available with all drivers.
#disassoc_low_ack=1
As it turns out, the LIFX bulbs that I've observed have low powered WiFi radios run by an Espressif ESP32 that often cause hostapd
to disassociate them over and over again due to low powered responses from those radios / "stations". The bulbs use a PCB antenna similar to most IoT devices. NOTE: The lights act as WiFi clients, and all clients are called "STA
" in the hostapd
logs, which is short for "station".
This can be seen in the hostapd
logs similar to the following example:
Note: 00:00:5E:00:53:00 -> 00:00:5E:00:53:FF
used for documentation/examples (as per RFC 9542)
hostapd: wlan0: STA 00:00:5E:00:53:00 WPA: group key handshake completed (RSN)
hostapd: wlan0: STA 00:00:5E:00:53:00 IEEE 802.11: disconnected due to excessive missing ACKs
hostapd: wlan0: STA 00:00:5E:00:53:00 IEEE 802.11: deauthenticated due to inactivity (timer DEAUTH/REMOVE)
I'm sure that a lot of embedded proprietary routers actually run Linux and hostapd
under the hood, but unfortunately don't often let the user configure detailed hostapd
settings like disassoc_low_ack
, max_listen_interval
, or ap_max_inactivity
. If possible, consider switching to OpenWrt or a router that is supported by OpenWrt so you can configure these settings.
Speaking of which, one other problem is that the LIFX bulbs sometimes don't respond frequently enough to the AP and get disassociated due to inactivity. There are a few configuration settings for hostapd
related to this, as we can read about in the example hostapd.conf
.
Also see: OpenWrt wireless inactivity settings
# Station inactivity limit
#
# If a station does not send anything in ap_max_inactivity seconds, an
# empty data frame is sent to it in order to verify whether it is
# still in range. If this frame is not ACKed, the station will be
# disassociated and then deauthenticated. This feature is used to
# clear station table of old entries when the STAs move out of the
# range.
#
# The station can associate again with the AP if it is still in range;
# this inactivity poll is just used as a nicer way of verifying
# inactivity; i.e., client will not report broken connection because
# disassociation frame is not sent immediately without first polling
# the STA with a data frame.
# default: 300 (i.e., 5 minutes)
#ap_max_inactivity=300
#
# The inactivity polling can be disabled to disconnect stations based on
# inactivity timeout so that idle stations are more likely to be disconnected
# even if they are still in range of the AP. This can be done by setting
# skip_inactivity_poll to 1 (default 0).
#skip_inactivity_poll=0
# Disassociate stations based on excessive transmission failures or other
# indications of connection loss. This depends on the driver capabilities and
# may not be available with all drivers.
#disassoc_low_ack=1
# Maximum allowed Listen Interval (how many Beacon periods STAs are allowed to
# remain asleep). Default: 65535 (no limit apart from field size)
#max_listen_interval=100
Finally, some newer LIFX light models use multicast DNS for Apple HomeKit support. Multicast DNS (a.k.a. mDNS, Zeroconf, Bonjour) which requires multicast packets to be sent and received over the WiFi radio. This in and of itself is fine, but depending on the hostapd
WiFi AP configuration and how frequently and how long client stations sleep, those multicast packets can suffer speed or delivery timing problems.
For example, we can use avahi-daemon
(Linux) or dns-sd
(macOS) to look for LIFX lights advertising the HomeKit Accessory Protocol HAP
(_hap._tcp
):
Note: This example uses avahi-browse
. For macOS, use dns-sd
instead.
$ avahi-browse -d local _hap._tcp --resolve -t --verbose
Server version: avahi 0.8; Host name: saturn.local
E Ifce Prot Name Type Domain
+ eth0 IPv6 LIFX Color 005300 _hap._tcp local
+ eth0 IPv6 LIFX Pls A19 005301 _hap._tcp local
+ eth0 IPv4 LIFX Pls A19 005301 _hap._tcp local
+ eth0 IPv4 LIFX Color 005300 _hap._tcp local
= eth0 IPv6 LIFX Color 005300 _hap._tcp local
hostname = [LIFX-Color-005300.local]
address = [192.168.1.123]
port = [50029]
txt = ["c#=3" "ff=2" "id=00:00:5E:00:53:00" "md=LIFX Color" "pv=1.1" "s#=177" "sf=0" "ci=5" "sh=LEQg9g=="]
= eth0 IPv4 LIFX Color 005300 _hap._tcp local
hostname = [LIFX-Color-005300.local]
address = [192.168.1.123]
port = [50029]
txt = ["c#=3" "ff=2" "id=00:00:5E:00:53:00" "md=LIFX Color" "pv=1.1" "s#=177" "sf=0" "ci=5" "sh=LEQg9g=="]
= eth0 IPv6 LIFX Pls A19 005301 _hap._tcp local
hostname = [LIFX-Pls-A19-005301.local]
address = [192.168.1.239]
port = [49152]
txt = ["sh=DpXTZw==" "ci=5" "sf=0" "s#=1" "pv=1.1" "md=LIFX Pls A19" "id=00:00:5E:00:53:01" "ff=1" "c#=3"]
= eth0 IPv4 LIFX Pls A19 005301 _hap._tcp local
hostname = [LIFX-Pls-A19-005301.local]
address = [192.168.1.239]
port = [49152]
txt = ["sh=DpXTZw==" "ci=5" "sf=0" "s#=1" "pv=1.1" "md=LIFX Pls A19" "id=00:00:5E:00:53:01" "ff=1" "c#=3"]
: Cache exhausted
: All for now
macOS example:
# Browse for advertised _hap._tcp devices
$ dns-sd -B _hap._tcp
Browsing for _hap._tcp
DATE: ---Thu 22 May 2025---
15:56:03.519 ...STARTING...
Timestamp A/R Flags if Domain Service Type Instance Name
15:56:03.520 Add 3 4 local. _hap._tcp. LIFX Color 005300
15:56:03.520 Add 2 4 local. _hap._tcp. LIFX Pls A19 005301
# Hint: see the full zone-file-like view with: dns-sd -Z _hap._tcp
# Resolve the record for an advertised LIFX bulb
# Hint: Names are oddly separated with octal '\032' internally in the dns-sd
# utility, which is ASCII 0x1A = SUB (substitute) control character.
# On the CLI, we replace or substitute these with
# spaces ' ' to resolve or lookup an mDNS record.
$ dns-sd -L 'LIFX Color 005300' _hap._tcp
Lookup LIFX Color 005300._hap._tcp.local
DATE: ---Thu 22 May 2025---
16:05:27.225 ...STARTING...
16:05:27.226 LIFX\032Color\032005300._hap._tcp.local. can be reached at LIFX-Color-005300.local.:50029 (interface 4)
sh=RpSH1w== ci=5 sf=0 s#=177 pv=1.1 md=LIFX\ Color id=00:00:5E:00:53:00 ff=2 c#=3
So we can see that two LIFX bulbs are advertising mDNS records over multicast on the network. We can capture mDNS traffic by filtering on port 5353
with tcpdump
:
sudo tcpdump -nnXs 0 -i eth0 -w /tmp/ipv4-mdns.pcap ip4 and udp port 5353
That can help to debug multicast DNS packet delivery problems over the WiFi. Try capturing mDNS traffic from another WiFi client, and also on the router if possible (if using OpenWrt or dd-wrt, etc...). You might find that multicast packets are not being delivered at timings when the LIFX lights are asleep.
You also might find that multicast packets are being sent by the AP at the slowest supported 802.11 rate on the network, which is the least common denominator supported by all WiFi clients. If the AP is still supporting 802.11
b, this could mean 2
, 5
, and 11
Mbps rates. If the AP is configured to use 802.11 b and legacy rates, it can cause a massive slowdown over the entire WiFi network for multicast packets.
Some examples of basic rates in hostapd.conf
:
Note that the slowest rate is 1 Mbps
in this example!
Multicast will be sent at this rate and thus use more radio airtime.
# The entries in this list are in 100 kbps, i.e., 11 Mbps = 110.
# 802.11b / legacy rates (1 Mbps - 54 Mbps)
supported_rates=10 20 55 110 60 90 120 180 240 360 480 540
basic_rates=10 20 55 110
For most LIFX bulbs, they support 802.11g
, but not anything newer (e.g. Not . 802.11n/a/ax
, and no fast roaming 802.11r
). So, we can bump up the basic rate speed to the 802.11g
rates:
# 802.11g rates (6Mbps - 54 Mbps)
supported_rates=60 90 120 180 240 360 480 540
basic_rates=60 120 240
Note
In OpenWrt, this is what the option legacy_rates '0'
setting does: turn off 802.11b
rates and only enable 802.11g
and above.
When using OpenWrt, just set the legacy_rates
option to 0
/ off.
uci set wireless.radio0.legacy_rates=0
uci commit
Or simply add the following to /etc/config/wireless
config wifi-device 'radio0'
#... other radio config settings here...
option legacy_rates '0'
One more thing that can impact multicast: DTIM Delivery Traffic Indication bitMap interval.
Multicast and broadcast packets are sent at the DTIM interval (hostapd
default: dtim_period=1
which means a DTIM is sent every 1
beacon frames / intervals). Many newer routers are configured with dtim_period=3
, which allows iOS, Android, and battery-powered IoT or mobile devices to sleep longer between waking up at the DTIM interval (every 3
beacon frames) to receive any multicast and broadcast packets.
These settings can affect Apple Homekit with IoT devices such as LIFX bulbs, or any other IoT devices that need mDNS to advertise services and be discovered. LIFX has not published anything regarding what their bulbs recommended DTIM interval is. Apple recommends dtim_interval=3
for iOS devices.
However, we can infer that LIFX bulbs do sleep rather long at times based on observing that they often are unresponsive to both the max_listen_interval=100
time limit (remaining silent for over 100
beacon periods ~10.24 seconds
), and even sometimes the ap_max_inactivity=300
(5 minutes +/- 20 seconds random jitter). Note that this apparent intermittent 5 minute inactivity could also be due to bad WiFi signal, and noise in the neighborhood from other WiFi APs using the same channels. In this case, we might also need to set disassoc_low_ack=0
. However, based on log data alone it does appear to happen and eventually the LIFX bulbs fail to rejoin the network until hostapd
is restarted. I didn't have a great WiFi capture card at the time to conclusively determine if this was due to noisy neighbors, low reception or signal from LIFX bulbs, or simply bulbs sleeping too long.
Nonetheless, we can try to mitigate all these issues by increasing the dtim_period
to match Apple's recommendations to accomodate IoT devices that sleep longer to save power, and increasing the timeout limits for inactivity. We can also increase the max_listen_interval
to the maximum allowed value for a 16-bit unsigned integer in C: 65535
. This should prevent the hostapd
AP from deassociating the LIFX bulbs for inactivity as often, and allow clients the longest possible interval to remain quiet. Also, since the LIFX bulbs are older hardware and do not support fast roaming 802.11r
, we can try to adjust settings to avoid deassociating them as frequently. It makes sense to also disable 802.11r
on an IoT-specific WiFi AP. When have you seen a LIFX bulb roaming around your house?
# Default beacon period (100 TUs / "Time Units")
# 1 Time Unit = 1024 µs (microseconds)
# Therefore 100 TUs = 102,400 µs = 102.4 ms
beacon_int=100
# Send multicast DTIM every 3 beacon periods
# 3 * 100 TUs = 300 TUs = 30.72 seconds
dtim_period=3
# Allow clients to remain quiet for the maximum possible
# 65535 * 100 TUs = 6710784000 µs = 1.86410667 hours
max_listen_interval=65535
# Do not disassociate clients for low signal quality issues,
# or excessive transmission failures.
# Should help LIFX bulbs with low-powered radios from being deassociated as
# often.
disassoc_low_ack=0
# Increase STA inactivity timeout to 1 hour
# 60 min = 3600 seconds
ap_max_inactivity=3600
# Do NOT skip inactivity polling
# Still send the inactivity probes and wait for ACKs from STA clients
skip_inactivity_poll=0
Note
For OpenWrt, these settings can be changed in /etc/config/wireless
:
config wifi-device 'radio0'
# ... Existing Config for IoT WiFi radio PHY device
option beacon_int '100'
config wifi-iface
option device 'radio0'
option mode 'ap'
# ... Existing Config for IoT WiFi radio AP
option max_listen_interval '65535'
option disassoc_low_ack '0'
option max_inactivity '3600'
option dtim_period '3'
option skip_inactivity_poll '0'
Or, using uci
:
uci set wireless.radio0.beacon_int='100'
uci set wireless.@wifi-iface[0].max_listen_interval='65535'
uci set wireless.@wifi-iface[0].disassoc_low_ack='0'
uci set wireless.@wifi-iface[0].max_inactivity='3600'
uci set wireless.@wifi-iface[0].dtim_period='3'
uci set wireless.@wifi-iface[0].skip_inactivity_poll='0'
uci commit
If running OpenWrt, also disable 802.11r
fast roaming with the following in /etc/config/wireless
:
config wifi-iface
# ... Existing Config for IoT WiFi radio AP (e.g. radio0) ...
option ieee80211r '0'
Alternatively, uci
may be used to change the setting:
uci set wireless.@wifi-iface[0].ieee80211r=0
uci commit
One other setting is ap_isolate=1
, which isolates WiFi clients. Setting ap_isolate=1
stops the AP from doing L2 forwarding between clients using the pairwise keys. This can impact Layer 2 packet delivery between WiFi clients. For a home network with a lot of IoT devices, it's probably recommended to turn this off and allow clients to speak to one another. Ideally you'd want to have a separate IoT WiFi AP anyway that guests do not connect to, avoiding security and isolation concerns.
/etc/config/hostapd.conf
(OpenWrt generates these per-device in /var/run/hostapd-phyNN.conf
):
# Do NOT isolate WiFI clients / IoT devices on Layer 2
ap_isolate=0
Note
For OpenWrt, this setting should be changed in /etc/config/wireless
:
config wifi-iface
# ... Existing Config for IoT WiFi radio AP
option isolate '0'
Or with uci
:
uci set wireless.@wifi-iface[0].isolate=0
uci commit
Finally, it should go without saying that ideally you should be using a WiFi channel / frequency that is not being used by neighboring WiFi APs. This avoids the "noisy neighbors" problem of the WiFi APs struggling to talk over one another on the same radio frequencies. While this is not always possible to avoid, it should be a first line of action when dealing with frequent client disassociations. Do a wireless site survey and see which channels are already being used by other WiFi APs in the neighborhood. Pick a channel that is the least noisy.
Usually a good rule of thumb is to prefer to choose channels 1
, 6
, and 11
to avoid overlapping. However, if this is not possible and all of those are being used, pick 3
, 4
, 8
, or 9
and look for the one with the least noisy two adjacent channels. If all of those are being used, then fallback to 2
, 5
, 7
, or 10
while again picking the one with the least noisy neighbors (the lowest dBm
AP signals).
With some combination of these hostapd
and OpenWrt settings, hopefully your LIFX lights and IoT devices can stay associated and be more reliable!