A Flutter package for provisioning Viam robots using hotspot connections. This widget provides a complete flow for connecting (or reconnecting) to a robot's hotspot, selecting a network, and provisioning the robot with network credentials.
flutter pub add viam_flutter_hotspot_provisioning_widget
Before using this widget, you must flash your device with the Viam defaults configuration:
- 
Flash your Device: Use the Viam CLI to flash your device: For more instructions on device, see the Viam Documentation for an example on flashing a Raspberry Pi. 
- 
Configure provisioning defaults.: Create a provisioning configuration file ( viam-defaults.json), by specifying at least the following info:Important: The hotspot_prefixmust be at least 3 characters long.{ "network_configuration": { "hotspot_prefix": "your-hotspot-prefix", "disable_captive_portal_redirect": true, "hotspot_password": "your-hotspot-password", "fragment_id": "your-fragment-id", } }For more instructions on setting up the config, see the Viam Documentation. 
- 
Install viam-agent: Run the pre-install script and pass in the location of your viam-defaults.json. This way your machine will know the hotspot prefix and password: sudo ./preinstall.sh For more instructions on running the pre-install script, see the Viam Documentation. 
Add the following to your Entitlements:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>com.apple.developer.networking.HotspotConfiguration</key>
    <true/>
    <key>com.apple.developer.networking.wifi-info</key>
    <true/>
</dict>
</plist>Add the following to your Info.plist:
<key>NSBluetoothAlwaysUsageDescription</key>
<string>Finding and connecting nearby local bluetooth devices</string>Add the following permissions to your android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>Before starting the provisioning flow, you need to:
- Initialize Viam instance: Create a Viam instance with your API credentials
- Create or get a robot: Either create a new robot or retrieve an existing one from your Viam organization
- Get the main part: Retrieve the main robot part that will be provisioned
These steps are required because the widget needs a valid robot and Viam instance to communicate with the Viam cloud and provision the robot.
import 'package:viam_flutter_hotspot_provisioning_widget/viam_flutter_hotspot_provisioning_widget.dart';
// 1. Initialize a Viam instance with your API credentials
final viam = await Viam.withApiKey(apiKeyId, apiKey);
// 2. Create a new robot or get an existing one
final robot = await viam.appClient.getRobot(robotId);
// OR create a new robot:
// final robotId = await viam.appClient.newMachine(robotName, locationId);
// final robot = await viam.appClient.getRobot(robotId);
// 3. Get the main robot part
final mainPart = (await viam.appClient.listRobotParts(robot.id))
    .firstWhere((element) => element.mainPart);
