Sensor: add temperature.

Fixes #2241.
This commit is contained in:
Dennis Guse
2026-01-04 09:56:44 +01:00
parent 738201c1c2
commit 54844b9a9a
36 changed files with 435 additions and 44 deletions
@@ -61,6 +61,7 @@ public class GPXTrackExporter implements TrackExporter {
private static final NumberFormat SPEED_FORMAT = NumberFormat.getInstance(Locale.US);
private static final NumberFormat DISTANCE_FORMAT = NumberFormat.getInstance(Locale.US);
private static final NumberFormat HEARTRATE_FORMAT = NumberFormat.getInstance(Locale.US);
private static final NumberFormat TEMPERATURE_FORMAT = NumberFormat.getInstance(Locale.US);
private static final NumberFormat CADENCE_FORMAT = NumberFormat.getInstance(Locale.US);
private static final NumberFormat POWER_FORMAT = NumberFormat.getInstance(Locale.US);
@@ -82,6 +83,9 @@ public class GPXTrackExporter implements TrackExporter {
HEARTRATE_FORMAT.setMaximumFractionDigits(0);
HEARTRATE_FORMAT.setGroupingUsed(false);
TEMPERATURE_FORMAT.setMaximumFractionDigits(2);
TEMPERATURE_FORMAT.setGroupingUsed(false);
CADENCE_FORMAT.setMaximumFractionDigits(0);
CADENCE_FORMAT.setGroupingUsed(false);
@@ -321,6 +325,10 @@ public class GPXTrackExporter implements TrackExporter {
trackPointExtensionV2Content += "<gpxtpx:hr>" + HEARTRATE_FORMAT.format(trackPoint.heartRate().getBPM()) + "</gpxtpx:hr>\n";
}
if (trackPoint.temperature() != null) {
trackPointExtensionV2Content += "<gpxtpx:atemp>" + TEMPERATURE_FORMAT.format(trackPoint.temperature().getCelsius()) + "</gpxtpx:atemp>\n";
}
if (trackPoint.cadence() != null) {
trackPointExtensionV2Content += "<gpxtpx:cad>" + CADENCE_FORMAT.format(trackPoint.cadence().getRPM()) + "</gpxtpx:cad>\n";
}
@@ -67,8 +67,9 @@ public class KMLTrackExporter implements TrackExporter {
public static final String EXTENDED_DATA_TYPE_TRACKPOINT = "trackpoint_type";
public static final String EXTENDED_DATA_TYPE_SPEED = "speed";
public static final String EXTENDED_DATA_TYPE_DISTANCE = "distance";
public static final String EXTENDED_DATA_TYPE_CADENCE = "cadence";
public static final String EXTENDED_DATA_TYPE_HEARTRATE = "heartrate";
public static final String EXTENDED_DATA_TYPE_TEMPERATURE = "temperature";
public static final String EXTENDED_DATA_TYPE_CADENCE = "cadence";
public static final String EXTENDED_DATA_TYPE_POWER = "power";
public static final String EXTENDED_DATA_TYPE_ALTITUDE_GAIN = "elevation_gain";
public static final String EXTENDED_DATA_TYPE_ALTITUDE_LOSS = "elevation_loss";
@@ -95,6 +96,7 @@ public class KMLTrackExporter implements TrackExporter {
private final List<Float> powerList = new ArrayList<>();
private final List<Float> cadenceList = new ArrayList<>();
private final List<Float> heartRateList = new ArrayList<>();
private final List<Float> temperatureList = new ArrayList<>();
private final List<Float> altitudeGainList = new ArrayList<>(); //TODO Join with altitudeLossList
private final List<Float> altitudeLossList = new ArrayList<>();
private final List<Float> accuracyHorizontal = new ArrayList<>();
@@ -237,7 +239,7 @@ public class KMLTrackExporter implements TrackExporter {
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/kml/2.3 http://schemas.opengis.net/kml/2.3/ogckml23.xsd
http://opentracksapp.com/xmlschemas/v1 http://opentracksapp.com/xmlschemas/OpenTracks_v1.xsd">
"""); //TODO ADD xsi:schemaLocation for atom
"""); //NOTE: There is no XSD for Atom
printWriter.println("<Document>");
printWriter.println("<open>1</open>");
printWriter.println("<visibility>1</visibility>");
@@ -254,6 +256,7 @@ public class KMLTrackExporter implements TrackExporter {
writeSimpleArrayStyle(EXTENDED_DATA_TYPE_POWER, context.getString(R.string.description_sensor_power));
writeSimpleArrayStyle(EXTENDED_DATA_TYPE_CADENCE, context.getString(R.string.description_sensor_cadence));
writeSimpleArrayStyle(EXTENDED_DATA_TYPE_HEARTRATE, context.getString(R.string.description_sensor_heart_rate));
writeSimpleArrayStyle(EXTENDED_DATA_TYPE_TEMPERATURE, context.getString(R.string.description_sensor_temperature));
printWriter.println("</Schema>");
}
@@ -321,6 +324,7 @@ public class KMLTrackExporter implements TrackExporter {
powerList.clear();
cadenceList.clear();
heartRateList.clear();
temperatureList.clear();
altitudeGainList.clear();
altitudeLossList.clear();
accuracyHorizontal.clear();
@@ -349,6 +353,9 @@ public class KMLTrackExporter implements TrackExporter {
if (heartRateList.stream().anyMatch(Objects::nonNull)) {
writeSimpleArraySensorData(heartRateList, EXTENDED_DATA_TYPE_HEARTRATE);
}
if (temperatureList.stream().anyMatch(Objects::nonNull)) {
writeSimpleArraySensorData(temperatureList, EXTENDED_DATA_TYPE_TEMPERATURE);
}
if (altitudeGainList.stream().anyMatch(Objects::nonNull)) {
writeSimpleArraySensorData(altitudeGainList, EXTENDED_DATA_TYPE_ALTITUDE_GAIN);
}
@@ -381,6 +388,7 @@ public class KMLTrackExporter implements TrackExporter {
distanceList.add(trackPoint.sensorDistance() != null ? (float) trackPoint.sensorDistance().toM() : null);
heartRateList.add(trackPoint.heartRate() != null ? trackPoint.heartRate().getBPM() : null);
temperatureList.add(trackPoint.temperature() != null ? trackPoint.temperature().getCelsius() : null);
cadenceList.add(trackPoint.cadence() != null ? trackPoint.cadence().getRPM() : null);
powerList.add(trackPoint.power() != null ? trackPoint.power().getW() : null);
if (trackPoint.altitudeGainLoss() != null) {
@@ -40,6 +40,7 @@ import de.dennisguse.opentracks.data.models.Marker;
import de.dennisguse.opentracks.data.models.Position;
import de.dennisguse.opentracks.data.models.Power;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.Temperature;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.data.statistics.SegmentStatisticUpdater;
@@ -83,6 +84,7 @@ public class GPXTrackImporter extends DefaultHandler implements XMLImporter.Trac
*/
private static final String TAG_EXTENSION_SPEED_COMPAT = "speed";
private static final String TAG_EXTENSION_HEARTRATE = "gpxtpx:hr";
private static final String TAG_EXTENSION_TEMPERATURE = "gpxtpx:atemp";
private static final String TAG_EXTENSION_CADENCE = "gpxtpx:cad";
private static final String TAG_EXTENSION_POWER = "pwr:PowerInWatts";
@@ -113,6 +115,7 @@ public class GPXTrackImporter extends DefaultHandler implements XMLImporter.Trac
private String time;
private String speed;
private String heartrate;
private String temperature;
private String cadence;
private String power;
private String markerType;
@@ -218,6 +221,11 @@ public class GPXTrackImporter extends DefaultHandler implements XMLImporter.Trac
heartrate = content.trim();
}
}
case TAG_EXTENSION_TEMPERATURE -> {
if (content != null) {
temperature = content.trim();
}
}
case TAG_EXTENSION_CADENCE -> {
if (content != null) {
cadence = content.trim();
@@ -354,6 +362,15 @@ public class GPXTrackImporter extends DefaultHandler implements XMLImporter.Trac
}
}
Temperature parsedTemperature = null;
if (temperature != null) {
try {
parsedTemperature = Temperature.of(Float.parseFloat(temperature));
} catch (NumberFormatException e) {
throw new ParsingException(createErrorMessage(String.format(Locale.US, "Unable to parse temperature: %s", temperature)), e);
}
}
Cadence parsedCadence = null;
if (cadence != null) {
try {
@@ -396,6 +413,7 @@ public class GPXTrackImporter extends DefaultHandler implements XMLImporter.Trac
),
parsedSensorDistance,
parsedHeartRate,
parsedTemperature,
parsedCadence,
parsedPower,
altitudeGainLoss
@@ -415,9 +433,10 @@ public class GPXTrackImporter extends DefaultHandler implements XMLImporter.Trac
sensorDistance = null;
accuracyHorizontal = null;
accuracyVertical = null;
power = null;
heartrate = null;
temperature = null;
cadence = null;
power = null;
}
private void onMarkerStart(Attributes attributes) {
@@ -42,6 +42,7 @@ import de.dennisguse.opentracks.data.models.Marker;
import de.dennisguse.opentracks.data.models.Position;
import de.dennisguse.opentracks.data.models.Power;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.Temperature;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.io.file.exporter.KMLTrackExporter;
@@ -109,6 +110,7 @@ public class KMLTrackImporter extends DefaultHandler implements XMLImporter.Trac
private final ArrayList<Float> sensorDistanceList = new ArrayList<>();
private final ArrayList<Float> sensorCadenceList = new ArrayList<>();
private final ArrayList<Float> sensorHeartRateList = new ArrayList<>();
private final ArrayList<Float> sensorTemperatureList = new ArrayList<>();
private final ArrayList<Float> sensorPowerList = new ArrayList<>();
private final ArrayList<Float> altitudeGainList = new ArrayList<>();
private final ArrayList<Float> altitudeLossList = new ArrayList<>();
@@ -312,6 +314,7 @@ public class KMLTrackImporter extends DefaultHandler implements XMLImporter.Trac
sensorSpeedList.clear();
sensorDistanceList.clear();
sensorHeartRateList.clear();
sensorTemperatureList.clear();
sensorCadenceList.clear();
sensorPowerList.clear();
altitudeGainList.clear();
@@ -334,6 +337,7 @@ public class KMLTrackImporter extends DefaultHandler implements XMLImporter.Trac
Speed speed = null;
Distance sensorDistance = null;
HeartRate heartRate = null;
Temperature temperature = null;
Cadence cadence = null;
Power power = null;
AltitudeGainLoss altitudeGainLoss = null;
@@ -352,6 +356,9 @@ public class KMLTrackImporter extends DefaultHandler implements XMLImporter.Trac
if (i < sensorHeartRateList.size()) {
heartRate = HeartRate.ofOrNull(sensorHeartRateList.get(i));
}
if (i < sensorTemperatureList.size() && sensorTemperatureList.get(i) != null) {
temperature = Temperature.of(sensorTemperatureList.get(i));
}
if (i < sensorCadenceList.size() && sensorCadenceList.get(i) != null) {
cadence = Cadence.of(sensorCadenceList.get(i));
}
@@ -399,6 +406,7 @@ public class KMLTrackImporter extends DefaultHandler implements XMLImporter.Trac
position,
sensorDistance,
heartRate,
temperature,
cadence,
power,
altitudeGainLoss
@@ -467,6 +475,7 @@ public class KMLTrackImporter extends DefaultHandler implements XMLImporter.Trac
case KMLTrackExporter.EXTENDED_DATA_TYPE_POWER -> sensorPowerList.add(value);
case KMLTrackExporter.EXTENDED_DATA_TYPE_HEARTRATE,
EXTENDED_DATA_TYPE_HEART_RATE_LEGACY -> sensorHeartRateList.add(value);
case KMLTrackExporter.EXTENDED_DATA_TYPE_TEMPERATURE -> sensorTemperatureList.add(value);
case KMLTrackExporter.EXTENDED_DATA_TYPE_CADENCE -> sensorCadenceList.add(value);
case KMLTrackExporter.EXTENDED_DATA_TYPE_ALTITUDE_GAIN -> altitudeGainList.add(value);
case KMLTrackExporter.EXTENDED_DATA_TYPE_ALTITUDE_LOSS -> altitudeLossList.add(value);