NMEA Protocol Parser
Reason this release was yanked:
obsolete
Project description
pynmeagps
pynmeagps
is an original lightweight Python library aimed primarily at the subset of the NMEA 0183 protocol relevant to GNSS/GPS receivers - that is, NMEA 0183 'talkers' 'Gx' (standard) or 'Px' (proprietary).
The intention is to make it as easy as possible to read, parse and utilise NMEA GNSS/GPS messages in Python applications.
The pynmeagps
homepage is located at http://github.com/semuconsulting/pynmeagps.
FYI There is a companion library pyubx2, which handles u-blox UBX protocol GNSS/GPS messages.
Current Status
At time of writing the library implements a comprehensive set of GNSS NMEA messages relating to GNSS/GPS devices, but is readily extensible. Refer to NMEA_MSGIDS
in nmeatypes_core.py for the complete dictionary of messages currently supported. Additional NMEA 'talkers' may be added in due course.
Sphinx API Documentation in HTML format is available at http://semuconsulting.com/pynmeagps.
Contributions welcome - please refer to CONTRIBUTING.MD.
Bug reports and Feature requests - please use the templates provided.
Installation
pynmeagps
is compatible with Python 3.6+ and has no third-party library dependencies.
In the following, python
& pip
refer to the python3 executables. You may need to type
python3
or pip3
, depending on your particular environment.
The recommended way to install the latest version of pynmeagps
is with
pip:
python -m pip install --upgrade pynmeagps
If required, pynmeagps
can also be installed using virtualenv, e.g.:
python -m pip install --user --upgrade virtualenv
python -m virtualenv env
source env/bin/activate (or env\Scripts\activate on Windows)
(env) python -m pip install --upgrade pynmeagps
...
deactivate
Reading (Streaming)
You can create an NMEAReader
object by calling the constructor with an active stream object.
The stream object can be any data stream which supports a read(n) -> bytes
method (e.g. File or Serial, with
or without a buffer wrapper).
Individual input NMEA messages can then be read using the NMEAReader.read()
function, which returns both the raw data (as bytes) and the parsed data (as an NMEAMessage
object, via the parse()
method). The function is thread-safe in so far as the incoming data stream object is thread-safe. NMEAReader
also implements an iterator.
The NMEAReader
constructor includes an optional nmea_only
flag which governs behaviour if the stream includes non-NMEA data (e.g. UBX or Garmin binary protocols). If set to 'False' (the default), it will ignore such data and continue with the next valid NMEA message. If set to 'True', it will raise a NMEAStreamError
. NB: if the nmea_only
flag is set to 'False', the NMEAReader.read()
function will block until it receives a NMEA message (or the input stream times out).
The NMEAReader
constructor also includes an optional validate
flag which is passed to the parse()
function - see Parsing below.
A further optional mode
flag signifies the message stream mode (GET/SET/POLL). Ordinarily this can be left at the default 0 (GET)).
Examples:
- Serial input - this example will ignore any non-NMEA data.
>>> from serial import Serial
>>> from pynmeagps import NMEAReader
>>> stream = Serial('/dev/tty.usbmodem14101', 9600, timeout=3)
>>> nmr = NMEAReader(stream)
>>> (raw_data, parsed_data) = nmr.read()
- File input (using iterator) - this example will produce a
NMEAStreamError
if non-NMEA data is encountered.
>>> from pynmeagps import NMEAReader
>>> stream = open('nmeadata.log', 'rb')
>>> nmr = MEAReader(stream, True)
>>> for (raw_data, parsed_data) in nmr: print(parsed_data)
...
Parsing
You can parse individual NMEA messages using the static NMEAReader.parse(data, validate=1)
function, which takes a string or bytes containing an NMEA message and returns a NMEAMessage
object.
An optional validate
flag governs the level of validation applied during message parsing. The options are VALNONE (0 - no validation), VALCKSUM (1 - validate checksum, the default) and/or VALMSGID (2 - validate msgID). If invalid, an NMEAParseError
is raised.
Example:
>>> from pynmeagps import NMEAReader
>>> msg = NMEAReader.parse('$GNGLL,5327.04319,S,00214.41396,E,223232.00,A,A*68\r\n', 1)
>>> print(msg)
<NMEA(GNGLL, lat=-53.45072, NS=S, lon=2.240233, EW=E, time=22:32:32, status=A, posMode=A)>
The NMEAMessage
object exposes different public properties depending on its message ID,
e.g. the RMC
message has the following properties:
>>> print(msg)
<NMEA(GNRMC, time=22:18:38, status=A, lat=52.62063, NS=N, lon=-2.16012, EW=W, spd=37.84, cog=, date=2021-03-05, mv=, mvEW=, posMode=A)>
>>> msg.msgID
'RMC'
>>> msg.lat, msg.lon
(52.62063, -2.16012)
>>> msg.spd
37.84
Generating
You can create an NMEAMessage
object by calling the constructor with the following parameters:
- talker (must be a valid talker from
pynmeagps.NMEA_TALKERS
, or blank for proprietary messages) - message id (must be a valid id from
pynmeagps.NMEA_MSGIDS
) - mode (0=GET, 1=SET, 2=POLL)
- (optional) a series of keyword parameters representing the message payload
The 'mode' parameter signifies whether the message payload refers to a:
- GET message (i.e. output from the receiver - NB these would normally be generated via the NMEAReader.read() or NMEAReader.parse() methods but can also be created manually)
- SET message (i.e. command input to the receiver)
- POLL message (i.e. query input to the receiver in anticipation of a response back)
The message payload can be defined via keyword parameters in one of two ways:
- A single keyword parameter of
payload
containing the full payload as a list of string values (any other keyword parameters will be ignored). - One or more keyword parameters corresponding to individual message attributes. Any attributes not explicitly provided as keyword parameters will be set to a nominal value according to their type.
e.g. Create a GLL message, passing the entire payload as a list of strings in native NMEA format:
>>> from pynmeagps import NMEAMessage, GET
>>> pyld=['4330.00000','N','00245.000000','W','120425.234','A','A']
>>> msg = NMEAMessage('GN', 'GLL', GET, payload=pyld)
print(msg)
<NMEA(GNGLL, lat=43.5, NS=N, lon=-2.75, EW=W, time=12:04:25.234000, status=A, posMode=A)>
e.g. Create GLL and GPQ message, passing individual typed values as keywords, with any omitted keywords defaulting to nominal values (in the GLL example, the 'time' parameter has been omitted and has defaulted to the current time):
>>> from pynmeagps import NMEAMessage, GET
>>> msg = NMEAMessage('GN', 'GLL', GET, lat=43.5, NS='N', lon=2.75, EW='W', status='A', posMode='A')
>>> print(msg)
<NMEA(GNGLL, lat=43.5, NS='N', lon=-2.75, EW='W', time='12:04:25.234745', status='A', posMode='A')>
>>> from pynmeagps import NMEAMessage, POLL
>>> msg = NMEAMessage('GN', 'GPQ', POLL, msgId='GGA')
>>> print(msg)
<NMEA(GNGPQ, msgId=GGA)>
NB: Once instantiated, an NMEAMessage
object is immutable.
Serializing
The NMEAMessage
class implements a serialize()
method to convert an NMEAMessage
object to a bytes array suitable for writing to an output stream.
>>> from serial import Serial
>>> from pynmeagps import NMEAMessage, POLL
>>> stream = Serial('COM6', 38400, timeout=3)
>>> msg = NMEAMessage('GN','GPQ', POLL, msgId='GGA')
>>> msg.serialize()
b'$GNGPQ,GGA*22\r\n'
>>> stream.write(msg.serialize())
Examples
The following examples can be found in the \examples
folder:
-
nmeadump.py
is a simple command line utility to stream the parsed NMEA output of a GNSS/GPS device on a specified port. -
nmeastreamer.py
illustrates how to implement a threaded serial reader for NMEA messages using pynmeagps.NMEAReader, and send poll requests for specific NMEA message types. -
nmeafile.py
illustrates how to implement a binary file reader for NMEA messages using the pynmeagps.NMEAReader iterator function. -
gpxtracker.py
illustrates a simple CLI tool to convert an NMEA data dump to a*.gpx
track file using pynmeagps.NMEAReader.
Extensibility
The NMEA protocol is principally defined in the modules nmeatypes_*.py
as a series of dictionaries. Additional message types
can be readily added to the appropriate dictionary. Message payload definitions must conform to the following rules:
1. attribute names must be unique within each message class
2. attribute types must be one of the valid types (IN, DE, CH, etc.)
3. repeating groups must be defined as a tuple ('numr', {dict}), where:
'numr' is either:
a. an integer representing a fixed number of repeats e.g. 32
b. a string representing the name of a preceding attribute containing the number of repeats e.g. 'numSv'
c. 'None' for an indeterminate repeating group. Only one such group is permitted per payload and it must be at the end.
{dict} is the nested dictionary of repeating items
Graphical Client
A python/tkinter graphical GPS client which supports both NMEA and UBX protocols is available at:
http://github.com/semuconsulting/PyGPSClient
Author Information
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for pynmeagps-0.1.3-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | cb1f9237ce477465cc338d9046f7185f845925264e34bb3c7dda85928d51055d |
|
MD5 | 84157208b05f0be73be29046d9788367 |
|
BLAKE2b-256 | 0e2a4e8d54b75d2e08cd841b172297d54ae59a5971bbe754de016454b43cf4aa |