Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stream science data without running tests #158

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion lib/src/data/protobuf.dart
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,8 @@ extension ScienceStateUtils on ScienceState {
switch (this) {
case ScienceState.SCIENCE_STATE_UNDEFINED: return "Unknown";
case ScienceState.STOP_COLLECTING: return "Idle";
case ScienceState.COLLECT_DATA: return "Collecting data";
case ScienceState.COLLECT_DATA: return "Start test";
case ScienceState.STREAM_DATA: return "Stream data";
}
// Do not use default or else you'll lose exhaustiveness checking.
throw ArgumentError("Unrecognized task: $this");
Expand Down
2 changes: 1 addition & 1 deletion lib/src/models/view/builders/science_command.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import "package:rover_dashboard/data.dart";
import "package:rover_dashboard/models.dart";

/// A [ValueBuilder] to modify and send an [AutonomyCommand].
/// A [ValueBuilder] to modify and send an [ScienceCommand].
class ScienceCommandBuilder extends ValueBuilder<ScienceCommand> {
/// The sample number being tested.
final sample = NumberBuilder<int>(1, min: 1, max: 3);
Expand Down
29 changes: 22 additions & 7 deletions lib/src/models/view/science.dart
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,15 @@ class ScienceAnalysis {
final SampleData data = SampleData();

/// Passes the overriden data to the sensor's test to determine signs of life.
ScienceResult get testResult => data.readings.isEmpty
ScienceResult get testResult => data.readings.isEmpty
? ScienceResult.loading : sensor.test(SampleData()
..min = testBuilder.min.value
..average = testBuilder.average.value
..max = testBuilder.max.value,
);

/// Clears all readings from this analysis.
void clear() {
void clear() {
data.clear();
testBuilder.update(data);
}
Expand All @@ -87,7 +87,7 @@ class ScienceModel with ChangeNotifier {
/// A list of all the samples for all the sensors.
Map<ScienceSensor, List<ScienceAnalysis>> allSamples = {
for (final sensor in sensors) sensor: [
for (int i = 0; i < models.settings.science.numSamples; i++)
for (int i = 0; i < models.settings.science.numSamples; i++)
ScienceAnalysis(sensor),
],
};
Expand Down Expand Up @@ -140,11 +140,14 @@ class ScienceModel with ChangeNotifier {
/// Whether the page is currently loading.
bool isLoading = false;

/// Whether the pump command has just been sent.
bool isPumping = false;

/// The error, if any, that occurred while loading the data.
String? errorText;

/// Adds a value to the correct analysis for the sensor and sample.
void addReading(ScienceSensor sensor, int sample, Timestamp timestamp, double value) =>
void addReading(ScienceSensor sensor, int sample, Timestamp timestamp, double value) =>
allSamples[sensor]![sample].addReading(timestamp, value);

/// Adds a [WrappedMessage] containing a [ScienceData] to the UI.
Expand All @@ -154,9 +157,9 @@ class ScienceModel with ChangeNotifier {
final sample = data.sample;
if (!wrapper.hasTimestamp()) { throw ArgumentError("Data is missing a timestamp"); }
if (sample >= numSamples) throw RangeError("Got data for sample #${sample + 1}, but there are only $numSamples samples.\nChange the number of samples in the settings and reload.");
if (data.co2 != 0) addReading(co2, sample, wrapper.timestamp, data.co2);
if (data.humidity != 0) addReading(humidity, sample, wrapper.timestamp, data.humidity);
if (data.temperature != 0) addReading(temperature, sample, wrapper.timestamp, data.temperature);
if (data.co2 != 0) addReading(co2, sample, wrapper.timestamp, data.co2);
if (data.humidity != 0) addReading(humidity, sample, wrapper.timestamp, data.humidity);
if (data.temperature != 0) addReading(temperature, sample, wrapper.timestamp, data.temperature);
}

/// Clears all the readings from all the samples.
Expand All @@ -170,6 +173,18 @@ class ScienceModel with ChangeNotifier {
models.home.setMessage(severity: Severity.info, text: "Science UI will update on new data");
}

/// Sends a [ScienceCommand] to fill the pumps
Future<void> fillPumps() async{
isPumping = true;
notifyListeners();
models.messages.sendMessage(ScienceCommand(pumps: PumpState.PUMP_ON));
models.home.setMessage(severity: Severity.info, text: "Science command submitted. Check the video feed to confirm");
await Future<void>.delayed(const Duration(seconds: 3));
isPumping = false;
notifyListeners();
return;
}

/// Calls [addMessage] for each message in the picked file.
Future<void> loadFile() async {
// Pick a file
Expand Down
40 changes: 23 additions & 17 deletions lib/src/pages/science.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import "package:rover_dashboard/widgets.dart";
/// Allows desktop users to scroll with their mouse or other device.
class DesktopScrollBehavior extends MaterialScrollBehavior {
@override
Set<PointerDeviceKind> get dragDevices => {
Set<PointerDeviceKind> get dragDevices => {
PointerDeviceKind.touch,
PointerDeviceKind.mouse,
PointerDeviceKind.stylus,
Expand All @@ -30,12 +30,12 @@ class ScrollingRow extends ReusableReactiveWidget<SettingsModel> {

@override
Widget build(BuildContext context, SettingsModel model) => SizedBox(
height: height,
height: height,
child: model.science.scrollableGraphs
? ScrollConfiguration(
behavior: DesktopScrollBehavior(),
child: ListView(
scrollDirection: Axis.horizontal,
scrollDirection: Axis.horizontal,
children: [for (final child in children) SizedBox(width: 400, child: child)],
),
)
Expand All @@ -53,17 +53,17 @@ class ChartsRow extends StatelessWidget {
/// The height of this row.
final double height;

/// The data for these charts.
/// The data for these charts.
final List<ScienceAnalysis> analyses;

/// The chart to show for each piece of data.
final Widget Function(ScienceAnalysis) builder;

/// A const constructor.
const ChartsRow({
required this.title,
required this.analyses,
required this.builder,
required this.title,
required this.analyses,
required this.builder,
this.height = 300,
});

Expand Down Expand Up @@ -95,29 +95,29 @@ class SciencePage extends ReactiveWidget<ScienceModel> {
static final red = HSVColor.fromColor(Colors.red);
/// Purple, used as the color for the last sample.
static final purple = HSVColor.fromColor(Colors.purple);
/// Gets a color between red and purple
/// Gets a color between red and purple
///
/// [value] must be between 0.0 and 1.0.
/// [value] must be between 0.0 and 1.0.
Color getColor(double value) => HSVColor.lerp(red, purple, value)!.toColor();

/// The `package:fl_chart` helper class for the details charts.
LineChartData getDetailsData(ScienceAnalysis analysis, Color color) => LineChartData(
lineBarsData: [
LineChartBarData(
spots: [
for (final reading in analysis.data.readings)
for (final reading in analysis.data.readings)
FlSpot(reading.time, reading.value),
],
],
color: color,
preventCurveOverShooting: true,
isCurved: true,
),
],
],
titlesData: FlTitlesData(
topTitles: const AxisTitles(),
topTitles: const AxisTitles(),
bottomTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
showTitles: true,
getTitlesWidget: (double value, TitleMeta meta) => SideTitleWidget(
axisSide: AxisSide.bottom,
space: 3,
Expand All @@ -140,10 +140,10 @@ class SciencePage extends ReactiveWidget<ScienceModel> {
BarChartGroupData(x: 2, barRods: [BarChartRodData(color: color, fromY: 0, toY: analysis.data.max ?? 0)]),
],
titlesData: FlTitlesData(
topTitles: const AxisTitles(),
topTitles: const AxisTitles(),
bottomTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
showTitles: true,
getTitlesWidget: (double value, TitleMeta meta) => SideTitleWidget(
axisSide: AxisSide.bottom,
space: 3,
Expand All @@ -167,10 +167,16 @@ class SciencePage extends ReactiveWidget<ScienceModel> {
Widget build(BuildContext context, ScienceModel model) => Column(children: [
Row(children: [ // The header at the top
const SizedBox(width: 8),
Text("Science Analysis", style: context.textTheme.headlineMedium),
Text("Science Analysis", style: context.textTheme.headlineMedium),
const SizedBox(width: 12),
if (model.isLoading) const SizedBox(height: 20, width: 20, child: CircularProgressIndicator()),
const Spacer(),
ElevatedButton(
onPressed: model.isPumping ? null : model.fillPumps,
style: ElevatedButton.styleFrom(backgroundColor: Colors.green),
child: const Text("Fill Pumps"),
),
const SizedBox(width: 12),
DropdownButton(
value: model.sample,
onChanged: model.updateSample,
Expand Down
2 changes: 1 addition & 1 deletion lib/src/widgets/atomic/science_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class ScienceCommandEditor extends ReactiveWidget<ScienceCommandBuilder> {
name: "State: ",
value: model.state,
onChanged: model.updateState,
items: const [ScienceState.STOP_COLLECTING, ScienceState.COLLECT_DATA],
items: const [ScienceState.STOP_COLLECTING, ScienceState.COLLECT_DATA, ScienceState.STREAM_DATA],
humanName: (state) => state.humanName,
),),
const SizedBox(width: 12),
Expand Down
54 changes: 27 additions & 27 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,10 @@ packages:
dependency: transitive
description:
name: cli_util
sha256: c05b7406fdabc7a49a3929d4af76bcaccbbffcbcdcf185b082e1ae07da323d19
sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c
url: "https://pub.dev"
source: hosted
version: "0.4.1"
version: "0.4.2"
clock:
dependency: transitive
description:
Expand Down Expand Up @@ -126,10 +126,10 @@ packages:
dependency: transitive
description:
name: equatable
sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2
sha256: "567c64b3cb4cf82397aac55f4f0cbd3ca20d77c6c03bedbc4ceaddc08904aef7"
url: "https://pub.dev"
source: hosted
version: "2.0.5"
version: "2.0.7"
fake_async:
dependency: transitive
description:
Expand All @@ -150,10 +150,10 @@ packages:
dependency: "direct main"
description:
name: file_picker
sha256: aac85f20436608e01a6ffd1fdd4e746a7f33c93a2c83752e626bdfaea139b877
sha256: "16dc141db5a2ccc6520ebb6a2eb5945b1b09e95085c021d9f914f8ded7f1465c"
url: "https://pub.dev"
source: hosted
version: "8.1.3"
version: "8.1.4"
fixnum:
dependency: transitive
description:
Expand All @@ -166,10 +166,10 @@ packages:
dependency: "direct main"
description:
name: fl_chart
sha256: "94307bef3a324a0d329d3ab77b2f0c6e5ed739185ffc029ed28c0f9b019ea7ef"
sha256: "74959b99b92b9eebeed1a4049426fd67c4abc3c5a0f4d12e2877097d6a11ae08"
url: "https://pub.dev"
source: hosted
version: "0.69.0"
version: "0.69.2"
flutter:
dependency: "direct main"
description: flutter
Expand Down Expand Up @@ -279,10 +279,10 @@ packages:
dependency: "direct main"
description:
name: just_audio
sha256: b41646a8241688f1d99c2e69c4da2bb26aa4b3a99795f6ff205c2a165e033fda
sha256: a49e7120b95600bd357f37a2bb04cd1e88252f7cdea8f3368803779b925b1049
url: "https://pub.dev"
source: hosted
version: "0.9.41"
version: "0.9.42"
just_audio_platform_interface:
dependency: transitive
description:
Expand Down Expand Up @@ -335,10 +335,10 @@ packages:
dependency: transitive
description:
name: logger
sha256: "697d067c60c20999686a0add96cf6aba723b3aa1f83ecf806a8097231529ec32"
sha256: be4b23575aac7ebf01f225a241eb7f6b5641eeaf43c6a8613510fc2f8cf187d1
url: "https://pub.dev"
source: hosted
version: "2.4.0"
version: "2.5.0"
matcher:
dependency: transitive
description:
Expand Down Expand Up @@ -383,10 +383,10 @@ packages:
dependency: "direct main"
description:
name: package_info_plus
sha256: df3eb3e0aed5c1107bb0fdb80a8e82e778114958b1c5ac5644fb1ac9cae8a998
sha256: da8d9ac8c4b1df253d1a328b7bf01ae77ef132833479ab40763334db13b91cce
url: "https://pub.dev"
source: hosted
version: "8.1.0"
version: "8.1.1"
package_info_plus_platform_interface:
dependency: transitive
description:
Expand All @@ -407,18 +407,18 @@ packages:
dependency: "direct main"
description:
name: path_provider
sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378
sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
version: "2.1.5"
path_provider_android:
dependency: transitive
description:
name: path_provider_android
sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a
sha256: "8c4967f8b7cb46dc914e178daa29813d83ae502e0529d7b0478330616a691ef7"
url: "https://pub.dev"
source: hosted
version: "2.2.12"
version: "2.2.14"
path_provider_foundation:
dependency: transitive
description:
Expand Down Expand Up @@ -503,10 +503,10 @@ packages:
dependency: transitive
description:
name: sdl3
sha256: abe5e6ffe27029f3de176a136503ada7ccd4d4c113e3beb32604d971a055e0f7
sha256: "145b12886dfbd53992f7b96538455826eab09fe46986e0048e682fe90e2203d1"
url: "https://pub.dev"
source: hosted
version: "0.1.39"
version: "0.1.44"
sdl_gamepad:
dependency: transitive
description:
Expand Down Expand Up @@ -604,10 +604,10 @@ packages:
dependency: transitive
description:
name: url_launcher_android
sha256: "0dea215895a4d254401730ca0ba8204b29109a34a99fb06ae559a2b60988d2de"
sha256: "6fc2f56536ee873eeb867ad176ae15f304ccccc357848b351f6f0d8d4a40d193"
url: "https://pub.dev"
source: hosted
version: "6.3.13"
version: "6.3.14"
url_launcher_ios:
dependency: transitive
description:
Expand All @@ -620,10 +620,10 @@ packages:
dependency: transitive
description:
name: url_launcher_linux
sha256: e2b9622b4007f97f504cd64c0128309dfb978ae66adbe944125ed9e1750f06af
sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935"
url: "https://pub.dev"
source: hosted
version: "3.2.0"
version: "3.2.1"
url_launcher_macos:
dependency: transitive
description:
Expand Down Expand Up @@ -700,10 +700,10 @@ packages:
dependency: transitive
description:
name: win32
sha256: e1d0cc62e65dc2561f5071fcbccecf58ff20c344f8f3dc7d4922df372a11df1f
sha256: "84ba388638ed7a8cb3445a320c8273136ab2631cd5f2c57888335504ddab1bc2"
url: "https://pub.dev"
source: hosted
version: "5.7.1"
version: "5.8.0"
xdg_directories:
dependency: transitive
description:
Expand All @@ -729,5 +729,5 @@ packages:
source: hosted
version: "3.1.2"
sdks:
dart: ">=3.5.3 <4.0.0"
dart: ">=3.5.4 <4.0.0"
flutter: ">=3.24.0"
Loading