Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,18 @@
"request": "launch",
"type": "dart",
"flutterMode": "release"
}
},
{
"name": "viam_robot_example_app",
"cwd": "example/viam_robot_example_app",
"request": "launch",
"type": "dart"
},
{
"name": "hotspot_provisioning_example_app",
"cwd": "example/hotspot_provisioning_example_app",
"request": "launch",
"type": "dart"
},
]
}
}
4 changes: 4 additions & 0 deletions example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,7 @@ This directory contains examples on how to use the Viam Flutter SDK.
- Start using the Viam SDK from scratch! This example will walk you through the canonical way of using the SDK, using API Keys with a fully documented example app.
- [Viam Robot Example App](https://github.com/viamrobotics/viam-flutter-sdk/tree/main/example/viam_robot_example_app)
- This example uses Location secrets to connect to a robot. It has a bit more customization, but is not as well documented.

- [Hotspot Provisioning Example App](https://github.com/viamrobotics/viam-flutter-sdk/tree/main/example/hotspot_provisioning_example_app)
- This example demonstrates how to use the Hotspot Provisioning Widget to provision new machines, reconnect existing machines to new networks, and replace hardware while preserving machine configurations.

160 changes: 160 additions & 0 deletions example/hotspot_provisioning_example_app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# Do not remove or rename entries in this file, only add new ones
# See https://github.com/flutter/flutter/issues/128635 for more context.

# Miscellaneous
*.class
*.lock
*.log
*.pyc
*.swp
.DS_Store
.atom/
.build/
.buildlog/
.history
.svn/
.swiftpm/
migrate_working_dir/

# As packages are no longer pinned, we use a lockfile for testing locally.
# When unpinning packages, Using lockfiles ensures that failures in PRs are
# actually due to those PRs, not due to a package being updated.
!/pubspec.lock

# IntelliJ related
*.iml
*.ipr
*.iws
.idea/

# Visual Studio Code related
.classpath
.project
.settings/
.vscode/*
.ccls-cache

# Flutter repo-specific
/bin/internal/engine.version
/bin/cache/
/bin/internal/bootstrap.bat
/bin/internal/bootstrap.sh
/bin/internal/engine.realm
/bin/mingit/
/dev/benchmarks/mega_gallery/
/dev/bots/.recipe_deps
/dev/bots/android_tools/
/dev/devicelab/ABresults*.json
/dev/docs/doc/
/dev/docs/api_docs.zip
/dev/docs/flutter.docs.zip
/dev/docs/lib/
/dev/docs/pubspec.yaml
/dev/integration_tests/**/xcuserdata
/dev/integration_tests/**/Pods
/packages/flutter/coverage/
version
analysis_benchmark.json

# packages file containing multi-root paths
.packages.generated

# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
**/generated_plugin_registrant.dart
.packages
.pub-preload-cache/
.pub-cache/
.pub/
build/
flutter_*.png
linked_*.ds
unlinked.ds
unlinked_spec.ds

# Android related
**/android/**/gradle-wrapper.jar
.gradle/
**/android/captures/
**/android/gradlew
**/android/gradlew.bat
**/android/**/GeneratedPluginRegistrant.java
**/android/key.properties
*.jks
local.properties
**/.cxx/
/android/app/debug
/android/app/profile
/android/app/release

# iOS/Xcode related
**/ios/**/*.mode1v3
**/ios/**/*.mode2v3
**/ios/**/*.moved-aside
**/ios/**/*.pbxuser
**/ios/**/*.perspectivev3
**/ios/**/*sync/
**/ios/**/.sconsign.dblite
**/ios/**/.tags*
**/ios/**/.vagrant/
**/ios/**/DerivedData/
**/ios/**/Icon?
**/ios/**/Pods/
**/ios/**/.symlinks/
**/ios/**/profile
**/ios/**/xcuserdata
**/ios/.generated/
**/ios/Flutter/.last_build_id
**/ios/Flutter/App.framework
**/ios/Flutter/Flutter.framework
**/ios/Flutter/Flutter.podspec
**/ios/Flutter/Generated.xcconfig
**/ios/Flutter/ephemeral
**/ios/Flutter/app.flx
**/ios/Flutter/app.zip
**/ios/Flutter/flutter_assets/
**/ios/Flutter/flutter_export_environment.sh
**/ios/ServiceDefinitions.json
**/ios/Runner/GeneratedPluginRegistrant.*

# macOS
**/Flutter/ephemeral/
**/Pods/
**/macos/Flutter/GeneratedPluginRegistrant.swift
**/macos/Flutter/ephemeral
**/xcuserdata/

# Windows
**/windows/flutter/ephemeral/
**/windows/flutter/generated_plugin_registrant.cc
**/windows/flutter/generated_plugin_registrant.h
**/windows/flutter/generated_plugins.cmake

# Linux
**/linux/flutter/ephemeral/
**/linux/flutter/generated_plugin_registrant.cc
**/linux/flutter/generated_plugin_registrant.h
**/linux/flutter/generated_plugins.cmake

# Coverage
coverage/

# Symbols / Obfuscation
app.*.symbols
app.*.map.json

# Environment
*.env

# Exceptions to above rules
!**/ios/**/default.mode1v3
!**/ios/**/default.mode2v3
!**/ios/**/default.pbxuser
!**/ios/**/default.perspectivev3
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
!/dev/ci/**/Gemfile.lock
!.vscode/settings.json
46 changes: 46 additions & 0 deletions example/hotspot_provisioning_example_app/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Viam Flutter Hotspot Provisioning Example
This example project demonstrates how to use the Viam Flutter Hotspot Provisioning Widget to connect robots to the Viam platform.

## Getting Started

1. Ensure you have the required Viam API credentials configured in `lib/consts.dart`. This would be the `apiKeyId`, `apiKey`, and `organizationId`.
2. Ensure you have both `hotspotPrefix` and `hotspotPassword` configured in `lib/consts.dart`.
- These values should match the prefix and password that were set in the viam-defaults.json.
- See the [Machine Setup section](../../README.md#machine-setup) for more info on the viam-defaults.json.
2. Run the example app by running `flutter run`
3. Choose "Provision New Machine", "Reconnect Machine", or "Replace Hardware"
4. Follow the on-screen instructions

## Use Cases
The app showcases three main use cases:

### 1. Provision a new machine
This flow demonstrates how to connect a **new robot** to the Viam platform for the first time. The process:
- Creates a new robot instance in your Viam organization
- Initiates the hotspot provisioning flow to establish the initial connection
- Guides the user through the connection process
<img src="../../screenshots/provisioning_demo.gif" width="250" alt="Provisioning Flow">

### 2. Reconnect an existing machine
This flow demonstrates how to **reconnect an existing robot** to a new wifi network. The process:
- Lists all existing robots in your Viam organization
- Shows their current connection status (online/offline/awaiting setup)
- Allows you to select any robot and initiate the reconnection process
- Uses the same hotspot provisioning flow but with an existing robot instance
<img src="../../screenshots/reconnect_demo.gif" width="250" alt="Re-provisioning Flow">

### 3. Replace hardware
This flow demonstrates how to **replace hardware** while preserving the robot's configuration. The process:
- Saves the robot configuration from the old hardware
- Creates a new robot instance for the replacement hardware
- Applies the saved configuration to the new robot during provisioning
- Ensures the new hardware has the same settings as the old hardware

## How It Works

All three flows utilize the same underlying `HotspotProvisioningFlow` widget, which:
1. Connects to the robot's hotspot network
2. Configures the robot's network settings
3. Establishes a connection to the Viam platform
4. Applies saved robot configuration (when replacing hardware)
5. Returns the connection status
28 changes: 28 additions & 0 deletions example/hotspot_provisioning_example_app/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.

# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml

linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at https://dart.dev/lints.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule

# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
13 changes: 13 additions & 0 deletions example/hotspot_provisioning_example_app/android/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java

# Remember to never publicly share your keystore.
# See https://flutter.dev/to/reference-keystore
key.properties
**/*.keystore
**/*.jks
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
plugins {
id "com.android.application"
id "kotlin-android"
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id "dev.flutter.flutter-gradle-plugin"
}

android {
namespace = "com.example.viam_example_app"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion

compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8
}

defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "com.example.viam_example_app"
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = 29
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
versionName = flutter.versionName
}

buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig = signingConfigs.debug
}
}
}

flutter {
source = "../.."
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<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"/>
<application
android:label="Hotspot Provisioning Example"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:taskAffinity=""
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
<!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility and
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.

In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
<queries>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT"/>
<data android:mimeType="text/plain"/>
</intent>
</queries>
</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.example.viam_example_app

import io.flutter.embedding.android.FlutterActivity

class MainActivity: FlutterActivity()
Loading