210 lines
5.3 KiB
Go
210 lines
5.3 KiB
Go
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))
|
|
}
|