flutter_aclas_scale 1.0.0
flutter_aclas_scale: ^1.0.0 copied to clipboard
Aclas Scale Flutter Plugin.
example/lib/main.dart
import 'dart:async';
import 'dart:io' show Platform;
import 'package:flutter/material.dart';
import 'package:flutter_aclas_scale/flutter_aclas_scale.dart';
import 'package:permission_handler/permission_handler.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: ScaleTestScreen(),
);
}
}
class ScaleTestScreen extends StatefulWidget {
const ScaleTestScreen({super.key});
@override
State<ScaleTestScreen> createState() => _ScaleTestScreenState();
}
class _ScaleTestScreenState extends State<ScaleTestScreen> {
final AclasScale _scale = AclasScale();
StreamSubscription? _eventSub;
String _status = 'Disconnected';
double _weight = 0.0;
String _type = 'usb';
bool _scanning = false;
List<String> _devices = const [];
Map _deviceData = {};
Map _weightInfo = {};
bool _isConnected = false;
void _snack(String msg) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(msg),
duration: const Duration(milliseconds: 1500),
),
);
}
@override
void initState() {
super.initState();
_eventSub = _scale.events.listen((event) {
final evt = event['event'];
if (evt == 'connected') {
_isConnected = true;
_deviceData = event;
setState(() => _status = 'Connected');
_snack('Connected');
} else if (evt == 'disconnected') {
_isConnected = false;
setState(() {
_status = 'Disconnected';
_weight = 0.0;
});
_snack('Disconnected');
} else if (evt == 'error') {
setState(
() => _status = 'Error: ${event['code'] ?? ''} ${event['msg'] ?? ''}',
);
_snack('Error: ${event['code'] ?? ''} ${event['msg'] ?? ''}');
} else if (evt == 'usb_attached') {
_snack('USB attached');
_refreshDevices();
} else if (evt == 'usb_detached') {
_isConnected = false;
_snack('USB detached');
} else if (evt == 'weight') {
_weightInfo = event;
final w = (event['weight'] as num?)?.toDouble() ?? 0.0;
setState(() => _weight = w);
}
});
_requestPermissions().then((_) => _refreshDevices());
}
@override
void dispose() {
_eventSub?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('ACLAS Scale Demo')),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Device Info',
style: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
),
),
Text(
'statusOk: ${_deviceData["statusOk"]}',
style: const TextStyle(fontSize: 12),
),
Text(
'gravity: ${_deviceData["gravity"]}',
style: const TextStyle(fontSize: 12),
),
Text(
'protocol: ${_deviceData["protocol"]}',
style: const TextStyle(fontSize: 12),
),
Text(
'id: ${_deviceData["id"]}',
style: const TextStyle(fontSize: 12),
),
Text(
'fw: ${_deviceData["fw"]}',
style: const TextStyle(fontSize: 12),
),
Text(
'sdk: ${_deviceData["sdk"]}',
style: const TextStyle(fontSize: 12),
),
Text(
'rangeCode: ${_deviceData["rangeCode"]}',
style: const TextStyle(fontSize: 12),
),
/*| rangeCode | rangeKg |
| --------- | ------- |
| 6 | 15 kg |
| 7 | 30 kg |
| 8 | 60 kg |
| 9 | 150 kg |
| 10 | 300 kg |
| 11 | 600 kg |
*/
],
),
Column(
children: [
Text(
'Weight Info',
style: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
),
),
Text(
'weight: ${_weightInfo["weight"]}',
style: const TextStyle(fontSize: 12),
),
Text(
'unit: ${_weightInfo["unit"]}',
style: const TextStyle(fontSize: 12),
),
Text(
'decimal: ${_weightInfo["decimal"]}',
style: const TextStyle(fontSize: 12),
),
Text(
'stable: ${_weightInfo["stable"]}',
style: const TextStyle(fontSize: 12),
),
Text(
'tare: ${_weightInfo["tare"]}',
style: const TextStyle(fontSize: 12),
),
Text(
'zero: ${_weightInfo["zero"]}',
style: const TextStyle(fontSize: 12),
),
],
),
],
),
const SizedBox(height: 40),
Text('Status: $_status', style: const TextStyle(fontSize: 18)),
const SizedBox(height: 12),
Text(
'Weight: ${_weight.toStringAsFixed(2)}',
style: const TextStyle(fontSize: 28, fontWeight: FontWeight.bold),
),
const SizedBox(height: 24),
Row(
children: [
const Text('Mode:'),
const SizedBox(width: 12),
DropdownButton<String>(
value: _type,
items: const [
DropdownMenuItem(value: 'usb', child: Text('USB')),
DropdownMenuItem(value: 'serial', child: Text('Serial')),
DropdownMenuItem(value: 'ble', child: Text('BLE')),
],
onChanged: (v) {
if (v == null) return;
setState(() {
_type = v;
});
_refreshDevices();
},
),
const Spacer(),
ElevatedButton(
onPressed: _scanning ? null : _refreshDevices,
child: Text(_scanning ? 'Scanning...' : 'Scan'),
),
],
),
const SizedBox(height: 12),
Expanded(
child: _devices.isEmpty
? const Center(child: Text('No devices'))
: ListView.separated(
itemCount: _devices.length,
separatorBuilder: (_, __) => const Divider(height: 1),
itemBuilder: (ctx, i) {
final name = _devices[i];
return ListTile(
title: Text(name),
onTap: () => _connectToIndex(i),
);
},
),
),
const SizedBox(height: 12),
Wrap(
spacing: 12,
runSpacing: 12,
children: [
Visibility(
visible: _isConnected == true,
child: ElevatedButton(
onPressed: () async {
_snack('Disconnecting');
await _scale.disconnect();
},
child: const Text('Disconnect'),
),
),
ElevatedButton(
onPressed: () async {
final w = await _scale.getWeight();
setState(() => _weight = w);
_snack('Weight: $w');
},
child: const Text('Get Weight'),
),
ElevatedButton(
onPressed: () async {
final ok = await _scale.zero();
_snack(ok ? "Zero Success" : "Zero Failed");
},
child: const Text('Zero'),
),
ElevatedButton(
onPressed: () async {
final ok = await _scale.tare();
_snack(ok ? "Tare Success" : "Tare Failed");
},
child: const Text('Tare'),
),
ElevatedButton(
onPressed: () async {
final ok = await _scale.stopLiveWeight();
_snack(
ok ? "Stop Live Weight Success" : "Stop Live Weight Fail",
);
},
child: const Text('Stop Live Weight'),
),
ElevatedButton(
onPressed: () async {
final ok = await _scale.startLiveWeight();
_snack(
ok
? "Start Live Weight Success"
: "Start Live Weight Fail",
);
},
child: const Text('Start Live Weight'),
),
ElevatedButton(
onPressed: () async {
final ok = await _scale.isConnect();
_snack(
ok ? "Device is Connected" : "Device is Not Connected",
);
},
child: const Text('Check Connection'),
),
],
),
],
),
),
);
}
Future<void> _refreshDevices() async {
setState(() {
_scanning = true;
_devices = const [];
});
try {
final list = await _scale.listDevices(
type: _type,
timeoutMs: _type == 'ble' ? 2500 : 500,
);
setState(() {
_devices = list;
});
} catch (_) {
setState(() {
_devices = const [];
});
} finally {
setState(() {
_scanning = false;
});
}
}
Future<void> _connectToIndex(int index) async {
bool ok = false;
if (_type == 'serial') {
final path = _devices.elementAt(index);
ok = await _scale.connect(type: 'serial', path: path);
} else if (_type == 'usb') {
ok = await _scale.connect(type: 'usb', index: index);
} else {
ok = await _scale.connect(type: 'ble', index: index);
}
}
Future<void> _requestPermissions() async {
if (!Platform.isAndroid) return;
final req = <Permission>[
Permission.bluetoothScan,
Permission.bluetoothConnect,
Permission.locationWhenInUse,
];
await req.request();
}
}