diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index c2adee8..8b93256 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -34,7 +34,7 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "com.tuanpm.esp_provisioning_example" - minSdkVersion 16 + minSdkVersion 19 targetSdkVersion 28 versionCode flutterVersionCode.toInteger() versionName flutterVersionName diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index 8c369ef..caa9e56 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -5,9 +5,11 @@ In most cases you can leave this as-is, but you if you want to provide additional functionality it is fine to subclass or reimplement FlutterApplication and put your custom class here. --> + + diff --git a/example/ios/Podfile b/example/ios/Podfile deleted file mode 100644 index 6697f0a..0000000 --- a/example/ios/Podfile +++ /dev/null @@ -1,87 +0,0 @@ -# Uncomment this line to define a global platform for your project -# platform :ios, '9.0' - -# CocoaPods analytics sends network stats synchronously affecting flutter build latency. -ENV['COCOAPODS_DISABLE_STATS'] = 'true' - -project 'Runner', { - 'Debug' => :debug, - 'Profile' => :release, - 'Release' => :release, -} - -def parse_KV_file(file, separator='=') - file_abs_path = File.expand_path(file) - if !File.exists? file_abs_path - return []; - end - generated_key_values = {} - skip_line_start_symbols = ["#", "/"] - File.foreach(file_abs_path) do |line| - next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } - plugin = line.split(pattern=separator) - if plugin.length == 2 - podname = plugin[0].strip() - path = plugin[1].strip() - podpath = File.expand_path("#{path}", file_abs_path) - generated_key_values[podname] = podpath - else - puts "Invalid plugin specification: #{line}" - end - end - generated_key_values -end - -target 'Runner' do - use_frameworks! - use_modular_headers! - - # Flutter Pod - - copied_flutter_dir = File.join(__dir__, 'Flutter') - copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework') - copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec') - unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path) - # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet. - # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration. - # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist. - - generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig') - unless File.exist?(generated_xcode_build_settings_path) - raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first" - end - generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path) - cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR']; - - unless File.exist?(copied_framework_path) - FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir) - end - unless File.exist?(copied_podspec_path) - FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir) - end - end - - # Keep pod path relative so it can be checked into Podfile.lock. - pod 'Flutter', :path => 'Flutter' - - # Plugin Pods - - # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock - # referring to absolute paths on developers' machines. - system('rm -rf .symlinks') - system('mkdir -p .symlinks/plugins') - plugin_pods = parse_KV_file('../.flutter-plugins') - plugin_pods.each do |name, path| - symlink = File.join('.symlinks', 'plugins', name) - File.symlink(path, symlink) - pod name, :path => File.join(symlink, 'ios') - end -end - -post_install do |installer| - installer.pods_project.targets.each do |target| - target.build_configurations.each do |config| - config.build_settings['ENABLE_BITCODE'] = 'NO' - end - end -end diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock deleted file mode 100644 index 789bb2f..0000000 --- a/example/ios/Podfile.lock +++ /dev/null @@ -1,41 +0,0 @@ -PODS: - - esp_provisioning (0.0.1): - - Flutter - - Flutter (1.0.0) - - flutter_ble_lib (2.2.3): - - Flutter - - MultiplatformBleAdapter (= 0.1.5) - - MultiplatformBleAdapter (0.1.5) - - "permission_handler (5.0.0+hotfix.3)": - - Flutter - -DEPENDENCIES: - - esp_provisioning (from `.symlinks/plugins/esp_provisioning/ios`) - - Flutter (from `Flutter`) - - flutter_ble_lib (from `.symlinks/plugins/flutter_ble_lib/ios`) - - permission_handler (from `.symlinks/plugins/permission_handler/ios`) - -SPEC REPOS: - trunk: - - MultiplatformBleAdapter - -EXTERNAL SOURCES: - esp_provisioning: - :path: ".symlinks/plugins/esp_provisioning/ios" - Flutter: - :path: Flutter - flutter_ble_lib: - :path: ".symlinks/plugins/flutter_ble_lib/ios" - permission_handler: - :path: ".symlinks/plugins/permission_handler/ios" - -SPEC CHECKSUMS: - esp_provisioning: f23d52f966f1de0f66007d805220abb52f61a2f1 - Flutter: 0e3d915762c693b495b44d77113d4970485de6ec - flutter_ble_lib: 20e79f0b1d78d921d9ed68ab4451e190029bc3d9 - MultiplatformBleAdapter: 3c4391d428382738a47662ae1f665a29ce78ff39 - permission_handler: 4a985b5448897c27fdeadde84f7452520c0e6c58 - -PODFILE CHECKSUM: c34e2287a9ccaa606aeceab922830efb9a6ff69a - -COCOAPODS: 1.9.0.beta.2 diff --git a/example/lib/ble_screen/ble_screen.dart b/example/lib/ble_screen/ble_screen.dart index 296624d..a9d0975 100644 --- a/example/lib/ble_screen/ble_screen.dart +++ b/example/lib/ble_screen/ble_screen.dart @@ -34,7 +34,7 @@ class _BleScreenState extends State { return Container( padding: EdgeInsets.only(top: 5.0), height: MediaQuery.of(context).size.height - 50, - child: WiFiScreen(), + child: WiFiScreenBLE(peripheral: item), ); }); bottomSheetController.whenComplete(() { diff --git a/example/lib/ble_service.dart b/example/lib/ble_service.dart index febd56f..460d189 100644 --- a/example/lib/ble_service.dart +++ b/example/lib/ble_service.dart @@ -50,12 +50,13 @@ class BleService { }); }); + var state = await _waitForBluetoothPoweredOn(); if (Platform.isAndroid) { - log.v('enableRadio'); - await _bleManager.enableRadio(); + if (state.index != 3) { // check if bluetooth is already open + log.v('enableRadio'); + await _bleManager.enableRadio(); + } } - - var state = await _waitForBluetoothPoweredOn(); _isPowerOn = true; return state; } diff --git a/example/lib/main.dart b/example/lib/main.dart index 4e3a3dc..3bf0e05 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,3 +1,4 @@ +import 'package:esp_provisioning_example/softap_screen/softap_screen.dart'; import 'package:flutter/material.dart'; import 'ble_screen/ble_screen.dart'; @@ -26,7 +27,7 @@ class HomeScreen extends StatelessWidget { Navigator.push( context, MaterialPageRoute( - builder: (BuildContext context) => BleScreen())); + builder: (BuildContext context) => SoftApScreen())); }, child: Text( 'Start Provisioning', diff --git a/example/lib/softap_screen/softap_bloc.dart b/example/lib/softap_screen/softap_bloc.dart new file mode 100644 index 0000000..2949617 --- /dev/null +++ b/example/lib/softap_screen/softap_bloc.dart @@ -0,0 +1,25 @@ + +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:esp_provisioning_example/softap_screen/softap_event.dart'; +import 'package:esp_provisioning_example/softap_screen/softap_state.dart'; +import 'package:esp_provisioning_example/softap_service.dart'; + + + +class SoftApBloc extends Bloc { + + @override + // TODO: implement initialState + get initialState => SoftApStateLoaded(); + + @override + Stream mapEventToState(event) async* { + if (event is SoftApEventStart){ + yield* _mapStartToState(); + } + } + Stream _mapStartToState() async* { + + } +} + diff --git a/example/lib/softap_screen/softap_event.dart b/example/lib/softap_screen/softap_event.dart new file mode 100644 index 0000000..12efecd --- /dev/null +++ b/example/lib/softap_screen/softap_event.dart @@ -0,0 +1,10 @@ +import 'package:equatable/equatable.dart'; + +abstract class SoftApEvent extends Equatable { + const SoftApEvent(); + + @override + List get props => []; +} + +class SoftApEventStart extends SoftApEvent {} \ No newline at end of file diff --git a/example/lib/softap_screen/softap_screen.dart b/example/lib/softap_screen/softap_screen.dart new file mode 100644 index 0000000..ce6f455 --- /dev/null +++ b/example/lib/softap_screen/softap_screen.dart @@ -0,0 +1,99 @@ +import 'package:esp_provisioning_example/softap_screen/softap_bloc.dart'; +import 'package:esp_provisioning_example/softap_screen/softap_event.dart'; +import 'package:esp_provisioning_example/softap_screen/softap_state.dart'; +import 'package:esp_provisioning_example/wifi_screen/wifi.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_spinkit/flutter_spinkit.dart'; + +class SoftApScreen extends StatefulWidget { + @override + _SoftApScreenState createState() => _SoftApScreenState(); +} + +class _SoftApScreenState extends State { + + void _showBottomSheet(BuildContext _context) { + // BlocProvider.of(_context).add(SoftApEventStart()); + + var bottomSheetController = showModalBottomSheet( + context: context, + backgroundColor: Colors.white, + isScrollControlled: true, + elevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: const Radius.circular(20.0), + topRight: const Radius.circular(20.0), + ), + ), + builder: (BuildContext context) { + return Container( + padding: EdgeInsets.only(top: 5.0), + height: MediaQuery.of(context).size.height - 50, + child: WiFiScreenSoftAP(), + ); + }); + bottomSheetController.whenComplete(() { + // after prov. + BlocProvider.of(_context).add(SoftApEventStart()); + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: Colors.redAccent, + title: const Text('Scanning BLE devices'), + ), + body: BlocProvider( + create: (BuildContext context) => SoftApBloc(), + child: BlocBuilder( + builder: (BuildContext context, SoftApState state) { + if (state is SoftApStateLoaded) { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + padding: EdgeInsets.all(4.0), + width: MediaQuery.of(context).size.width * 0.85, + child:Text('Please connect WiFi to Subol_Gas_Sensor_ in "Wi-Fi Settings". Once you complete it please tap on "Ready" button.', + style: TextStyle(fontSize: 18),), + ), + + SizedBox(height: MediaQuery.of(context).size.width * 0.1,), + MaterialButton( + color: Colors.redAccent, + elevation: 5, + padding: EdgeInsets.all(15.0), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(5))), + child: Text( + 'Ready', + style: Theme.of(context) + .textTheme + .headline6 + .copyWith(color: Colors.white), + ), + + onPressed: () { + _showBottomSheet(this.context); + }, + ), + ], + ) + + ); + } + + return Center( + child: SpinKitRipple(color: Theme.of(context).textSelectionColor), + ); + }, + ), + ), + ); + } +} diff --git a/example/lib/softap_screen/softap_state.dart b/example/lib/softap_screen/softap_state.dart new file mode 100644 index 0000000..d89e041 --- /dev/null +++ b/example/lib/softap_screen/softap_state.dart @@ -0,0 +1,10 @@ +import 'package:equatable/equatable.dart'; + +abstract class SoftApState extends Equatable { + const SoftApState(); + + @override + List get props => []; +} + +class SoftApStateLoaded extends SoftApState {} diff --git a/example/lib/softap_service.dart b/example/lib/softap_service.dart new file mode 100644 index 0000000..e9ea7ac --- /dev/null +++ b/example/lib/softap_service.dart @@ -0,0 +1,20 @@ +import 'dart:async'; +import 'dart:io'; +import 'package:flutter_ble_lib/flutter_ble_lib.dart'; +import 'package:esp_provisioning/esp_provisioning.dart'; + +class SoftAPService { + final String hostname; + final int port; + SoftAPService(this.hostname, this.port); + + Future startProvisioning() async { + EspProv prov = EspProv( + transport: TransportHTTP(this.hostname, this.port), security: Security1(pop: 'abcd1234')); + var success = await prov.establishSession(); + if (!success) { + throw Exception('Error establishSession'); + } + return prov; + } +} \ No newline at end of file diff --git a/example/lib/wifi_screen/wifi_bloc.dart b/example/lib/wifi_screen/wifi_bloc.dart index 7197842..f91db6c 100644 --- a/example/lib/wifi_screen/wifi_bloc.dart +++ b/example/lib/wifi_screen/wifi_bloc.dart @@ -3,9 +3,10 @@ import 'package:bloc/bloc.dart'; import 'package:esp_provisioning/esp_provisioning.dart'; import 'package:logger/logger.dart'; import '../ble_service.dart'; +import '../softap_service.dart'; import './wifi.dart'; -class WifiBloc extends Bloc { +class WifiBlocBLE extends Bloc { var bleService = BleService.getInstance(); EspProv prov; Logger log = Logger(printer: PrettyPrinter()); @@ -17,9 +18,10 @@ class WifiBloc extends Bloc { Stream mapEventToState( WifiEvent event, ) async* { - if (event is WifiEventLoad) { + if (event is WifiEventLoadBLE) { + bleService.select(event.selectedDevice['peripheral']); yield* _mapLoadToState(); - } else if (event is WifiEventStartProvisioning) { + } else if (event is WifiEventStartProvisioningBLE) { yield* _mapProvisioningToState(event); } } @@ -45,7 +47,7 @@ class WifiBloc extends Bloc { } Stream _mapProvisioningToState( - WifiEventStartProvisioning event) async* { + WifiEventStartProvisioningBLE event) async* { yield WifiStateProvisioning(); await prov?.sendWifiConfig(ssid: event.ssid, password: event.password); await prov?.applyWifiConfig(); @@ -59,3 +61,39 @@ class WifiBloc extends Bloc { return super.close(); } } + +class WiFiBlocSoftAP extends Bloc { + var softApService = SoftAPService("192.168.4.1:80", 80); + EspProv prov; + Logger log = Logger(printer: PrettyPrinter()); + + @override + // TODO: implement initialState + WifiState get initialState => WifiStateLoading(); + + @override + Stream mapEventToState(WifiEvent event) async* { + if (event is WifiEventLoadSoftAP) { + yield* _mapLoadToState(); + } + } + + Stream _mapLoadToState() async*{ + yield WifiStateConnecting(); + try { + prov = await softApService.startProvisioning(); + } catch (e) { + log.e('Error connecting to device $e'); + yield WifiStateError('Error connecting to device'); + } + yield WifiStateScanning(); + try { + var listWifi = await prov.startScanWiFi(); + yield WifiStateLoaded(wifiList: listWifi ?? []); + log.v('Wifi $listWifi'); + } catch (e) { + log.e('Error scan WiFi network $e'); + yield WifiStateError('Error scan WiFi network'); + } + } +} diff --git a/example/lib/wifi_screen/wifi_event.dart b/example/lib/wifi_screen/wifi_event.dart index d9ae0ea..5d6af4d 100644 --- a/example/lib/wifi_screen/wifi_event.dart +++ b/example/lib/wifi_screen/wifi_event.dart @@ -7,29 +7,65 @@ abstract class WifiEvent extends Equatable { List get props => []; } -class WifiEventLoad extends WifiEvent {} +// events for BLE provisioning +class WifiEventLoadBLE extends WifiEvent { + final Map selectedDevice; -class WifiEventConnecting extends WifiEvent {} + const WifiEventLoadBLE(this.selectedDevice); -class WifiEventScanning extends WifiEvent {} + @override + List get props => [selectedDevice]; +} + +class WifiEventConnectingBLE extends WifiEvent {} -class WifiEventScanned extends WifiEvent {} +class WifiEventScanningBLE extends WifiEvent {} -class WifiEventLoaded extends WifiEvent { +class WifiEventScannedBLE extends WifiEvent {} + +class WifiEventLoadedBLE extends WifiEvent { final String wifiName; - WifiEventLoaded({this.wifiName}); + WifiEventLoadedBLE({this.wifiName}); @override List get props => [wifiName]; } -class WifiEventStartProvisioning extends WifiEvent { +class WifiEventStartProvisioningBLE extends WifiEvent { final String ssid; final String password; - WifiEventStartProvisioning({this.ssid, this.password}); + WifiEventStartProvisioningBLE({this.ssid, this.password}); @override List get props => [ssid, password]; } + +// events for softap provisioning +class WifiEventLoadSoftAP extends WifiEvent {} + +class WifiEventConnectingSoftAP extends WifiEvent {} + +class WifiEventScanningSoftAP extends WifiEvent {} + +class WifiEventScannedSoftAP extends WifiEvent {} + +class WifiEventLoadedSoftAP extends WifiEvent { + final String wifiName; + + WifiEventLoadedSoftAP({this.wifiName}); + + @override + List get props => [wifiName]; +} + +class WifiEventStartProvisioningSoftAP extends WifiEvent { + final String ssid; + final String password; + + WifiEventStartProvisioningSoftAP({this.ssid, this.password}); + + @override + List get props => [ssid, password]; +} \ No newline at end of file diff --git a/example/lib/wifi_screen/wifi_screen.dart b/example/lib/wifi_screen/wifi_screen.dart index 42ef7f2..be4ef39 100644 --- a/example/lib/wifi_screen/wifi_screen.dart +++ b/example/lib/wifi_screen/wifi_screen.dart @@ -1,3 +1,4 @@ +import 'package:esp_provisioning_example/ble_screen/ble_bloc.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart'; @@ -6,14 +7,15 @@ import '../scan_list.dart'; import 'wifi.dart'; import 'wifi_dialog.dart'; -class WiFiScreen extends StatefulWidget { - WiFiScreen({Key key}) : super(key: key); - +// ignore: must_be_immutable +class WiFiScreenBLE extends StatefulWidget { + Map peripheral; + WiFiScreenBLE({Key key, this.peripheral}) : super(key: key); @override - _WiFiScreenState createState() => _WiFiScreenState(); + _WiFiScreenBLEState createState() => _WiFiScreenBLEState(); } -class _WiFiScreenState extends State { +class _WiFiScreenBLEState extends State { void _showDialog(Map wifi, BuildContext _context) { showDialog( context: _context, @@ -22,8 +24,8 @@ class _WiFiScreenState extends State { wifiName: wifi['ssid'], onSubmit: (ssid, password) { print('ssid =$ssid, password = $password'); - BlocProvider.of(_context).add( - WifiEventStartProvisioning(ssid: ssid, password: password)); + BlocProvider.of(_context).add( + WifiEventStartProvisioningBLE(ssid: ssid, password: password)); }, ); }); @@ -33,7 +35,7 @@ class _WiFiScreenState extends State { List _statusWidget = [ Column( children: [ - FlatButton.icon( + ElevatedButton.icon( onPressed: () {}, icon: SpinKitThreeBounce( color: Colors.black, @@ -44,7 +46,7 @@ class _WiFiScreenState extends State { ), Column( children: [ - FlatButton.icon( + ElevatedButton.icon( onPressed: () {}, icon: Icon( Icons.check, @@ -56,7 +58,7 @@ class _WiFiScreenState extends State { color: Colors.green, ), )), - FlatButton.icon( + ElevatedButton.icon( onPressed: () {}, icon: SpinKitThreeBounce( color: Colors.black, @@ -114,8 +116,167 @@ class _WiFiScreenState extends State { ), ), body: BlocProvider( - create: (BuildContext context) => WifiBloc()..add(WifiEventLoad()), - child: BlocBuilder( + create: (BuildContext context) => WifiBlocBLE()..add(WifiEventLoadBLE(widget.peripheral)), + child: BlocBuilder( + builder: (BuildContext context, WifiState state) { + if (state is WifiStateConnecting) { + return _buildStepper(0, state); + } + if (state is WifiStateScanning) { + return _buildStepper(1, state); + } + if (state is WifiStateLoaded) { + return _buildStepper(2, state); + } + if (state is WifiStateProvisioning) { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SpinKitThreeBounce( + color: Theme.of(context).textSelectionColor, + size: 20, + ), + Text('Provisioning', + style: Theme.of(context).textTheme.bodyText1), + ], + ), + ); + } + if (state is WifiStateProvisioned) { + return Container( + child: Center( + child: MaterialButton(child: Text('Done'), color: Colors.redAccent, onPressed: () { + Navigator.of(context).pop(); + },), + ), + ); + } + return Container( + child: Center( + child: SpinKitThreeBounce( + color: Theme.of(context).textSelectionColor, + size: 20, + ), + ), + ); + }, + ), + ), + ); + } +} + + +class WiFiScreenSoftAP extends StatefulWidget { + WiFiScreenSoftAP({Key key}) : super(key: key); + @override + _WiFiScreenSoftAPState createState() => _WiFiScreenSoftAPState(); +} + +class _WiFiScreenSoftAPState extends State { + void _showDialog(Map wifi, BuildContext _context) { + showDialog( + context: _context, + builder: (BuildContext context) { + return WifiDialog( + wifiName: wifi['ssid'], + onSubmit: (ssid, password) { + print('ssid =$ssid, password = $password'); + BlocProvider.of(_context).add( + WifiEventStartProvisioningSoftAP(ssid: ssid, password: password)); + }, + ); + }); + } + + Widget _buildStepper(int step, WifiState state) { + List _statusWidget = [ + Column( + children: [ + ElevatedButton.icon( + onPressed: () {}, + icon: SpinKitThreeBounce( + color: Colors.black, + size: 20, + ), + label: Text('Connecting..')) + ], + ), + Column( + children: [ + ElevatedButton.icon( + onPressed: () {}, + icon: Icon( + Icons.check, + color: Colors.green, + ), + label: Text( + 'Connected', + style: TextStyle( + color: Colors.green, + ), + )), + ElevatedButton.icon( + onPressed: () {}, + icon: SpinKitThreeBounce( + color: Colors.black, + size: 20, + ), + label: Text('Scanning...')) + ], + ) + ]; + + var wifiList; + if (state is WifiStateLoaded) { + wifiList = Expanded( + child: ScanList(state.wifiList, Icons.wifi, disableLoading: true, + onTap: (Map item, BuildContext _context) { + _showDialog(item, _context); + })); + } + var body = Expanded(child: Container()); + var statusWidget; + if (step < 2) { + statusWidget = Expanded(child: _statusWidget[step]); + body = Expanded( + child: + SpinKitDoubleBounce(color: Theme.of(context).textSelectionColor)); + } else { + body = wifiList; + } + return Column( + children: [ + Center( + child: Text( + 'Select Wifi network', + style: Theme.of(context).textTheme.headline5, + )), + body, + statusWidget ?? Container(), + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.transparent, + appBar: AppBar( + elevation: 0, + iconTheme: IconThemeData( + color: Colors.black, //change your color here + ), + backgroundColor: Colors.transparent, + title: Text( + 'Provisioning...', + style: Theme.of(context).textTheme.bodyText1, + ), + ), + body: BlocProvider( + create: (BuildContext context) => WiFiBlocSoftAP()..add(WifiEventLoadSoftAP()), + child: BlocBuilder( builder: (BuildContext context, WifiState state) { if (state is WifiStateConnecting) { return _buildStepper(0, state); diff --git a/example/pubspec.lock b/example/pubspec.lock index 0186d91..f841f5a 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -7,7 +7,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.4.1" + version: "2.5.0" bloc: dependency: transitive description: @@ -21,28 +21,35 @@ packages: name: boolean_selector url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.0" + characters: + dependency: transitive + description: + name: characters + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" charcode: dependency: transitive description: name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.1.3" + version: "1.2.0" clock: dependency: transitive description: name: clock url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "1.1.0" collection: dependency: transitive description: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.14.12" + version: "1.15.0" convert: dependency: transitive description: @@ -84,14 +91,14 @@ packages: path: ".." relative: true source: path - version: "1.0.0+4" + version: "1.0.0+5" fake_async: dependency: transitive description: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.2.0" fixnum: dependency: transitive description: @@ -130,6 +137,20 @@ packages: description: flutter source: sdk version: "0.0.0" + http: + dependency: transitive + description: + name: http + url: "https://pub.dartlang.org" + source: hosted + version: "0.13.1" + http_parser: + dependency: transitive + description: + name: http_parser + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.0" io: dependency: transitive description: @@ -157,14 +178,14 @@ packages: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.6" + version: "0.12.10" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.1.8" + version: "1.3.0" nested: dependency: transitive description: @@ -178,7 +199,14 @@ packages: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.7.0" + version: "1.8.0" + pedantic: + dependency: transitive + description: + name: pedantic + url: "https://pub.dartlang.org" + source: hosted + version: "1.11.0" permission_handler: dependency: "direct main" description: @@ -239,56 +267,63 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.7.0" + version: "1.8.0" stack_trace: dependency: transitive description: name: stack_trace url: "https://pub.dartlang.org" source: hosted - version: "1.9.3" + version: "1.10.0" stream_channel: dependency: transitive description: name: stream_channel url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.0.5" + version: "1.1.0" + string_validator: + dependency: "direct main" + description: + name: string_validator + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.0" term_glyph: dependency: transitive description: name: term_glyph url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.2.0" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.16" + version: "0.2.19" typed_data: dependency: transitive description: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.1.6" + version: "1.3.0" vector_math: dependency: transitive description: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.0.8" + version: "2.1.0" sdks: - dart: ">=2.7.0 <3.0.0" - flutter: ">=1.12.8 <2.0.0" + dart: ">=2.12.0 <3.0.0" + flutter: ">=1.12.8" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 26af80a..d7b75e4 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -20,6 +20,7 @@ dependencies: flutter_spinkit: ^4.1.2+1 cupertino_icons: ^0.1.3 + string_validator: ^0.3.0 dev_dependencies: flutter_test: diff --git a/lib/esp_provisioning.dart b/lib/esp_provisioning.dart index 1fa3897..a395bde 100644 --- a/lib/esp_provisioning.dart +++ b/lib/esp_provisioning.dart @@ -2,4 +2,5 @@ export 'src/esp_prov.dart'; export 'src/security.dart'; export 'src/security1.dart'; export 'src/transport.dart'; -export 'src/transport_ble.dart'; \ No newline at end of file +export 'src/transport_ble.dart'; +export 'src/transport_http.dart'; \ No newline at end of file diff --git a/lib/src/transport_http.dart b/lib/src/transport_http.dart new file mode 100644 index 0000000..ed8e277 --- /dev/null +++ b/lib/src/transport_http.dart @@ -0,0 +1,75 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:typed_data'; +import 'package:flutter/material.dart'; + +import 'transport.dart'; +import 'dart:io'; +import 'package:string_validator/string_validator.dart'; + +class TransportHTTP implements ProvTransport{ + HttpClient client = new HttpClient(); + String hostname; + final int port; + //Map headers; + TransportHTTP(String hostname, this.port) { + if (!isIP(hostname)) { + throw FormatException('hostname should be an IP address.'); + } + else { + this.hostname = hostname; + } + this.client.connectionTimeout = Duration(seconds: 45); + } + + @override + Future connect() async { + HttpClientRequest request; + try { + print('Connecting to' + this.hostname); + request = await this.client.post(this.hostname, this.port,'/'); + request.headers.set(HttpHeaders.contentTypeHeader, 'application/x-www-form-urlencoded'); + request.headers.set(HttpHeaders.acceptHeader, 'text/plain'); + await request.close(); + print('Connection successful'); + return true; + } + catch(e){ + print('Connection error ' + e.toString()); + return false; + } + + } + + @override + Future disconnect() { + // TODO: implement disconnect + throw UnimplementedError(); + } + + @override + Future sendReceive(String epName, Uint8List data) async { + HttpClientRequest request; + try { + print('Connecting to' + this.hostname); + request = await this.client.post(this.hostname, this.port, epName); + request.headers.set( + HttpHeaders.contentTypeHeader, 'application/x-www-form-urlencoded'); + request.headers.set(HttpHeaders.acceptHeader, 'text/plain'); + request.write(data); + print('Connection successful'); + } + catch (e) { + print('Connection error ' + e.toString()); + } + final response = await request.close(); + response.transform(utf8.decoder).listen((contents) { + print(contents); + }); + + return Uint8List(5); + } + } + + +