ogn_client-ruby 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4a6d60e5f26f6b6c18c2e1f6e4aba695901e5473
4
- data.tar.gz: 75e00d14055934f85c66acdd1c7046173425aeba
3
+ metadata.gz: cac6cf6364fa78e20954308deb6258c8ae789661
4
+ data.tar.gz: b5c802a8c11071a73549abaa50d7cf8e7cf03128
5
5
  SHA512:
6
- metadata.gz: 1c1e7c3788ab24ead12e31e5cc67bd0a3a9b12cfef99885dd16cef31d5a780faf1e7f860f7d2efdbf958085904bd36d0ee7031493e15ae89624fce0cf321b8f7
7
- data.tar.gz: fb2171f7a02881b8a12c160271172c9bb515e35b7498320ffa9f5ae624cd7baf31dbc0ff51d2f9ae96c2c13d0d88721a93cbf7e0669e1288ad8b8229241dd564
6
+ metadata.gz: e60aabf34f6e4967e9423b732d676149fda8fb1f3470d3e02b37f791b4804ddc637dfb09538dcac92ecc4687672eb4c2cf84f802d694a031f59734394ac448b1
7
+ data.tar.gz: 1e6903681dcb6c26c5f3612f304914b867113b7598f7816f5d907c46cbade23d8392bc0a31fa43a4d61102fa08fe402e1a818bb0e9aaed06ac33c8c9d12c67df
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- ruby-2.3.0
1
+ ruby-2.4.1
data/.travis.yml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  language: ruby
3
3
  rvm:
4
- - 2.3.1
5
- - 2.2.5
4
+ - 2.3.3
5
+ - 2.2.6
6
6
  - 2.1.10
7
- before_install: gem install bundler -v 1.13.2
7
+ before_install: gem install bundler -v 1.13.6
data/CHANGELOG.md CHANGED
@@ -1,3 +1,19 @@
1
+ ## 0.2.0
2
+
3
+ * support for receiver versions <= 0.2.6
4
+ * renamed `Sender` to `SenderBeacon`
5
+ * devided `Receiver` to `ReceiverBeacon` and `ReceiverStatus`
6
+ * `ReceiverStatus` is *not* available for receiver versions < 0.2.6
7
+
8
+ ## 0.1.3
9
+
10
+ * renamed sender and receiver attributes
11
+ * `Sender#signal` -> `Sender#signal_quality`
12
+ * `Sender#power` -> `Sender#signal_power`
13
+ * `Receiver#signal` -> `Receiver#signal_quality`
14
+ * `Receiver#senders_signal` -> `Receiver#senders_signal_quality`
15
+ * `Receiver#good_senders_signal` -> `Receiver#good_senders_signal_quality`
16
+
1
17
  ## 0.1.2
2
18
 
