Flutter: how to ssh into a Raspberry Pi - ssh

So I'm trying to do a very simple thing (in theory). I want to communicate with my Raspberry Pi and I want to make it into an app. I was looking at flutter packages and there's one that allows you to ssh. So I thought I'd just ssh into my Pi and run a script but I get an error which I have no idea what it means. Thanks for the help in advance! Here's my code and the error:
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:flutter/material.dart';
import 'package:ssh/ssh.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Lights',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: RaisedButton(
onPressed: lightsOff,
child: Text("Lights Off"),
),
),
],
),
);
}
Future<void> lightsOff() async {
final pi = new SSHClient(
host: "IP_ADDRESS",
port: 22,
username: "pi",
passwordOrKey: "raspberry",
);
String result;
try {
result = await pi.connect();
if (result == "session_connected")
result = await pi.execute("sudo python /home/pi/Desktop/scripts/lightOff.py");
} on PlatformException catch (e) {
print('Error: ${e.code}\nError Message: ${e.message}');
}
}
}
Error:
flutter: ══╡ EXCEPTION CAUGHT BY SERVICES LIBRARY ╞══════════════════════════════════════════════════════════
flutter: The following MissingPluginException was thrown while activating platform stream on channel
flutter: shell_sftp:
flutter: MissingPluginException(No implementation found for method listen on channel shell_sftp)
flutter:
flutter: When the exception was thrown, this was the stack:
flutter: #0 MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:291:7)
flutter: <asynchronous suspension>
flutter: #1 EventChannel.receiveBroadcastStream.<anonymous closure> (package:flutter/src/services/platform_channel.dart:437:29)
flutter: <asynchronous suspension>
flutter: #9 new SSHClient (package:ssh/ssh.dart:40:40)
flutter: #10 _MyHomePageState.lightsOff (package:lights/main.dart:48:20)
flutter: <asynchronous suspension>
flutter: #11 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:507:14)
flutter: #12 _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:562:30)
flutter: #13 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:102:24)
flutter: #14 TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:242:9)
flutter: #15 TapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:175:7)
flutter: #16 PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:315:9)
flutter: #17 PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:73:12)
flutter: #18 PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:101:11)
flutter: #19 _WidgetsFlutterBinding&BindingBase&GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:180:19)
flutter: #20 _WidgetsFlutterBinding&BindingBase&GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:158:22)
flutter: #21 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:138:7)
flutter: #22 _WidgetsFlutterBinding&BindingBase&GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:101:7)
flutter: #23 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:85:7)
flutter: #24 _invoke1 (dart:ui/hooks.dart:168:13)
flutter: #25 _dispatchPointerDataPacket (dart:ui/hooks.dart:122:5)
flutter: (elided 7 frames from package dart:async)
flutter: ════════════════════════════════════════════════════════════════════════════════════════════════════
[VERBOSE-2:shell.cc(184)] Dart Error: Unhandled exception:
MissingPluginException(No implementation found for method connectToHost on channel ssh)
#0 MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:291:7)
<asynchronous suspension>
#1 SSHClient.connect (package:ssh/ssh.dart:63:33)
<asynchronous suspension>
#2 _MyHomePageState.lightsOff (package:lights/main.dart:57:25)
#3 _AsyncAwaitCompleter.start (dart:async/runtime/libasync_patch.dart:49:6)
#4 _MyHomePageState.lightsOff (package:lights/main.dart:47:25)
#5 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:507:14)
#6 _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:562:30)
#7 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:102:24)
#8 TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:242:9)
#9 TapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gesture<…>

The exception is thrown when you try to Hot Reload or Hot Restart after just adding new package to your pubspec.yaml.
Try to stop the running project(app) and then freshly run it again. So that the added package(which contains the implementations) also pushed to the device.

Related

Proper way to mock react-navigation-shared-element

I want to run my test by i'm getting errors related to SharedElement component from react-navigation-shared-element
My mocks are this:
jest.mock('react-native-shared-element', () => {
return () => ({});
});
jest.mock('react-navigation-shared-element', () => {
return () => ({
createSharedElementStackNavigator: jest.fn(),
});
});
When I run my tests:
Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

How to test a callback function in a Flutter widget

