From 58673fe99027c839cd0a500ba9e5a18504940bf7 Mon Sep 17 00:00:00 2001 From: ubergesundheit Date: Sun, 3 Dec 2017 14:13:51 +0100 Subject: [PATCH] implement csv writing. yet to be tested --- cmd/senseboxpi/senseboxpi.go | 10 +++++- sensebox/sensebox.go | 60 ++++++++++++++++++++++++++++++------ sensebox/sensor.go | 16 +++------- sensebox/serialization.go | 13 +++++++- 4 files changed, 75 insertions(+), 24 deletions(-) diff --git a/cmd/senseboxpi/senseboxpi.go b/cmd/senseboxpi/senseboxpi.go index 7271b6c..71b60ec 100644 --- a/cmd/senseboxpi/senseboxpi.go +++ b/cmd/senseboxpi/senseboxpi.go @@ -38,7 +38,7 @@ func readFlags() (configPath, csvOutputPath string, offline bool) { } func main() { - configPath, _, offline := readFlags() + configPath, csvOutputPath, offline := readFlags() configBytes, err := ioutil.ReadFile(configPath) if err != nil { @@ -54,6 +54,13 @@ func main() { log.Fatal(err) } + if csvOutputPath != "" { + err := senseBox.AppendCSV(csvOutputPath) + if err != nil { + log.Fatal(err) + } + } + if offline == false { errs := senseBox.SubmitMeasurements() if errs != nil { @@ -62,4 +69,5 @@ func main() { } } } + senseBox.ClearMeasurements() } diff --git a/sensebox/sensebox.go b/sensebox/sensebox.go index d158091..00d1edf 100644 --- a/sensebox/sensebox.go +++ b/sensebox/sensebox.go @@ -1,10 +1,14 @@ package sensebox import ( + "encoding/csv" "encoding/hex" "encoding/json" + "errors" "fmt" "net/url" + "os" + "time" "github.com/parnurzeal/gorequest" ) @@ -12,9 +16,10 @@ import ( type id string type senseBox struct { - ID id `json:"_id"` - Sensors []*sensor `json:"sensors"` - PostDomain string `json:"postDomain"` + ID id `json:"_id"` + Sensors []*sensor `json:"sensors"` + PostDomain string `json:"postDomain"` + measurements []measurement } func validateID(id string) error { @@ -45,18 +50,16 @@ func NewFromJSON(jsonBytes []byte) (senseBox, error) { // SubmitMeasurements tries to send the measurements of the Sensors of the senseBox // to the openSenseMap func (s *senseBox) SubmitMeasurements() []error { - var measurements []measurement - for _, sensor := range s.Sensors { - measurements = append(measurements, sensor.measurements...) - // clear measurements - sensor.measurements = nil + if len(s.measurements) == 0 { + return []error{errors.New("No measurements. Did you forgot to call ReadSensors?")} } + postURL, err := url.Parse("https://" + s.PostDomain + "/boxes/" + string(s.ID) + "/data") if err != nil { return []error{err} } resp, body, errs := gorequest.New().Post(postURL.String()). - Send(measurements). + Send(s.measurements). End() if errs != nil { @@ -68,15 +71,25 @@ func (s *senseBox) SubmitMeasurements() []error { return nil } +// ClearMeasurements clears the measurements previously read through ReadSensors +func (s *senseBox) ClearMeasurements() { + s.measurements = make([]measurement, len(s.Sensors)) +} + +// ReadSensors reads measurements from all sensors func (s *senseBox) ReadSensors() error { for _, sensor := range s.Sensors { - if err := sensor.AddMeasurementReading(); err != nil { + m, err := sensor.ReadMeasurement() + if err != nil { return err } + s.measurements = append(s.measurements, m) } return nil } +// ReadSensorsAndSubmitMeasurements takes readings from all sensors and submits +// these measurements through calling SubmitMeasurements func (s *senseBox) ReadSensorsAndSubmitMeasurements() []error { err := s.ReadSensors() if err != nil { @@ -85,3 +98,30 @@ func (s *senseBox) ReadSensorsAndSubmitMeasurements() []error { return s.SubmitMeasurements() } + +func (s *senseBox) AppendCSV(path string) error { + if len(s.measurements) == 0 { + return errors.New("No measurements. Did you forgot to call ReadSensors?") + } + + // If the file doesn't exist, create it, or append to the file + f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + return err + } + defer f.Close() + + writer := csv.NewWriter(f) + defer writer.Flush() + + // csv-stringify the measurements + for _, measurement := range s.measurements { + m := []string{measurement.Sensor.ID.String(), measurement.Value.String(), measurement.Timestamp.Format(time.RFC3339)} + writer.Write(m) + } + + if err := writer.Error(); err != nil { + return err + } + return nil +} diff --git a/sensebox/sensor.go b/sensebox/sensor.go index 6e4f517..f336037 100644 --- a/sensebox/sensor.go +++ b/sensebox/sensor.go @@ -11,7 +11,6 @@ type sensor struct { ID id `json:"_id"` Phenomenon string `json:"phenomenon"` SensorType string `json:"sensorType"` - measurements []measurement sensorDevice sensors.SensorI } @@ -46,18 +45,11 @@ func (s *sensor) TakeReading() (float64, error) { return s.sensorDevice.ReadValue(s.Phenomenon) } -// AddMeasurementReading calls the sensors TakeReading function and adds the -//result to the sensors measurements through AddMeasurement -func (s *sensor) AddMeasurementReading() error { +// ReadMeasurement calls the sensors TakeReading function and returns a measurement +func (s *sensor) ReadMeasurement() (measurement, error) { reading, err := s.TakeReading() if err != nil { - return err + return measurement{}, err } - s.AddMeasurement(reading, time.Now()) - return nil -} - -// AddMeasurement adds a new measurement to the Sensor -func (s *sensor) AddMeasurement(value float64, timestamp time.Time) { - s.measurements = append(s.measurements, measurement{s, number(value), timestamp.UTC()}) + return measurement{s, number(reading), time.Now().UTC()}, nil } diff --git a/sensebox/serialization.go b/sensebox/serialization.go index 7c66659..511073c 100644 --- a/sensebox/serialization.go +++ b/sensebox/serialization.go @@ -15,7 +15,13 @@ type number float64 // MarshalJSON of type number formats the float with two decimals and trims // excess zeroes and dots func (f number) MarshalJSON() ([]byte, error) { - return []byte(strings.TrimRight(strings.TrimRight(fmt.Sprintf("%.2f", f), "0"), ".")), nil + return []byte(f.String()), nil +} + +// String returns the numbers string representation (float with two decimals and +// trimed excess zeroes and dot +func (f number) String() string { + return strings.TrimRight(strings.TrimRight(fmt.Sprintf("%.2f", f), "0"), ".") } // UnmarshalJSON of type id checks the id for validity @@ -29,3 +35,8 @@ func (i *id) UnmarshalJSON(jsonBytes []byte) error { return nil } + +// String returns the id as 24 digit hex string +func (i *id) String() string { + return string(*i) +}