Intro #
In an ideal scenario all IoT/Smart Home devices should be blocked from accessing the internet. This ensures that no bad actors can tamper with them, and stops them from sending data back to their manufacturers, something that can be a major privacy concern, especially with devices like cameras.
Most IoT device manufacturers intend their products to be linked to an app made by them. Unfortunately, for many of these apps this requires allowing your device to have internet access, and connects it to the manufacturer’s cloud. The device manufacturer typically markets this as a feature, advertising the capability to control your device from anywhere. While this can be a benefit, it also comes with some major drawbacks, including the privacy concerns noted above, as well as giving full control of your smart devices to that company, something that can go very badly.
For these reasons, I opt to use home assistant to control my smart home locally, thereby leaving me in charge of my devices. When I added my IoT/Smart Home devices to home assistant, however, migrating from controlling them via their manufacturers’ apps to using only home assistant was a gradual process. This wasn’t a quick switch for me, mostly because at the time I started out with home assistant I was having some hardware issues with my server. These issues resulted in a fair amount of downtime, which made it even harder to fully commit to using just home assistant. I’ve since resolved my server’s hardware issues, and now that I can reliably have home assistant running, it’s finally time to secure my IoT devices by limiting their network access and ditching their manufacturer-proprietary apps.
Networking Configuration #
Starting on this endeavor I had 3 IoT devices still on my main LAN and using cloud-connected apps:
- A Bond Home fan/light fixture
- A Midea Window Air Conditioner
- A Hubspace fan/light fixture
In order to limit the access of these devices, as well as future IoT devices, I’m going to be using two different VLANs to isolate them from my trusted subnets as well as the internet.
VLAN 30 will be a new VLAN I create for IoT devices only. This VLAN will be on subnet 192.168.30.0/24, and my router will have firewall rules denying all traffic from this subnet to any destination, meaning these devices cannot send packets to any other subnets, including the internet. This is where I will put any ethernet connected IoT devices, such as cameras and hubs.
I already use VLAN 10 as my home’s guest network, with it being the only other SSID advertised by my UniFi access points. IoT devices that connect via Wi-Fi will be put on this network, with firewall rules set to deny these specific IoT devices access to the internet (the Guest network already denies all devices on it access to my other local subnets). While having my IoT devices on the same subnet as guest users could normally be a security concern, my APs have “Client Device Isolation” enabled on the Guest SSID in the my UniFi controller, meaning the APs don’t allow communication between wireless clients on this SSID, despite them being on the same subnet. One thing that is an issue with this setup, though, is that rogue IoT devices could manually set their IP to a different IP on this subnet that isn’t blocked, making these per-host internet-blocking firewall rules an imperfect solution. This scenario is pretty unlikely, though, and this setup still offers better security than having these devices on my main LAN. Since I don’t want another SSID adding additional wireless interference this will have to do for my few IoT devices that need a Wi-Fi connection.
There are a couple more things to note about both of these VLANs. In order to allow home assistant and MQTT to communicate directly with these IoT devices, my linux host which is running them in docker will have an IP on both of these new subnets. I’ll be relying on docker’s default behavior of binding bridge network port mappings to all host interfaces here. Additionally, the IoT devices on each VLAN will be set with static DHCP mappings, so they’ll recieve their IP via DHCP, but will get the same IP leased to them every time based on their MAC address, allowing me to configure integrations for them in home assistant via their IP without having to worry about it changing. Once I set all this networking up, it was time to move on to configuring each device and connecting them to home assistant.
Configuring and Connecting the Devices #
Bond Fan #
First up was my Bond Home fan, which connects to the network via Wi-Fi. I first removed it from the bond app so it wouldn’t be searching for an unreachable device after I blocked internet access. Next, I accessed the fan’s web interface at its current IP on my main LAN. Here I was able to change its network configuration, moving it over to the guest network where it could obtain an IP via DHCP. Once it got its IP, I set the lease to a static mapping, ensuring it would get the same IP every time it connected to the network, then set firewall rules to deny any packets from the fan, restricting it to only the subnet it’s on. After this I just had to change the configuration for the fan to its new IP in home assistant. From here I could control the fan via home assistant, but it was otherwise completely isolated, unable to access the internet or other subnets.
Unfortunately, the fan really did not like being denied internet access. On my firewall I was constantly seeing blocked dns requests from it every second, with it trying both google and cloudflare’s DNS at 8.8.8.8 and 1.1.1.1 respectively. Additionally, the fan was running its configuration AP constantly, advertising its SSID for anybody within range to take control of it, as well as restarting frequently.
I was able to find a couple forum posts from people with similar issues with their bond devices running on a network with no internet connection. Per the conversations there as well as the Bond Local API Docs, I was able to find that disabling MQTT (which is how the fan communicates with the cloud) on the fan via the local API would stop it from running its AP and restarting. Technically I could also connect the fan to my local MQTT instance instead of disabling MQTT, but controlling the fan via the homeassistant plugin (which uses calls to this local API) is working fine. Here are the commands I ran from linux to disable MQTT on the fan:
curl -iH "BOND-Token: <token>" -H "Content-Type: application/json" -X PATCH -d '{ "enabled": false }' http://<ip>/v2/api/mqtt
curl -iX PUT -d '{"_token": "<token>"}' http://<ip>/v2/sys/reboot
While this did stop the AP running and the fan rebooting, it was still making tons of DNS requests. In the forum posts I linked above there was talk by the API devs of implementing a local only mode which would stop the fan rebooting/running the AP as well as stopping these needless DNS requests, but it appears the commands I just ran were as far as they got with that plan. After scouring the docs I found one more thing to try, disabling the “Bond Cloud watchdog”:
curl -iH "BOND-Token: <token>" -H "Content-Type: application/json" -X PATCH -d '{ "rwdg_disable": true }' http://<ip>/v2/sys/wifi/watchdog
curl -iX PUT -d '{"_token": "<token>"}' http://<ip>/v2/sys/reboot
Unfortunately this did not help, and per the docs it only disables the rebooting behavior, which I already stopped by disabling MQTT.
I also tried manually configuring the fan’s network settings, setting its DNS server to 127.0.0.1 (loopback address) in hopes of stopping the DNS requests from leaving the device. I do think this decreased the amount of DNS messages being sent to my router, but it didn’t outright stop them. At the end of the day a few DNS packets getting chucked at my firewall isn’t that big a deal, so without much of a solution in sight I decided to accept it and move on.
Midea Air Conditioner #
Home assistant doesn’t have a direct integration for Midea products, so I had to turn to community-created plugins. While searching I found four github repos for Midea integrations:
- NeoAcheron/midea-ac-py
- andersonshatch/midea-ac-lib
- mac-zhou/midea-msmart
- georgezhao2010/midea_ac_lan
These options all seemed to be building on code from each previous repo in the list. The last two seemed to be the only ones still active, with both claiming to allow control via the local network rather than hooking into the existing cloud integration, which is good since I am hoping to remove the cloud integration altogether. I started out by trying the last integration on my list since it was updated most recently and had the most downloads, installing version 0.3.16 via the Home Assistant Community Store (HACS).
Once I installed the integration I added the Air Conditioner through the integration, first clicking “Add Integration”, then finding “Midea AC LAN”. The first step the configuration has is how it should find your device, with four options: “Auto”, “By IP”, “Manual”, and “Just list appliances”. I don’t know the point of the last option, but both it and “Auto” gave an error. This probably isn’t the integration’s fault as Home Assistant auto discovery doesn’t work when running it in docker using bridge network mode as I am.
Selecting “Manual” asked for a ton of information I didn’t know, and I couldn’t find all of it in the Midea App. Luckily, once I chose “By IP” and entered the A/C’s IP, it autopopulated almost all of these fields, including “Token” and “Key”, though I still had to select the device’s type of “Air Conditioner”. From here I was able to control the device via home assistant.
I find it a bit concerning that this integration could find all of the details it needed to control the device just by having network access to it, but it isn’t too surprising considering the general lack of security with most IoT devices. Since I couldn’t find any documentation suggesting the A/C was intended to be controllable within your home network, I’m assuming this home assistant addon is just pretending to be the midea cloud when it’s sending commands to the air conditioner.
Since the device was now working in home assistant I set up my firewall rules to block its access to the internet, which fortunately didn’t impact home assistant’s ability to control it. After rebooting the device it started spamming DNS requests every second, just like my fan. At this point I guess this is just the cost of using Wi-Fi IoT devices without allowing them to phone home.
Hubspace Fan #
Like the air conditioner, home assistant has no native integration for Hubspace. Turning to the community again I found this thread, where somebody has created an integration to control Hubspace products through home assistant by connecting to the Hubspace cloud. When starting this process I wanted to avoid having devices connect to the internet if possible, but it seems this is the only integration that home assistant users have created so far. The only other option I could come up with to control the fan locally would be using RF, mimicing the controls the fan’s remote uses and controlling this via home assistant. Since I not in the mood to go out and buy hardware to do this, I’m going to be using the aforementioned integration, though I may change this in the future, and will leave an update here if I do.
I added the integration to home assistant, using HACS to add it as a custom repository per the instructions on the integration’s github page. After downloading v1.93 and adding the required config to my configuration.yaml the entities for the light and fan were available in home assistant.
Though this integration works for controlling the fan & lights, sending commands is painfully slow. Despite the fan being right next to the phone using home assistant, packets have a long path to take in order to reach the fan due to the cloud-only control. Sometimes a command takes up to 10 seconds to register a change on the fan, significantly slower than the <1 second response time of most locally controlled IoT devices. While I’m glad somebody made an integration enabling control of the fan through home assistant, I will likely look to a different solution in the future.
Conclusion #
While I have been able to at least limit the access of my IoT devices, I am still disappointed with how difficult, and sometimes even impossible, it is to control many IoT devices locally. Of the devices I worked on today, I have to give kudos to Bond for having a locally accessable REST API, though I would still like a local-only mode where it would stop spamming DNS requests.
From now on I plan to be much more selective with the IoT devices I buy for my home, ensuring future devices are locally controllable & do not require internet. In my future plans is a zigbee network, on which none of the devices will have/need internet access - an aspect of the zigbee protocol that is a major draw for me.