Version Tests Code Climate Donorbox


OGN broadcasts aircraft positions as APRS/APRS-IS messages. This gem hooks into this stream of data and provides the necessary classes to parse the raw message strings into meaningful objects.

:loudspeaker: A word from the shameless commerce division: Looking for a freelance Ruby developer? Surf to and contact Sven. Or show your support with a donation. Yes, we do sponsored features, too.



This gem is cryptographically signed in order to assure it hasn't been tampered with. Unless already done, please add the author's public key as a trusted certificate now:

gem cert --add <(curl -Ls


Add the following to the Gemfile or gems.rb of your Bundler powered Ruby project:

gem 'ogn_client-ruby', require: 'ogn_client'

And then install the bundle:

bundle install --trust-policy MediumSecurity


If you're only going to use the executables:

gem install ogn_client-ruby --trust-policy MediumSecurity


Subscribe to OGN

Choose a valid callsign and appropriate filters, then start listening to the broadcasted raw messages:

require 'ogn_client'

OGNClient::APRS.start(callsign: "ROCT#{rand(1000)}", filter: 'r/47/2/500') do |aprs|
  while raw = aprs.gets
    puts raw   # do more interesting stuff here

Parse Raw Message Strings

:point_up: Refer to the wiki for an introduction to OGN flavoured APRS messages.

In the above example, each aprs.gets returns a raw message string. To decode this string, just pass it to the message parser:


: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".

The factory method OGNClient::Message.parse will return one an instance of OGNClient::Sender, OGNClient::Receiver, OGNClient::Comment or raise an error. When this happens, either the message is crippled, the OGN specifications have changed or you have found a bug in the parser code.

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 and replay them once the bug has been fixed.

:point_up: Raw APRS messages do not contain the date, but assume the current day. This may cause trouble around midnight, however, the parser deals with such edge cases gracefully. Things are a little different when parsing raw APRS messages recorded in the past e.g. with ognlogd. Since the parser has no means to detect the date the APRS messages have been sent, you have to pass it as an option:

raw_aprs ='2017-06-24.log', &:gets)
OGNClient::Message.parse(raw_aprs, date: '2017-06-24')


Sender beacons are usually coming from aircraft equipped with FLARM (anti-collision warning system) or similar devices which broadcast position data as RF beacons.

The data is converted into the metric system since OGN is primarily made for gliders which mostly use the metric system for ground speed, climb rate and so forth.


  • callsign - origin callsign
  • receiver - receiver callsign
  • time - zulu/UTC time with date
  • longitude - WGS84 degrees from -180 (W) to 180 (E)
  • latitude - WGS84 degrees from -90 (S) to 90 (N)
  • altitude - WGS84 meters above mean see level QNH
  • heading - degrees from 1 to 360
  • ground_speed - kilometers per hour
  • sender_type - see SENDER_TYPES
  • address_type - see ADDRESS_TYPES
  • id - device ID
  • stealth_mode - boolean (should always be false)
  • no_tracking - boolean
  • flight_level - 100 feet QNE
  • climb_rate - meters per second
  • turn_rate - revolutions per minute
  • signal_power - power ratio in dBm
  • signal_quality - signal to noise ratio in decibel
  • errors - number of CRC errors
  • frequency_offset - kilohertz
  • gps_accuracy - array [vertical meters, horizontal meters]
  • flarm_software_version - version as "major.minor"
  • flarm_hardware_version - version as integer
  • flarm_id - FLARM device ID
  • proximity - array of FLARM device ID tails


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.


  • callsign - origin callsign
  • receiver - receiver callsign
  • time - zulu/UTC time with date
  • longitude - WG84 degrees from -180 (W) to 180 (E)
  • latitude - WG84 degrees from -90 (S) to 90 (N)
  • altitude - WG84 meters above mean sea level QNH
  • heading - degrees from 1 to 360
  • ground_speed - kilometers per hour

Please note: These receiver beacons contained status information up until version 0.2.5.


Receivers of version 0.2.6 and higher send status messages on a regular basis:


  • callsign - origin callsign
  • receiver - receiver callsign
  • time - zulu/UTC time with date
  • version - software version as "major.minor.patch"
  • platform - e.g. :arm
  • cpu_load - as reported by "uptime"
  • cpu_temperature - in degrees celsius
  • ram_free - megabytes
  • ram_total - megabytes
  • ntp_offset - milliseconds
  • ntp_correction - parts-per-million
  • voltage - board voltage in V
  • amperage - board amperage in A
  • rf_correction_manual - manual frequency correction as per configuration
  • rf_correction_automatic - automatic frequency correction based on GSM
  • senders - number of senders received within the last hour
  • visible_senders - number of visible senders withint the last hour
  • invisible_senders - number of invisible senders ("no-track" on device or "invisible" in database)
  • signal_quality - signal-to-noise ratio in decibel
  • senders_signal_quality - average signal-to-noise ratio across all senders
  • senders_messages - number of messages analyzed to calculate the above
  • good_senders_signal_quality - average signal-to-noise ratio in decibel of good senders (transmitting properly) within the last 24 hours
  • good_and_bad_senders - number of good and bad senders within the last 24 hours
  • good_senders - number of good senders (transmitting properly) within the last 24 hours
  • bad_senders - number of bad senders (not transmitting properly) within the last 24 hours


Comments are sent on a regular basis to keep the connection alive.


  • comment - raw message with the comment marker stripped


The following domain specific errors may be raised:

  • OGNClient::MessageError - errors during the parsing of a message
  • OGNClient::ReceiverError - errors during the parsing of a receiver message

They all inherit from OGNClient::Error. An fault-tolerant subscription could therefore look as follows:

require 'ogn_client'
require 'logger'

logger ='/tmp/ogn_client.log')
options = { callsign: "ROCT#{rand(1000)}", filter: 'r/47/2/500' }
loop do
  OGNClient::APRS.start(options) do |aprs|
    while raw = aprs.gets
        message = OGNClient::Message.parse aprs.gets
      rescue OGNClient::Error => error
        logger.error error.message
      puts message.raw   # do more interesting stuff here

: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.



A simple daemon to log raw APRS messages to daily files.

ognlogd --help

ogn2kml and ogn2geojson

Convert raw APRS messages (e.g. from ognlogd) to KML or GeoJSON.

ogn2kml --help
ogn2geojson --help

Community Support


To install the development dependencies and then run the test suite:

bundle install bundle exec rake # run tests once bundle exec guard # run tests whenever files are modified

The test suite may run against live OGN data if you set the SPEC_SCOPE environment variable, by default, these tests are skipped.

export SPEC_SCOPE=all

Please submit issues on:

To contribute code, fork the project on Github, add your code and submit a pull request:

Feature Brainstorming

  • registration lookups
  • configuration option to switch between metric and aeronautical units
  • more data sources such as ADS-B


The gem is available as open source under the terms of the MIT License.