When you unbox a smart appliance and set it up for the first time, something that feels like magic happens: your phone finds the device, connects it to your home WiFi, and suddenly you can control it from anywhere. But this process has an interesting problem at its core.
The appliance needs your WiFi password to connect to your home network. But it’s not on your network yet — so how does your phone give the password to a device it can’t talk to?
There’s a second problem too: the appliance has no screen. It can’t show you a setup page. It can’t prompt you to enter a password. It needs to be set up through your phone, and your phone needs a way to discover it.
There are three main approaches the industry uses to solve this.
Approach 1 — Bluetooth for the initial handshake
Many modern smart home devices use Bluetooth for the setup conversation. The phone scans for nearby Bluetooth devices, finds the new appliance, and opens a temporary encrypted connection. Over Bluetooth, the app sends the WiFi credentials to the device. The device then disconnects from Bluetooth and connects to WiFi. This is the approach used by Philips Hue, many Google Home devices, and newer Apple HomeKit accessories.
The advantage is that Bluetooth is short-range and encrypted, so only someone physically next to the device can set it up. The disadvantage is that the app needs CoreBluetooth permissions and the hardware needs a Bluetooth chip.
Approach 2 — The device creates a temporary WiFi hotspot
When an appliance hasn’t been configured yet, it broadcasts its own WiFi network — something like “SmartOven-Setup-A3F2”. The user’s phone connects to that hotspot, which gives the phone a direct connection to the device. The setup app then opens an HTTP connection directly to the device (often at a fixed IP like 192.168.4.1) and POSTs the home WiFi credentials. The device saves them, disconnects the hotspot, and connects to the home network.
This is sometimes called “SoftAP” (Software Access Point) pairing. It works on devices with only a WiFi chip — no Bluetooth required. The user experience is slightly awkward because the phone has to leave its home network temporarily, though iOS 14+ allows apps to do this programmatically with NEHotspotConfiguration without bothering the user.
Approach 3 — QR code + cloud registration
Some devices ship with a QR code on the label that encodes a unique device ID and a pairing token. The app scans the QR code, sends those values to a cloud backend, and the backend associates the device with the user’s account. The device itself connects to WiFi by having the user enter the password on the app and relaying it over the cloud connection, or by using one of the above hardware approaches for the initial credential handshake.
This is the model this app uses in its prototype flow.
The AddDeviceFlow in this app simulates the full user experience of a three-step pairing flow without implementing real Bluetooth or SoftAP communication. It demonstrates the UX pattern so the interface can be designed, tested, and iterated on before real hardware integration is added.
Step 1 — QR Scan
The user points their camera at the QR code on the appliance label. In production this would use AVCaptureSession with a metadata output tuned to qr codes. The decoded string would carry the device’s serial number, device type, and a one-time pairing token.
In the prototype, tapping “Tap to Simulate Scan” calls DummyDevice.generate(), which creates a DeviceInfo with a random serial number:
enum DummyDevice {
static func generate() -> DeviceInfo {
DeviceInfo(
id: "SN-\(Int.random(in: 100000...999999))",
name: "Smart Wall Oven",
type: "oven",
location: "",
compartments: []
)
}
}
Step 2 — Device Found
The scanned info is displayed for confirmation: device name, serial, and type. The user enters a location label (Kitchen, Garage) so they can identify the device later. The Continue button is disabled until the location field is non-empty, and the text field border highlights in accent blue when focused using @FocusState.
Step 3 — WiFi Credential Entry
The app shows a list of nearby networks (in production, this would be retrieved from the device over Bluetooth or SoftAP). The user selects their network and enters the password, which is securely transmitted to the device to complete the connection.
In production, this step would call either:
- A CoreBluetooth write to a custom characteristic on the device’s GATT profile, or
- An HTTP POST to the device’s SoftAP address, or
- A cloud API that relays the credentials to the device
Adding to the app
On completion, finishAdding() calls DeviceViewModel.addDevice(_:), which appends the device to the list and seeds placeholder state so it appears in the dashboard immediately without waiting for a server round-trip:
func finishAdding() {
let device = DeviceInfo(id: scanned.id, name: scanned.name,
type: scanned.type, location: location,
compartments: scanned.compartments)
devices.addDevice(device)
dismiss()
}
In DeviceViewModel.addDevice:
func addDevice(_ device: DeviceInfo) {
devices.append(device)
telemetry.record(.deviceAdded(deviceId: device.id, deviceType: device.type))
if device.isOvenType { ovenVM.seedState(for: device) }
else if device.isFridgeType { fridgeVM.seedState(for: device) }
else if device.isDishwasherType { dishwasherVM.seedState(for: device) }
}
The hardware complexity of real device pairing is significant, but the UX challenge — making it feel seamless to a non-technical user — is just as important. Designing and iterating on the flow before the hardware is finalised saves a lot of time, and that’s exactly what a prototype pairing flow enables.


Leave a Reply
You must be logged in to post a comment.