diff --git a/cmd/server/main.go b/cmd/collector/main.go similarity index 100% rename from cmd/server/main.go rename to cmd/collector/main.go diff --git a/go.mod b/go.mod index d605cae..e5f18ab 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,9 @@ module git.loafle.net/outsourcing/kiast-drone-collector go 1.12 + +require ( + github.com/influxdata/influxdb1-client v0.0.0-20190402204710-8ff2fc3824fc + github.com/stretchr/testify v1.3.0 // indirect + github.com/vjeantet/jodaTime v0.0.0-20170816150230-be924ce213fb +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..dc2231e --- /dev/null +++ b/go.sum @@ -0,0 +1,11 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/influxdata/influxdb1-client v0.0.0-20190402204710-8ff2fc3824fc h1:KpMgaYJRieDkHZJWY3LMafvtqS/U8xX6+lUN+OKpl/Y= +github.com/influxdata/influxdb1-client v0.0.0-20190402204710-8ff2fc3824fc/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/vjeantet/jodaTime v0.0.0-20170816150230-be924ce213fb h1:9Cx/q/wd5p+BjCDBjY+rauPbwoS+chrnQ9MKMUtv/hs= +github.com/vjeantet/jodaTime v0.0.0-20170816150230-be924ce213fb/go.mod h1:XK4iy/zfkdRGe+lWQYwmebWh0IIMIe6+wi3APUAiCJ0= diff --git a/pkg/drone/protocol.go b/pkg/drone/protocol.go index a43202a..ab80ca1 100644 --- a/pkg/drone/protocol.go +++ b/pkg/drone/protocol.go @@ -1,13 +1,115 @@ package drone -type DroneGPS struct { - Date string - Time string - Latitude string - Longitude string - Altitude string - Speed string - Direction string - Fixed string +import ( + "fmt" + "strconv" + "strings" + + "github.com/vjeantet/jodaTime" +) + +type droneGPS struct { + Time int64 + // 위도 + Latitude float64 + // 경도 + Longitude float64 + // 고도 + Altitude float32 + // 속도 + Speed int32 + // 방향 + Direction int16 + // A or V + Fixed string + // LTE 통신 상태 LTEStatus string + // EMM 오류 정보 + EMMError string + // ESM 오류 정보 + ESMError string + // 신호세기 + SignalStrength int32 + // 위성 갯수 + SatelliteCount int32 + // 위성 신호세기 ex) 17-44,19-43,6-42,28-41 + SatelliteSignalStrength string +} + +// fixed +// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, +// $$GPS, 년월일, 시분초, 위도, 경도, 고도, 속도, 방향, A, LTE 통신 상태, EMM 오류 정보, ESM 오류 정보, 신호세기, 위성 갯수, 위성 ID-신호세기, 위성 ID-신호세기, 위성 ID-신호세기, 위성 ID-신호세기 +// $$GPS,20190718,050519,37396586,126968913,798,0,0,A,2,255,255,-53,13,17-44,19-43,6-42,28-41 + +// unfixed +// $$GPS,,,,,,,, V, LTE 통신 상태, EMM 오류 정보, ESM 오류 정보, 신호세기, 위성 갯수, 위성 ID-신호세기, 위성 ID-신호세기, 위성 ID-신호세기, 위성 ID-신호세기 +// $$GPS,,,,,,,,V,2,255,255,-53,4,17-44,19-42,6-40,28-40 +func parseProtocol(buf []byte) (*droneGPS, error) { + data := string(buf) + items := strings.Split(data, ",") + + gps := &droneGPS{ + // A or V + Fixed: items[8], + // LTE 통신 상태 + LTEStatus: items[9], + // EMM 오류 정보 + EMMError: items[10], + // ESM 오류 정보 + ESMError: items[11], + } + + gps.SatelliteSignalStrength = strings.Join(items[12:], ",") + + signalStrength, err := strconv.ParseInt(items[12], 10, 32) + if nil != err { + return nil, err + } + gps.SignalStrength = int32(signalStrength) + + satelliteCount, err := strconv.ParseInt(items[13], 10, 32) + if nil != err { + return nil, err + } + gps.SatelliteCount = int32(satelliteCount) + + if "A" == gps.Fixed { + dateTime, err := jodaTime.Parse("YYYYMMDDHHmmss", fmt.Sprintf("%s%s", items[1], items[2])) + if nil != err { + return nil, err + } + gps.Time = dateTime.Unix() + + latitude, err := strconv.ParseFloat(fmt.Sprintf("%s.%s", items[3][0:len(items[3])-6], items[3][len(items[3])-6:]), 64) + if nil != err { + return nil, err + } + gps.Latitude = latitude + + longitude, err := strconv.ParseFloat(fmt.Sprintf("%s.%s", items[4][0:len(items[4])-6], items[4][len(items[4])-6:]), 64) + if nil != err { + return nil, err + } + gps.Longitude = longitude + + altitude, err := strconv.ParseFloat(fmt.Sprintf("%s.%s", items[5][0:len(items[5])-1], items[5][len(items[5])-1:]), 32) + if nil != err { + return nil, err + } + gps.Altitude = float32(altitude) + + speed, err := strconv.ParseInt(items[6], 10, 32) + if nil != err { + return nil, err + } + gps.Speed = int32(speed) + + direction, err := strconv.ParseInt(items[7], 10, 16) + if nil != err { + return nil, err + } + gps.Direction = int16(direction) + } + + return gps, nil } diff --git a/pkg/drone/service.go b/pkg/drone/service.go index 3eb0255..771a351 100644 --- a/pkg/drone/service.go +++ b/pkg/drone/service.go @@ -1,15 +1,20 @@ package drone import ( + "bufio" "log" "net" + "os" "sync" "time" + + influxdb "github.com/influxdata/influxdb1-client/v2" ) // An uninteresting service. type Service struct { ch chan bool + influx influxdb.Client waitGroup *sync.WaitGroup } @@ -27,6 +32,18 @@ func NewService() *Service { // if anything is received on the service's channel. func (s *Service) Serve(listener *net.TCPListener) { defer s.waitGroup.Done() + + influx, err := influxdb.NewHTTPClient(influxdb.HTTPConfig{ + Addr: "http://localhost:8086", + Username: os.Getenv("INFLUX_USER"), + Password: os.Getenv("INFLUX_PWD"), + }) + if err != nil { + panic(err) // error handling here; normally we wouldn't use fmt but it works for the example + } + + s.influx = influx + for { select { case <-s.ch: @@ -52,6 +69,7 @@ func (s *Service) Serve(listener *net.TCPListener) { // Stop the service by closing the service's channel. Block until the service // is really stopped. func (s *Service) Stop() { + s.influx.Close() close(s.ch) s.waitGroup.Wait() } @@ -70,8 +88,11 @@ func (s *Service) serve(conn *net.TCPConn) { default: } conn.SetDeadline(time.Now().Add(1e9)) - buf := make([]byte, 4096) - if _, err := conn.Read(buf); nil != err { + //buf := make([]byte, 4096) + + reader := bufio.NewReader(conn) + buf, err := reader.ReadBytes('#') + if nil != err { if opErr, ok := err.(*net.OpError); ok && opErr.Timeout() { continue } @@ -79,17 +100,38 @@ func (s *Service) serve(conn *net.TCPConn) { return } - // fixed - // $$GPS, 년월일, 시분초, 위도, 경도, 고도, 속도, 방향, A, LTE 통신 상태, EMM 오류 정보, ESM 오류 정보, 신호세기, 위성 갯수, 위성 ID-신호세기, 위성 ID-신호세기, 위성 ID-신호세기, 위성 ID-신호세기 - // $$GPS,20190718,050519,37396586,126968913,798,0,0,A,2,255,255,-53,13,17-44,19-43,6-42,28-41 + p, err := parseProtocol(buf) + if err != nil { + log.Println(err) + } - // unfixed - // $$GPS,,,,,,,, V, LTE 통신 상태, EMM 오류 정보, ESM 오류 정보, 신호세기, 위성 갯수, 위성 ID-신호세기, 위성 ID-신호세기, 위성 ID-신호세기, 위성 ID-신호세기 - // $$GPS,,,,,,,,V,2,255,255,-53,4,17-44,19-42,6-40,28-40 + bp, _ := influxdb.NewBatchPoints(influxdb.BatchPointsConfig{ + Database: "kiast", + Precision: "s", + }) + // Create a point and add to batch + tags := map[string]string{} + fields := map[string]interface{}{ + "time": p.Time, + "latitude": p.Latitude, + "longitude": p.Longitude, + "altitude": p.Altitude, + "speed": p.Speed, + "direction": p.Direction, + "fixed": p.Fixed, + "lte_status": p.LTEStatus, + "emm_error": p.EMMError, + "esm_error": p.ESMError, + "signal_strength": p.SignalStrength, + "satellite_count": p.SatelliteCount, + "satellite_signal_strength": p.SatelliteSignalStrength, + } + pt, err := influxdb.NewPoint("drone_gps", tags, fields, time.Now()) + if err != nil { + log.Println(err) + } + bp.AddPoint(pt) - // if _, err := conn.Write(buf); nil != err { - // log.Println(err) - // return - // } + s.influx.Write(bp) } }