diff --git a/receiver/LoraToGPSServer/device/device.go b/receiver/LoraToGPSServer/device/device.go index 790dfdc..7f44d20 100644 --- a/receiver/LoraToGPSServer/device/device.go +++ b/receiver/LoraToGPSServer/device/device.go @@ -63,7 +63,6 @@ func (self *Manager) Parse(r *http.Request) ([]*Data, error) { if os.Getenv("DEBUG") == "1" { log.Printf("incoming request body:%v RemoteAddr:%v headers:%+v \n", string(c), r.RemoteAddr, r.Header) } - data := &DataUpPayload{} err = json.Unmarshal(c, data) if err != nil { @@ -74,14 +73,17 @@ func (self *Manager) Parse(r *http.Request) ([]*Data, error) { if !ok { return nil, fmt.Errorf("request payload doesn't include device type tags:%+v", data.Tags) } - var points []*Data switch devType { case "rpi": points, err = Rpi(string(data.Data)) + case "antratek": + points, err = Antratek(data) case "irnas": points, err = Irnas(data) + case "Second": + points, err = G62Parse(data) default: return nil, fmt.Errorf("unsuported device type:%v", devType) } @@ -143,6 +145,12 @@ func (self *Manager) update(data *Data) error { } else { // Distance from each gateway that received this data. for _, gwMeta := range data.Payload.RXInfo { + if gwMeta.Location == nil { + if os.Getenv("DEBUG") == "1" { + log.Println("recieved meta gateway without location") + } + continue + } if data.Valid { dist, err := Distance(data.Lat, data.Lon, gwMeta.Location.Latitude, gwMeta.Location.Longitude, "K") if err != nil { @@ -322,31 +330,149 @@ func irnasParseSingle(data dataInterface) (*Data, error) { return dataParsed, nil } + + + +func G62Parse(data *DataUpPayload) ([]*Data, error) { + + dataParsed := &Data{ + Valid: true, + Attr: map[string]string{}, + } + + // Non GPS data. + if data.FPort != 1 { + dataParsed.Valid = false + if os.Getenv("DEBUG") == "1" { + log.Printf("skipping non gps data, fport:%+v", data.FPort) + } + return []*Data{dataParsed}, nil + } + + lat, ok := data.Object["latitudeDeg"] + if !ok { + return nil, errors.New("data doesn't contain lat") + } + lon, ok := data.Object["longitudeDeg"] + + if !ok { + return nil, errors.New("data object doesn't contain lon") + } + + dataParsed.Time = int64( data.Time.Unix()) + + + + + dataParsed.Lat = lat.(float64) + dataParsed.Lon = lon.(float64) + if dataParsed.Lat == 0.0 || dataParsed.Lon == 0.0 { + dataParsed.Valid = false + } + + if val, ok := data.Object["speedKmph"]; ok { + dataParsed.Speed = fmt.Sprintf("%v", val.(float64)) + dataParsed.Motion = true + } + if val, ok := data.Object["tempC"]; ok && int64(val.(float64)) > 0 { + dataParsed.Attr["temperature"] = fmt.Sprintf("%v", val.(float64)) + } + + return []*Data{dataParsed}, nil +} + +func antratekParse(data *DataUpPayload) ([]*Data, error) { + + dataParsed := &Data{ + Valid: true, + Attr: map[string]string{}, + } + + // Non GPS data. + if data.FPort != 136 { + dataParsed.Valid = false + if os.Getenv("DEBUG") == "1" { + log.Printf("skipping non gps data, fport:%+v", data.FPort) + } + return []*Data{dataParsed}, nil + } + + lat, ok := data.Object["positionLatitude"] + if !ok { + return nil, errors.New("data doesn't contain lat") + } + lon, ok := data.Object["positionLongitude"] + + if !ok { + return nil, errors.New("data object doesn't contain lon") + } + + dataParsed.Time = int64( data.Time.Unix()) + + + // Port 12 status messages contain only lat/lon. + hdop, ok := data.Object["hdop"] + if !ok { + log.Printf("data object doesn't contain hdop so setting to 0") + hdop = 0.0 + } + dataParsed.Hdop = hdop.(float64) + + dataParsed.Lat = lat.(float64) + dataParsed.Lon = lon.(float64) + if dataParsed.Lat == 0.0 || dataParsed.Lon == 0.0 { + dataParsed.Valid = false + } + + if val, ok := data.Object["battery"]; ok { + dataParsed.Attr["battery"] = fmt.Sprintf("%v", val.(float64)) + } + if val, ok := data.Object["temperature"]; ok && int64(val.(float64)) > 0 { + dataParsed.Attr["temperature"] = fmt.Sprintf("%v", val.(float64)) + } + + return []*Data{dataParsed}, nil +} + // DataUpPayload represents a data-up payload. type DataUpPayload struct { - ApplicationID int64 `json:"applicationID,string"` - ApplicationName string `json:"applicationName"` - DeviceName string `json:"deviceName"` - DevEUI lorawan.EUI64 `json:"devEUI"` - RXInfo []RXInfo `json:"rxInfo,omitempty"` - TXInfo TXInfo `json:"txInfo"` - ADR bool `json:"adr"` - FCnt uint32 `json:"fCnt"` - FPort uint8 `json:"fPort"` - Data []byte `json:"data"` - Object map[string]interface{} `json:"object,omitempty"` - Tags map[string]string `json:"tags,omitempty"` - Variables map[string]string `json:"-"` + Time *time.Time `json:"time"` + TXInfo TXInfo `json:"txInfo"` + ADR bool `json:"adr"` + FCnt uint32 `json:"fCnt"` + FPort uint8 `json:"fPort"` + Data []byte `json:"data"` + Object map[string]interface{} `json:"object,omitempty"` + Variables map[string]string `json:"-"` + DeviceInfo `json:"deviceInfo"` +} + + +type DeviceInfo struct { + TenantId string `json:"tenantId"` + TenantName string `json:"tenantName"` + ApplicationName string `json:"applicationName"` + ApplicationId string `json:"applicationId"` + DeviceProfileId string `json:"deviceProfileId"` + DeviceProfileName string `json:"deviceProfileName"` + DeviceName string `json:"deviceName"` + DevEui lorawan.EUI64 `json:"devEui"` + RXInfo []RXInfo `json:"rxInfo,omitempty"` + Tags map[string]string `json:"tags"` +} + +type Tags struct { + Type string `json:"type"` } // RXInfo contains the RX information. type RXInfo struct { GatewayID lorawan.EUI64 `json:"gatewayID"` Name string `json:"name"` - Time *time.Time `json:"time,omitempty"` - RSSI int `json:"rssi"` - LoRaSNR float64 `json:"loRaSNR"` - Location *Location `json:"location"` + + RSSI int `json:"rssi"` + LoRaSNR float64 `json:"loRaSNR"` + Location *Location `json:"location"` } // TXInfo contains the TX information. @@ -456,5 +582,5 @@ func Speed(point1 *Data, point2 *Data) (float64, error) { } func GenID(data *DataUpPayload) string { - return data.DeviceName + "-" + data.DevEUI.String() + return data.DeviceName + "-" + data.DeviceInfo.DevEui.String() } diff --git a/receiver/LoraToGPSServer/traccar/traccar.go b/receiver/LoraToGPSServer/traccar/traccar.go index 6e9d660..a758bd6 100644 --- a/receiver/LoraToGPSServer/traccar/traccar.go +++ b/receiver/LoraToGPSServer/traccar/traccar.go @@ -63,8 +63,8 @@ func (s *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { defer log.SetPrefix("") for n, v := range point.Attr { - s.lastAttrs[point.Payload.DevEUI] = make(map[string]string) - s.lastAttrs[point.Payload.DevEUI][n] = v + s.lastAttrs[point.Payload.DevEui] = make(map[string]string) + s.lastAttrs[point.Payload.DevEui][n] = v } if !point.Valid { @@ -98,7 +98,7 @@ func (s *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } q := req.URL.Query() - q.Add("id", point.Payload.DevEUI.String()) + q.Add("id", point.Payload.DevEui.String()) q.Add("lat", fmt.Sprintf("%g", point.Lat)) q.Add("timestamp", strconv.Itoa(int(point.Time))) q.Add("lon", fmt.Sprintf("%g", point.Lon)) @@ -108,7 +108,7 @@ func (s *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Add last reocorded attributes in case they are missing in the new request // and they will be overrided by the new value if the attr exists. - for n, v := range s.lastAttrs[point.Payload.DevEUI] { + for n, v := range s.lastAttrs[point.Payload.DevEui] { q.Set(n, fmt.Sprintf("%v", v)) } // Override the attr with the new values.