If you are securing your home network by setting up a dedicated IoT VLAN, moving dozens of smart devices to the new SSID is usually a nightmare. You typically have to factory reset every single plug and re-pair it manually.
This guide provides a Python automation script to scan your network and command all your TP-Link Tapo/Kasa devices to switch to a new Wi-Fi network simultaneously, saving you hours of manual work.
WARNINGRisk of Connection Loss: If you enter the wrong Wi-Fi password in the script, your devices will disconnect from the current network and fail to join the new one. You will then have to manually factory reset them to recover access. Double-check your credentials before running!
Why Automate the Migration?
When moving devices like the Tapo P110, H100 Hub, or Kasa Strips to a new VLAN (e.g., Roze_IoT), the official app forces you to:
- Delete the device.
- Reset it physically (hold the button for 10s).
- Re-add it via Bluetooth/Wi-Fi AP mode.
If you have 20+ devices, this process takes hours. Our solution uses the Klap protocol (via Python) to push the new Wi-Fi credentials to the devices while they are still online, causing them to โhopโ networks instantly.
Solution Overview
The solution involves a Python script using the python-kasa library. It performs an authenticated scan of your local network and sends a wifi_join command to every compatible device found.
Tools Used:
- Python 3.10+ installed on your PC (Windows/Linux/Mac).
- python-kasa library for device communication.
- TP-Link Cloud Credentials (Email/Password) for authentication.
Step 1: Install Prerequisites
First, you need to install the required Python library. Open your terminal or command prompt and run:
pip install python-kasaNote: We use python-kasa because modern Tapo firmware requires cloud authentication to accept local control commands.
Step 2: Create the Migration Script
Create a new file named migrate_tapo.py and paste the code below.
Key Features of this Script:
- Universal Support: Works for Plugs (P110, P100), Bulbs (L530), and Hubs (H100).
- Broadcast Targeting: Includes a fix for Windows users running the script via Ethernet.
- Auto-Encryption: Automatically handles WPA2/WPA3 negotiation.
import asyncioimport sysfrom kasa import Discover, KasaException
# --- CONFIGURATION ---# Your TP-Link / Tapo Cloud credentials# REQUIRED: Modern firmware rejects local control without cloud authTAPO_PASSWORD = "your_cloud_password"
# The DESTINATION Network (Where you want devices to go)NEW_SSID = "Roze_IoT"NEW_PASSWORD = "your_iot_password"
# Targeted broadcast IP.# If you are on Windows, use the broadcast address of your interface.# Example: 192.168.1.255 for a /24 network.BROADCAST_IP = "192.168.1.255"
async def main(): print(f"๐ Scanning subnet {BROADCAST_IP} for ALL Tapo/Kasa devices...")
try: # We pass credentials immediately to ensure we can identify locked devices found_devices = await Discover.discover( target=BROADCAST_IP, discovery_timeout=5, username=TAPO_EMAIL, password=TAPO_PASSWORD ) except Exception as e: print(f"โ Error during discovery: {e}") return
if not found_devices: print("โ No devices found. Check your firewall or IP configuration.") return
print(f"๐ Found {len(found_devices)} devices. Starting migration...\n")
for ip, dev in found_devices.items(): try: # Refresh device state await dev.update()
print(f"๐ค Processing: {dev.alias} ({dev.model})") print(f" => Sending command to join '{NEW_SSID}'...")
try: # The wifi_join command pushes the new credentials to the device. await dev.wifi_join(NEW_SSID, NEW_PASSWORD)
# If we get here, the device accepted the command. print(f" โ
Command sent! Device should switch networks now.")
except Exception as e: # A disconnect error here is actually a SUCCESS. # It means the device dropped the current connection to switch to the new one. print(f" โ
Command sent (Device disconnected as expected).")
except Exception as e: print(f" โ Error processing {dev.alias}: {e}")
finally: # Cleanup connection try: await dev.disconnect() except: pass
# Small delay to prevent network congestion await asyncio.sleep(2)
print("\n๐ Process complete. Check your IoT VLAN for new clients.")
if __name__ == "__main__": # Windows-specific fix for asyncio event loops if sys.platform == "win32": asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) asyncio.run(main())Step 3: Run the Migration
Edit Credentials:
Open the script and fill in:
TAPO_EMAIL/TAPO_PASSWORDNEW_SSID/NEW_PASSWORDBROADCAST_IP(e.g.,192.168.1.255if your IP is192.168.1.X)
Execute:
Run the script from your terminal:
python migrate_tapo.pyYou should see output indicating that devices are receiving the command.
Step 4: Troubleshooting & Verification
Common Issues:
-
โNo devices foundโ on Windows: Windows Firewall often blocks Python broadcast packets.
- Fix: Temporarily disable the firewall or allow
python.exeon Private Networks. - Fix: Ensure
BROADCAST_IPmatches your current subnet (e.g., if you are on10.0.0.5, use10.0.0.255).
- Fix: Temporarily disable the firewall or allow
-
Script Crashes with
ImportError: You might have an old version of the library.- Fix: Run
pip install --upgrade python-kasa.
- Fix: Run
-
Device Stuck: If a device fails to join the new network (e.g., weak signal), it may reboot into โSetup Modeโ (Orange/Green blinking).
- Fix: You will need to re-add this specific device manually using the Tapo app.
Verification:
Log into your Router or UniFi Controller and check the Client List for your IoT VLAN. You should see all your plugs reappearing with new IP addresses (e.g., in the 192.168.20.x range if that is your IoT subnet).
Conclusion
This script turns a 3-hour manual reset task into a 30-second automated job. By using python-kasa, we can programmatically manage our smart home infrastructure, making it much easier to enforce security best practices like VLAN segmentation.