mirror of
https://github.com/zjs81/meshcore-open.git
synced 2026-06-18 16:36:27 +10:00
Telemetry: room-server request fix #2
The telemetry parser has been expanded and should now support significantly more metrics. It has been ported from the Python implementation of meshcore_py.
This commit is contained in:
@@ -210,7 +210,7 @@ class _TelemetryScreenState extends State<TelemetryScreen> {
|
||||
if (widget.contact.type != advTypeChat) {
|
||||
frame = buildSendBinaryReq(
|
||||
widget.contact.publicKey,
|
||||
payload: Uint8List.fromList([reqTypeGetTelemetry]),
|
||||
payload: buildTelemetryBinaryPayload(),
|
||||
);
|
||||
} else {
|
||||
frame = buildSendTelemetryReq(widget.contact.publicKey);
|
||||
@@ -466,7 +466,6 @@ class _TelemetryScreenState extends State<TelemetryScreen> {
|
||||
int channel,
|
||||
bool isImperialUnits,
|
||||
) {
|
||||
final l10n = context.l10n;
|
||||
return Card(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
@@ -491,41 +490,164 @@ class _TelemetryScreenState extends State<TelemetryScreen> {
|
||||
),
|
||||
const Divider(),
|
||||
for (final entry in channelData.entries)
|
||||
if (entry.key == 'voltage' && channel == 1)
|
||||
_buildInfoRow(
|
||||
l10n.telemetry_batteryLabel,
|
||||
_batteryText(entry.value),
|
||||
)
|
||||
else if (entry.key == 'voltage')
|
||||
_buildInfoRow(
|
||||
l10n.telemetry_voltageLabel,
|
||||
l10n.telemetry_voltageValue(entry.value.toString()),
|
||||
)
|
||||
else if (entry.key == 'temperature' && channel == 1)
|
||||
_buildInfoRow(
|
||||
l10n.telemetry_mcuTemperatureLabel,
|
||||
_temperatureText(entry.value, isImperialUnits),
|
||||
)
|
||||
else if (entry.key == 'temperature')
|
||||
_buildInfoRow(
|
||||
l10n.telemetry_temperatureLabel,
|
||||
_temperatureText(entry.value, isImperialUnits),
|
||||
)
|
||||
else if (entry.key == 'current' && channel == 1)
|
||||
_buildInfoRow(
|
||||
l10n.telemetry_currentLabel,
|
||||
l10n.telemetry_currentValue(entry.value.toString()),
|
||||
)
|
||||
else if (entry.key == 'gps')
|
||||
_buildGpsInfo(entry.value)
|
||||
else
|
||||
_buildInfoRow(entry.key, entry.value.toString()),
|
||||
_buildTelemetryField(entry, channel, isImperialUnits),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTelemetryField(
|
||||
MapEntry<String, dynamic> entry,
|
||||
int channel,
|
||||
bool isImperialUnits,
|
||||
) {
|
||||
if (entry.key == 'gps') {
|
||||
return _buildGpsInfo(entry.value);
|
||||
}
|
||||
|
||||
final display = _formatTelemetryField(
|
||||
entry.key,
|
||||
entry.value,
|
||||
channel,
|
||||
isImperialUnits,
|
||||
);
|
||||
return _buildInfoRow(display.label, display.value);
|
||||
}
|
||||
|
||||
_TelemetryFieldDisplay _formatTelemetryField(
|
||||
String key,
|
||||
dynamic value,
|
||||
int channel,
|
||||
bool isImperialUnits,
|
||||
) {
|
||||
final l10n = context.l10n;
|
||||
final text = _telemetryValueText(value);
|
||||
|
||||
switch (key) {
|
||||
case 'digitalInput':
|
||||
return _TelemetryFieldDisplay(l10n.telemetry_digitalInputLabel, text);
|
||||
case 'digitalOutput':
|
||||
return _TelemetryFieldDisplay(l10n.telemetry_digitalOutputLabel, text);
|
||||
case 'analogInput':
|
||||
return _TelemetryFieldDisplay(
|
||||
l10n.telemetry_analogInputLabel,
|
||||
l10n.telemetry_analogValue(text),
|
||||
);
|
||||
case 'analogOutput':
|
||||
return _TelemetryFieldDisplay(
|
||||
l10n.telemetry_analogOutputLabel,
|
||||
l10n.telemetry_analogValue(text),
|
||||
);
|
||||
case 'generic':
|
||||
return _TelemetryFieldDisplay(l10n.telemetry_genericLabel, text);
|
||||
case 'luminosity':
|
||||
return _TelemetryFieldDisplay(
|
||||
l10n.telemetry_luminosityLabel,
|
||||
l10n.telemetry_luminosityValue(text),
|
||||
);
|
||||
case 'presence':
|
||||
return _TelemetryFieldDisplay(l10n.telemetry_presenceLabel, text);
|
||||
case 'temperature':
|
||||
return _TelemetryFieldDisplay(
|
||||
channel == 1
|
||||
? l10n.telemetry_mcuTemperatureLabel
|
||||
: l10n.telemetry_temperatureLabel,
|
||||
_temperatureText(value, isImperialUnits),
|
||||
);
|
||||
case 'humidity':
|
||||
return _TelemetryFieldDisplay(l10n.telemetry_humidityLabel, text);
|
||||
case 'accelerometer':
|
||||
return _TelemetryFieldDisplay(
|
||||
l10n.telemetry_accelerometerLabel,
|
||||
_telemetryAxisText(value),
|
||||
);
|
||||
case 'pressure':
|
||||
return _TelemetryFieldDisplay(
|
||||
l10n.telemetry_pressureLabel,
|
||||
l10n.telemetry_pressureValue(text),
|
||||
);
|
||||
case 'altitude':
|
||||
return _TelemetryFieldDisplay(
|
||||
l10n.telemetry_altitudeLabel,
|
||||
l10n.telemetry_altitudeValue(text),
|
||||
);
|
||||
case 'voltage':
|
||||
return _TelemetryFieldDisplay(
|
||||
channel == 1
|
||||
? l10n.telemetry_batteryLabel
|
||||
: l10n.telemetry_voltageLabel,
|
||||
channel == 1
|
||||
? _batteryText(value)
|
||||
: l10n.telemetry_voltageValue(text),
|
||||
);
|
||||
case 'current':
|
||||
return _TelemetryFieldDisplay(
|
||||
l10n.telemetry_currentLabel,
|
||||
l10n.telemetry_currentValue(text),
|
||||
);
|
||||
case 'frequency':
|
||||
return _TelemetryFieldDisplay(
|
||||
l10n.telemetry_frequencyLabel,
|
||||
l10n.telemetry_frequencyValue(text),
|
||||
);
|
||||
case 'percentage':
|
||||
return _TelemetryFieldDisplay(
|
||||
l10n.telemetry_percentageLabel,
|
||||
l10n.telemetry_percentageValue(text),
|
||||
);
|
||||
case 'concentration':
|
||||
return _TelemetryFieldDisplay(
|
||||
l10n.telemetry_concentrationLabel,
|
||||
l10n.telemetry_concentrationValue(text),
|
||||
);
|
||||
case 'power':
|
||||
return _TelemetryFieldDisplay(
|
||||
l10n.telemetry_powerLabel,
|
||||
l10n.telemetry_powerValue(text),
|
||||
);
|
||||
case 'distance':
|
||||
return _TelemetryFieldDisplay(
|
||||
l10n.telemetry_distanceLabel,
|
||||
l10n.telemetry_distanceValue(text),
|
||||
);
|
||||
case 'energy':
|
||||
return _TelemetryFieldDisplay(
|
||||
l10n.telemetry_energyLabel,
|
||||
l10n.telemetry_energyValue(text),
|
||||
);
|
||||
case 'direction':
|
||||
return _TelemetryFieldDisplay(
|
||||
l10n.telemetry_directionLabel,
|
||||
l10n.telemetry_directionValue(text),
|
||||
);
|
||||
case 'time':
|
||||
return _TelemetryFieldDisplay(
|
||||
l10n.telemetry_timeLabel,
|
||||
_telemetryTimeText(value),
|
||||
);
|
||||
case 'gyrometer':
|
||||
return _TelemetryFieldDisplay(
|
||||
l10n.telemetry_gyrometerLabel,
|
||||
_telemetryAxisText(value),
|
||||
);
|
||||
case 'colour':
|
||||
return _TelemetryFieldDisplay(
|
||||
l10n.telemetry_colourLabel,
|
||||
_telemetryColorText(value),
|
||||
);
|
||||
case 'switch':
|
||||
return _TelemetryFieldDisplay(l10n.telemetry_switchLabel, text);
|
||||
case 'polyline':
|
||||
return _TelemetryFieldDisplay(
|
||||
l10n.telemetry_polylineLabel,
|
||||
_telemetryMapText(value),
|
||||
);
|
||||
default:
|
||||
return _TelemetryFieldDisplay(key, text);
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildAutoRefreshCard() {
|
||||
final l10n = context.l10n;
|
||||
final counterText = _autoRefreshCounterText();
|
||||
@@ -762,7 +884,7 @@ class _TelemetryScreenState extends State<TelemetryScreen> {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildInfoRow('gps', gpsText),
|
||||
_buildInfoRow(context.l10n.telemetry_gpsLabel, gpsText),
|
||||
if (isValidPosition)
|
||||
TelemetryLocationMap(
|
||||
// The map renders only after bounds validation, keeping malformed
|
||||
@@ -794,6 +916,53 @@ class _TelemetryScreenState extends State<TelemetryScreen> {
|
||||
longitude <= 180.0;
|
||||
}
|
||||
|
||||
String _telemetryValueText(dynamic value) {
|
||||
if (value == null) return context.l10n.common_notAvailable;
|
||||
if (value is double) {
|
||||
return value.toStringAsFixed(value.truncateToDouble() == value ? 0 : 2);
|
||||
}
|
||||
if (value is num) {
|
||||
return value.toString();
|
||||
}
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
String _telemetryAxisText(dynamic value) {
|
||||
if (value is! Map) return _telemetryValueText(value);
|
||||
final x = _telemetryValueText(value['x']);
|
||||
final y = _telemetryValueText(value['y']);
|
||||
final z = _telemetryValueText(value['z']);
|
||||
return 'X: $x, Y: $y, Z: $z';
|
||||
}
|
||||
|
||||
String _telemetryColorText(dynamic value) {
|
||||
if (value is! Map) return _telemetryValueText(value);
|
||||
final red = _telemetryValueText(value['red']);
|
||||
final green = _telemetryValueText(value['green']);
|
||||
final blue = _telemetryValueText(value['blue']);
|
||||
return 'R: $red, G: $green, B: $blue';
|
||||
}
|
||||
|
||||
String _telemetryMapText(dynamic value) {
|
||||
if (value is! Map) return _telemetryValueText(value);
|
||||
return value.entries
|
||||
.map((entry) => '${entry.key}: ${entry.value}')
|
||||
.join(', ');
|
||||
}
|
||||
|
||||
String _telemetryTimeText(dynamic value) {
|
||||
if (value is! num || value <= 0) return _telemetryValueText(value);
|
||||
final dateTime = DateTime.fromMillisecondsSinceEpoch(
|
||||
value.toInt() * 1000,
|
||||
isUtc: true,
|
||||
).toLocal();
|
||||
final localizations = MaterialLocalizations.of(context);
|
||||
final time = localizations.formatTimeOfDay(
|
||||
TimeOfDay.fromDateTime(dateTime),
|
||||
);
|
||||
return '${localizations.formatFullDate(dateTime)} $time';
|
||||
}
|
||||
|
||||
Widget _buildInfoRow(String label, String value) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 6),
|
||||
@@ -862,3 +1031,10 @@ class _TelemetryScreenState extends State<TelemetryScreen> {
|
||||
return '${tempC.toStringAsFixed(1)}°C';
|
||||
}
|
||||
}
|
||||
|
||||
class _TelemetryFieldDisplay {
|
||||
final String label;
|
||||
final String value;
|
||||
|
||||
const _TelemetryFieldDisplay(this.label, this.value);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user