1

I work with Flutter and want to log and store the collected Data of the Sensor Model: OP174. I'm using the Accelorometer, Gyroscope, Magnetometer and Temperatur.

I see in the Movesense.swift that there is a Logbook_path and a Datalogger_config_path but I can't figure out how to get it to save the collected Data, it tried another soloution that i post below.

How can i store this Data in a CSV File and will be the Timestamp automaticly included?

Getting the Gyroscope Data

int _gyroSubscription;
  String _gyroscopeData = "";
  String get gyroscopeData => _gyroscopeData;
  bool get gyroscopeSubscribed => _gyroSubscription != null;

void subscribeToGyroscope() {
    _gyroscopeData = "";
    _gyroSubscription = Mds.subscribe(
        Mds.createSubscriptionUri(_serial, "/Meas/Gyro/104"),
        "{}",
        (d, c) => {},
        (e, c) => {},
        (data) => _onNewGyroscopeData(data),
        (e, c) => {});
    notifyListeners();
  }

  void _onNewGyroscopeData(String data) {
    Map<String, dynamic> gyroData = jsonDecode(data);
    Map<String, dynamic> body = gyroData["Body"];
    List<dynamic> gyroArry = body["ArrayGyro"];
    dynamic gyro = gyroArry.last;
    _gyroscopeData = "x: " +
        gyro["x"].toStringAsFixed(2) +
        "\ny: " +
        gyro["y"].toStringAsFixed(2) +
        "\nz: " +
        gyro["z"].toStringAsFixed(2);
    notifyListeners();
  }

Trying to save the Data

Future<String> getFilePath() async {
    Directory appDocumentsDirectory = await getExternalStorageDirectory();
    List<FileSystemEntity> directory = appDocumentsDirectory.listSync();
    directory.forEach((x) => debugPrint(x.path));
    String appDocumentsPath = appDocumentsDirectory.path;
    String filePath = '$appDocumentsPath/recording.csv';

    return filePath;
  }

  void saveFile(DeviceModel deviceModel) async {
    File file = File(await getFilePath());
    file.writeAsString(deviceModel.gyroscopeData);
  }

New Code Edit

import 'dart:convert';

import 'package:csv/csv.dart';
import 'package:flutter/foundation.dart';
import 'package:intl/intl.dart';
import 'package:mdsflutter/Mds.dart';
import 'dart:io';

import 'package:path_provider/path_provider.dart';

import 'dart:developer' as developer;

class DeviceModel extends ChangeNotifier {
  String _serial;
  String _name;

  bool _skipAccelerometer = false;
  bool _skipGyroscope = false;
  bool _skipMagneto = false;

  set skipAccelerometer(bool x) {
    _skipAccelerometer = x;
  }

  bool get skipAccelerometer => _skipAccelerometer;

  set skipGyroscope(bool x) {
    _skipGyroscope = x;
  }

  bool get skipGyroscope => _skipGyroscope;

  set skipMagneto(bool x) {
    _skipMagneto = x;
  }

  bool get skipMagneto => _skipMagneto;

  List<List<dynamic>> _accelerometerList = new List<List<dynamic>>();
  List<List<dynamic>> _gyroscopeList = new List<List<dynamic>>();
  List<List<dynamic>> _magnetoList = new List<List<dynamic>>();

  String get name => _name;

  String get serial => _serial;

  int _accSubscription;
  String _accelerometerData = "";

  String get accelerometerData => _accelerometerData;

  bool get accelerometerSubscribed => _accSubscription != null;

  int _gyroSubscription;
  String _gyroscopeData = "";

  String get gyroscopeData => _gyroscopeData;

  bool get gyroscopeSubscribed => _gyroSubscription != null;

  int _magnSubscription;
  String _magnetoData = "";

  String get magnetoData => _magnetoData;

  bool get magnetoSubscribed => _magnSubscription != null;

  int _hrSubscription;
  String _hrData = "";

  String get hrData => _hrData;

  bool get hrSubscribed => _hrSubscription != null;

  bool _ledStatus = false;

  bool get ledStatus => _ledStatus;

  String _temperature = "";

  String get temperature => _temperature;

  DeviceModel(this._name, this._serial);

  void subscribeToAccelerometer() {
    _accelerometerData = "";
    _accSubscription = Mds.subscribe(
        Mds.createSubscriptionUri(_serial, "/Meas/Acc/104"),
        "{}",
        (d, c) => {},
        (e, c) => {},
        (data) => _onNewAccelerometerData(data),
        (e, c) => {});
    notifyListeners();
  }

