--- a/gobm65.go Sat Mar 13 19:31:49 2021 +0100
+++ b/gobm65.go Sat Jul 10 20:54:14 2021 +0200
@@ -25,6 +25,9 @@
// ... also display World Health Organization classification:
// % gobm65 --stats --class
//
+// Display all records but reduce the list so that close records are replaced
+// with their average:
+// % gobm65 --reduce
// Display the latest 3 records with the average:
// % gobm65 -l 3 --average
// Display all records since a specific date:
@@ -346,6 +349,13 @@
return
}
+// diffTime returns the duration between two (decreasing) sorted measurements
+func diffTime(a, b measurement) time.Duration {
+ dateA := time.Date(a.Year, time.Month(a.Month), a.Day, a.Hour, a.Minute, 0, 0, time.Local)
+ dateB := time.Date(b.Year, time.Month(b.Month), b.Day, b.Hour, b.Minute, 0, 0, time.Local)
+ return dateA.Sub(dateB)
+}
+
func average(items []measurement) (measurement, error) {
var avgMeasure measurement
var avgCount int
@@ -459,6 +469,49 @@
return dev, nil
}
+// reduceList reduces the measurement list by regrouping close measurements;
+// if the time difference between several measurements is less than the given
+// threshold, they are replaced with their average.
+func reduceList(list []measurement, threshold time.Duration) []measurement {
+ var newList, acc []measurement
+
+ // flushAcc flushes the accumulator and adds an average measurement to
+ // the new list.
+ flushAcc := func() {
+ // setAvgTime computes the average date of the list and sets
+ // the measurement date to this average.
+ setAvgTime := func(m *measurement, l []measurement) {
+ var timestamp int64 = 0
+ for _, i := range l {
+ iDate := time.Date(i.Year, time.Month(i.Month), i.Day,
+ i.Hour, i.Minute, 0, 0, time.Local)
+ timestamp += iDate.Unix()
+ }
+ timestamp /= int64(len(l))
+ avgTime := time.Unix(timestamp, 0)
+ m.Year = avgTime.Year()
+ m.Month = int(avgTime.Month())
+ m.Day = avgTime.Day()
+ m.Hour = avgTime.Hour()
+ m.Minute = avgTime.Minute()
+ }
+ avg, _ := average(acc)
+ avg.Header = acc[0].Header // Arbitrary…
+ setAvgTime(&avg, acc)
+ newList = append(newList, avg)
+ acc = acc[:0]
+ }
+
+ for _, item := range list {
+ if len(acc) > 0 && diffTime(acc[len(acc)-1], item) > threshold {
+ flushAcc()
+ }
+ acc = append(acc, item)
+ }
+ flushAcc()
+ return newList
+}
+
func (m measurement) WHOClass() (int, int) {
flag := 0
@@ -527,6 +580,7 @@
device := flag.StringP("device", "d", "/dev/ttyUSB0", "Serial device")
fromTime := flag.String("from-time", "", "Select records after time (HH:MM)")
toTime := flag.String("to-time", "", "Select records bofore time (HH:MM)")
+ reduce := flag.BoolP("reduce", "r", false, "Reduce number of measurements (regroup measurements)")
flag.StringVar(fromDate, "since", "", "Same as --from-date")
@@ -663,6 +717,10 @@
items = newItems
}
+ if *reduce {
+ items = reduceList(items, time.Hour)
+ }
+
if *limit > 0 && len(items) > int(*limit) {
items = items[0:*limit]
}