diff --git a/docs/dev/reference/changelog.md b/docs/dev/reference/changelog.md index 4b66fa417d..01215f1e15 100644 --- a/docs/dev/reference/changelog.md +++ b/docs/dev/reference/changelog.md @@ -42,6 +42,11 @@ date: "2024-09-18" # updated: "" # When the content was last entirely checked --- +{{% changelog color="added" title="Bluetooth provisioning" date="2025-06-02" %}} +Added support for Bluetooth Low Energy (BLE) provisioning, allowing devices to be set up over Bluetooth connection. +For an example implementation, see the [Flutter Provisioning package](https://github.com/viamrobotics/viam_flutter_provisioning/). +{{% /changelog %}} + {{% changelog color="removed" title="Frame tab removed, use Add Frame button" date="2025-05-15" %}} The frame tab no longer exists in the Viam app. diff --git a/docs/manage/fleet/provision/end-user-setup.md b/docs/manage/fleet/provision/end-user-setup.md index ac33af742a..ab247fe4e9 100644 --- a/docs/manage/fleet/provision/end-user-setup.md +++ b/docs/manage/fleet/provision/end-user-setup.md @@ -55,15 +55,18 @@ If you have already created a machine, select it. If you have not yet created a machine, click on **Add new smart machine** and give your machine a name. {{% /tablestep %}} {{% tablestep number=3 %}} -**Follow the instructions in the app** +**Turn on your machine and follow the app instructions** Turn on the smart machine you are attempting to connect to. Then leave the app and navigate to your mobile device's WiFi settings and connect to the WiFi hotspot your machine has created. You may need to wait a short time for your machine to boot and create its WiFi hotspot. + Your machine's WiFi hotspot name will begin with `viam-setup-`. Unless you have been given other instructions, the WiFi password for this hotspot network is `viamsetup`. -Once you are connected to your machine's WiFi hotspot return to the Viam mobile app. +Return to the Viam mobile app once connected + +You may need to wait a short time for your machine to boot and start its provisioning services. {{% /tablestep %}} {{% tablestep number=4 %}} **Provide the network information for the machine** @@ -72,6 +75,7 @@ In the mobile app, you will be prompted to provide the network information for t The machine will now disable the hotspot network and attempt to connect using the provided network information. If the machine cannot establish a connection using the provided network information, the machine will create the hotspot again and prompt you to re-enter the network information until a connection is successfully established. + {{% /tablestep %}} {{% tablestep number=5 %}} **Wait for machine to complete setup** @@ -135,6 +139,59 @@ Note that any features that require internet access will not function if the con {{% /tablestep %}} {{< /table >}} +## Set up your machine using a custom Flutter app + +The [Flutter Provisioning package](https://github.com/viamrobotics/viam_flutter_provisioning/) shows an example for Bluetooth provisioning. + +When developing your own application, if you support both Bluetooth and WiFi Hotspot provisioning, make the app choose the best available method. +We recommend using Bluetooth by default for a smoother setup experience. + +### App Development Considerations + +When developing mobile apps with Bluetooth provisioning, ensure your app requests appropriate Bluetooth permissions. + +## Troubleshooting + +### Bluetooth connection issues + +If you're having trouble with Bluetooth provisioning: + +1. Verify the device supports Bluetooth Low Energy (BLE) + +1. **Check Bluetooth permissions**: Ensure the Viam mobile app has Bluetooth permissions enabled on your device. + +1. **Verify Bluetooth is enabled**: Make sure Bluetooth is turned on in your mobile device settings. + +1. **Check device compatibility**: Ensure your mobile device supports Bluetooth Low Energy (BLE). + +1. **Restart Bluetooth**: Try turning Bluetooth off and on again on your mobile device. + +If you can open a terminal on the machine: + +1. Check if Bluetooth is available: + + ```sh {class="command-line" data-prompt="$"} + bluetoothctl list + ``` + +1. Verify Bluetooth service status: + + ```sh {class="command-line" data-prompt="$"} + sudo systemctl status bluetooth + ``` + +### WiFi connection issues + +If your machine cannot connect to your WiFi network: + +1. **Check network credentials**: Verify that the WiFi network name (SSID) and password are correct. + +1. **Check network compatibility**: Ensure your WiFi network is compatible with your machine's WiFi adapter. + +1. **Check signal strength**: Make sure your machine is within range of your WiFi router. + +1. **Try a different network**: If possible, try connecting to a different WiFi network to isolate the issue. + ## Next Steps You can now use your machine. diff --git a/docs/manage/fleet/provision/setup.md b/docs/manage/fleet/provision/setup.md index edd1670f6b..603792ba9e 100644 --- a/docs/manage/fleet/provision/setup.md +++ b/docs/manage/fleet/provision/setup.md @@ -34,10 +34,10 @@ To parse the readings and provide tailored guidance to a ship's captain, the com By having the end customer set up the machine, the company: - eliminates per-device setup and individualization at the factory -- allows for tailored configurations per customer as needed - allows customer to provide their own WiFi credentials +- allows for tailored configurations per customer as needed -This guide will show you how to install and configure `viam-agent`. +This guide shows you how to install and configure `viam-agent`. ## Prerequisites @@ -60,9 +60,12 @@ For Bullseye, the installation of `viam-agent` changes the network configuration {{< /alert >}} -## Decide on the provisioning method +## Choose provisioning methods -You can choose to let your end users complete machine setup by using a captive web portal or a mobile app. +You can let your end users complete machine setup over WiFi or Bluetooth: + +- **WiFi Hotspot Provisioning**: When device boots, it creates a temporary WiFi hotspot that users connect to for setup either by using a captive web portal or a mobile app. Be aware that the WiFi hotspot is open to anyone. +- **Bluetooth Low Energy (BLE) Provisioning**: When device boots, it searches for Bluetooth connections and a user connects to it using a mobile app. If you choose to have a mobile app experience, you can use the [Viam mobile app](/manage/troubleshoot/teleoperate/default-interface/#viam-mobile-app) or create your own custom mobile app using the [Flutter SDK](https://flutter.viam.dev/viam_protos.provisioning.provisioning/ProvisioningServiceClient-class.html) or the [TypeScript SDK](https://github.com/viamrobotics/viam-typescript-sdk/blob/main/src/app/provisioning-client.ts) to connect to `viam-agent` and provision your machines. @@ -74,100 +77,10 @@ If you do not yet have a fragment, follow the steps to [Create a configuration f If you are not using Flutter or TypeScript and would like to use provisioning, please [contact us](mailto:support@viam.com). {{< /alert >}} -If you choose to use the captive web portal, you can optionally create a machine in advance and provide its machine cloud credentials file at /etc/viam.json. - -You can get the machine cloud credentials by clicking the copy icon next to **Machine cloud credentials** in the part status dropdown to the right of your machine's name on the top of the page. - -{{}} - -{{% expand "Want to create a machine and obtain its machine cloud credentials programmatically?" %}} - -You can use the [Fleet Management API](/dev/reference/apis/fleet/) to create machines, and obtain their machine cloud credentials: - -```python {class="line-numbers linkable-line-numbers"} -import asyncio -import requests - -from viam.rpc.dial import DialOptions, Credentials -from viam.app.viam_client import ViamClient -from viam.app.app_client import APIKeyAuthorization - -# Replace "" (including brackets) with your API key -API_KEY = "" -# Replace "" (including brackets) with your API key ID -API_KEY_ID = "" -# The id of the location to create the machine in -LOCATION_ID = "" -# The name for the machine to create -MACHINE_NAME = "" - - -async def connect() -> ViamClient: - dial_options = DialOptions( - credentials=Credentials( - type="api-key", - payload=API_KEY, - ), - auth_entity=API_KEY_ID - ) - return await ViamClient.create_from_dial_options(dial_options) - - -async def main(): - - # Make a ViamClient - viam_client = await connect() - # Instantiate an AppClient called "cloud" - # to run fleet management API methods on - cloud = viam_client.app_client - new_machine_id = await cloud.new_robot( - name=MACHINE_NAME, location_id=LOCATION_ID) - print("Machine created: " + new_machine_id) - list_of_parts = await cloud.get_robot_parts( - robot_id=new_machine_id) - print("Part id: " + list_of_parts[0].id) - - org_list = await cloud.list_organizations() - print(org_list[0].id) - - auth = APIKeyAuthorization( - role="owner", - resource_type="robot", - resource_id=new_machine_id - ) - api_key, api_key_id = await cloud.create_key( - org_list[0].id, [auth], "test_provisioning_key") - print(api_key, api_key_id) - - headers = { - 'key_id': api_key_id, - 'key': api_key - } - params = { - "client": 'true', - "id": list_of_parts[0].id - } - res = requests.get( - 'https://app.viam.com/api/json1/config', - params=params, - headers=headers, - timeout=10 - ) - print(res.text) - - with open("viam.json", "w") as text_file: - text_file.write(res.text) - - viam_client.close() - -if __name__ == '__main__': - asyncio.run(main()) -``` - -{{% /expand%}} - ## Configure defaults +The defaults file allows you to configure the provisioning experience for the users setting up their machines. + {{< table >}} {{% tablestep number=1 %}} @@ -191,6 +104,9 @@ Create a defaults file called viam-defaults.json with the following "hotspot_prefix": "", # machine creates a hotspot during setup "disable_captive_portal_redirect": false, # set to true if using a mobile app "hotspot_password": "", # password for the hotspot + "disable_bt_provisioning": false, # set to true to disable Bluetooth provisioning + "disable_wifi_provisioning": false, # set to true to disable WiFi hotspot provisioning + "bluetooth_adapter_name": "", # optional: specify Bluetooth adapter for machines with multiple adapters "turn_on_hotspot_if_wifi_has_no_internet": false, "offline_before_starting_hotspot_minutes": "3m30s", "user_idle_minutes": "2m30s", @@ -212,6 +128,8 @@ Create a defaults file called viam-defaults.json with the following "hotspot_prefix": "skywalker-setup", "disable_captive_portal_redirect": false, "hotspot_password": "skywalker123", + "disable_bt_provisioning": false, + "disable_wifi_provisioning": false, "turn_on_hotspot_if_wifi_has_no_internet": false, "offline_before_starting_hotspot_minutes": "3m30s", "user_idle_minutes": "2m30s", @@ -235,9 +153,12 @@ It also configures timeouts to control how long `viam-agent` waits for a valid l | `model` | string | Optional | Purely informative. May be displayed on captive portal or provisioning app. Default: `"custom"`. | | `fragment_id` | string | Optional | The `fragment_id` of the fragment to configure machines with. Required when using the Viam mobile app for provisioning. The Viam mobile app uses the fragment to configure the machine. | | `hotspot_interface` | string | Optional | The interface to use for hotspot/provisioning/wifi management. Example: `"wlan0"`. Default: first discovered 802.11 device. | -| `hotspot_prefix` | string | Optional | `viam-agent` will prepend this to the hostname of the device and use the resulting string for the provisioning hotspot SSID. Default: `"viam-setup"`. | +| `hotspot_prefix` | string | Optional | `viam-agent` will prepend this to the hostname of the device and use the resulting string for the provisioning hotspot SSID. For bluetooth provisioning the device name will be the hotspot prefix and the model (`-`). Default: `"viam-setup"`. | | `hotspot_password` | string | Optional | The Wifi password for the provisioning hotspot. Default: `"viamsetup"`. | | `disable_captive_portal_redirect` | boolean | Optional | By default, all DNS lookups are redirected to the "sign in" portal, which can cause mobile devices to automatically display the portal. When set to true, only DNS requests for domains ending in .setup, like `viam.setup` are redirected, preventing the portal from appearing unexpectedly, especially convenient when using a mobile app for provisioning. Default: `false`. | +| `disable_bt_provisioning` | boolean | Optional | When set to true, disables Bluetooth provisioning. The machine will not advertise Bluetooth services for provisioning. Default: `false`. | +| `disable_wifi_provisioning` | boolean | Optional | When set to true, disables WiFi hotspot provisioning. The machine will not create a WiFi hotspot for provisioning. Default: `false`. | +| `bluetooth_adapter_name` | string | Optional | For machines with multiple Bluetooth adapters, specify which adapter to use for provisioning. If not specified, the first available Bluetooth adapter will be used. Example: `"hci0"`. Default: `""` (auto-detect). | | `turn_on_hotspot_if_wifi_has_no_internet` | boolean | Optional | By default, the device connects to a single prioritized WiFi network (provided during provisioning) and is considered online even if the global internet is not reachable. When `turn_on_hotspot_if_wifi_has_no_internet` is true and the primary network lacks internet connectivity, the device will try all configured networks and only mark itself as online if it successfully connects to the internet. Default: `false`. | | `offline_before_starting_hotspot_minutes` | integer | Optional | Will only enter provisioning mode (hotspot) after being disconnected longer than this time. Useful on flaky connections, or when part of a system where the device may start quickly, but the wifi/router may take longer to be available. Default: `2` (2 minutes). | | `user_idle_minutes` | integer | Optional | Amount of time before considering a user (using the captive web portal or provisioning app) idle, and resuming normal behavior. Used to avoid interrupting provisioning mode (for example for network tests/retries) when a user might be busy entering details. Default: `5` (5 minutes). | @@ -270,6 +191,8 @@ The following configuration defines the connection information and credentials f "hotspot_prefix": "skywalker-setup", "disable_captive_portal_redirect": false, "hotspot_password": "skywalker123", + "disable_bt_provisioning": false, + "disable_wifi_provisioning": false, "turn_on_hotspot_if_wifi_has_no_internet": false, "offline_before_starting_hotspot_minutes": "3m30s", "user_idle_minutes": "2m30s", @@ -304,6 +227,100 @@ The following configuration defines the connection information and credentials f {{% /tablestep %}} {{< /table >}} +## (Optional) Create a machine in advance + +If you provision devices using a captive web portal, you can optionally create a machine in advance and provide its machine cloud credentials file at /etc/viam.json. + +You can get the machine cloud credentials by clicking the copy icon next to **Machine cloud credentials** in the part status dropdown to the right of your machine's name on the top of the page. + +{{}} + +{{% expand "Want to create a machine and obtain its machine cloud credentials programmatically?" %}} + +You can use the [Fleet Management API](/dev/reference/apis/fleet/) to create machines, and obtain their machine cloud credentials: + +```python {class="line-numbers linkable-line-numbers"} +import asyncio +import requests + +from viam.rpc.dial import DialOptions, Credentials +from viam.app.viam_client import ViamClient +from viam.app.app_client import APIKeyAuthorization + +# Replace "" (including brackets) with your API key +API_KEY = "" +# Replace "" (including brackets) with your API key ID +API_KEY_ID = "" +# The id of the location to create the machine in +LOCATION_ID = "" +# The name for the machine to create +MACHINE_NAME = "" + + +async def connect() -> ViamClient: + dial_options = DialOptions( + credentials=Credentials( + type="api-key", + payload=API_KEY, + ), + auth_entity=API_KEY_ID + ) + return await ViamClient.create_from_dial_options(dial_options) + + +async def main(): + + # Make a ViamClient + viam_client = await connect() + # Instantiate an AppClient called "cloud" + # to run fleet management API methods on + cloud = viam_client.app_client + new_machine_id = await cloud.new_robot( + name=MACHINE_NAME, location_id=LOCATION_ID) + print("Machine created: " + new_machine_id) + list_of_parts = await cloud.get_robot_parts( + robot_id=new_machine_id) + print("Part id: " + list_of_parts[0].id) + + org_list = await cloud.list_organizations() + print(org_list[0].id) + + auth = APIKeyAuthorization( + role="owner", + resource_type="robot", + resource_id=new_machine_id + ) + api_key, api_key_id = await cloud.create_key( + org_list[0].id, [auth], "test_provisioning_key") + print(api_key, api_key_id) + + headers = { + 'key_id': api_key_id, + 'key': api_key + } + params = { + "client": 'true', + "id": list_of_parts[0].id + } + res = requests.get( + 'https://app.viam.com/api/json1/config', + params=params, + headers=headers, + timeout=10 + ) + print(res.text) + + with open("viam.json", "w") as text_file: + text_file.write(res.text) + + viam_client.close() + +if __name__ == '__main__': + asyncio.run(main()) +``` + +{{% /expand%}} + ## Install `viam-agent` `viam-agent` is a self-updating service manager that maintains the lifecycle for several Viam services and keeps them updated. @@ -470,6 +487,33 @@ Some systems can't scan for WiFi networks while in hotspot mode, meaning they wo The `retry_connection_timeout_minutes` causes your device to exit hotspot mode, at which point your device will be able to detect newly available networks. If your device does not connect to your network, adjust the `retry_connection_timeout_minutes` value in the [`defaults` file](/manage/fleet/provision/setup/#configure-defaults). +### WiFi provisioning not working + +WiFi provisioning may be less reliable in environments with many WiFi networks. +If possible, use Bluetooth provisioning or move to an area with fewer WiFi networks in range. + +### Bluetooth provisioning not working + +If Bluetooth provisioning is not working, check the following: + +1. **Bluetooth adapter availability**: Ensure your device has a working Bluetooth adapter. You can check this with: + + ```sh {class="command-line" data-prompt="$"} + bluetoothctl list + ``` + +1. **Bluetooth service status**: Verify the Bluetooth service is running: + + ```sh {class="command-line" data-prompt="$"} + sudo systemctl status bluetooth + ``` + +1. **Multiple adapters**: If your device has multiple Bluetooth adapters, specify which one to use with the `bluetooth_adapter_name` configuration option. + +1. **Mobile device compatibility**: Ensure your mobile device supports Bluetooth Low Energy (BLE) and has the necessary permissions enabled for the provisioning app. + +1. **Configuration check**: Verify that `disable_bt_provisioning` is set to `false` in your configuration. + ### Test GRPC components of the provisioning service If you need to test the GRPC components of the provisioning service, there is a CLI client available. @@ -484,7 +528,7 @@ The following steps show you the end user experience using the mobile app or the For a guide you can give to end users for setting up their machine, see [Setup machine](/manage/fleet/provision/end-user-setup/). {{< tabs >}} -{{% tab name="Mobile app" min-height="703px" %}} +{{% tab name="Mobile app (WiFi)" min-height="703px" %}} {{