package logfile import ( "os" "path/filepath" "sort" "time" "github.com/go-flucky/flucky/pkg/types" ) // AppendTemperatures with temperature values from a logfile. As additional option it's possible to compress the temperature data. func AppendTemperatures(logfile Logfile, compression bool, temperatures []*types.Temperature) error { allTemperatures := make([]*types.Temperature, 0) if _, err := os.Stat(logfile.GetLogfile()); err == nil { temperaturesFromLogfile, err := logfile.ReadTemperatures() if err != nil { return err } allTemperatures = append(allTemperatures, temperaturesFromLogfile...) } allTemperatures = append(allTemperatures, temperatures...) if compression { allTemperatures = CompressTemperature(allTemperatures) } err := logfile.WriteTemperatures(allTemperatures) if err != nil { return err } return nil } // CompressTemperature compresses the temperatures from an array. It is checked // whether the measured temperature of a value corresponds to that of the // predecessor. If this is the case, the current value is discarded and the // validity date of the predecessor value is set to that of the current value. // No information is lost as a result. The validity period of the measured value // is thereby exclusively increased. func CompressTemperature(temperatures []*types.Temperature) []*types.Temperature { compressedTemperatures := make([]*types.Temperature, 0) lastTemperatureBySensors := make(map[string]*types.Temperature, 0) // Sort all measured temperatures beforehand by the starting validity date to // avoid errors when compressing the temperatures. SortTemperatures(temperatures) for _, temperature := range temperatures { if lastTemperatureBySensor, ok := lastTemperatureBySensors[temperature.SensorID]; ok { if lastTemperatureBySensor.TemperatureValue == temperature.TemperatureValue { lastTemperatureBySensors[temperature.SensorID].TemperatureTillDate = temperature.TemperatureTillDate now := time.Now() lastTemperatureBySensors[temperature.SensorID].UpdateDate = &now } else { compressedTemperatures = append(compressedTemperatures, lastTemperatureBySensors[temperature.SensorID]) lastTemperatureBySensors[temperature.SensorID] = temperature } } else { lastTemperatureBySensors[temperature.SensorID] = temperature } } // Copy all remaining entries from the map into the array for _, lastTemperatureBySensor := range lastTemperatureBySensors { compressedTemperatures = append(compressedTemperatures, lastTemperatureBySensor) } return compressedTemperatures } // New returns a log file with basic functions for reading and writing data. // The file extension of the logfile is taken into account to format the logfile // into the correct format. func New(logfile string) Logfile { ext := filepath.Ext(logfile) switch ext { case ".csv": return &csvLogfile{ logfile: logfile, } case ".json": return &jsonLogfile{ logfile: logfile, } case ".xml": return &xmlLogfile{ logfile: logfile, } default: return &jsonLogfile{ logfile: logfile, } } } // SplittTemperatures into multiple arrays. The Size can be defined by // temperatureSplitBy parameter. func SplittTemperatures(temperatures []*types.Temperature, templeratureSplitBy int) [][]*types.Temperature { splittedTemperatures := make([][]*types.Temperature, 0) newTemperatures := make([]*types.Temperature, 0) for _, temperature := range temperatures { if len(newTemperatures) == templeratureSplitBy { splittedTemperatures = append(splittedTemperatures, newTemperatures) newTemperatures = make([]*types.Temperature, 0) } newTemperatures = append(newTemperatures, temperature) } splittedTemperatures = append(splittedTemperatures, newTemperatures) return splittedTemperatures } // SortTemperatures by TemperatureFromDate func SortTemperatures(temperatures []*types.Temperature) { sort.SliceStable(temperatures, func(i int, j int) bool { return temperatures[i].TemperatureFromDate.Before(temperatures[j].TemperatureFromDate) }) }