  void _onNewAccelerometerData(String data) {
    Map<String, dynamic> accData = jsonDecode(data);
    Map<String, dynamic> body = accData["Body"];
    List<dynamic> accArray = body["ArrayAcc"];
    dynamic acc = accArray.last;
    _accelerometerData = "x: " +
        acc["x"].toStringAsFixed(2) +
        "\ny: " +
        acc["y"].toStringAsFixed(2) +
        "\nz: " +
        acc["z"].toStringAsFixed(2);

    //Option 1
    DateTime now = DateTime.now();
    var dateLocal = now.toLocal();
    var formattedDate = DateFormat('yyyy-MM-dd HH:mm:ss').format(dateLocal);

    //Option 2
    //var formattedDate = DateTime.now().millisecondsSinceEpoch;

    List<dynamic> row = new List<dynamic>();
    row.add(formattedDate);
    row.add(acc["x"].toStringAsFixed(2));
    row.add(acc["y"].toStringAsFixed(2));
    row.add(acc["z"].toStringAsFixed(2));

    _accelerometerList.add(row);
    notifyListeners();
  }

  void unsubscribeFromAccelerometer() {
    Mds.unsubscribe(_accSubscription);
    _accSubscription = null;
    notifyListeners();
  }

  void subscribeToGyroscope() {
    _gyroscopeData = "";
    _gyroSubscription = Mds.subscribe(
        Mds.createSubscriptionUri(_serial, "/Meas/Gyro/26"),
        "{}",
        (d, c) => {},
        (e, c) => {},
        (data) => _onNewGyroscopeData(data),
        (e, c) => {});
    notifyListeners();
  }

  void _onNewGyroscopeData(String data) {
    Map<String, dynamic> gyroData = jsonDecode(data);
    Map<String, dynamic> body = gyroData["Body"];
    List<dynamic> gyroArry = body["ArrayGyro"];
    dynamic gyro = gyroArry.last;
    _gyroscopeData = "x: " +
        gyro["x"].toStringAsFixed(2) +
        "\ny: " +
        gyro["y"].toStringAsFixed(2) +
        "\nz: " +
        gyro["z"].toStringAsFixed(2);

    //Option 1
    DateTime now = DateTime.now();
    var dateLocal = now.toLocal();
    var formattedDate = DateFormat('yyyy-MM-dd HH:mm:ss').format(dateLocal);

    //Option 2
    //var formattedDate = DateTime.now().millisecondsSinceEpoch;

    List<dynamic> row = new List<dynamic>();
    row.add(formattedDate);
    row.add(gyro["x"].toStringAsFixed(2));
    row.add(gyro["y"].toStringAsFixed(2));
    row.add(gyro["z"].toStringAsFixed(2));
    _gyroscopeList.add(row);
    notifyListeners();
  }

  void unsubscribeFromGyroscope() {
    Mds.unsubscribe(_gyroSubscription);
    _gyroSubscription = null;
    notifyListeners();
  }

  void subscribeToMagnetometer() {
    _magnetoData = "";
    _magnSubscription = Mds.subscribe(
        Mds.createSubscriptionUri(_serial, "/Meas/Magn/104"),
        "{}",
        (d, c) => {},
        (e, c) => {},
        (data) => _onNewMagnetometerData(data),
        (e, c) => {});
    notifyListeners();
  }

  // static int count = 0;

  void _onNewMagnetometerData(String data) {
    Map<String, dynamic> magnData = jsonDecode(data);
    Map<String, dynamic> body = magnData["Body"];
    List<dynamic> magnArry = body["ArrayMagn"];
    dynamic magn = magnArry.last;
    // int c = count++;
    _magnetoData = "x: " +
        magn["x"].toStringAsFixed(2) +
        "\ny: " +
        magn["y"].toStringAsFixed(2) +
        "\nz: " +
        magn["z"].toStringAsFixed(2);

    //Option 1
    DateTime now = DateTime.now();
    var dateLocal = now.toLocal();
    var formattedDate = DateFormat('yyyy-MM-dd HH:mm:ss').format(dateLocal);

    //Option 2
    //var formattedDate = DateTime.now().millisecondsSinceEpoch;

    List<dynamic> row = new List<dynamic>();
    row.add(formattedDate);
    row.add(magn["x"].toStringAsFixed(2));
    row.add(magn["y"].toStringAsFixed(2));
    row.add(magn["z"].toStringAsFixed(2));
    // row.add(c.toString());

    _magnetoList.add(row);
    notifyListeners();
  }

  void unsubscribeFromMagnetometer() {
    Mds.unsubscribe(_magnSubscription);
    _magnSubscription = null;
    notifyListeners();
  }

  void subscribeToHr() {
    _hrData = "";
    _hrSubscription = Mds.subscribe(
        Mds.createSubscriptionUri(_serial, "/Meas/HR"),
        "{}",
        (d, c) => {},
        (e, c) => {},
        (data) => _onNewHrData(data),
        (e, c) => {});
    notifyListeners();
  }

  void _onNewHrData(String data) {
    Map<String, dynamic> hrData = jsonDecode(data);
    Map<String, dynamic> body = hrData["Body"];
    double hr = body["average"];
    _hrData = hr.toStringAsFixed(1) + " bpm";
    notifyListeners();
  }

  void unsubscribeFromHr() {
    Mds.unsubscribe(_hrSubscription);
    _hrSubscription = null;
    notifyListeners();
  }

