mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-11 09:41:40 -05:00
Merge pull request #374 from Freika/fix/gpx-geojson-speed-recording
Fix/gpx geojson speed recording
This commit is contained in:
commit
657f69db44
9 changed files with 253 additions and 32 deletions
|
|
@ -1 +1 @@
|
||||||
0.16.0
|
0.16.1
|
||||||
|
|
|
||||||
11
CHANGELOG.md
11
CHANGELOG.md
|
|
@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
|
||||||
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
|
# 0.16.1 - 2024-11-08
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Speed is now being recorded into points when a GPX file is being imported. Previously, the speed was not being recorded.
|
||||||
|
- GeoJSON file from GPSLogger now can be imported to Dawarich. Previously, the import was failing due to incorrect parsing of the file.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- The Vists suggestion job is disabled. It will be re-enabled in the future with a new approach to the visit suggestion process.
|
||||||
|
|
||||||
# 0.16.0 - 2024-11-07
|
# 0.16.0 - 2024-11-07
|
||||||
|
|
||||||
## The Websockets release
|
## The Websockets release
|
||||||
|
|
|
||||||
|
|
@ -39,10 +39,10 @@ class Geojson::Params
|
||||||
battery: battery_level(feature[:properties][:battery_level]),
|
battery: battery_level(feature[:properties][:battery_level]),
|
||||||
timestamp: timestamp(feature),
|
timestamp: timestamp(feature),
|
||||||
altitude: altitude(feature),
|
altitude: altitude(feature),
|
||||||
velocity: feature[:properties][:speed],
|
velocity: speed(feature),
|
||||||
tracker_id: feature[:properties][:device_id],
|
tracker_id: feature[:properties][:device_id],
|
||||||
ssid: feature[:properties][:wifi],
|
ssid: feature[:properties][:wifi],
|
||||||
accuracy: feature[:properties][:horizontal_accuracy],
|
accuracy: accuracy(feature),
|
||||||
vertical_accuracy: feature[:properties][:vertical_accuracy],
|
vertical_accuracy: feature[:properties][:vertical_accuracy],
|
||||||
raw_data: feature
|
raw_data: feature
|
||||||
}
|
}
|
||||||
|
|
@ -50,19 +50,19 @@ class Geojson::Params
|
||||||
|
|
||||||
def build_line(feature)
|
def build_line(feature)
|
||||||
feature[:geometry][:coordinates].map do |point|
|
feature[:geometry][:coordinates].map do |point|
|
||||||
build_line_point(feature, point)
|
build_line_point(point)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def build_multi_line(feature)
|
def build_multi_line(feature)
|
||||||
feature[:geometry][:coordinates].map do |line|
|
feature[:geometry][:coordinates].map do |line|
|
||||||
line.map do |point|
|
line.map do |point|
|
||||||
build_line_point(feature, point)
|
build_line_point(point)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def build_line_point(feature, point)
|
def build_line_point(point)
|
||||||
{
|
{
|
||||||
latitude: point[1],
|
latitude: point[1],
|
||||||
longitude: point[0],
|
longitude: point[0],
|
||||||
|
|
@ -84,7 +84,23 @@ class Geojson::Params
|
||||||
def timestamp(feature)
|
def timestamp(feature)
|
||||||
return Time.zone.at(feature[3]) if feature.is_a?(Array)
|
return Time.zone.at(feature[3]) if feature.is_a?(Array)
|
||||||
|
|
||||||
value = feature.dig(:properties, :timestamp) || feature.dig(:geometry, :coordinates, 3)
|
value = feature.dig(:properties, :timestamp) ||
|
||||||
Time.zone.at(value)
|
feature.dig(:geometry, :coordinates, 3)
|
||||||
|
|
||||||
|
return Time.zone.at(value.to_i) if value.is_a?(Numeric)
|
||||||
|
|
||||||
|
### GPSLogger for Android case ###
|
||||||
|
time = feature.dig(:properties, :time)
|
||||||
|
|
||||||
|
Time.zone.parse(time).to_i if time.present?
|
||||||
|
### /GPSLogger for Android case ###
|
||||||
|
end
|
||||||
|
|
||||||
|
def speed(feature)
|
||||||
|
feature.dig(:properties, :speed).to_f.round(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
def accuracy(feature)
|
||||||
|
feature.dig(:properties, :accuracy) || feature.dig(:properties, :horizontal_accuracy)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ class Gpx::TrackParser
|
||||||
altitude: point['ele'].to_i,
|
altitude: point['ele'].to_i,
|
||||||
timestamp: Time.parse(point['time']).to_i,
|
timestamp: Time.parse(point['time']).to_i,
|
||||||
import_id: import.id,
|
import_id: import.id,
|
||||||
|
velocity: speed(point),
|
||||||
raw_data: point,
|
raw_data: point,
|
||||||
user_id:
|
user_id:
|
||||||
)
|
)
|
||||||
|
|
@ -54,4 +55,12 @@ class Gpx::TrackParser
|
||||||
user_id:
|
user_id:
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def speed(point)
|
||||||
|
return if point['extensions'].blank?
|
||||||
|
|
||||||
|
(
|
||||||
|
point.dig('extensions', 'speed') || point.dig('extensions', 'TrackPointExtension', 'speed')
|
||||||
|
).to_f.round(1)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,11 @@ area_visits_calculation_scheduling_job:
|
||||||
class: "AreaVisitsCalculationSchedulingJob"
|
class: "AreaVisitsCalculationSchedulingJob"
|
||||||
queue: visit_suggesting
|
queue: visit_suggesting
|
||||||
|
|
||||||
visit_suggesting_job:
|
# Disabled until fixed
|
||||||
cron: "0 1 * * *" # every day at 1:00
|
# visit_suggesting_job:
|
||||||
class: "VisitSuggestingJob"
|
# cron: "0 1 * * *" # every day at 1:00
|
||||||
queue: visit_suggesting
|
# class: "VisitSuggestingJob"
|
||||||
|
# queue: visit_suggesting
|
||||||
|
|
||||||
watcher_job:
|
watcher_job:
|
||||||
cron: "0 */1 * * *" # every 1 hour
|
cron: "0 */1 * * *" # every 1 hour
|
||||||
|
|
|
||||||
23
spec/fixtures/files/geojson/gpslogger_example.json
vendored
Normal file
23
spec/fixtures/files/geojson/gpslogger_example.json
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"features": [
|
||||||
|
{
|
||||||
|
"geometry": {
|
||||||
|
"coordinates": [
|
||||||
|
106.64234449272531,
|
||||||
|
10.758321212464024
|
||||||
|
],
|
||||||
|
"type": "Point"
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"accuracy": 4.7551565,
|
||||||
|
"altitude": 17.634344400269068,
|
||||||
|
"provider": "gps",
|
||||||
|
"speed": 1.2,
|
||||||
|
"time": "2024-11-03T16:30:11.331+07:00",
|
||||||
|
"time_long": 1730626211331
|
||||||
|
},
|
||||||
|
"type": "Feature"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "FeatureCollection"
|
||||||
|
}
|
||||||
31
spec/fixtures/files/gpx/garmin_example.gpx
vendored
Normal file
31
spec/fixtures/files/gpx/garmin_example.gpx
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<gpx version="1.1" creator="GPSLogger 131 - http://gpslogger.mendhak.com/"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.topografix.com/GPX/1/1"
|
||||||
|
xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v2"
|
||||||
|
xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd
|
||||||
|
http://www.garmin.com/xmlschemas/TrackPointExtension/v2 https://www8.garmin.com/xmlschemas/TrackPointExtensionv2.xsd
|
||||||
|
">
|
||||||
|
<metadata>
|
||||||
|
<time>2024-11-03T16:30:11.331+07:00</time>
|
||||||
|
</metadata>
|
||||||
|
<trk>
|
||||||
|
<name>20241103</name>
|
||||||
|
<trkseg>
|
||||||
|
<trkpt lat="10.758321212464024" lon="106.64234449272531">
|
||||||
|
<ele>17.634344400269068</ele>
|
||||||
|
<time>2024-11-03T16:30:11.331+07:00</time>
|
||||||
|
<extensions>
|
||||||
|
<gpxtpx:TrackPointExtension>
|
||||||
|
<gpxtpx:speed>2.8</gpxtpx:speed>
|
||||||
|
</gpxtpx:TrackPointExtension>
|
||||||
|
</extensions>
|
||||||
|
<geoidheight>-1.6</geoidheight>
|
||||||
|
<src>gps</src>
|
||||||
|
<sat>3</sat>
|
||||||
|
<hdop>1.9</hdop>
|
||||||
|
<vdop>8.6</vdop>
|
||||||
|
<pdop>8.8</pdop>
|
||||||
|
</trkpt>
|
||||||
|
</trkseg>
|
||||||
|
</trk>
|
||||||
|
</gpx>
|
||||||
108
spec/services/geojson/params_spec.rb
Normal file
108
spec/services/geojson/params_spec.rb
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe Geojson::Params do
|
||||||
|
describe '#call' do
|
||||||
|
let(:file_path) { Rails.root.join('spec/fixtures/files/geojson/export.json') }
|
||||||
|
let(:file) { File.read(file_path) }
|
||||||
|
let(:json) { JSON.parse(file) }
|
||||||
|
let(:params) { described_class.new(json) }
|
||||||
|
|
||||||
|
subject { params.call }
|
||||||
|
|
||||||
|
it 'returns an array of points' do
|
||||||
|
expect(subject).to be_an_instance_of(Array)
|
||||||
|
expect(subject.first).to be_an_instance_of(Hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns the correct data for each point' do
|
||||||
|
expect(subject.first).to eq(
|
||||||
|
latitude: '0.0',
|
||||||
|
longitude: '0.0',
|
||||||
|
battery_status: nil,
|
||||||
|
battery: nil,
|
||||||
|
timestamp: Time.zone.at(1_609_459_201),
|
||||||
|
altitude: 1,
|
||||||
|
velocity: 0,
|
||||||
|
tracker_id: nil,
|
||||||
|
ssid: nil,
|
||||||
|
accuracy: 1,
|
||||||
|
vertical_accuracy: 1,
|
||||||
|
raw_data: {
|
||||||
|
'type' => 'Feature',
|
||||||
|
'geometry' => {
|
||||||
|
'type' => 'Point',
|
||||||
|
'coordinates' => [
|
||||||
|
'0.0',
|
||||||
|
'0.0'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'properties' => {
|
||||||
|
'battery_status' => 'unplugged',
|
||||||
|
'ping' => 'MyString',
|
||||||
|
'battery' => 1,
|
||||||
|
'tracker_id' => 'MyString',
|
||||||
|
'topic' => 'MyString',
|
||||||
|
'altitude' => 1,
|
||||||
|
'longitude' => '0.1',
|
||||||
|
'velocity' => 'MyString',
|
||||||
|
'trigger' => 'background_event',
|
||||||
|
'bssid' => 'MyString',
|
||||||
|
'ssid' => 'MyString',
|
||||||
|
'connection' => 'wifi',
|
||||||
|
'vertical_accuracy' => 1,
|
||||||
|
'accuracy' => 1,
|
||||||
|
'timestamp' => 1_609_459_201,
|
||||||
|
'latitude' => '0.1',
|
||||||
|
'mode' => 1,
|
||||||
|
'inrids' => [],
|
||||||
|
'in_regions' => [],
|
||||||
|
'raw_data' => '',
|
||||||
|
'city' => nil,
|
||||||
|
'country' => nil,
|
||||||
|
'geodata' => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the json is exported from GPSLogger' do
|
||||||
|
let(:file_path) { Rails.root.join('spec/fixtures/files/geojson/gpslogger_example.json') }
|
||||||
|
|
||||||
|
it 'returns the correct data for each point' do
|
||||||
|
expect(subject.first).to eq(
|
||||||
|
latitude: 10.758321212464024,
|
||||||
|
longitude: 106.64234449272531,
|
||||||
|
battery_status: nil,
|
||||||
|
battery: nil,
|
||||||
|
timestamp: Time.parse('2024-11-03T16:30:11.331+07:00').to_i,
|
||||||
|
altitude: 17.634344400269068,
|
||||||
|
velocity: 1.2,
|
||||||
|
tracker_id: nil,
|
||||||
|
ssid: nil,
|
||||||
|
accuracy: 4.7551565,
|
||||||
|
vertical_accuracy: nil,
|
||||||
|
raw_data: {
|
||||||
|
'geometry' => {
|
||||||
|
'coordinates' => [
|
||||||
|
106.64234449272531,
|
||||||
|
10.758321212464024
|
||||||
|
],
|
||||||
|
'type' => 'Point'
|
||||||
|
},
|
||||||
|
'properties' => {
|
||||||
|
'accuracy' => 4.7551565,
|
||||||
|
'altitude' => 17.634344400269068,
|
||||||
|
'provider' => 'gps',
|
||||||
|
'speed' => 1.2,
|
||||||
|
'time' => '2024-11-03T16:30:11.331+07:00',
|
||||||
|
'time_long' => 1_730_626_211_331
|
||||||
|
},
|
||||||
|
'type' => 'Feature'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -11,31 +11,29 @@ RSpec.describe Gpx::TrackParser do
|
||||||
let(:raw_data) { Hash.from_xml(File.read(file_path)) }
|
let(:raw_data) { Hash.from_xml(File.read(file_path)) }
|
||||||
let(:import) { create(:import, user:, name: 'gpx_track.gpx', raw_data:) }
|
let(:import) { create(:import, user:, name: 'gpx_track.gpx', raw_data:) }
|
||||||
|
|
||||||
context 'when file exists' do
|
context 'when file has a single segment' do
|
||||||
context 'when file has a single segment' do
|
it 'creates points' do
|
||||||
it 'creates points' do
|
expect { parser }.to change { Point.count }.by(301)
|
||||||
expect { parser }.to change { Point.count }.by(301)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'broadcasts importing progress' do
|
|
||||||
expect_any_instance_of(Imports::Broadcaster).to receive(:broadcast_import_progress).exactly(301).times
|
|
||||||
|
|
||||||
parser
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when file has multiple segments' do
|
it 'broadcasts importing progress' do
|
||||||
let(:file_path) { Rails.root.join('spec/fixtures/files/gpx/gpx_track_multiple_segments.gpx') }
|
expect_any_instance_of(Imports::Broadcaster).to receive(:broadcast_import_progress).exactly(301).times
|
||||||
|
|
||||||
it 'creates points' do
|
parser
|
||||||
expect { parser }.to change { Point.count }.by(558)
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'broadcasts importing progress' do
|
context 'when file has multiple segments' do
|
||||||
expect_any_instance_of(Imports::Broadcaster).to receive(:broadcast_import_progress).exactly(558).times
|
let(:file_path) { Rails.root.join('spec/fixtures/files/gpx/gpx_track_multiple_segments.gpx') }
|
||||||
|
|
||||||
parser
|
it 'creates points' do
|
||||||
end
|
expect { parser }.to change { Point.count }.by(558)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'broadcasts importing progress' do
|
||||||
|
expect_any_instance_of(Imports::Broadcaster).to receive(:broadcast_import_progress).exactly(558).times
|
||||||
|
|
||||||
|
parser
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -51,6 +49,30 @@ RSpec.describe Gpx::TrackParser do
|
||||||
|
|
||||||
parser
|
parser
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'creates points with correct data' do
|
||||||
|
parser
|
||||||
|
|
||||||
|
expect(Point.first.latitude).to eq(37.17221.to_d)
|
||||||
|
expect(Point.first.longitude).to eq(-3.55468.to_d)
|
||||||
|
expect(Point.first.altitude).to eq(1066)
|
||||||
|
expect(Point.first.timestamp).to eq(Time.zone.parse('2024-04-21T10:19:55Z').to_i)
|
||||||
|
expect(Point.first.velocity).to eq('2.9')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when file exported from Garmin' do
|
||||||
|
let(:file_path) { Rails.root.join('spec/fixtures/files/gpx/garmin_example.gpx') }
|
||||||
|
|
||||||
|
it 'creates points with correct data' do
|
||||||
|
parser
|
||||||
|
|
||||||
|
expect(Point.first.latitude).to eq(10.758321.to_d)
|
||||||
|
expect(Point.first.longitude).to eq(106.642344.to_d)
|
||||||
|
expect(Point.first.altitude).to eq(17)
|
||||||
|
expect(Point.first.timestamp).to eq(1_730_626_211)
|
||||||
|
expect(Point.first.velocity).to eq('2.8')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue