package main import ( "bytes" "encoding/base64" "encoding/binary" "encoding/hex" "encoding/json" "fmt" "io/ioutil" "log" "net/http" "os" "strconv" "strings" "time" ) const ( outputfile = "/home/appuser/wo-bisch-lorahandler/wo-bisch-lorahandler.log" ) type MessageProperties struct { Time string `json:"Time"` Payload_hex string `json:"payload_hex"` DevEUI string `json:"DevEUI"` DevAddr string `json:"DevAddr"` } type Message struct { Prop MessageProperties `json:"DevEUI_uplink"` } // Global variables var file *os.File func WriteStringToFile(s string, deveui string) { n, err := file.WriteString(s) if err != nil { fmt.Println(err) os.Exit(1) } if n != len(s) { fmt.Println("failed to write data") os.Exit(1) } // Also write to individual files datestr := time.Now().Format("2006-01") individual_file := "/home/appuser/wo-bisch-lorahandler/logs/" + deveui + "-" + datestr + ".log" fi, err := os.OpenFile(individual_file, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644) if err != nil { fmt.Println(err) os.Exit(1) } defer fi.Close() fi.WriteString(s) } func Convert2Hex(payload_raw string) (string, error) { res := "error" p, err := base64.StdEncoding.DecodeString(payload_raw) if err == nil { res = hex.EncodeToString(p) } return res, err } // 0: inside greenzone, 1: outside greenzone, 2: no GPS func IsOutsideGreenzone(deveui string, lon float64, lat float64) int { if lon < 1 { return 2 } if lat < 1 { return 2 } res := false greenzone := getDevGreenzone(deveui) if greenzone != "" { coords := strings.Split(greenzone, ",") if len(coords) == 4 { lon_min, _ := strconv.ParseFloat(coords[0], 32) lat_min, _ := strconv.ParseFloat(coords[1], 32) lon_max, _ := strconv.ParseFloat(coords[2], 32) lat_max, _ := strconv.ParseFloat(coords[3], 32) res = (lon < lon_min || lon > lon_max || lat < lat_min || lat > lat_max) } else { log.Printf("greenzone does not have right format: %s!", greenzone) } } if res { return 1 } else { return 0 } } func DecodePayload(s string, deveui string) { type payload struct { Latitude uint32 Longitude uint32 AlarmBat uint16 Flag uint8 } var ba []byte var pl payload if len(s) >= 22 { ba, _ = hex.DecodeString(s[0:22]) br := bytes.NewReader(ba) pl = payload{} err := binary.Read(br, binary.BigEndian, &pl) if err != nil { fmt.Println(err) } log.Printf("Latitude: %.5f", float32(pl.Latitude)/1000000.0) log.Printf("Longitude: %.5f", float32(pl.Longitude)/1000000.0) log.Printf("AlarmBat: %d", pl.AlarmBat) log.Printf("Flag: %d", pl.Flag) vbat := (pl.AlarmBat & 0x3fff) // Battery Voltage in mV fw := 160 + (pl.Flag & 0x1f) // Firmware version; 5 bits alarm := (pl.AlarmBat & 0x4000) == 0x4000 // Alarm Bit outsideGreenzone := IsOutsideGreenzone(deveui, float64(pl.Longitude)/1000000.0, float64(pl.Latitude)/1000000.0) flags := 0 if outsideGreenzone == 1 { flags += 2 } if alarm { flags += 1 } log.Printf("AlarmBit: %v", alarm) log.Printf("outsideGreenzone: %d", outsideGreenzone) mystring := fmt.Sprintf("measurement,deveui=%s lat=%.5f,lon=%.5f,vbat=%d,fw=%d,flags=%d %d\n", deveui, float32(pl.Latitude)/1000000.0, float32(pl.Longitude)/1000000.0, vbat, fw, flags, (time.Now().Unix() * 1000 * 1000 * 1000)) WriteStringToFile(mystring, deveui) // we send an alert, when the alert bit is set if alarm { log.Printf("DispatchAlert (button pressed) for %s\n", deveui) DispatchAlert(deveui, "alert_button") } if outsideGreenzone == 1 { log.Printf("DispatchAlert (outside greenzone) for %s\n", deveui) DispatchAlert(deveui, "alert_greenzone") } else if outsideGreenzone == 0 { // we reset the alert, when we are again withing the greenzone if AlertAlreadySentRecently(deveui, "alert_greenzone") { fmt.Printf("Info: we are again in Greenzone for Deveui %s, clear alert!", deveui) DeleteGreenzoneAlert(deveui) } } } else { log.Printf("Payload is not >= 11 bytes (22 chars): %s", s) } } func main() { // Init Redis initDB() // Open Output File f, err := os.OpenFile(outputfile, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644) file = f if err != nil { fmt.Println(err) os.Exit(1) } defer file.Close() http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { var message_swisscom Message if r.Body == nil { http.Error(w, "Please send a request body", 400) return } buf, bodyErr := ioutil.ReadAll(r.Body) if bodyErr != nil { log.Print("bodyErr ", bodyErr.Error()) http.Error(w, bodyErr.Error(), http.StatusInternalServerError) return } rdr1 := ioutil.NopCloser(bytes.NewBuffer(buf)) rdr2 := ioutil.NopCloser(bytes.NewBuffer(buf)) log.Printf("BODY: %s", rdr1) r.Body = rdr2 fmt.Printf("Length of JSON Body: %d\n", len(buf)) err := json.NewDecoder(r.Body).Decode(&message_swisscom) if err != nil { http.Error(w, err.Error(), 400) return } fmt.Println("Time: " + message_swisscom.Prop.Time) fmt.Println("Payload Hex: " + message_swisscom.Prop.Payload_hex) fmt.Println("DevEUI: " + message_swisscom.Prop.DevEUI) fmt.Println("DevAddr: " + message_swisscom.Prop.DevAddr) DecodePayload(message_swisscom.Prop.Payload_hex, message_swisscom.Prop.DevEUI) }) log.Fatal(http.ListenAndServe(":8080", nil)) }