3
19
  * support for receiver versions <= 0.2.5
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
  [![Continuous Integration](https://img.shields.io/travis/svoop/ogn_client-ruby/master.svg?style=flat)](https://travis-ci.org/svoop/ogn_client-ruby)
3
3
  [![Code Climate](https://img.shields.io/codeclimate/github/svoop/ogn_client-ruby.svg?style=flat)](https://codeclimate.com/github/svoop/ogn_client-ruby)
4
4
  [![Gitter](https://img.shields.io/gitter/room/svoop/ogn_client-ruby.svg?style=flat)](https://gitter.im/svoop/ogn_client-ruby)
5
- [![Donorbox](https://img.shields.io/badge/donate-on donorbox-yellow.svg)](https://donorbox.org/bitcetera-ogn_client-ruby)
5
+ [![Donorbox](https://img.shields.io/badge/donate-on_donorbox-yellow.svg)](https://donorbox.org/bitcetera-ogn_client-ruby)
6
6
 
7
7
  # ogn_client-ruby
8
8
 
@@ -36,8 +36,12 @@ Or install it yourself with:
36
36
  Choose a [valid callsign](http://www.aprs-is.net/Connecting.aspx#loginrules) and [appropriate filters](http://www.aprs-is.net/javAPRSFilter.aspx), then start listening to the broadcasted raw messages:
37
37
 
38
38
  ```ruby
39
- OGNClient::APRS.start(callsign: 'ROCT', filter: 'r/33/-97/200') do |aprs|
40
- loop { puts aprs.gets }
39
+ require 'ogn_client'
40
+
41
+ OGNClient::APRS.start(callsign: "ROCT#{rand(1000)}", filter: 'r/47/2/500') do |aprs|
42
+ while raw = aprs.gets
43
+ puts raw # do more interesting stuff here
44
+ end
41
45
  end
42
46
  ```
43
47
 
@@ -53,11 +57,13 @@ OGNClient::Message.parse(aprs.gets)
53
57
 
54
58
  :point_up: Raw APRS messages as returned by `aprs.gets` are "ASCII-8BIT" encoded and may contain tailing whitespace. The parser removes this whitespace and converts the string to "UTF-8".
55
59
 
56
- The factory method `OGNClient::Message.parse` will return one an instance of `OGNClient::Sender`, `OGNClient::Receiver`, `OGNClient::comment` or [raise an error](#errors). When this happens, either the message is crippled, the [OGN](http://glidernet.org) specifications have changed or you have found a bug in the parser code. You may want to store such messages, [file a bug](#community-support) and replay them once the bug has been fixed.
60
+ The factory method `OGNClient::Message.parse` will return one an instance of `OGNClient::Sender`, `OGNClient::Receiver`, `OGNClient::Comment` or [raise an error](#errors). When this happens, either the message is crippled, the [OGN](http://glidernet.org) specifications have changed or you have found a bug in the parser code.
61
+
62
+ In production, you may want to rescue from these errors and ignore the message. You should, however, log the offending messages messages, [file a bug](#community-support) and replay them once the bug has been fixed.
57
63
 
58
- #### OGNClient::Sender
64
+ #### OGNClient::SenderBeacon
59
65
 
60
- Senders are usually aircraft equipped with [FLARM](https://flarm.com) (anti-collision warning system) or similar devices which broadcast position data as RF beacons.
66
+ Sender beacons are usually coming from aircraft equipped with [FLARM](https://flarm.com) (anti-collision warning system) or similar devices which broadcast position data as RF beacons.
61
67
 
62
68
  The data is converted into the metric system since [OGN](http://glidernet.org) is primarily made for gliders which mostly use the metric system for ground speed, climb rate and so forth.
63
69
 
@@ -78,19 +84,19 @@ Attributes:
78
84
  * **flight_level** - 100 feet QNE
79
85
  * **climb_rate** - meters per second
80
86
  * **turn_rate** - revolutions per minute
81
- * **power** - power ratio in dBm
82
- * **signal** - signal to noise ratio in decibel
87
+ * **signal_power** - power ratio in dBm
88
+ * **signal_quality** - signal to noise ratio in decibel
83
89
  * **errors** - number of CRC errors
84
90
  * **frequency_offset** - kilohertz
85
91
  * **gps_accuracy** - array [vertical meters, horizontal meters]
86
- * **flarm_software_version** - version as #<Gem::Version "major.minor">
87
- * **flarm_hardware_version** - version as #<Gem::Version "major">
92
+ * **flarm_software_version** - version as "major.minor"
93
+ * **flarm_hardware_version** - version as integer
88
94
  * **flarm_id** - FLARM device ID
89
95
  * **proximity** - array of FLARM device ID tails
90
96
 
91
- #### OGNClient::Receiver
97
+ #### OGNClient::ReceiverBeacon
92
98
 
93
- Receivers are little RF boxes which pick up the RF beacons from aircraft and relay them to the OGN servers as messages. They send their own status messages on a regular basis.
99
+ Receivers are little RF boxes which pick up the RF beacons from aircraft and relay them to the OGN servers as messages. They send their own beacons on a regular basis.
94
100
 
95
101
  Attributes:
96
102
  * **callsign** - origin callsign
@@ -101,7 +107,18 @@ Attributes:
101
107
  * **altitude** - WG84 meters above mean sea level QNH
102
108
  * **heading** - degrees from 1 to 360
103
109
  * **ground_speed** - kilometers per hour
104
- * **version** - software version as #<Gem::Version "major.minor.patch">
110
+
111
+ Please note: These receiver beacons contained status information up until version 0.2.5.
112
+
113
+ #### OGNClient::ReceiverStatus
114
+
115
+ Receivers of version 0.2.6 and higher send status messages on a regular basis:
116
+
117
+ Attributes:
118
+ * **callsign** - origin callsign
119
+ * **receiver** - receiver callsign
120
+ * **time** - zulu/UTC time with date
121
+ * **version** - software version as "major.minor.patch"
105
122
  * **platform** - e.g. :arm
106
123
  * **cpu_load** - as reported by "uptime"
107
124
  * **cpu_temperature** - in degrees celsius
@@ -116,10 +133,10 @@ Attributes:
116
133
  * **senders** - number of senders received within the last hour
117
134
  * **visible_senders** - number of visible senders withint the last hour
118
135
  * **invisible_senders** - number of invisible senders ("no-track" on device or "invisible" in database)
119
- * **signal** - signal-to-noise ratio in decibel
120
- * **senders_signal** - average signal-to-noise ratio across all senders
136
+ * **signal_quality** - signal-to-noise ratio in decibel
137
+ * **senders_signal_quality** - average signal-to-noise ratio across all senders
121
138
  * **senders_messages** - number of messages analyzed to calculate the above
122
- * **good_senders_signal** - average signal-to-noise ratio in decibel of good senders (transmitting properly) within the last 24 hours
139
+ * **good_senders_signal_quality** - average signal-to-noise ratio in decibel of good senders (transmitting properly) within the last 24 hours
123
140
  * **good_and_bad_senders** - number of good and bad senders within the last 24 hours
124
141
  * **good_senders** - number of good senders (transmitting properly) within the last 24 hours
125
142
  * **bad_senders** - number of bad senders (not transmitting properly) within the last 24 hours
@@ -142,9 +159,10 @@ They all inherit from `OGNClient::Error`. An fault-tolerant subscription could t
142
159
 
143
160
  ```ruby
144
161
  require 'ogn_client'
162
+ require 'logger'
145
163
 
146
164
  logger = Logger.new('/tmp/ogn_client.log')
147
- options = { callsign: 'ROCT', filter: 'r/47/2/500' }
165
+ options = { callsign: "ROCT#{rand(1000)}", filter: 'r/47/2/500' }
148
166
  loop do
149
167
  OGNClient::APRS.start(options) do |aprs|
150
168
  while raw = aprs.gets
@@ -160,13 +178,15 @@ loop do
160
178
  end
161
179
  ```
162
180
 
181
+ :point_up: Receiver versions ("major.minor.patch") are will only raise an error when the offending version has a higher major or minor version digit. Patch level differences will only trigger a warning.
182
+
163
183
  ## Community Support
164
184
 
165
185
  * Look for developers and users on [Gitter](https://gitter.im/svoop/ogn_client-ruby).
166
186
  * Ask your questions on [Stackoverflow](https://stackoverflow.com/questions/ask?tags=ogn_client-ruby,ruby,gem).
167
187
  * Annotated source code on [omniref](https://www.omniref.com/repositories/svoop/ogn_client-ruby)
168
188
  * Bug reports, feature and pull requests are welcome on [GitHub](https://github.com/svoop/ogn_client-ruby).
169
- * [Donations with Stripe or PayPal](https://donorbox.org/bitcetera-ogn_client-ruby) are welcome as well. If you prefer to sponsor a feature, please create an issue on [GitHub](https://github.com/svoop/ogn_client-ruby) first and state your intentions.
189
+ * [Donations are welcome as well](https://donorbox.org/bitcetera-ogn_client-ruby)l. If you prefer to sponsor a feature, please create an issue on [GitHub](https://github.com/svoop/ogn_client-ruby) first and state your intentions.
170
190
 
171
191
  ## Development
172
192
 
@@ -178,7 +198,7 @@ Check out the repository, install the dependencies and run the test suite:
178
198
  $ bin/setup
179
199
  $ rake
180
200
 
181
- If you are on Mac OS X, +guard+, +guard-minitest+ and +minitest-osx+ are also installed and therefore you get the test results as notifications by running a guard watchdog with:
201
+ If you are on macOS, *guard*, *guard-minitest* and *minitest-osx* are also installed and therefore you get the test results as notifications by running a guard watchdog with:
182
202
 
183
203
  $ guard
184
204
 
data/lib/ogn_client.rb CHANGED
@@ -5,5 +5,6 @@ require_relative 'ogn_client/errors'
5
5
  require_relative 'ogn_client/aprs'
6
6
  require_relative 'ogn_client/message'
7
7
  require_relative 'ogn_client/messages/comment'
8
- require_relative 'ogn_client/messages/receiver'
9
- require_relative 'ogn_client/messages/sender'
8
+ require_relative 'ogn_client/messages/receiver_beacon'
9
+ require_relative 'ogn_client/messages/receiver_status'
10
+ require_relative 'ogn_client/messages/sender_beacon'
@@ -27,8 +27,9 @@ module OGNClient
27
27
  (?<time>\d{6})h
28
28
  (?:(?<latitude>\d{4}\.\d{2}[NS]).(?<longitude>\d{5}\.\d{2}[EW]).)?
29
29
  (?:(?<heading>\d{3})/(?<ground_speed>\d{3}))?
30
- (?:/A=(?<altitude>\d{6}))?\s+
30
+ (?:/A=(?<altitude>\d{6}))?\s*
31
31
  (?:!W((?<latitude_enhancement>\d)(?<longitude_enhancement>\d))!)?
32
+ (?:\s|$)
32
33
  )x
33
34
 
34
35
  attr_reader :raw
@@ -44,8 +45,9 @@ module OGNClient
44
45
  def self.parse(raw)
45
46
  fail(OGNClient::MessageError, "raw message must be String but is #{raw.class}") unless raw.is_a? String
46
47
  raw = raw.chomp.force_encoding('ASCII-8BIT').encode('UTF-8')
47
- OGNClient::Sender.new.send(:parse, raw) ||
48
- OGNClient::Receiver.new.send(:parse, raw) ||
48
+ OGNClient::SenderBeacon.new.send(:parse, raw) ||
49
+ OGNClient::ReceiverStatus.new.send(:parse, raw) ||
50
+ OGNClient::ReceiverBeacon.new.send(:parse, raw) ||
49
51
  OGNClient::Comment.new.send(:parse, raw) ||
50
52
  fail(OGNClient::MessageError, "message payload parsing failed: `#{raw}'")
51
53
  end
@@ -0,0 +1,21 @@
1
+ module OGNClient
2
+
3
+ class ReceiverBeacon < Message
4
+
5
+ RECEIVER_BEACON_PATTERN = %r(^
6
+ .+?>APRS,(?:.+?,){1,2}
7
+ (?:GLIDERN|GIGA|NYMSERV)\d*:
8
+ )x
9
+
10
+ private
11
+
12
+ def parse(raw)
13
+ raw.match RECEIVER_BEACON_PATTERN do
14
+ super unless @raw
15
+ self
16
+ end
17
+ end
18
+
19
+ end
20
+
21
+ end
@@ -0,0 +1,161 @@
1
+ module OGNClient
2
+
3
+ class ReceiverStatus < Message
4
+
5
+ RECEIVER_STATUS_PATTERN = %r(
6
+ (?:
7
+ v(?<version>\d+\.\d+\.\d+)
8
+ (?:\.(?<platform>.+?))?
9
+ \s)?
10
+ CPU:(?<cpu_load>[\d.]+)\s
11
+ RAM:(?<ram_free>[\d.]+)/(?<ram_total>[\d.]+)MB\s
12
+ NTP:(?<ntp_offset>[\d.]+)ms/(?<ntp_correction>[+-][\d.]+)ppm\s
13
+ (?:(?<voltage>[\d.]+)V\s)?
14
+ (?:(?<amperage>[\d.]+)A\s)?
15
+ (?:(?<cpu_temperature>[+-][\d.]+)C\s*)?
16
+ (?:(?<visible_senders>\d+)/(?<senders>\d+)Acfts\[1h\]\s*)?
17
+ (?:RF:
18
+ (?:
19
+ (?<rf_correction_manual>[+-][\d]+)
20
+ (?<rf_correction_automatic>[+-][\d.]+)ppm/
21
+ )?
22
+ (?<signal_quality>[+-][\d.]+)dB
23
+ (?:/(?<senders_signal_quality>[+-][\d.]+)dB@10km\[(?<senders_messages>\d+)\])?
24
+ (?:/(?<good_senders_signal_quality>[+-][\d.]+)dB@10km\[(?<good_senders>\d+)/(?<good_and_bad_senders>\d+)\])?
25
+ )?
26
+ $)x
27
+
28
+ NO_WARN_RECEIVER_VERSIONS = Gem::Dependency.new('', '>= 0.2.6', '< 0.2.8')
29
+ NO_FAIL_RECEIVER_VERSIONS = Gem::Dependency.new('', '< 0.3')
30
+
31
+ attr_reader :version # software version as "major.minor.patch"
32
+ attr_reader :platform # e.g. "ARM"
33
+ attr_reader :cpu_load # as reported by "uptime"
34
+ attr_reader :cpu_temperature # degrees celsius
35
+ attr_reader :ram_free # megabytes
36
+ attr_reader :ram_total # megabytes
37
+ attr_reader :ntp_offset # milliseconds
38
+ attr_reader :ntp_correction # parts-per-million
39
+ attr_reader :voltage # board voltage in V
40
+ attr_reader :amperage # board amperage in A
41
+ attr_reader :rf_correction_manual # as per configuration
42
+ attr_reader :rf_correction_automatic # based on GSM
43
+ attr_reader :senders # number of senders within the last hour
44
+ attr_reader :visible_senders # number of visible senders within the last hour
45
+ attr_reader :signal_quality # signal-to-noise ratio in decibel
46
+ attr_reader :senders_signal_quality # average signal-to-noise ratio in decibel across all senders
47
+ attr_reader :senders_messages # number of messages analyzed to calculate the above
48
+ attr_reader :good_senders_signal_quality # average signal-to-noise ratio in decibel of good senders (transmitting properly) within the last 24 hours
49
+ attr_reader :good_and_bad_senders # number of good and bad senders within the last 24 hours
50
+ attr_reader :good_senders # number of good senders (transmitting properly) within the last 24 hours
51
+
52
+ def invisible_senders
53
+ senders - visible_senders
54
+ rescue
55
+ nil
56
+ end
57
+
58
+ def bad_senders
59
+ good_and_bad_senders - good_senders
60
+ rescue
61
+ nil
62
+ end
63
+
64
+ private
65
+
66
+ def parse(raw)
67
+ raw.match RECEIVER_STATUS_PATTERN do |match|
68
+ super unless @raw
69
+ %i(version platform cpu_load cpu_temperature ram_free ram_total ntp_offset ntp_correction voltage amperage rf_correction_manual rf_correction_automatic senders visible_senders signal_quality senders_signal_quality senders_messages good_senders_signal_quality good_and_bad_senders good_senders).each do |attr|
70
+ send("#{attr}=", match[attr]) if match[attr]
71
+ end
72
+ self
73
+ end
74
+ end
75
+
76
+ def version=(raw)
77
+ @version = raw
78
+ fail(OGNClient::ReceiverError, "receiver version `#{@version}'") unless NO_FAIL_RECEIVER_VERSIONS.match?('', @version)
79
+ warn("WARNING: receiver version `#{@version}'") unless NO_WARN_RECEIVER_VERSIONS.match?('', @version)
80
+ @version
81
+ end
82
+
83
+ def platform=(raw)
84
+ @platform = raw.to_sym.downcase
85
+ end
86
+
87
+ def cpu_load=(raw)
88
+ @cpu_load = raw.to_f.round(2)
89
+ end
90
+
91
+ def cpu_temperature=(raw)
92
+ @cpu_temperature = raw.to_f.round(2)
93
+ end
94
+
95
+ def ram_free=(raw)
96
+ @ram_free = raw.to_f.round(2)
97
+ end
98
+
99
+ def ram_total=(raw)
100
+ @ram_total = raw.to_f.round(2)
101
+ end
102
+
103
+ def ntp_offset=(raw)
104
+ @ntp_offset = raw.to_f.round(2)
105
+ end
106
+
107
+ def ntp_correction=(raw)
108
+ @ntp_correction = raw.to_f.round(2)
109
+ end
110
+
111
+ def voltage=(raw)
112
+ @voltage = raw.to_f.round(3)
113
+ end
114
+
115
+ def amperage=(raw)
116
+ @amperage = raw.to_f.round(3)
117
+ end
118
+
119
+ def rf_correction_manual=(raw)
120
+ @rf_correction_manual = raw.to_i
121
+ end
122
+
123
+ def rf_correction_automatic=(raw)
124
+ @rf_correction_automatic = raw.to_f.round(1)
125
+ end
126
+
127
+ def senders=(raw)
128
+ @senders = raw.to_i
129
+ end
130
+
131
+ def visible_senders=(raw)
132
+ @visible_senders = raw.to_i
133
+ end
134
+
135
+ def signal_quality=(raw)
136
+ @signal_quality = raw.to_f.round(3)
137
+ end
138
+
139
+ def senders_signal_quality=(raw)
140
+ @senders_signal_quality = raw.to_f.round(3)
141
+ end
142
+
143
+ def senders_messages=(raw)
144
+ @senders_messages = raw.to_i
145
+ end
146
+
147
+ def good_senders_signal_quality=(raw)
148
+ @good_senders_signal_quality = raw.to_f.round(3)
149
+ end
150
+
151
+ def good_and_bad_senders=(raw)
152
+ @good_and_bad_senders = raw.to_i
153
+ end
154
+
155
+ def good_senders=(raw)
156
+ @good_senders = raw.to_i
157
+ end
158
+
159
+ end
160
+
161
+ end
@@ -1,20 +1,20 @@
1
1
  module OGNClient
2
2
 
3
- class Sender < Message
3
+ class SenderBeacon < Message
4
4
 
5
- SENDER_PATTERN = %r(
6
- id(?<details>\w{2})(?<id>\w+?)\s
7
- (?<climb_rate>[+-]\d+?)fpm\s
8
- (?<turn_rate>[+-][\d.]+?)rot\s
5
+ SENDER_BEACON_PATTERN = %r(
6
+ id(?<details>\w{2})(?<id>\w+?)\s?
7
+ (?:(?<climb_rate>[+-]\d+?)fpm\s)?
8
+ (?:(?<turn_rate>[+-][\d.]+?)rot\s)?
9
9
  (?:FL(?<flight_level>[\d.]+)\s)?
10
- (?<signal>[\d.]+?)dB\s
11
- (?<errors>\d+)e\s
12
- (?<frequency_offset>[+-][\d.]+?)kHz\s?
10
+ (?:(?<signal_quality>[\d.]+?)dB\s)?
11
+ (?:(?<errors>\d+)e\s)?
12
+ (?:(?<frequency_offset>[+-][\d.]+?)kHz\s?)?
13
13
  (?:gps(?<gps_accuracy>\d+x\d+)\s?)?
14
14
  (?:s(?<flarm_software_version>[\d.]+)\s?)?
15
15
  (?:h(?<flarm_hardware_version>[\dA-F]{2})\s?)?
16
16
  (?:r(?<flarm_id>[\dA-F]+)\s?)?
17
- (?:(?<power>[+-][\d.]+)dBm\s?)?
17
+ (?:(?<signal_power>[+-][\d.]+)dBm\s?)?
18
18
  (?:hear(?<proximity>.+))?
19
19
  $)x
20
20
 
@@ -50,22 +50,22 @@ module OGNClient
50
50
  attr_reader :flight_level # 100 feet QNE
51
51
  attr_reader :climb_rate # meters per second
52
52
  attr_reader :turn_rate # revolutions per minute
53
- attr_reader :power # power ratio in dBm
54
- attr_reader :signal # signal to noise ratio in decibel
53
+ attr_reader :signal_power # power ratio in dBm
54
+ attr_reader :signal_quality # signal-to-noise ratio in decibel
55
55
  attr_reader :errors # number of CRC errors
56
56
  attr_reader :frequency_offset # kilohertz
57
57
  attr_reader :gps_accuracy # array [vertical meters, horizontal meters]
58
- attr_reader :flarm_software_version # version as #<Gem::Version "major.minor">
59
- attr_reader :flarm_hardware_version # version as #<Gem::Version "major">
58
+ attr_reader :flarm_software_version # version as "major.minor"
59
+ attr_reader :flarm_hardware_version # version as "major"
60
60
  attr_reader :flarm_id # FLARM device ID
61
61
  attr_reader :proximity # array of FLARM device ID tails
62
62
 
63
63
  private
64
64
 
65
65
  def parse(raw)
66
- raw.match SENDER_PATTERN do |match|
66
+ raw.match SENDER_BEACON_PATTERN do |match|
67
67
  super unless @raw
68
- %i(details id flight_level climb_rate turn_rate power signal errors frequency_offset gps_accuracy flarm_software_version flarm_hardware_version flarm_id proximity).each do |attr|
68
+ %i(details id flight_level climb_rate turn_rate signal_power signal_quality errors frequency_offset gps_accuracy flarm_software_version flarm_hardware_version flarm_id proximity).each do |attr|
69
69
  send("#{attr}=", match[attr]) if match[attr]
70
70
  end
71
71
  # NOTE: [@svoop] [ruby21] workaround necessary until support for ruby21 is removed
@@ -99,12 +99,12 @@ module OGNClient
99
99
  @turn_rate = (raw.to_i / 4.0).round(1)
100
100
  end
101
101
 
102
- def power=(raw)
103
- @power = raw.to_f.round(3)
102
+ def signal_power=(raw)
103
+ @signal_power = raw.to_f.round(3)
104
104
  end
105
105
 
106
- def signal=(raw)
107
- @signal = raw.to_f.round(1)
106
+ def signal_quality=(raw)
107
+ @signal_quality = raw.to_f.round(1)
108
108
  end
109
109
 
110
110
  def errors=(raw)
@@ -120,11 +120,11 @@ module OGNClient
120
120
  end
121
121
 
122
122
  def flarm_software_version=(raw)
123
- @flarm_software_version = Gem::Version.new raw
123
+ @flarm_software_version = raw
124
124
  end
125
125
 
126
126
  def flarm_hardware_version=(raw)
127
- @flarm_hardware_version = Gem::Version.new raw.to_i(16)
127
+ @flarm_hardware_version = raw.to_i(16)
128
128
  end
129
129
 
130
130
  def flarm_id=(raw)
@@ -1,3 +1,3 @@
1
1
  module OGNClient
2
- VERSION = "0.1.2".freeze
2
+ VERSION = "0.2.0".freeze
3
3
  end
data/tasks/test.rake CHANGED
@@ -1,28 +1,57 @@
1
1
  require 'ogn_client'
2
+ require 'tempfile'
3
+ require 'fileutils'
2
4
 
3
5
  namespace :test do
4
6
 
5
- desc "Receive and dump real-time APRS messages"
6
- task :receiver do
7
- OGNClient::APRS.start(callsign: "ROCT-#{rand(100)}") do |aprs|
8
- loop do
9
- print aprs.gets
10
- end
11
- end
7
+ desc "Reset the test suite"
8
+ task :reset do
9
+ FileUtils.rm_f('spec/fixtures/messages.txt')
12
10
  end
13
11
 
14
- desc "Parse real-time APRS messages and test the parser"
15
- task :parser do
16
- callsign = "ROCT-#{rand(100)}"
12
+ desc "Feed live APRS messages to the parser"
13
+ task :live do
14
+ callsign = "ROCT#{rand(1000)}"
15
+ counter = 0
17
16
  loop do
18
17
  OGNClient::APRS.start(callsign: callsign) do |aprs|
19
18
  while raw = aprs.gets do
20
- print '.'
21
19
  begin
22
20
  OGNClient::Message.parse raw
23
21
  rescue OGNClient::Error => error
24
- puts
25
- warn "WARNING: #{error.message}"
22
+ puts "ERROR: #{error.message}"
23
+ end
24
+ counter += 1
25
+ puts "INFO: captured #{counter} messages" if counter % 1000 == 0
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ namespace :live do
32
+ desc "Record live APRS messages"
33
+ task :record do
34
+ callsign = "ROCT#{rand(1000)}"
35
+ counter = 0
36
+ File.open("#{Dir.tmpdir}/ogn_messages.txt", "w") do |file|
37
+ OGNClient::APRS.start(callsign: callsign) do |aprs|
38
+ while raw = aprs.gets do
39
+ file.print raw
40
+ counter += 1
41
+ puts "INFO: captured #{counter} messages" if counter % 1000 == 0
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ desc "Feed recorded APRS messages to the parser"
48
+ task :replay do
49
+ File.open("#{Dir.tmpdir}/ogn_messages.txt") do |file|
50
+ while raw = file.gets do
51
+ begin
52
+ OGNClient::Message.parse raw
53
+ rescue OGNClient::Error => error
54
+ puts "ERROR: #{error.message}"
26
55
  end
27
56
  end
28
57
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ogn_client-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sven Schwyn
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-10-10 00:00:00.000000000 Z
11
+ date: 2017-04-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -121,8 +121,9 @@ files:
121
121
  - lib/ogn_client/errors.rb
122
122
  - lib/ogn_client/message.rb
123
123
  - lib/ogn_client/messages/comment.rb
124
- - lib/ogn_client/messages/receiver.rb
125
- - lib/ogn_client/messages/sender.rb
124
+ - lib/ogn_client/messages/receiver_beacon.rb
125
+ - lib/ogn_client/messages/receiver_status.rb
126
+ - lib/ogn_client/messages/sender_beacon.rb
126
127
  - lib/ogn_client/version.rb
127
128
  - ogn_client-ruby.gemspec
128
129
  - tasks/test.rake
@@ -146,7 +147,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
146
147
  version: '0'
147
148
  requirements: []
148
149
  rubyforge_project:
149
- rubygems_version: 2.5.1
150
+ rubygems_version: 2.6.11
150
151
  signing_key:
151
152
  specification_version: 4
152
153
  summary: Subscriber and parser for APRS messages from OGN
@@ -1,159 +0,0 @@
1
- module OGNClient
2
-
3
- class Receiver < Message
4
-
5
- RECEIVER_PATTERN = %r(
6
- (?:
7
- v(?<version>\d+\.\d+\.\d+)
8
- (?:\.(?<platform>.+?))?
9
- \s)?
10
- CPU:(?<cpu_load>[\d.]+)\s
11
- RAM:(?<ram_free>[\d.]+)/(?<ram_total>[\d.]+)MB\s
12
- NTP:(?<ntp_offset>[\d.]+)ms/(?<ntp_correction>[+-][\d.]+)ppm\s
13
- (?:(?<voltage>[\d.]+)V\s)?
14
- (?:(?<amperage>[\d.]+)A\s)?
15
- (?:(?<cpu_temperature>[+-][\d.]+)C\s*)?
16
- (?:(?<visible_senders>\d+)/(?<senders>\d+)Acfts\[1h\]\s*)?
17
- (?:RF:
18
- (?:
19
- (?<rf_correction_manual>[+-][\d]+)
20
- (?<rf_correction_automatic>[+-][\d.]+)ppm/
21
- )?
22
- (?<signal>[+-][\d.]+)dB
23
- (?:/(?<senders_signal>[+-][\d.]+)dB@10km\[(?<senders_messages>\d+)\])?
24
- (?:/(?<good_senders_signal>[+-][\d.]+)dB@10km\[(?<good_senders>\d+)/(?<good_and_bad_senders>\d+)\])?
25
- )?
26
- $)x
27
-
28
- SUPPORTED_RECEIVER_VERSION = Gem::Version.new('0.2.5')
29
-
30
- attr_reader :version # software version as #<Gem::Version "major.minor.patch">
31
- attr_reader :platform # e.g. "ARM"
32
- attr_reader :cpu_load # as reported by "uptime"
33
- attr_reader :cpu_temperature # degrees celsius
34
- attr_reader :ram_free # megabytes
35
- attr_reader :ram_total # megabytes
36
- attr_reader :ntp_offset # milliseconds
37
- attr_reader :ntp_correction # parts-per-million
38
- attr_reader :voltage # board voltage in V
39
- attr_reader :amperage # board amperage in A
40
- attr_reader :rf_correction_manual # as per configuration
41
- attr_reader :rf_correction_automatic # based on GSM
42
- attr_reader :senders # number of senders within the last hour
43
- attr_reader :visible_senders # number of visible senders within the last hour
44
- attr_reader :signal # signal-to-noise ratio in decibel
45
- attr_reader :senders_signal # average signal-to-noise ratio in decibel across all senders
46
- attr_reader :senders_messages # number of messages analyzed to calculate the above
47
- attr_reader :good_senders_signal # average signal-to-noise ratio in decibel of good senders (transmitting properly) within the last 24 hours
48
- attr_reader :good_and_bad_senders # number of good and bad senders within the last 24 hours
49
- attr_reader :good_senders # number of good senders (transmitting properly) within the last 24 hours
50
-
51
- def invisible_senders
52
- senders - visible_senders
53
- rescue
54
- nil
55
- end
56
-
57
- def bad_senders
58
- good_and_bad_senders - good_senders
59
- rescue
60
- nil
61
- end
62
-
63
- private
64
-
65
- def parse(raw)
66
- raw.match RECEIVER_PATTERN do |match|
67
- super unless @raw
68
- %i(version platform cpu_load cpu_temperature ram_free ram_total ntp_offset ntp_correction voltage amperage rf_correction_manual rf_correction_automatic senders visible_senders signal senders_signal senders_messages good_senders_signal good_and_bad_senders good_senders).each do |attr|
69
- send("#{attr}=", match[attr]) if match[attr]
70
- end
71
- self
72
- end
73
- end
74
-
75
- def version=(raw)
76
- @version = Gem::Version.new(raw)
77
- fail(OGNClient::ReceiverError, "unsupported receiver version: `#{@raw}'") if @version > SUPPORTED_RECEIVER_VERSION
78
- @version
79
- end
80
-
81
- def platform=(raw)
82
- @platform = raw.to_sym.downcase
83
- end
84
-
85
- def cpu_load=(raw)
86
- @cpu_load = raw.to_f.round(2)
87
- end
88
-
89
- def cpu_temperature=(raw)
90
- @cpu_temperature = raw.to_f.round(2)
91
- end
92
-
93
- def ram_free=(raw)
94
- @ram_free = raw.to_f.round(2)
95
- end
96
-
97
- def ram_total=(raw)
98
- @ram_total = raw.to_f.round(2)
99
- end
100
-
101
- def ntp_offset=(raw)
102
- @ntp_offset = raw.to_f.round(2)
103
- end
104
-
105
- def ntp_correction=(raw)
106
- @ntp_correction = raw.to_f.round(2)
107
- end
108
-
109
- def voltage=(raw)
110
- @voltage = raw.to_f.round(3)
111
- end
112
-
113
- def amperage=(raw)
114
- @amperage = raw.to_f.round(3)
115
- end
116
-
117
- def rf_correction_manual=(raw)
118
- @rf_correction_manual = raw.to_i
119
- end
120
-
121
- def rf_correction_automatic=(raw)
122
- @rf_correction_automatic = raw.to_f.round(1)
123
- end
124
-
125
- def senders=(raw)
126
- @senders = raw.to_i
127
- end
128
-
129
- def visible_senders=(raw)
130
- @visible_senders = raw.to_i
131
- end
132
-
133
- def signal=(raw)
134
- @signal = raw.to_f.round(3)
135
- end
136
-
137
- def senders_signal=(raw)
138
- @senders_signal = raw.to_f.round(3)
139
- end
140
-
141
- def senders_messages=(raw)
142
- @senders_messages = raw.to_i
143
- end
144
-
145
- def good_senders_signal=(raw)
146
- @good_senders_signal = raw.to_f.round(3)
147
- end
148
-
149
- def good_and_bad_senders=(raw)
150
- @good_and_bad_senders = raw.to_i
151
- end
152
-
153
- def good_senders=(raw)
154
- @good_senders = raw.to_i
155
- end
156
-
157
- end
158
-
159
- end