23 // ... display more statistics: |
23 // ... display more statistics: |
24 // % gobm65 --stats |
24 // % gobm65 --stats |
25 // ... also display World Health Organization classification: |
25 // ... also display World Health Organization classification: |
26 // % gobm65 --stats --class |
26 // % gobm65 --stats --class |
27 // |
27 // |
|
28 // Display all records but reduce the list so that close records are replaced |
|
29 // with their average: |
|
30 // % gobm65 --reduce |
28 // Display the latest 3 records with the average: |
31 // Display the latest 3 records with the average: |
29 // % gobm65 -l 3 --average |
32 // % gobm65 -l 3 --average |
30 // Display all records since a specific date: |
33 // Display all records since a specific date: |
31 // % gobm65 --since "2016-06-01" |
34 // % gobm65 --since "2016-06-01" |
32 // Display all records before a specific date: |
35 // Display all records before a specific date: |
344 func parseTime(timeStr string) (t simpleTime, err error) { |
347 func parseTime(timeStr string) (t simpleTime, err error) { |
345 _, err = fmt.Sscanf(timeStr, "%d:%d", &t.hour, &t.minute) |
348 _, err = fmt.Sscanf(timeStr, "%d:%d", &t.hour, &t.minute) |
346 return |
349 return |
347 } |
350 } |
348 |
351 |
|
352 // diffTime returns the duration between two (decreasing) sorted measurements |
|
353 func diffTime(a, b measurement) time.Duration { |
|
354 dateA := time.Date(a.Year, time.Month(a.Month), a.Day, a.Hour, a.Minute, 0, 0, time.Local) |
|
355 dateB := time.Date(b.Year, time.Month(b.Month), b.Day, b.Hour, b.Minute, 0, 0, time.Local) |
|
356 return dateA.Sub(dateB) |
|
357 } |
|
358 |
349 func average(items []measurement) (measurement, error) { |
359 func average(items []measurement) (measurement, error) { |
350 var avgMeasure measurement |
360 var avgMeasure measurement |
351 var avgCount int |
361 var avgCount int |
352 |
362 |
353 for _, data := range items { |
363 for _, data := range items { |
455 dev.Systolic = int(sumSys / float64(len(items))) |
465 dev.Systolic = int(sumSys / float64(len(items))) |
456 dev.Diastolic = int(sumDia / float64(len(items))) |
466 dev.Diastolic = int(sumDia / float64(len(items))) |
457 dev.Pulse = int(sumPul / float64(len(items))) |
467 dev.Pulse = int(sumPul / float64(len(items))) |
458 |
468 |
459 return dev, nil |
469 return dev, nil |
|
470 } |
|
471 |
|
472 // reduceList reduces the measurement list by regrouping close measurements; |
|
473 // if the time difference between several measurements is less than the given |
|
474 // threshold, they are replaced with their average. |
|
475 func reduceList(list []measurement, threshold time.Duration) []measurement { |
|
476 var newList, acc []measurement |
|
477 |
|
478 // flushAcc flushes the accumulator and adds an average measurement to |
|
479 // the new list. |
|
480 flushAcc := func() { |
|
481 // setAvgTime computes the average date of the list and sets |
|
482 // the measurement date to this average. |
|
483 setAvgTime := func(m *measurement, l []measurement) { |
|
484 var timestamp int64 = 0 |
|
485 for _, i := range l { |
|
486 iDate := time.Date(i.Year, time.Month(i.Month), i.Day, |
|
487 i.Hour, i.Minute, 0, 0, time.Local) |
|
488 timestamp += iDate.Unix() |
|
489 } |
|
490 timestamp /= int64(len(l)) |
|
491 avgTime := time.Unix(timestamp, 0) |
|
492 m.Year = avgTime.Year() |
|
493 m.Month = int(avgTime.Month()) |
|
494 m.Day = avgTime.Day() |
|
495 m.Hour = avgTime.Hour() |
|
496 m.Minute = avgTime.Minute() |
|
497 } |
|
498 avg, _ := average(acc) |
|
499 avg.Header = acc[0].Header // Arbitrary… |
|
500 setAvgTime(&avg, acc) |
|
501 newList = append(newList, avg) |
|
502 acc = acc[:0] |
|
503 } |
|
504 |
|
505 for _, item := range list { |
|
506 if len(acc) > 0 && diffTime(acc[len(acc)-1], item) > threshold { |
|
507 flushAcc() |
|
508 } |
|
509 acc = append(acc, item) |
|
510 } |
|
511 flushAcc() |
|
512 return newList |
460 } |
513 } |
461 |
514 |
462 func (m measurement) WHOClass() (int, int) { |
515 func (m measurement) WHOClass() (int, int) { |
463 flag := 0 |
516 flag := 0 |
464 |
517 |
525 whoClass := flag.BoolP("class", "c", false, "Display WHO classification") |
578 whoClass := flag.BoolP("class", "c", false, "Display WHO classification") |
526 merge := flag.BoolP("merge", "m", false, "Try to merge input JSON file with fetched data") |
579 merge := flag.BoolP("merge", "m", false, "Try to merge input JSON file with fetched data") |
527 device := flag.StringP("device", "d", "/dev/ttyUSB0", "Serial device") |
580 device := flag.StringP("device", "d", "/dev/ttyUSB0", "Serial device") |
528 fromTime := flag.String("from-time", "", "Select records after time (HH:MM)") |
581 fromTime := flag.String("from-time", "", "Select records after time (HH:MM)") |
529 toTime := flag.String("to-time", "", "Select records bofore time (HH:MM)") |
582 toTime := flag.String("to-time", "", "Select records bofore time (HH:MM)") |
|
583 reduce := flag.BoolP("reduce", "r", false, "Reduce number of measurements (regroup measurements)") |
530 |
584 |
531 flag.StringVar(fromDate, "since", "", "Same as --from-date") |
585 flag.StringVar(fromDate, "since", "", "Same as --from-date") |
532 |
586 |
533 var startTime, endTime simpleTime |
587 var startTime, endTime simpleTime |
534 |
588 |