I have a custom Flutter widget, RadioSelect, which accepts an array of options and a callback function when one of those options is pressed. The callback is called with the selected option passed as it's only parameter. I'm trying to write a test which verifies that the callback was called and checks that the returned parameter is correct but I'm not sure how to structure it. What's a sensible way to check that a standalone callback function was called?
await tester.pumpWidget(
StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return MaterialApp(
home: RadioSelect(
["option1","option2", "option3"],
// callback function passed here
),
);
},
),
);
expect(find.text('option1'), findsOneWidget);
await tester.press(find.text('option2'));
await tester.pump();
// test for callback here
You can also use a Completer
testWidgets('callback', (WidgetTester tester) async {
final completer = Completer<void>();
await tester.pumpWidget(
MaterialApp(
home: FlatButton(
child: Text('press me'),
onPressed: completer.complete,
),
),
);
await tester.tap(find.byType(FlatButton));
expect(completer.isCompleted, isTrue);
});
source: https://luksza.org/2020/testing-flutter-callbacks/
In the body of a Callback function, you can print the received arguments, and then expect if it prints correctly.
Here is another sample doing a similar test:
CHILD OF A TESTING WIDGET:
...
...
Checkbox(
key: Key('StatusCheckBox'),
value: isCompleted,
onChanged: (_) => toggleCompletionStatus(),
),
...
...
I'm passing print('Call') as a body of toggleCompletionStatus()
Which can be tested this way:
expectLater(
() => tester.tap(find.byKey(Key('StatusCheckBox'))), prints('Call\n'));

Flutter Test Driver Run All Test

In our Flutter application we have multiple integration tests.
I run them one by one by issuing:
flutter drive --target=test_driver/screenshot.dart
However I can't seem to figure out how to run all integration test inside the test_driver folder?
With Groups, but this only half addresses the issue, have your app_test.dart like normal just a main method with some grouped tests
Future<void> main() async {
group(
'Registration and password',
() {
setUp(() async {
await versionTest(driver, tester, reporter);
});
test('Register Account', () async {
await testRegisterAccount(driver, tester, reporter);
});
test('Register Account 2', () async {
await testRegisterAccount2(driver, tester, reporter);
});
tearDown(() async {
await driver.requestData('go-back');
});
},
timeout: const Timeout(
Duration(minutes: 5),
),
);
then we have an app.dart which creates the app wrapped in a test app. We mainly did this to test a splash screen that checked the apps version, so we needed a hook into before the app had really started
void main() {
makeTestApp();
}
makeTestApp does all the normal stuff like enableFlutterDriverExtensions etc but its also where we build our app with a custom launcher, the launcher is just a blank page with a button which starts the app, each test should start and finish here, going back was harder you can see we used the FlutterDriverExtensions handler message - driver.requestData('go-back')
Widget _buildHome(BuildContext context) {
return Scaffold(
child: Center(
child: GestureDetector(
onTap: () {
Navigator.of(context).pushReplacementNamed('/authentication');
},
child: SizedBox(
height: 200,
width: 200,
child: Image.asset(
'assets/images/logo.png',
fit: BoxFit.cover,
),
),
),
),
);
}
WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]).then((_) {
runApp(App(
launcher: (context) => _buildHome(context),
));
});
now you can start the app using something like
flutter run --flavor dev --observatory-port 8888 --disable-service-auth-codes --no-hot test_driver/app.dart
and when the app is running it will display our launcher waiting for you to run a test using the code lens tools from the dart library,
One way to do it is to open a terminal window in the root directory of your Flutter app and type flutter test
See: https://github.com/flutter/flutter/wiki/Running-and-writing-tests#running-unit-tests

Flutter: testing, how to extrapolate part of the UI

I have something like:
class _RootPageState extends State<RootPage> {
#override
Widget build(BuildContext context) {
return StreamBuilder(
key: Key("rootStreamBuilder"),
stream: _bloc.loadRootPage,
builder: (context, snapshot) {
if (snapshot.hasData) {
...
});
I want to test this StreamBuilder, how can I extrapolate from this class? So that I can do something like:
testWidgets("test", (WidgetTester tester) async {
await tester.pumpWidget(new MaterialApp(
home: StreamBuilder
...

HandleInvalidRoute not working with Durandal

Here's my shell.js vm:
var vm = {
router: router,
auth: auth,
viewAttached: function () {
},
activate: function () {
router.useConvention();
router.handleInvalidRoute = function (route, params) {
debugger;
toastr.info('No Route Found: ' + route);
};
router.map([
{ url: 'error', moduleId: 'viewmodels/error', name: 'Error', visible: false }
]);
router.mapAuto();
if (auth.isAuthenticated)
//return router.activate('folder/2');
return router.activate('home');
else {
return router.activate('home');
}
}
};
return vm;
});
When I navigate to an invalid route (/folders, for example), the debugger in my handleInvalidRoute block isn't hit, and I get a scripterror from require.js:
GET http://appname.com/App/viewmodels/folders.js 404 (Not Found)
require.js:33 Uncaught Error: Script error
http://requirejs.org/docs/errors.html#scripterror require.js:8 J
require.js:8 j.onScriptError
That's all I have to work with. Any idea what's going on?
This has been answered by #EisenbergEffect in the Durandal newsgroup https://groups.google.com/forum/#!topic/durandaljs/eZrIcgn3aU8.
It is because you called mapAuto which always attempts to map urls to
modules, whether or not they actually exist. Effectively,
handleInvalidRoute will never be called.