Initial import
This commit is contained in:
187
bin/owntracks_import.dart
Normal file
187
bin/owntracks_import.dart
Normal file
@ -0,0 +1,187 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import 'package:args/args.dart';
|
||||
|
||||
const String version = '0.0.1';
|
||||
|
||||
ArgParser buildParser() {
|
||||
return ArgParser()
|
||||
..addOption('source', abbr: 's', help: 'Source GeoJSON file')
|
||||
..addOption('destination',
|
||||
abbr: 'd', help: 'OwnTracks Recorder server address')
|
||||
..addOption('user', abbr: 'u', help: 'User for OwnTrack record')
|
||||
..addFlag(
|
||||
'help',
|
||||
abbr: 'h',
|
||||
negatable: false,
|
||||
help: 'Print this usage information.',
|
||||
)
|
||||
..addFlag(
|
||||
'verbose',
|
||||
abbr: 'v',
|
||||
negatable: false,
|
||||
help: 'Show additional command output.',
|
||||
)
|
||||
..addFlag(
|
||||
'no-limits',
|
||||
abbr: 'n',
|
||||
defaultsTo: false,
|
||||
help:
|
||||
'Disable 2 seconds delay to not hit reverse geocoding API rate limits.',
|
||||
)
|
||||
..addFlag(
|
||||
'version',
|
||||
negatable: false,
|
||||
help: 'Print the tool version.',
|
||||
);
|
||||
}
|
||||
|
||||
void printUsage(ArgParser argParser) {
|
||||
print('Usage: dart owntracks_import.dart <options> <flags>');
|
||||
print(argParser.usage);
|
||||
}
|
||||
|
||||
void main(List<String> arguments) async {
|
||||
final ArgParser argParser = buildParser();
|
||||
try {
|
||||
final ArgResults results = argParser.parse(arguments);
|
||||
|
||||
bool verbose = false;
|
||||
|
||||
if (results.wasParsed('help')) {
|
||||
printUsage(argParser);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (results.wasParsed('version')) {
|
||||
print('owntracks_import version: $version');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (results.wasParsed('verbose')) {
|
||||
verbose = true;
|
||||
}
|
||||
|
||||
final sourceFilePath = results.option('source');
|
||||
|
||||
if (sourceFilePath == null) {
|
||||
throw FormatException('No source file specified');
|
||||
}
|
||||
|
||||
final rawData = await File(sourceFilePath).readAsString();
|
||||
|
||||
final data = jsonDecode(rawData);
|
||||
|
||||
final recordsList = data['features'];
|
||||
|
||||
final List<dynamic> failedList = [];
|
||||
|
||||
int n = 1;
|
||||
|
||||
for (final record in recordsList) {
|
||||
final Map<String, dynamic> payload = {'_type': 'location', 't': 'u'};
|
||||
|
||||
final recordProps = record['properties'];
|
||||
|
||||
payload['tst'] = recordProps['timestamp'];
|
||||
|
||||
payload['lat'] = double.tryParse(recordProps['latitude']);
|
||||
|
||||
payload['lon'] = double.tryParse(recordProps['longitude']);
|
||||
|
||||
payload['acc'] = recordProps['accuracy'];
|
||||
|
||||
payload['alt'] = recordProps['altitude'];
|
||||
|
||||
payload['vac'] = recordProps['vertical_accuracy'];
|
||||
|
||||
payload['vel'] = recordProps['velocity'];
|
||||
|
||||
int? batt = recordProps['battery'] != null
|
||||
? int.tryParse(recordProps['battery'])
|
||||
: null;
|
||||
|
||||
if (batt != null && batt <= 1) {
|
||||
batt = batt * 100;
|
||||
}
|
||||
|
||||
payload['batt'] = batt;
|
||||
|
||||
payload['bs'] = recordProps['battery_status'];
|
||||
|
||||
payload['inregions'] = recordProps['in_regions'];
|
||||
|
||||
payload['SSID'] = recordProps['ssid'];
|
||||
|
||||
payload['conn'] = recordProps['connection'];
|
||||
|
||||
if (verbose) {
|
||||
print(' ');
|
||||
print('Record $n of ${recordsList.length}');
|
||||
print(payload);
|
||||
}
|
||||
|
||||
String device = recordProps['tracker_id'] ?? 'phone';
|
||||
|
||||
if (device.startsWith('device_tracker.')) {
|
||||
device = device.replaceAll('device_tracker.', '');
|
||||
}
|
||||
|
||||
final user = results.option('user');
|
||||
|
||||
final url = '${results.option('destination')}/pub?u=$user&d=$device';
|
||||
|
||||
if (verbose) {
|
||||
print(' ');
|
||||
print('...Sending to: $url');
|
||||
}
|
||||
|
||||
final response = await http.post(
|
||||
Uri.parse('${results.option('destination')}/pub?u=$user&d=$device'),
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: jsonEncode(payload),
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
if (verbose) {
|
||||
print('Success: ${response.body}');
|
||||
}
|
||||
} else {
|
||||
print('Error sending record. ${response.statusCode}: ${response.body}');
|
||||
|
||||
failedList.add(payload);
|
||||
}
|
||||
|
||||
if (!results.flag('no-limits')) {
|
||||
if (verbose) {
|
||||
print('Waiting 2 seconds to not hit API rate limit');
|
||||
}
|
||||
|
||||
await Future.delayed(Duration(seconds: 2));
|
||||
}
|
||||
|
||||
n++;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
print('Finished all records.');
|
||||
}
|
||||
|
||||
if (failedList.isNotEmpty) {
|
||||
print('The list of failed records:');
|
||||
print(failedList);
|
||||
}
|
||||
} on FormatException catch (e) {
|
||||
// Print usage information if an invalid argument was provided.
|
||||
print(e.message);
|
||||
print('');
|
||||
printUsage(argParser);
|
||||
} on Exception catch (e) {
|
||||
print(e);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user