diff --git a/api/rest-api.go b/api/rest-api.go index 85b43c8..1e58243 100644 --- a/api/rest-api.go +++ b/api/rest-api.go @@ -43,19 +43,38 @@ func (api *weatherRestApi) handleRequests() *mux.Router { router.HandleFunc("/random", api.randomWeatherHandler) router.HandleFunc("/randomlist", api.randomWeatherListHandler) router.HandleFunc("/addData", api.addDataHandler) - router.HandleFunc("/getData", api.getData) + router.HandleFunc("/getData/{id}", api.getData) router.HandleFunc("/registerWeatherSensor/{name}", api.registerWeatherSensor) return router } func (api *weatherRestApi) getData(w http.ResponseWriter, r *http.Request) { w.Header().Add("content-type", "application/json") - data, err := api.weaterStorage.GetData() + + vars := mux.Vars(r) + id := vars["id"] + + query, err := storage.ParseFromUrlQuery(r.URL.Query()) + if err != nil { + http.Error(w, fmt.Sprintf("could not parse query: %v", err.Error()), http.StatusBadRequest) + return + } + + query.SensorId, err = uuid.Parse(id) + if err != nil { + http.Error(w, "could not parse uuid", http.StatusBadRequest) + return + } + + fmt.Println(query) + + data, err := api.weaterStorage.GetData(query) if err != nil { http.Error(w, "", http.StatusBadRequest) return } - json.NewEncoder(w).Encode(data) + res := storage.GetOnlyQueriedFields(data, query) + json.NewEncoder(w).Encode(res) } func (api *weatherRestApi) randomWeatherHandler(w http.ResponseWriter, r *http.Request) { diff --git a/storage/influxdb-storage.go b/storage/influxdb-storage.go index 8b670f0..43f8e42 100644 --- a/storage/influxdb-storage.go +++ b/storage/influxdb-storage.go @@ -53,11 +53,37 @@ func (storage *influxStorage) Save(data WeatherData) error { } //GetData datapoints from InfluxDB -func (storage *influxStorage) GetData() ([]*WeatherData, error) { +func (storage *influxStorage) GetData(query *WeatherQuery) ([]*WeatherData, error) { - query := fmt.Sprintf("from(bucket:\"%v\")|> range(start: -40m, stop: -20m) |> filter(fn: (r) => r._measurement == \"data\" and r.location == \"Hamburg\")", storage.bucket) + fields := "" + concat := "" - res, err := storage.executeFluxQuery(query) + if query.Temperature { + fields = fmt.Sprintf("%v %v r._field == \"temperature\"", fields, concat) + concat = "or" + } + + if query.Humidity { + fields = fmt.Sprintf("%v %v r._field == \"humidity\"", fields, concat) + concat = "or" + } + + if query.Pressure { + fields = fmt.Sprintf("%v %v r._field == \"pressure\"", fields, concat) + concat = "or" + } + + if query.Co2Level { + fields = fmt.Sprintf("%v %v r._field == \"co2level\"", fields, concat) + concat = "or" + } + + fields = fmt.Sprintf(" and ( %v )", fields) + + fluxQuery := fmt.Sprintf("from(bucket:\"%v\")|> range(start: %v, stop: %v) |> filter(fn: (r) => r._measurement == \"%v\" %v)", storage.bucket, query.Start.Format(time.RFC3339), query.End.Format(time.RFC3339), storage.measurement, fields) + fmt.Println(fluxQuery) + + res, err := storage.executeFluxQuery(fluxQuery) return res, err } diff --git a/storage/weather-data.go b/storage/weather-data.go index 658fb1d..2ff4dd0 100644 --- a/storage/weather-data.go +++ b/storage/weather-data.go @@ -1,7 +1,10 @@ package storage import ( + "fmt" "math/rand" + "net/url" + "strconv" "time" "github.com/google/uuid" @@ -10,7 +13,7 @@ import ( //WeatherStorage interface for different storage-implementations of weather data type WeatherStorage interface { Save(WeatherData) error - GetData() ([]*WeatherData, error) + GetData(*WeatherQuery) ([]*WeatherData, error) Close() error } @@ -25,13 +28,41 @@ type SensorRegistry interface { //WeatherData type type WeatherData struct { Humidity float64 `json:"humidity"` - Pressure float64 `json:"airPressure"` + Pressure float64 `json:"pressure"` Temperature float64 `json:"temperature"` CO2Level float64 `json:"co2level"` - SensorId uuid.UUID `json:"SensorId"` + SensorId uuid.UUID `json:"sensorId"` TimeStamp time.Time `json:"timestamp"` } +func (data *WeatherData) GetQueriedValues(query *WeatherQuery) map[string]string { + result := map[string]string{ + "sensorId": data.SensorId.String(), + "timestamp": data.TimeStamp.String(), + } + if query.Temperature { + result["temperature"] = strconv.FormatFloat(data.Temperature, 'f', -1, 32) + } + if query.Pressure { + result["pressure"] = strconv.FormatFloat(data.Pressure, 'f', -1, 32) + } + if query.Co2Level { + result["co2level"] = strconv.FormatFloat(data.CO2Level, 'f', -1, 32) + } + if query.Humidity { + result["humidity"] = strconv.FormatFloat(data.Humidity, 'f', -1, 32) + } + return result +} + +func GetOnlyQueriedFields(dataPoints []*WeatherData, query *WeatherQuery) []map[string]string { + var result []map[string]string + for _, data := range dataPoints { + result = append(result, data.GetQueriedValues(query)) + } + return result +} + //WeatherSensor is the data for a new Sensorregistration type WeatherSensor struct { Name string @@ -41,6 +72,74 @@ type WeatherSensor struct { Lattitude float64 } +type WeatherQuery struct { + Start time.Time + End time.Time + SensorId uuid.UUID + Temperature bool + Humidity bool + Pressure bool + Co2Level bool +} + +func (data *WeatherQuery) Init() { + data.Start = time.Now().Add(-1 * time.Hour * 24 * 14) + data.End = time.Now() + data.SensorId = uuid.Nil + data.Temperature = true + data.Humidity = true + data.Pressure = true + data.Co2Level = true +} + +func ParseFromUrlQuery(query url.Values) (*WeatherQuery, error) { + result := new(WeatherQuery) + result.Init() + + start := query.Get("start") + end := query.Get("end") + temperature := query.Get("temperature") + humidity := query.Get("humidity") + pressure := query.Get("pressure") + co2level := query.Get("co2level") + + if len(start) != 0 { + if tval, err := time.Parse(time.RFC3339, start); err == nil { + result.Start = tval + } else if err != nil { + fmt.Println(err) + return nil, err + } + } + + if len(end) != 0 { + if tval, err := time.Parse(time.RFC3339, end); err == nil { + result.End = tval + } else if err != nil { + fmt.Println(err) + return nil, err + } + } + + if bval, err := strconv.ParseBool(temperature); err == nil { + result.Temperature = bval + } + + if bval, err := strconv.ParseBool(humidity); err == nil { + result.Humidity = bval + } + + if bval, err := strconv.ParseBool(pressure); err == nil { + result.Pressure = bval + } + + if bval, err := strconv.ParseBool(co2level); err == nil { + result.Co2Level = bval + } + + return result, nil +} + //NewRandomWeatherData creates random WeatherData with given Location func NewRandomWeatherData(sensorId uuid.UUID) WeatherData { rand.Seed(time.Now().UnixNano())