  void switchLed() {
    Map<String, bool> contract = new Map<String, bool>();
    contract["isOn"] = !_ledStatus;
    Mds.put(
        Mds.createRequestUri(_serial, "/Component/Led"), jsonEncode(contract),
        (data, code) {
      _ledStatus = !_ledStatus;
      notifyListeners();
    }, (e, c) => {});
  }

  void getTemperature() {
    Mds.get(Mds.createRequestUri(_serial, "/Meas/Temp"), "{}", (data, code) {
      double kelvin = jsonDecode(data)["Content"]["Measurement"];
      double temperatureVal = kelvin - 274.15;
      _temperature = temperatureVal.toStringAsFixed(1) + " C";
      notifyListeners();
    }, (e, c) => {});
  }

  void startAccelerometerRecord() {
    _skipAccelerometer = false;
    _accelerometerList = new List<List<dynamic>>();
    List<dynamic> header = new List();
    header.add("timestamp");
    header.add("X");
    header.add("Y");
    header.add("Z");
    _accelerometerList.add(header);
  }

  void stopAccelerometerRecord() {
    _skipAccelerometer = true;
    writeToCsvAccelerometer();
  }

  void startGyroscopeRecord() {
    _skipGyroscope = false;
    _gyroscopeList = new List<List<dynamic>>();
    List<dynamic> header = new List();
    header.add("timestamp");
    header.add("X");
    header.add("Y");
    header.add("Z");
    _gyroscopeList.add(header);
  }

  void stopGyroscopeRecord() {
    _skipGyroscope = true;
    writeToCsvGyroscope();
  }

  void startMagnetoRecord() {
    _skipMagneto = false;
    _magnetoList = new List<List<dynamic>>();
    List<dynamic> header = new List();
    header.add("timestamp");
    header.add("X");
    header.add("Y");
    header.add("Z");
    _magnetoList.add(header);
  }

  void stopMagnetoRecord() {
    _skipMagneto = true;
    writeToCsvMagneto();
  }

  void writeToCsvAccelerometer() async {
    File file = File(await getFilePath("accelero"));
    String csv = const ListToCsvConverter().convert(_accelerometerList);
    file.writeAsString(csv);
  }

  void writeToCsvGyroscope() async {
    File file = File(await getFilePath("gyro"));
    String csv = const ListToCsvConverter().convert(_gyroscopeList);
    file.writeAsString(csv);
  }

  void writeToCsvMagneto() async {
    File file = File(await getFilePath("magneto"));
    String csv = const ListToCsvConverter().convert(_magnetoList);
    file.writeAsString(csv);
  }

  Future<String> getFilePath(String name) async {
    DateTime now = DateTime.now();
    var dateLocal = now.toLocal();
    var formattedDate = DateFormat('yyyy-MM-dd HH:mm').format(dateLocal);

    Directory appDocumentsDirectory;

    if (Platform.isAndroid) {
      appDocumentsDirectory = await getExternalStorageDirectory();
    } else if (Platform.isIOS) {
      appDocumentsDirectory = await getApplicationDocumentsDirectory();
    }
    List<FileSystemEntity> directory = appDocumentsDirectory.listSync();
    directory.forEach((x) => debugPrint(x.path));
    String appDocumentsPath = appDocumentsDirectory.path;
    String filePath = '$appDocumentsPath/' + name + '' + formattedDate + '.csv';

    return filePath;
  }
}
Tempelritter
  • 471
  • 9
  • 22

1 Answers1

0

For working with the DataLogger & Logbook, please see the Android example "DataLoggerSample" as well as the related API-documentation.

In short:

  1. PUT /Mem/DataLogger/Config that lists paths that you want to log. In your case they would be /Meas/IMU9/104 and /Meas/Temp.
  2. PUT /Mem/DataLogger/State to 3 (=LOGGING) -- you can disconnect here --
  3. Do you thing that you want to measure
  4. Re-connect to sensor
  5. PUT /Mem/DataLogger/State to 2 (=READY). This stops the recording.
  6. GET "suunto:/MDS/Logbook/{serial}/Entries" on mobile to have a list of entries on the sensors datamemory. The one with biggest LogID is the one you just recorded
  7. GET "suunto:/MDS/Logbook/{serial}/byId/{LogId}/Data" on mobile to get the recording as JSON.

NOTE: The paths you want to record fill up the data memory quite fast (< 100 seconds). Current sensor treats data mem as ring buffer and stores over the old data if it gets full so you'll get the last ~90s of data.

Full Disclosure: I work for the Movesense team

PetriL
  • 1,211
  • 1
  • 7
  • 11
  • Hello @PetriL, I have Subscribed to the Types of Sensor Data that I want. This is working and i get the Data. What my Problem is, as you see above, i set the Sample Rate to 104, but I get the Data from the Sensor only about 10-13 Entries per Seconds. What is my Problem there? I updated my Code above, you hopefully you can see if there is any error. Another Question on the API Documentation, I don't see with how much the Samplerate for the Magnetometer is, could you also please tell me that? – Tempelritter Feb 12 '21 at 08:41