ogn_client-ruby 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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