// 4. Start the provisioning flow
// Option 1: Use hardcoded credentials
final result = await HotspotProvisioningFlow.show(
  context,
  robot: robot,
  viam: viam,
  mainPart: mainPart,
  fragmentId: 'your-fragment-id', // Optional, if null, the fragmentId will be read from the device.
  hotspotPrefix: 'your-hotspot-prefix',  // Must match viam-defaults.json & must be at least 3 characters long 
  hotspotPassword: 'your-hotspot-password', // Must match viam-defaults.json
  promptForCredentials: false, // Use hardcoded credentials
  overrideFragment: true, // Set to true if you want to override the fragment, common for new machines. 
  replaceHardware: false, // Set to true when replacing hardware and want to apply saved robot config
  robotConfig: null, // Optional, pass saved robot config when replaceHardware is true
);
// Option 2: Prompt user for credentials
final result = await HotspotProvisioningFlow.show(
  context,
  robot: robot,
  viam: viam,
  mainPart: mainPart,
  fragmentId: 'your-fragment-id',
  promptForCredentials: true, // This will show a credential input screen
  overrideFragment: true, // Set to true if you want to override the fragment, common for new machines.
  replaceHardware: false, // Set to true when replacing hardware and want to apply saved robot config
  robotConfig: null, // Optional, pass saved robot config when replaceHardware is true
);
// 5. Handle the result
if (result != null) {
  if (result.status == RobotStatus.online) {
    // Robot successfully provisioned. Robot is online
    print('Robot ${result.robot.name} is online!');
  } else {
    // Provisioning failed or timed out. Robot is offline
    print('Robot provisioning failed');
  }
}The HotspotProvisioningFlow now supports two ways to provide hotspot credentials:
Pass the credentials directly as parameters.
final result = await HotspotProvisioningFlow.show(
  context,
  robot: robot,
  viam: viam,
  mainPart: mainPart,
  hotspotPrefix: 'your-prefix',
  hotspotPassword: 'your-password',
  promptForCredentials: false, // Use hardcoded credentials
  overrideFragment: true, // Set to true if you want to override the fragment, common for new machines.
  replaceHardware: false, // Set to true when replacing hardware and want to apply saved robot config
  robotConfig: null, // Optional, pass saved robot config when replaceHardware is true
);Prompt the user to enter credentials through a simple input screen.
final result = await HotspotProvisioningFlow.show(
  context,
  robot: robot,
  viam: viam,
  mainPart: mainPart,
  promptForCredentials: true, // This will show a credential input screen
  overrideFragment: true, // Set to true if you want to override the fragment, common for new machines.
  replaceHardware: false, // Set to true when replacing hardware and want to apply saved robot config
  robotConfig: null, // Optional, pass saved robot config when replaceHardware is true
);When promptForCredentials is true, the hotspotPrefix and hotspotPassword parameters are optional and will be ignored.
When replacing hardware, you can preserve the robot's configuration by setting replaceHardware: true and passing the saved robot configuration to robotConfig.
Important: To replace hardware, you need to:
- Create a new robot instance for the replacement hardware
- Save the configuration from the old robot's main part
- Apply the saved configuration to the new robot during provisioning
// Get the saved robot configuration from the old robot
final savedRobotConfig = oldRobotPart.robotConfig.toMap();
// Apply the saved configuration to the new robot
final result = await HotspotProvisioningFlow.show(
  context,
  robot: newRobot, // Pass in the new replacement robot
  viam: viam,
  mainPart: newMainPart, // Pass in the new replacement mainPart
  fragmentId: 'your-fragment-id',
  hotspotPrefix: 'your-hotspot-prefix',
  hotspotPassword: 'your-hotspot-password',
  promptForCredentials: false,
  overrideFragment: false,
  replaceHardware: true, // Enable hardware replacement mode
  robotConfig: savedRobotConfig, // Pass the saved configuration
);The main widget that handles the entire provisioning flow.
What you need to pass into the widget:
- robot: The Viam robot to provision
- viam: The Viam SDK instance
- fragmentId: The optional fragment ID you want to configure this robot with.
- mainPart: The main robot part
- hotspotPrefix: The SSID prefix for the robot's hotspot. This prefix must match the prefix you set in the viam-defaults.json. The hotspot prefix must be at least 3 characters long. (Optional when- promptForCredentialsis true)
- hotspotPassword: The password for the robot's hotspot. This password must match the password you set in the viam-defaults.json. (Optional when- promptForCredentialsis true)
- promptForCredentials: Whether to show a credential input screen for the user to enter hotspot prefix and password. When true,- hotspotPrefixand- hotspotPasswordare optional.
- overrideFragment: Whether this is a new machine being provisioned for the first time. Set to- truefor new machines,- falsefor reconnecting existing machines. When- true, the fragment override will be performed after successful provisioning.
- replaceHardware: Whether you are replacing hardware and want to apply a saved robot configuration. Set to- truewhen replacing hardware,- falseotherwise.
- robotConfig: Optional saved robot configuration to apply when- replaceHardwareis- true. Pass the configuration from the old robot that you want to apply to the new robot. Can be omitted when- replaceHardwareis- false.
Contains the result of the provisioning attempt:
- robot: The robot that was provisioned
- status: The robot's status (online/offline)
- Manual Network Entry: Fallback option to manually enter network credentials when automatic detection fails
- Error Handling: User-friendly error messages for common issues like incorrect hotspot password.
- Network Type Indicators: Icons to distinguish between public and private Wi-Fi networks
- Public Network Support: Connect to public networks that don't require a password
This package depends on:
- plugin_wifi_connect: For Wi-Fi connection functionality
- viam_sdk: For Viam robot communication
- permission_handler: For platform permissions
- flutter_platform_widgets: For platform-specific UI
- provider: For state management
See the example/hotspot_provisioning directory for a complete working example app that allows you to provision Viam devices.
- Do not connect manually: Users should not connect to the hotspot through their device's Wi-Fi settings. The app will prompt them to connect when ready.
- Hotspot credentials: The hotspot prefix and password must match what's configured in your viam-defaults.jsonfile.
- 
Cannot connect to hotspot: Ensure the hotspot prefix and password match your viam-defaults.jsonconfiguration.
- 
Permission errors: Make sure you've added the required iOS entitlements and permissions. 
- 
Robot not appearing: Verify your robot is properly flashed with the Viam image and viam-defaults.json.
- 
Network not found: Ensure your robot's hotspot is active and broadcasting. 
See the LICENSE file for license rights and limitations.
