gobm65.go
changeset 21 c00a10738af3
parent 20 fe86e794b63a
child 22 853f58e76ba5
equal deleted inserted replaced
20:fe86e794b63a 21:c00a10738af3
    20 //
    20 //
    21 // Get records and display the average:
    21 // Get records and display the average:
    22 // % gobm65 --average
    22 // % gobm65 --average
    23 // ... display more statistics:
    23 // ... display more statistics:
    24 // % gobm65 --stats
    24 // % gobm65 --stats
       
    25 // ... also display World Health Organization classification:
       
    26 // % gobm65 --stats --class
    25 //
    27 //
    26 // Display the latest 3 records with the average:
    28 // Display the latest 3 records with the average:
    27 // % gobm65 -l 3 --average
    29 // % gobm65 -l 3 --average
    28 // Display all records since a specific date:
    30 // Display all records since a specific date:
    29 // % gobm65 --since "2016-06-01"
    31 // % gobm65 --since "2016-06-01"
    79 	Year      int
    81 	Year      int
    80 }
    82 }
    81 
    83 
    82 type simpleTime struct {
    84 type simpleTime struct {
    83 	hour, minute int
    85 	hour, minute int
       
    86 }
       
    87 
       
    88 // World Heath Organization blood pressure classification
       
    89 const (
       
    90 	BPOptimal              = iota // < 120,80:  Optimal
       
    91 	BPNormal                      // < 130,85:  Normal
       
    92 	BPHighNormal                  // < 140,90:  High-Normal
       
    93 	BPMildHypertension            // < 160,100: Mild Hypertension
       
    94 	BPModerateHypertension        // < 180,110: Moderate Hypertension
       
    95 	BPSevereHypertension          // >=180,110: Severe Hypertension
       
    96 )
       
    97 
       
    98 // WHOPressureClassification contains the World Health Organization blood
       
    99 // pressure categories
       
   100 var WHOPressureClassification = []string{
       
   101 	"Optimal",
       
   102 	"Normal",
       
   103 	"High-Normal",
       
   104 	"Mild Hypertension",
       
   105 	"Moderate Hypertension",
       
   106 	"Severe Hypertension",
    84 }
   107 }
    85 
   108 
    86 func getData(s io.ReadWriteCloser, buf []byte, size int) (int, error) {
   109 func getData(s io.ReadWriteCloser, buf []byte, size int) (int, error) {
    87 	t := 0
   110 	t := 0
    88 	b := buf
   111 	b := buf
   421 	dev.Pulse = int(sumPul / float64(len(items)))
   444 	dev.Pulse = int(sumPul / float64(len(items)))
   422 
   445 
   423 	return dev, nil
   446 	return dev, nil
   424 }
   447 }
   425 
   448 
       
   449 func (m measurement) WHOClass() int {
       
   450 	switch {
       
   451 	case m.Systolic < 120 && m.Diastolic < 80:
       
   452 		return BPOptimal
       
   453 	case m.Systolic < 130 && m.Diastolic < 85:
       
   454 		return BPNormal
       
   455 	case m.Systolic < 140 && m.Diastolic < 90:
       
   456 		return BPHighNormal
       
   457 	case m.Systolic < 160 && m.Diastolic < 100:
       
   458 		return BPMildHypertension
       
   459 	case m.Systolic < 180 && m.Diastolic < 110:
       
   460 		return BPModerateHypertension
       
   461 	}
       
   462 	return BPSevereHypertension
       
   463 }
       
   464 
       
   465 func (m measurement) WHOClassString() string {
       
   466 	return WHOPressureClassification[m.WHOClass()]
       
   467 }
       
   468 
       
   469 func displayWHOClassStats(items []measurement) {
       
   470 	sum := 0
       
   471 	classes := make(map[int]int)
       
   472 	for _, m := range items {
       
   473 		s := m.WHOClass()
       
   474 		classes[s]++
       
   475 		sum += s
       
   476 	}
       
   477 
       
   478 	avg := float64(sum) / float64(len(items))
       
   479 	fmt.Printf("Average WHO classification: %s (%.2f)\n",
       
   480 		WHOPressureClassification[int(0.5+avg)], avg)
       
   481 
       
   482 	for c := range WHOPressureClassification {
       
   483 		fmt.Printf(" . %21s: %3d (%d%%)\n",
       
   484 			WHOPressureClassification[c], classes[c],
       
   485 			classes[c]*100/len(items))
       
   486 	}
       
   487 }
       
   488 
   426 func main() {
   489 func main() {
   427 	inFile := flag.String([]string{"-input-file", "i"}, "", "Input JSON file")
   490 	inFile := flag.String([]string{"-input-file", "i"}, "", "Input JSON file")
   428 	outFile := flag.String([]string{"-output-file", "o"}, "", "Output JSON file")
   491 	outFile := flag.String([]string{"-output-file", "o"}, "", "Output JSON file")
   429 	limit := flag.Uint([]string{"-limit", "l"}, 0, "Limit number of items to N first")
   492 	limit := flag.Uint([]string{"-limit", "l"}, 0, "Limit number of items to N first")
   430 	toDate := flag.String([]string{"-to-date"}, "",
   493 	toDate := flag.String([]string{"-to-date"}, "",
   432 	fromDate := flag.String([]string{"-from-date", "-since"}, "",
   495 	fromDate := flag.String([]string{"-from-date", "-since"}, "",
   433 		"Filter records from date (YYYY-mm-dd HH:MM:SS)")
   496 		"Filter records from date (YYYY-mm-dd HH:MM:SS)")
   434 	format := flag.String([]string{"-format", "f"}, "", "Output format (csv, json)")
   497 	format := flag.String([]string{"-format", "f"}, "", "Output format (csv, json)")
   435 	avg := flag.Bool([]string{"-average", "a"}, false, "Compute average")
   498 	avg := flag.Bool([]string{"-average", "a"}, false, "Compute average")
   436 	stats := flag.Bool([]string{"-stats"}, false, "Compute statistics")
   499 	stats := flag.Bool([]string{"-stats"}, false, "Compute statistics")
       
   500 	whoClass := flag.Bool([]string{"-class", "c"}, false, "Display WHO classification")
   437 	merge := flag.Bool([]string{"-merge", "m"}, false,
   501 	merge := flag.Bool([]string{"-merge", "m"}, false,
   438 		"Try to merge input JSON file with fetched data")
   502 		"Try to merge input JSON file with fetched data")
   439 	device := flag.String([]string{"-device", "d"}, "/dev/ttyUSB0", "Serial device")
   503 	device := flag.String([]string{"-device", "d"}, "/dev/ttyUSB0", "Serial device")
   440 	fromTime := flag.String([]string{"-from-time"}, "", "Select records after time (HH:MM)")
   504 	fromTime := flag.String([]string{"-from-time"}, "", "Select records after time (HH:MM)")
   441 	toTime := flag.String([]string{"-to-time"}, "", "Select records bofore time (HH:MM)")
   505 	toTime := flag.String([]string{"-to-time"}, "", "Select records bofore time (HH:MM)")
   579 
   643 
   580 	// Done with filtering
   644 	// Done with filtering
   581 
   645 
   582 	if *format == "csv" {
   646 	if *format == "csv" {
   583 		for i, data := range items {
   647 		for i, data := range items {
   584 			fmt.Printf("%d;%x;%d-%02d-%02d %02d:%02d;%d;%d;%d\n",
   648 			fmt.Printf("%d;%x;%d-%02d-%02d %02d:%02d;%d;%d;%d",
   585 				i+1, data.Header,
   649 				i+1, data.Header,
   586 				data.Year, data.Month, data.Day,
   650 				data.Year, data.Month, data.Day,
   587 				data.Hour, data.Minute,
   651 				data.Hour, data.Minute,
   588 				data.Systolic, data.Diastolic, data.Pulse)
   652 				data.Systolic, data.Diastolic, data.Pulse)
       
   653 			if *whoClass {
       
   654 				fmt.Printf(";%s", data.WHOClassString())
       
   655 			}
       
   656 			fmt.Println()
   589 		}
   657 		}
   590 	}
   658 	}
   591 
   659 
   592 	if *stats {
   660 	if *stats {
   593 		*avg = true
   661 		*avg = true
   596 	if *avg && len(items) > 0 {
   664 	if *avg && len(items) > 0 {
   597 		avgMeasure, err := average(items)
   665 		avgMeasure, err := average(items)
   598 		if err != nil {
   666 		if err != nil {
   599 			log.Println("Error:", err)
   667 			log.Println("Error:", err)
   600 		} else {
   668 		} else {
   601 			fmt.Printf("Average: %d;%d;%d\n", avgMeasure.Systolic,
   669 			fmt.Printf("Average: %d;%d;%d", avgMeasure.Systolic,
   602 				avgMeasure.Diastolic, avgMeasure.Pulse)
   670 				avgMeasure.Diastolic, avgMeasure.Pulse)
       
   671 			if *whoClass {
       
   672 				fmt.Printf("  [%s]", avgMeasure.WHOClassString())
       
   673 			}
       
   674 			fmt.Println()
   603 		}
   675 		}
   604 	}
   676 	}
   605 
   677 
   606 	if *stats && len(items) > 1 {
   678 	if *stats && len(items) > 1 {
   607 		d, err := stdDeviation(items)
   679 		d, err := stdDeviation(items)
   622 	if *stats && len(items) > 0 {
   694 	if *stats && len(items) > 0 {
   623 		m, err := median(items)
   695 		m, err := median(items)
   624 		if err != nil {
   696 		if err != nil {
   625 			log.Println("Error:", err)
   697 			log.Println("Error:", err)
   626 		} else {
   698 		} else {
   627 			fmt.Printf("Median values: %d;%d;%d\n",
   699 			fmt.Printf("Median values: %d;%d;%d",
   628 				m.Systolic, m.Diastolic, m.Pulse)
   700 				m.Systolic, m.Diastolic, m.Pulse)
       
   701 			if *whoClass {
       
   702 				fmt.Printf("  [%s]", m.WHOClassString())
       
   703 			}
       
   704 			fmt.Println()
       
   705 		}
       
   706 
       
   707 		if *whoClass {
       
   708 			displayWHOClassStats(items)
   629 		}
   709 		}
   630 	}
   710 	}
   631 
   711 
   632 	if *format == "json" || *outFile != "" {
   712 	if *format == "json" || *outFile != "" {
   633 		rawJSON, err := json.MarshalIndent(items, "", "  ")
   713 		rawJSON, err := json.MarshalIndent(items, "", "  ")