package main import ( "bufio" "bytes" "fmt" "io/ioutil" "log" "net/http" "os" "strconv" "strings" "time" ) type OneMetric struct { Deveui string Alias string Readonly bool Alarmactive string Smsnumber string Timestamp string Temperature string Humidity string Weight string Weight_kg string Pressure string BatteryPercent string ActiveUntil string DaysUntilDeactivated int // berechneter Wert } var INFLUX_RO_TOKEN = os.Getenv("INFLUX_RO_TOKEN") // metrics handler func validProperty(prop string) bool { valid_properties := [...]string{"w", "t", "h", "p", "vp"} for _, p := range valid_properties { if p == prop { return true } } return false } func metricsHandler(response http.ResponseWriter, request *http.Request) { name := getUserName(request) if name != "" { property, ok := request.URL.Query()["property"] if !ok || len(property[0]) < 1 { log.Println("Url Param 'property' is missing") fmt.Fprintf(response, "{ \"msg\": \"error: property must be specified in URL\" }") return } if !validProperty(property[0]) { log.Println("Url Param 'property' is invalid") fmt.Fprintf(response, "{ \"msg\": \"error: invalid property\" }") return } deveui, ok := request.URL.Query()["deveui"] if !ok || len(deveui[0]) < 1 { log.Println("Url Param 'deveui' is missing") fmt.Fprintf(response, "{ \"msg\": \"error: deveui must be specified in URL\" }") return } // Query()["deveui"] will return an array of items, // we only want the single item. mydeveui := deveui[0] if !(Contains(getMyDevs(name), mydeveui)) { log.Println("specified 'deveui' does not belong to this user") fmt.Fprintf(response, "{ \"msg\": \"error: specified deveui does not belong to this user\" }") return } if AboExpired(mydeveui) { log.Println("specified 'deveui' has an expired abo") fmt.Fprintf(response, "{ \"msg\": \"specified deveui has an expired abo\" }") return } log.Println("Url Param 'deveui' is: " + string(mydeveui)) // Format of start and stop: YYYY-MM-DDTHH:MI:SSZ stop, ok := request.URL.Query()["stop"] var mystop string if !ok || len(stop[0]) < 1 { log.Println("Url Param 'stop' is missing, set it to now") mystop = time.Now().Format("2006-01-02T15:04:05Z") } if ok { mystop = stop[0] } layout := "2006-01-02T15:04:05Z" stopDate, err := time.Parse(layout, mystop) if err != nil { fmt.Println(err) } start, ok := request.URL.Query()["start"] var mystart string if !ok || len(start[0]) < 1 { log.Println("Url Param 'start' is missing, set it to stop minus one day") t := stopDate.AddDate(0, 0, -1) mystart = t.Format("2006-01-02T15:04:05Z") } if ok { mystart = start[0] } url := "http://localhost:8086/api/v2/query?org=minibeieliorg" data := []byte(fmt.Sprintf(`from(bucket:"minibeielibucket") |> range(start: %s, stop: %s) |> filter(fn: (r) => r._measurement == "measurement") |> filter(fn: (r) => r._field == "%s") |> filter(fn: (r) => r.deveui == "%s")`, mystart, mystop, property[0], mydeveui)) req, err := http.NewRequest("POST", url, bytes.NewBuffer(data)) if err != nil { log.Fatal("Error reading request. ", err) } // Set headers req.Header.Set("Authorization", "Token "+INFLUX_RO_TOKEN) req.Header.Set("accept", "application/csv") req.Header.Set("content-type", "application/vnd.flux") // Set client timeout client := &http.Client{Timeout: time.Second * 10} // Send request resp, err := client.Do(req) if err != nil { log.Fatal("Error reading response. ", err) } defer resp.Body.Close() fmt.Println("response Status:", resp.Status) fmt.Println("response Headers:", resp.Header) body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal("Error reading body. ", err) } fmt.Fprintf(response, "[\n") scanner := bufio.NewScanner(strings.NewReader(string(body))) first := true for scanner.Scan() { s := strings.Split(scanner.Text(), ",") if (len(s) >= 7) && !(strings.HasPrefix(s[5], "_")) { t, err := time.Parse(time.RFC3339, s[5]) if err != nil { continue } a := t.Unix() b := s[6] if !(first) { fmt.Fprintf(response, ",") } else { first = false } fmt.Fprintf(response, "[%d000,%s]\n", a, b) } } fmt.Fprintf(response, "]\n") } else { fmt.Fprintf(response, "{ \"msg\": \"Only available for logged in users\" }") } } func lastmetricsHandler(response http.ResponseWriter, request *http.Request) { name := getUserName(request) if name != "" { deveui, ok := request.URL.Query()["deveui"] if !ok || len(deveui[0]) < 1 { log.Println("Url Param 'deveui' is missing") fmt.Fprintf(response, "{ \"msg\": \"deveui must be specified in URL\" }") return } // Query()["deveui"] will return an array of items, // we only want the single item. mydeveui := deveui[0] if !(Contains(getMyDevs(name), mydeveui)) { log.Println("specified 'deveui' does not belong to this user") fmt.Fprintf(response, "{ \"msg\": \"specified deveui does not belong to this user\" }") return } log.Println("Url Param 'deveui' is: " + string(mydeveui)) url := "http://localhost:8086/api/v2/query?org=minibeieliorg" //data := []byte(fmt.Sprintf(`from(bucket:"minibeielibucket") |> range(start:-365d) |> filter(fn: (r) => r.deveui == "%s") |> filter(fn: (r) => r._field == "v" or r._field == "t") |> last() |> yield(name: "last")`,mydeveui)) data := []byte(fmt.Sprintf(`from(bucket:"minibeielibucket") |> range(start:-365d) |> filter(fn: (r) => r._measurement == "measurement" and r.deveui == "%s") |> filter(fn: (r) => r._field == "t" or r._field == "h" or r._field == "w" or r._field == "p" or r._field == "vp") |> last() |> yield(name: "last")`, mydeveui)) req, err := http.NewRequest("POST", url, bytes.NewBuffer(data)) if err != nil { log.Fatal("Error reading request. ", err) } // Set headers req.Header.Set("Authorization", "Token "+INFLUX_RO_TOKEN) req.Header.Set("accept", "application/csv") req.Header.Set("content-type", "application/vnd.flux") // Set client timeout client := &http.Client{Timeout: time.Second * 10} // Send request resp, err := client.Do(req) if err != nil { log.Fatal("Error reading response. ", err) } defer resp.Body.Close() fmt.Println("response Status:", resp.Status) fmt.Println("response Headers:", resp.Header) body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal("Error reading body. ", err) } fmt.Println("response Body:", string(body)) scanner := bufio.NewScanner(strings.NewReader(string(body))) ts := "" t := "" h := "" w := "" p := "" vp := "" location, err := time.LoadLocation("Europe/Zurich") for scanner.Scan() { s := strings.Split(scanner.Text(), ",") if (len(s) >= 7) && !(strings.HasPrefix(s[5], "_")) { mytime, err := time.Parse(time.RFC3339, s[5]) if err != nil { continue } ts = mytime.In(location).Format("02.01.2006 15:04") value := s[6] field := s[7] if field == "t" { t = value } else if field == "h" { h = value } else if field == "w" { w = value } else if field == "p" { p = value } else if field == "vp" { vp = value } } } fmt.Fprintf(response, `{ "ts": "%s", "t": "%s", "h": "%s", "w": "%s", "p": "%s", "vp": "%s" }`, ts, t, h, w, p, vp) } else { fmt.Fprintf(response, "{ \"msg\": \"Only available for logged in users\" }") } } func CalcDaysUntil(mydate string) int { var days int layout := "02.01.2006" t, err := time.Parse(layout, mydate) if err != nil { days = 0 } days = int(t.Sub(time.Now()).Hours() / 24) return days } func getLastMetrics(deveui string) OneMetric { var res OneMetric url := "http://localhost:8086/api/v2/query?org=minibeieliorg" data := []byte(fmt.Sprintf(`from(bucket:"minibeielibucket") |> range(start:-365d) |> filter(fn: (r) => r._measurement == "measurement" and r.deveui == "%s") |> filter(fn: (r) => r._field == "t" or r._field == "h" or r._field == "w" or r._field == "p" or r._field == "vp") |> last(column: "_time") |> yield(name: "last")`, deveui)) req, err := http.NewRequest("POST", url, bytes.NewBuffer(data)) if err != nil { log.Fatal("Error reading request. ", err) } // Set headers req.Header.Set("Authorization", "Token "+INFLUX_RO_TOKEN) req.Header.Set("accept", "application/csv") req.Header.Set("content-type", "application/vnd.flux") // Set client timeout client := &http.Client{Timeout: time.Second * 10} // Send request resp, err := client.Do(req) if err != nil { log.Fatal("Error reading response. ", err) } defer resp.Body.Close() fmt.Println("response Status:", resp.Status) fmt.Println("response Headers:", resp.Header) body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal("Error reading body. ", err) } fmt.Println("response Body:", string(body)) scanner := bufio.NewScanner(strings.NewReader(string(body))) location, err := time.LoadLocation("Europe/Zurich") for scanner.Scan() { s := strings.Split(scanner.Text(), ",") if (len(s) >= 7) && !(strings.HasPrefix(s[5], "_")) { mytime, err := time.Parse(time.RFC3339, s[5]) if err != nil { continue } res.Timestamp = mytime.In(location).Format("02.01.2006 15:04") value := s[6] field := s[7] if field == "t" { res.Temperature = value } else if field == "h" { res.Humidity = value } else if field == "w" { res.Weight = value i, err := strconv.Atoi(value) if err == nil { res.Weight_kg = fmt.Sprintf("%.3f", float64(i)/1000.0) } else { res.Weight_kg = "ERR" } } else if field == "p" { res.Pressure = value } else if field == "vp" { res.BatteryPercent = value } } } res.Deveui = deveui res.Alias = getDevAlias(deveui) res.Readonly = false res.Alarmactive = getDevAlarmactive(deveui) res.Smsnumber = getDevSmsnumber(deveui) res.ActiveUntil = getActiveUntil(deveui) res.DaysUntilDeactivated = CalcDaysUntil(res.ActiveUntil) return res }