Skip to content

Commit

Permalink
Complete all IoT Monitoring functions
Browse files Browse the repository at this point in the history
- Add methods for retrieving previous/historical telemetry data
- Use timestamp from Realtime Database to update reload time instead of using timestamp generated on device
  • Loading branch information
rayjasson98 committed Jan 3, 2021
1 parent 5c158e8 commit 3ec6b11
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 10 deletions.
7 changes: 7 additions & 0 deletions lib/data/IoT/models/telemetry_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,11 @@ class TelemetryData {
value: data.value,
);
}

factory TelemetryData.from(String timestamp, String value) {
return TelemetryData(
timestamp: DateTime.fromMillisecondsSinceEpoch(int.parse(timestamp)),
value: value,
);
}
}
37 changes: 36 additions & 1 deletion lib/data/IoT/repositories/telemetry_data_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,43 @@ class TelemetryDataRepository {
Stream<TelemetryData> readData(String data) {
return _telemetryDb
.child(data)
.orderByValue()
.orderByKey()
.onChildAdded
.map((event) => TelemetryData.fromRealtimeDatabase(event.snapshot));
}

TelemetryData readPreviousReading(String data) {
TelemetryData telemetryData;
_telemetryDb
.child(data)
.orderByKey()
.limitToLast(1)
.onChildAdded
.forEach((event) {
if (event.snapshot != null) {
telemetryData = TelemetryData.fromRealtimeDatabase(event.snapshot);
}
});
return telemetryData;
}

List<TelemetryData> readPreviousReadings(String data, int num) {
List<TelemetryData> telemetryDataList = List();
_telemetryDb
.child(data)
.orderByKey()
.limitToLast(num)
.onValue
.forEach((event) {
if (event.snapshot != null && event.snapshot.value != null) {
Map<dynamic, dynamic> map = event.snapshot.value;
map = Map.fromEntries(map.entries.toList()
..sort((e1, e2) => int.parse(e1.key).compareTo(int.parse(e2.key))));
map.forEach((key, value) {
telemetryDataList.add(TelemetryData.from(key, value));
});
}
});
return telemetryDataList;
}
}
4 changes: 2 additions & 2 deletions lib/ui/IoT/reload_time.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ class ReloadTime extends ChangeNotifier {

String get reloadTime => _reloadTime;

void update() {
_reloadTime = DateFormat('dd-MM-yyyy HH:mm:ss').format(DateTime.now());
void update(DateTime timestamp) {
_reloadTime = DateFormat('dd-MM-yyyy HH:mm:ss').format(timestamp);
notifyListeners();
}
}
2 changes: 2 additions & 0 deletions lib/ui/IoT/telemetry_data_card.dart
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ class TelemetryDataCard extends StatelessWidget {
Expanded(
flex: 2,
child: TelemetryDataReading(
data: cardItem.data,
reloadTime: reloadTime,
),
),
Expand Down Expand Up @@ -135,6 +136,7 @@ class TelemetryDataCard extends StatelessWidget {
bottom: 12,
),
child: TelemetryDataChart(
data: cardItem.data,
numData: 6,
cardItem: cardItem,
),
Expand Down
35 changes: 31 additions & 4 deletions lib/ui/IoT/telemetry_data_chart.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,17 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:intl/intl.dart';

class TelemetryDataChart extends StatelessWidget {
TelemetryDataChart({Key key, @required this.numData, @required this.cardItem})
: spots = LineChartSpots(numData),
TelemetryDataChart({
Key key,
@required this.data,
@required this.numData,
@required this.cardItem,
}) : spots = LineChartSpots(numData),
bottomTitles = FixedSizedQueue(numData),
xIndexes = Iterable<int>.generate(numData).toList(),
super(key: key);

final String data;
final int numData;
final LineChartSpots spots;
final FixedSizedQueue<String> bottomTitles;
Expand All @@ -23,9 +28,31 @@ class TelemetryDataChart extends StatelessWidget {
Widget build(BuildContext context) {
TelemetryData telemetryData = context.watch<TelemetryData>();

// If real-time telemetry data is not available,
if (telemetryData == null) {
return Container();
} else {
// Tries to read previous telemetry data.
// Use Provider.of() method due to stricter restrictions imposed by
// context.read() method when it is called inside a build function.
List<TelemetryData> telemetryDataList =
RepositoryProvider.of<TelemetryDataRepository>(
context,
listen: false,
).readPreviousReadings(data, numData);

// Returns an empty container if previous telemetry data is also not available.
if (telemetryDataList.length == 0) {
return Container();
}
// Adds previous data into line chart points.
else {
telemetryDataList.forEach((telemetryData) {
spots.add(telemetryData.value);
bottomTitles.add(DateFormat.ms().format(telemetryData.timestamp));
});
}
}
// If real-time telemetry data is available, add data into line chart points.
else {
spots.add(telemetryData.value);
bottomTitles.add(DateFormat.ms().format(telemetryData.timestamp));
}
Expand Down
24 changes: 21 additions & 3 deletions lib/ui/IoT/telemetry_data_reading.dart
Original file line number Diff line number Diff line change
@@ -1,22 +1,40 @@
import 'package:farmassist/app_theme.dart';
import 'package:farmassist/data/IoT/models/telemetry_data.dart';
import 'package:farmassist/data/IoT/repositories/telemetry_data_repository.dart';
import 'package:farmassist/ui/IoT/reload_time.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:provider/provider.dart';

class TelemetryDataReading extends StatelessWidget {
const TelemetryDataReading({this.reloadTime});
const TelemetryDataReading({@required this.data, this.reloadTime});

final String data;
final ReloadTime reloadTime;

@override
Widget build(BuildContext context) {
TelemetryData telemetryData = context.watch<TelemetryData>();

// If real-time telemetry data is not available,
if (telemetryData == null) {
return _buildReading('N/A');
// Tries to read previous telemetry data.
// Use Provider.of() method due to stricter restrictions imposed by
// context.read() method when it is called inside a build function.
telemetryData = RepositoryProvider.of<TelemetryDataRepository>(
context,
listen: false,
).readPreviousReading(data);
}

// Returns "N/A" if previous telemetry data is also not available.
if (telemetryData == null) {
return _buildReading("N/A");
} else {
Future.delayed(Duration.zero, () => reloadTime.update());
Future.delayed(
Duration.zero,
() => reloadTime.update(telemetryData.timestamp),
);
return _buildReading(telemetryData.value);
}
}
Expand Down

1 comment on commit 3ec6b11

@rayjasson98
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Currently, only 1 historical telemetry data will be retrieved from Firebase.
  • Fail to retrieve more historical data due to design issue.
  • A FutureBuilder might be required to wait for the data retrieval to succeed and rebuild the widget.

Please sign in to comment.