Skip to content

Commit 2861f45

Browse files
authored
feat: add Switch component, ViamSwitchWidget (#348)
* feat: add switch component * feat: create ViamSwitchWidget * feat: add SwitchScreen to robot_example_app * chore: add test for switch component * refactor: run formatter * fix: remove commented out unused code in example app
1 parent ea60b51 commit 2861f45

File tree

14 files changed

+498
-3
lines changed

14 files changed

+498
-3
lines changed

example/viam_robot_example_app/lib/main.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import 'package:flutter/material.dart';
1+
import 'package:flutter/material.dart' hide Switch;
22
import 'package:flutter_dotenv/flutter_dotenv.dart';
33
import 'package:viam_sdk/viam_sdk.dart';
44
import 'package:viam_sdk/widgets.dart';
@@ -95,6 +95,7 @@ class _MyHomePageState extends State<MyHomePage> {
9595
PowerSensor.subtype.resourceSubtype,
9696
Sensor.subtype.resourceSubtype,
9797
Servo.subtype.resourceSubtype,
98+
Switch.subtype.resourceSubtype,
9899
].contains(rname.subtype);
99100
}
100101

@@ -131,6 +132,9 @@ class _MyHomePageState extends State<MyHomePage> {
131132
if (rname.subtype == Servo.subtype.resourceSubtype) {
132133
return ServoScreen(servo: Servo.fromRobot(_robot, rname.name), resourceName: rname);
133134
}
135+
if (rname.subtype == Switch.subtype.resourceSubtype) {
136+
return SwitchScreen(nswitch: Switch.fromRobot(_robot, rname.name), resourceName: rname);
137+
}
134138
if (rname.subtype == MovementSensor.subtype.resourceSubtype) {
135139
return MovementSensorScreen(movementSensor: MovementSensor.fromRobot(_robot, rname.name), resourceName: rname);
136140
}

example/viam_robot_example_app/lib/screens/screens.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ export 'power_sensor.dart';
77
export 'sensor.dart';
88
export 'servo.dart';
99
export 'stream.dart';
10+
export 'switch.dart';
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import 'package:flutter/material.dart' hide Switch;
2+
import 'package:flutter/services.dart';
3+
4+
import 'package:viam_sdk/viam_sdk.dart';
5+
import 'package:viam_sdk/widgets.dart';
6+
7+
class SwitchScreen extends StatelessWidget {
8+
final Switch nswitch;
9+
final ResourceName resourceName;
10+
11+
const SwitchScreen({super.key, required this.nswitch, required this.resourceName});
12+
13+
@override
14+
Widget build(BuildContext context) {
15+
return Scaffold(
16+
appBar: AppBar(
17+
title: Text(resourceName.name.toUpperCase()),
18+
),
19+
body: Center(
20+
child: Column(
21+
children: [
22+
const SizedBox(height: 8),
23+
Text(
24+
'${resourceName.namespace}:${resourceName.type}:${resourceName.subtype}/${resourceName.name}',
25+
style: const TextStyle(fontWeight: FontWeight.w300),
26+
),
27+
const SizedBox(height: 8),
28+
ViamSwitchWidget(nswitch: nswitch),
29+
],
30+
),
31+
),
32+
);
33+
}
34+
}

example/viam_robot_example_app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
ignoresPersistentStateOnLaunch = "NO"
4949
debugDocumentVersioning = "YES"
5050
debugServiceExtension = "internal"
51+
enableGPUValidationMode = "1"
5152
allowLocationSimulation = "YES">
5253
<BuildableProductRunnable
5354
runnableDebuggingMode = "0">
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
import Cocoa
22
import FlutterMacOS
33

4-
@NSApplicationMain
4+
@main
55
class AppDelegate: FlutterAppDelegate {
66
override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
77
return true
88
}
9+
10+
override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
11+
return true
12+
}
913
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import 'package:grpc/grpc_connection_interface.dart';
2+
3+
import '../../gen/common/v1/common.pb.dart';
4+
import '../../gen/component/nswitch/v1/switch.pbgrpc.dart';
5+
import '../../gen/google/protobuf/struct.pb.dart';
6+
import '../../resource/base.dart';
7+
import '../../utils.dart';
8+
import 'switch.dart';
9+
10+
/// {@category Components}
11+
/// gRPC client for the [Switch] component.
12+
class SwitchClient extends Switch implements ResourceRPCClient {
13+
@override
14+
final String name;
15+
16+
@override
17+
ClientChannelBase channel;
18+
19+
@override
20+
SwitchServiceClient get client => SwitchServiceClient(channel);
21+
22+
SwitchClient(this.name, this.channel);
23+
24+
@override
25+
Future<void> setPosition(int position, {Map<String, dynamic>? extra}) async {
26+
final request = SetPositionRequest()
27+
..name = name
28+
..position = position
29+
..extra = extra?.toStruct() ?? Struct();
30+
await client.setPosition(request);
31+
}
32+
33+
@override
34+
Future<int> getPosition({Map<String, dynamic>? extra}) async {
35+
final request = GetPositionRequest()
36+
..name = name
37+
..extra = extra?.toStruct() ?? Struct();
38+
final response = await client.getPosition(request);
39+
return response.position;
40+
}
41+
42+
@override
43+
Future<int> getNumberOfPositions({Map<String, dynamic>? extra}) async {
44+
final request = GetNumberOfPositionsRequest()
45+
..name = name
46+
..extra = extra?.toStruct() ?? Struct();
47+
final response = await client.getNumberOfPositions(request);
48+
return response.numberOfPositions;
49+
}
50+
51+
@override
52+
Future<Map<String, dynamic>> doCommand(Map<String, dynamic> command) async {
53+
final request = DoCommandRequest()
54+
..name = name
55+
..command = command.toStruct();
56+
final response = await client.doCommand(request);
57+
return response.result.toMap();
58+
}
59+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import 'package:grpc/grpc.dart';
2+
3+
import '../../gen/common/v1/common.pb.dart';
4+
import '../../gen/component/nswitch/v1/switch.pbgrpc.dart';
5+
import '../../resource/manager.dart';
6+
import '../../utils.dart';
7+
import 'switch.dart';
8+
9+
/// {@category Components}
10+
/// gRPC Service for a [Switch]
11+
class SwitchService extends SwitchServiceBase {
12+
final ResourceManager _manager;
13+
14+
SwitchService(this._manager);
15+
16+
Switch _fromManager(String name) {
17+
try {
18+
return _manager.getResource(Switch.getResourceName(name));
19+
} catch (e) {
20+
throw GrpcError.notFound(e.toString());
21+
}
22+
}
23+
24+
@override
25+
Future<SetPositionResponse> setPosition(ServiceCall call, SetPositionRequest request) async {
26+
final nswitch = _fromManager(request.name);
27+
await nswitch.setPosition(request.position, extra: request.extra.toMap());
28+
return SetPositionResponse();
29+
}
30+
31+
@override
32+
Future<DoCommandResponse> doCommand(ServiceCall call, DoCommandRequest request) async {
33+
final nswitch = _fromManager(request.name);
34+
final result = await nswitch.doCommand(request.command.toMap());
35+
return DoCommandResponse()..result = result.toStruct();
36+
}
37+
38+
@override
39+
Future<GetPositionResponse> getPosition(ServiceCall call, GetPositionRequest request) async {
40+
final nswitch = _fromManager(request.name);
41+
final position = await nswitch.getPosition(extra: request.extra.toMap());
42+
return GetPositionResponse()..position = position;
43+
}
44+
45+
@override
46+
Future<GetNumberOfPositionsResponse> getNumberOfPositions(ServiceCall call, GetNumberOfPositionsRequest request) async {
47+
final nswitch = _fromManager(request.name);
48+
final numberOfPositions = await nswitch.getNumberOfPositions();
49+
return GetNumberOfPositionsResponse()..numberOfPositions = numberOfPositions;
50+
}
51+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import '../../gen/common/v1/common.pb.dart';
2+
import '../../resource/base.dart';
3+
import '../../robot/client.dart';
4+
5+
/// {@category Components}
6+
/// Switch represents a set of finite positions.
7+
///
8+
/// For more information, see [Switch component](https://docs.viam.com/dev/reference/apis/components/switch/).
9+
abstract class Switch extends Resource {
10+
static const Subtype subtype = Subtype(resourceNamespaceRDK, resourceTypeComponent, 'switch');
11+
12+
/// Update the [Switch] to the provided position.
13+
///
14+
/// ```
15+
/// await mySwitch.setPosition(2);
16+
/// ```
17+
///
18+
/// For more information, see [Switch component](https://docs.viam.com/dev/reference/apis/components/servo/#setposition).
19+
Future<void> setPosition(int position, {Map<String, dynamic>? extra});
20+
21+
/// Get the current position (int) of the [Switch].
22+
///
23+
/// ```
24+
/// var position = await mySwitch.getPosition();
25+
/// ```
26+
///
27+
/// For more information, see [Switch component](https://docs.viam.com/dev/reference/apis/components/switch/#position).
28+
Future<int> getPosition({Map<String, dynamic>? extra});
29+
30+
/// Get the number of available positions (int) of the [Switch].
31+
///
32+
/// ```
33+
/// await myServo.getNumberOfPositions();
34+
/// ```
35+
///
36+
/// For more information, see [Switch component](https://docs.viam.com/dev/reference/apis/components/servo/#getnumberofpositions).
37+
Future<int> getNumberOfPositions({Map<String, dynamic>? extra});
38+
39+
/// Get the [ResourceName] for this [Switch] with the given [name].
40+
///
41+
/// ```
42+
/// // Example:
43+
/// var name = Switch.getResourceName('my_switch');
44+
/// ```
45+
///
46+
/// For more information, see [Switch component](https://docs.viam.com/dev/reference/apis/components/switch/#getresourcename).
47+
static ResourceName getResourceName(String name) {
48+
return Switch.subtype.getResourceName(name);
49+
}
50+
51+
/// Get the [Switch] named [name] from the provided robot.
52+
///
53+
/// ```
54+
/// final mySwitch = Switch.fromRobot(myRobotClient, "my_switch");
55+
/// ```
56+
///
57+
/// For more information, see [Switch component](https://docs.viam.com/dev/reference/apis/components/switch/).
58+
static Switch fromRobot(RobotClient robot, String name) {
59+
return robot.getResource(Switch.getResourceName(name));
60+
}
61+
}

lib/src/resource/registry.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import '../components/sensor/client.dart';
2424
import '../components/sensor/sensor.dart';
2525
import '../components/servo/client.dart';
2626
import '../components/servo/servo.dart';
27+
import '../components/switch/client.dart';
28+
import '../components/switch/switch.dart';
2729
import '../resource/base.dart';
2830
import '../services/discovery.dart';
2931
import '../services/vision.dart';
@@ -69,6 +71,7 @@ class Registry {
6971
registerSubtype(ResourceRegistration(PowerSensor.subtype, (name, channel) => PowerSensorClient(name, channel)));
7072
registerSubtype(ResourceRegistration(Sensor.subtype, (name, channel) => SensorClient(name, channel)));
7173
registerSubtype(ResourceRegistration(Servo.subtype, (name, channel) => ServoClient(name, channel)));
74+
registerSubtype(ResourceRegistration(Switch.subtype, (name, channel) => SwitchClient(name, channel)));
7275
registerSubtype(ResourceRegistration(VisionClient.subtype, (name, channel) => VisionClient(name, channel)));
7376
registerSubtype(ResourceRegistration(DiscoveryClient.subtype, (name, channel) => DiscoveryClient(name, channel)));
7477
}

lib/viam_sdk.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ export 'src/components/sensor/client.dart';
3333
export 'src/components/sensor/sensor.dart';
3434
export 'src/components/servo/client.dart';
3535
export 'src/components/servo/servo.dart';
36+
export 'src/components/switch/client.dart';
37+
export 'src/components/switch/switch.dart';
3638

3739
/// Necessary Protos
3840
export 'src/gen/common/v1/common.pb.dart'

0 commit comments

Comments
 (0)