Python library for parsing and generating NMEA 0183 protocol messages used in GPS and marine navigation systems
77
Proprietary sentences provide manufacturer-specific extensions to the standard NMEA protocol, allowing GPS and marine equipment manufacturers to include specialized data and functionality.
class ProprietarySentence(NMEASentence):
"""Base class for proprietary manufacturer sentences."""
manufacturer: str # Three-character manufacturer code
data: List[str] # List of sentence field data
def __init__(self, manufacturer: str, data: List[str]):
"""Initialize proprietary sentence with manufacturer code and data."""
def identifier(self) -> str:
"""Return sentence identifier (e.g., 'PGRM')."""class GRME(ProprietarySentence):
"""Garmin Estimated Position Error."""
subtype: str # Message subtype
hpe: str # Horizontal position error
hpe_unit: str # HPE unit (usually 'M')
vpe: str # Vertical position error
vpe_unit: str # VPE unit (usually 'M')
osepe: str # Overall spherical equivalent position error
osepe_unit: str # OSEPE unit (usually 'M')class GRMZ(ProprietarySentence):
"""Garmin Altitude Information."""
subtype: str # Message subtype
altitude: str # Altitude value
altitude_unit: str # Altitude unit ('f' = feet, 'M' = meters)
pos_fix_dim: str # Position fix dimension (2 = 2D, 3 = 3D)class ASHRPOS(ProprietarySentence, LatLonFix):
"""Ashtech Position Message."""
_r: str # 'R' indicator
subtype: str # Message subtype
mode: str # Positioning mode
sat_count: str # Number of satellites
timestamp: datetime.time # UTC time
lat: str # Latitude
lat_dir: str # Latitude direction
lon: str # Longitude
lon_dir: str # Longitude direction
altitude: str # Altitude
course: str # Course over ground
spd_over_grnd: str # Speed over ground
@property
def latitude(self) -> float:
"""Latitude in decimal degrees."""
@property
def longitude(self) -> float:
"""Longitude in decimal degrees."""class UBX00(ProprietarySentence, LatLonFix):
"""u-blox Lat/Long Position Data."""
_blank: str # Blank field
ubx_type: str # UBX message type
timestamp: datetime.time # UTC time
lat: str # Latitude
lat_dir: str # Latitude direction
lon: str # Longitude
lon_dir: str # Longitude direction
alt_ref: str # Altitude reference
nav_stat: str # Navigation status
h_acc: str # Horizontal accuracy
v_acc: str # Vertical accuracy
sog: str # Speed over ground
cog: str # Course over ground
v_vel: str # Vertical velocity
diff_age: str # Differential age
hdop: str # Horizontal DOP
vdop: str # Vertical DOP
tdop: str # Time DOP
num_svs: str # Number of satellites
reserved: str # Reserved fieldclass TNLAVR(ProprietarySentence):
"""Trimble AVR Message (Attitude and Heading)."""
_: str # Blank field
type: str # Message type
timestamp: datetime.time # UTC time
yaw_angle: str # Yaw angle in degrees
yaw: str # Yaw indicator
tilt_angle: str # Tilt angle in degrees
tilt: str # Tilt indicator
roll_angle: str # Roll angle in degrees
roll: str # Roll indicator
baseline: str # Baseline length
gps_quality: str # GPS quality indicator
pdop: str # Position DOP
num_sats: str # Number of satellitesclass NORBT0(ProprietarySentence, DatetimeFix):
"""Nortek Bottom Track DF350/DF351."""
timestamp: datetime.time # UTC time
datestamp: datetime.date # Date
# Additional bottom track fields...
@property
def datetime(self) -> datetime.datetime:
"""Combined date and time."""import pynmea2
# Parse Garmin position error
msg = pynmea2.parse("$PGRME,15.0,M,45.0,M,25.0,M*22")
print(f"Manufacturer: {msg.manufacturer}") # GRM
print(f"Horizontal error: {msg.hpe} {msg.hpe_unit}") # 15.0 M
print(f"Vertical error: {msg.vpe} {msg.vpe_unit}") # 45.0 M
print(f"Overall error: {msg.osepe} {msg.osepe_unit}") # 25.0 M
# Parse Garmin altitude
msg = pynmea2.parse("$PGRMZ,1494,f,3*21")
print(f"Altitude: {msg.altitude} {msg.altitude_unit}") # 1494 f
print(f"Fix dimension: {msg.pos_fix_dim}D") # 3D
# Parse Ashtech position
msg = pynmea2.parse("$PASHR,POS,0,3,184353.07,1929.045,S,02410.506,E,100.0,309.62,0.13,1.5,1.2,2.1,1.8,12*3F")
print(f"Position: {msg.latitude}, {msg.longitude}") # Decimal degrees
print(f"Satellites: {msg.sat_count}") # Number of satellites
print(f"Mode: {msg.mode}") # Positioning mode
# Parse u-blox position data
msg = pynmea2.parse("$PUBX,00,184353.07,1929.045,S,02410.506,E,100.0,G3,16,9,0.9,309.62,0.13,,,1.2,1.8,1.5,12,0,0*6F")
print(f"Navigation status: {msg.nav_stat}") # G3
print(f"Horizontal accuracy: {msg.h_acc}") # Accuracy estimate
print(f"Satellites used: {msg.num_svs}") # 12
# Create proprietary sentence
grme_data = ['15.0', 'M', '45.0', 'M', '25.0', 'M']
msg = pynmea2.GRME('GRM', grme_data)
print(str(msg)) # $PGRME,15.0,M,45.0,M,25.0,M*22| Code | Manufacturer | Common Sentences |
|---|---|---|
| ASH | Ashtech | RPOS, RATT, RHPR, RVEL |
| FEC | Furuno | GPatt, GPhve |
| GRM | Garmin | RME, RMZ, RMM, RMW |
| KWD | Kenwood | WPL, S (status messages) |
| MGN | Magellan | WPL (waypoint location) |
| NOR | Nortek | BT (bottom track), WT (water track) |
| RDI | RD Instruments | D (heading/pitch/roll) |
| SRF | SiRF | 100, 103 (configuration) |
| SXN | Seapath | 20-24 (quality, attitude, rates) |
| TNL | Trimble | AVR, GGK, VGK, VHD |
| UBX | u-blox | 00, 03, 04 (position, satellites) |
| VTX | Vectronix | 0000, 0002, 0012, 0020 |
import pynmea2
# Parse unknown proprietary sentence (falls back to generic ProprietarySentence)
msg = pynmea2.parse("$PXYZ,field1,field2,field3*12")
print(f"Type: {type(msg)}") # <class 'pynmea2.nmea.ProprietarySentence'>
print(f"Manufacturer: {msg.manufacturer}") # XYZ
print(f"Data: {msg.data}") # ['field1', 'field2', 'field3']
# Access raw field data
print(f"Field 1: {msg.data[0]}") # field1
print(f"Field 2: {msg.data[1]}") # field2Install with Tessl CLI
npx tessl i tessl/pypi-pynmea2docs
evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10