|
| 1 | +package main |
| 2 | + |
| 3 | +import ( |
| 4 | + "encoding/csv" |
| 5 | + "flag" |
| 6 | + "fmt" |
| 7 | + "math" |
| 8 | + "os" |
| 9 | + "strconv" |
| 10 | +) |
| 11 | + |
| 12 | +func main() { |
| 13 | + inputFile := flag.String("input", "", "Path to the CSV file to analyze") |
| 14 | + sampleSize := flag.Int("samples", 10, "Number of sample rows to display") |
| 15 | + flag.Parse() |
| 16 | + |
| 17 | + if *inputFile == "" { |
| 18 | + fmt.Println("Error: Please specify an input file with --input") |
| 19 | + os.Exit(1) |
| 20 | + } |
| 21 | + |
| 22 | + file, err := os.Open(*inputFile) |
| 23 | + if err != nil { |
| 24 | + fmt.Printf("Error opening file: %v\n", err) |
| 25 | + os.Exit(1) |
| 26 | + } |
| 27 | + defer func() { |
| 28 | + if closeErr := file.Close(); closeErr != nil { |
| 29 | + fmt.Printf("Warning: Error closing file: %v\n", closeErr) |
| 30 | + } |
| 31 | + }() |
| 32 | + |
| 33 | + reader := csv.NewReader(file) |
| 34 | + |
| 35 | + fmt.Printf("Analyzing file: %s\n", *inputFile) |
| 36 | + fmt.Printf("Showing %d sample rows:\n\n", *sampleSize) |
| 37 | + |
| 38 | + var timeDeltas []int64 |
| 39 | + var voltages []int64 |
| 40 | + var currents []int64 |
| 41 | + var temps []int64 |
| 42 | + |
| 43 | + fmt.Println("RAW DATA SAMPLES:") |
| 44 | + fmt.Println("---------------------------------------------------------------") |
| 45 | + fmt.Printf("%-15s %-15s %-15s %-15s\n", "TIME_DELTA", "VOLTAGE", "CURRENT", "TEMP") |
| 46 | + fmt.Println("---------------------------------------------------------------") |
| 47 | + |
| 48 | + for i := 0; i < *sampleSize; i++ { |
| 49 | + row, err := reader.Read() |
| 50 | + if err != nil { |
| 51 | + break |
| 52 | + } |
| 53 | + |
| 54 | + if len(row) != 4 { |
| 55 | + fmt.Printf("Row %d has %d columns, expected 4\n", i+1, len(row)) |
| 56 | + continue |
| 57 | + } |
| 58 | + |
| 59 | + timeDelta, _ := strconv.ParseInt(row[0], 10, 64) |
| 60 | + voltage, _ := strconv.ParseInt(row[1], 10, 64) |
| 61 | + current, _ := strconv.ParseInt(row[2], 10, 64) |
| 62 | + temp, _ := strconv.ParseInt(row[3], 10, 64) |
| 63 | + |
| 64 | + timeDeltas = append(timeDeltas, timeDelta) |
| 65 | + voltages = append(voltages, voltage) |
| 66 | + currents = append(currents, current) |
| 67 | + temps = append(temps, temp) |
| 68 | + |
| 69 | + fmt.Printf("%-15d %-15d %-15d %-15d\n", timeDelta, voltage, current, temp) |
| 70 | + } |
| 71 | + |
| 72 | + fmt.Println("\nVALUE RANGES:") |
| 73 | + fmt.Println("---------------------------------------------------------------") |
| 74 | + |
| 75 | + minTimeDelta, maxTimeDelta := findMinMax(timeDeltas) |
| 76 | + minTemp, maxTemp := findMinMax(temps) |
| 77 | + minVoltage, maxVoltage := findMinMax(voltages) |
| 78 | + minCurrent, maxCurrent := findMinMax(currents) |
| 79 | + |
| 80 | + fmt.Printf("Time Delta: Min=%d ms, Max=%d ms\n", minTimeDelta, maxTimeDelta) |
| 81 | + fmt.Printf("Temperature: Min=%d, Max=%d (Raw value)\n", minTemp, maxTemp) |
| 82 | + fmt.Printf(" Min=%.2f °C, Max=%.2f °C (Millicelsius)\n", float64(minTemp)/1000.0, float64(maxTemp)/1000.0) |
| 83 | + fmt.Printf(" Min=%.2f °C, Max=%.2f °C (Raw/100)\n", float64(minTemp)/100.0, float64(maxTemp)/100.0) |
| 84 | + |
| 85 | + fmt.Printf("Voltage: Min=%d, Max=%d (Raw value)\n", minVoltage, maxVoltage) |
| 86 | + fmt.Printf(" Min=%.6f V, Max=%.6f V (Microvolts)\n", float64(minVoltage)/1000000.0, float64(maxVoltage)/1000000.0) |
| 87 | + fmt.Printf(" Min=%.6f V, Max=%.6f V (Millivolts)\n", float64(minVoltage)/1000.0, float64(maxVoltage)/1000.0) |
| 88 | + |
| 89 | + fmt.Printf("Current: Min=%d, Max=%d (Raw value)\n", minCurrent, maxCurrent) |
| 90 | + fmt.Printf(" Min=%.6f A, Max=%.6f A (Nanoamperes)\n", float64(minCurrent)/1000000000.0, float64(maxCurrent)/1000000000.0) |
| 91 | + fmt.Printf(" Min=%.6f A, Max=%.6f A (Microamperes)\n", float64(minCurrent)/1000000.0, float64(maxCurrent)/1000000.0) |
| 92 | + |
| 93 | + fmt.Printf("\nSUGGESTED UNITS FOR YOUR ESP32 DATA:\n") |
| 94 | + fmt.Printf("---------------------------------------------------------------\n") |
| 95 | + |
| 96 | + suggestUnits(0, maxTemp, minVoltage, maxVoltage, minCurrent, maxCurrent) |
| 97 | + |
| 98 | + fmt.Printf("ENEMETER DATA FORMAT INFORMATION:\n") |
| 99 | + fmt.Printf("---------------------------------------------------------------\n") |
| 100 | + fmt.Printf("Column order: TIME_DELTA, VOLTAGE, CURRENT, TEMP\n") |
| 101 | + fmt.Printf("Temperature: Values are in millicelsius (°C = value / 1000)\n") |
| 102 | + fmt.Printf("Voltage: Values are in microvolts (V = value / 1000000)\n") |
| 103 | + fmt.Printf("Current: Values are in nanoamperes (A = value / 1000000000)\n") |
| 104 | +} |
| 105 | + |
| 106 | +func findMinMax(values []int64) (int64, int64) { |
| 107 | + if len(values) == 0 { |
| 108 | + return 0, 0 |
| 109 | + } |
| 110 | + |
| 111 | + min := values[0] |
| 112 | + max := values[0] |
| 113 | + |
| 114 | + for _, val := range values { |
| 115 | + if val < min { |
| 116 | + min = val |
| 117 | + } |
| 118 | + if val > max { |
| 119 | + max = val |
| 120 | + } |
| 121 | + } |
| 122 | + |
| 123 | + return min, max |
| 124 | +} |
| 125 | + |
| 126 | +func suggestUnits(_, maxTemp, minVoltage, maxVoltage, minCurrent, maxCurrent int64) { |
| 127 | + // Suggest temperature units |
| 128 | + if maxTemp > 100000 { |
| 129 | + fmt.Println("Temperature: Values appear to be in raw ADC format") |
| 130 | + fmt.Println(" Consider using raw_value / 10 as °C") |
| 131 | + } else if maxTemp > 10000 { |
| 132 | + fmt.Println("Temperature: Values appear to be in millicelsius") |
| 133 | + fmt.Println(" Consider using raw_value / 1000 as °C") |
| 134 | + } else if maxTemp > 1000 { |
| 135 | + fmt.Println("Temperature: Values appear to be in centicelsius") |
| 136 | + fmt.Println(" Consider using raw_value / 100 as °C") |
| 137 | + } else { |
| 138 | + fmt.Println("Temperature: Values appear to be direct celsius readings") |
| 139 | + } |
| 140 | + |
| 141 | + // Suggest voltage units |
| 142 | + if math.Abs(float64(minVoltage)) > 1000000 || math.Abs(float64(maxVoltage)) > 1000000 { |
| 143 | + fmt.Println("Voltage: Values appear to be in microvolts") |
| 144 | + fmt.Println(" Consider using raw_value / 1000000 as V") |
| 145 | + } else if math.Abs(float64(minVoltage)) > 1000 || math.Abs(float64(maxVoltage)) > 1000 { |
| 146 | + fmt.Println("Voltage: Values appear to be in millivolts") |
| 147 | + fmt.Println(" Consider using raw_value / 1000 as V") |
| 148 | + } else { |
| 149 | + fmt.Println("Voltage: Values appear to be direct voltage readings (V)") |
| 150 | + } |
| 151 | + |
| 152 | + // Suggest current units |
| 153 | + if maxCurrent > 1000000 || minCurrent < -1000000 { |
| 154 | + fmt.Println("Current: Values appear to be in nanoamperes") |
| 155 | + fmt.Println(" Consider using raw_value / 1000000000 as A") |
| 156 | + } else if maxCurrent > 1000 || minCurrent < -1000 { |
| 157 | + fmt.Println("Current: Values appear to be in microamperes") |
| 158 | + fmt.Println(" Consider using raw_value / 1000000 as A") |
| 159 | + } else { |
| 160 | + fmt.Println("Current: Values appear to be in milliamperes") |
| 161 | + fmt.Println(" Consider using raw_value / 1000 as A") |
| 162 | + } |
| 163 | +} |
0 commit comments