0
# Core Parsing and Generation
1
2
The core parsing system in pynmea2 provides functions and classes for converting between NMEA sentence strings and structured Python objects. This includes parsing incoming NMEA data, generating NMEA strings from data, and validating checksums.
3
4
## Main Parse Function
5
6
```python { .api }
7
def parse(line: str, check: bool = False) -> NMEASentence:
8
"""
9
Parse a string representing a NMEA 0183 sentence.
10
11
Args:
12
line: NMEA sentence string (leading '$' optional, trailing whitespace ignored)
13
check: If True, raise ChecksumError if checksum is missing
14
15
Returns:
16
NMEASentence object of appropriate subclass
17
18
Raises:
19
ParseError: If string cannot be parsed
20
ChecksumError: If checksum validation fails or missing when check=True
21
SentenceTypeError: If sentence type is not recognized
22
"""
23
```
24
25
### Usage Examples
26
27
```python
28
import pynmea2
29
30
# Parse with checksum validation (default)
31
msg = pynmea2.parse("$GPGGA,184353.07,1929.045,S,02410.506,E,1,04,2.6,100.00,M,-33.9,M,,0000*6D")
32
print(type(msg)) # <class 'pynmea2.types.talker.GGA'>
33
34
# Parse without requiring checksum
35
msg = pynmea2.parse("$GPGGA,184353.07,1929.045,S,02410.506,E,1,04,2.6,100.00,M,-33.9,M,,0000", check=False)
36
37
# Parse with strict checksum requirement
38
try:
39
msg = pynmea2.parse("$GPGGA,184353.07,1929.045,S,02410.506,E,1,04,2.6,100.00,M,-33.9,M,,0000", check=True)
40
except pynmea2.ChecksumError:
41
print("Checksum missing - required when check=True")
42
```
43
44
## Base NMEASentence Class
45
46
```python { .api }
47
class NMEASentence:
48
"""Base class for all NMEA sentence types."""
49
50
data: List[str]
51
sentence_types: Dict[str, Type['NMEASentence']]
52
53
@staticmethod
54
def parse(line: str, check: bool = False) -> 'NMEASentence':
55
"""
56
Parse NMEA sentence string into appropriate sentence object.
57
58
Args:
59
line: NMEA sentence string
60
check: Require checksum validation
61
62
Returns:
63
Appropriate NMEASentence subclass instance
64
"""
65
66
@staticmethod
67
def checksum(nmea_str: str) -> int:
68
"""
69
Calculate XOR checksum for NMEA string.
70
71
Args:
72
nmea_str: NMEA string without '$' or checksum
73
74
Returns:
75
Calculated checksum as integer
76
"""
77
78
def render(self, checksum: bool = True, dollar: bool = True, newline: Union[bool, str] = False) -> str:
79
"""
80
Render sentence as NMEA string.
81
82
Args:
83
checksum: Include checksum (*HH format)
84
dollar: Include leading '$'
85
newline: Include trailing newline (True = \\r\\n, str = custom)
86
87
Returns:
88
Formatted NMEA sentence string
89
"""
90
91
def identifier(self) -> str:
92
"""Return string identifier for sentence type (abstract method)."""
93
94
def __str__(self) -> str:
95
"""Return rendered NMEA sentence with checksum and dollar sign."""
96
97
def __repr__(self) -> str:
98
"""Return detailed representation showing field names and values."""
99
```
100
101
### Usage Examples
102
103
```python
104
import pynmea2
105
106
# Parse sentence
107
msg = pynmea2.parse("$GPGGA,184353.07,1929.045,S,02410.506,E,1,04,2.6,100.00,M,-33.9,M,,0000*6D")
108
109
# Generate NMEA string with different formatting options
110
print(msg.render()) # $GPGGA,184353.07,1929.045,S,02410.506,E,1,04,2.6,100.00,M,-33.9,M,,0000*6D
111
print(msg.render(checksum=False)) # $GPGGA,184353.07,1929.045,S,02410.506,E,1,04,2.6,100.00,M,-33.9,M,,0000
112
print(msg.render(dollar=False)) # GPGGA,184353.07,1929.045,S,02410.506,E,1,04,2.6,100.00,M,-33.9,M,,0000*6D
113
print(msg.render(newline=True)) # $GPGGA,184353.07,1929.045,S,02410.506,E,1,04,2.6,100.00,M,-33.9,M,,0000*6D\r\n
114
115
# Calculate checksum manually
116
nmea_str = "GPGGA,184353.07,1929.045,S,02410.506,E,1,04,2.6,100.00,M,-33.9,M,,0000"
117
checksum = pynmea2.NMEASentence.checksum(nmea_str)
118
print(f"Checksum: {checksum:02X}") # Checksum: 6D
119
120
# String representations
121
print(str(msg)) # $GPGGA,184353.07,1929.045,S,02410.506,E,1,04,2.6,100.00,M,-33.9,M,,0000*6D
122
print(repr(msg)) # <GGA(timestamp=datetime.time(18, 43, 53), lat='1929.045', ...)>
123
```
124
125
## TalkerSentence Class
126
127
```python { .api }
128
class TalkerSentence(NMEASentence):
129
"""Base class for standard NMEA talker sentences."""
130
131
talker: str
132
sentence_type: str
133
data: List[str]
134
135
def __init__(self, talker: str, sentence_type: str, data: List[str]):
136
"""
137
Initialize talker sentence.
138
139
Args:
140
talker: Two-character talker ID (e.g., 'GP', 'GL', 'GA')
141
sentence_type: Three-character sentence type (e.g., 'GGA', 'RMC')
142
data: List of sentence field data as strings
143
"""
144
145
def identifier(self) -> str:
146
"""Return sentence identifier (e.g., 'GPGGA,')."""
147
```
148
149
### Usage Examples
150
151
```python
152
import pynmea2
153
154
# Create GGA sentence manually
155
gga_data = ['184353.07', '1929.045', 'S', '02410.506', 'E', '1', '04', '2.6', '100.00', 'M', '-33.9', 'M', '', '0000']
156
msg = pynmea2.GGA('GP', 'GGA', gga_data)
157
158
print(msg.talker) # 'GP'
159
print(msg.sentence_type) # 'GGA'
160
print(msg.identifier()) # 'GPGGA,'
161
print(str(msg)) # $GPGGA,184353.07,1929.045,S,02410.506,E,1,04,2.6,100.00,M,-33.9,M,,0000*6D
162
```
163
164
## ProprietarySentence Class
165
166
```python { .api }
167
class ProprietarySentence(NMEASentence):
168
"""Base class for proprietary manufacturer sentences."""
169
170
manufacturer: str
171
data: List[str]
172
173
def __init__(self, manufacturer: str, data: List[str]):
174
"""
175
Initialize proprietary sentence.
176
177
Args:
178
manufacturer: Three-character manufacturer code (e.g., 'ASH', 'GRM')
179
data: List of sentence field data as strings
180
"""
181
182
def identifier(self) -> str:
183
"""Return sentence identifier (e.g., 'PASH')."""
184
```
185
186
### Usage Examples
187
188
```python
189
import pynmea2
190
191
# Parse proprietary sentence
192
msg = pynmea2.parse("$PGRME,15.0,M,45.0,M,25.0,M*22")
193
print(type(msg)) # <class 'pynmea2.types.proprietary.grm.GRME'>
194
print(msg.manufacturer) # 'GRM'
195
print(msg.identifier()) # 'PGRM'
196
197
# Create proprietary sentence manually
198
data = ['15.0', 'M', '45.0', 'M', '25.0', 'M']
199
msg = pynmea2.GRME('GRM', data)
200
print(str(msg)) # $PGRME,15.0,M,45.0,M,25.0,M*22
201
```
202
203
## QuerySentence Class
204
205
```python { .api }
206
class QuerySentence(NMEASentence):
207
"""Class for NMEA query sentences."""
208
209
talker: str
210
listener: str
211
sentence_type: str
212
data: List[str]
213
214
def __init__(self, talker: str, listener: str, sentence_type: str):
215
"""
216
Initialize query sentence.
217
218
Args:
219
talker: Two-character querying device ID
220
listener: Two-character target device ID
221
sentence_type: Three-character requested sentence type
222
"""
223
224
def identifier(self) -> str:
225
"""Return query identifier (e.g., 'CCGPQ,GGA')."""
226
```
227
228
### Usage Examples
229
230
```python
231
import pynmea2
232
233
# Parse query sentence
234
msg = pynmea2.parse("$CCGPQ,GGA")
235
print(type(msg)) # <class 'pynmea2.nmea.QuerySentence'>
236
print(msg.talker) # 'CC'
237
print(msg.listener) # 'GP'
238
print(msg.sentence_type) # 'GGA'
239
print(msg.identifier()) # 'CCGPQ,GGA'
240
241
# Create query sentence manually
242
query = pynmea2.QuerySentence('CC', 'GP', 'GGA')
243
print(str(query)) # $CCGPQ,GGA*27
244
```
245
246
## Field Access and Dynamic Properties
247
248
All sentence objects provide dynamic field access based on the sentence type's field definitions:
249
250
```python
251
import pynmea2
252
253
msg = pynmea2.parse("$GPGGA,184353.07,1929.045,S,02410.506,E,1,04,2.6,100.00,M,-33.9,M,,0000*6D")
254
255
# Access fields by name (defined in sentence class)
256
print(msg.timestamp) # datetime.time(18, 43, 53, 70000)
257
print(msg.lat) # '1929.045'
258
print(msg.lat_dir) # 'S'
259
print(msg.gps_qual) # '1'
260
print(msg.altitude) # 100.0
261
262
# Access raw field data by index
263
print(msg.data[0]) # '184353.07'
264
print(msg.data[1]) # '1929.045'
265
print(msg.data[2]) # 'S'
266
267
# Set field values (modifies data list)
268
msg.gps_qual = '2'
269
print(msg.gps_qual) # '2'
270
print(msg.data[5]) # '2'
271
```
272
273
## Error Handling
274
275
```python { .api }
276
class ParseError(ValueError):
277
"""Base exception for NMEA parsing errors."""
278
279
def __init__(self, message: str, data: str):
280
"""Initialize with error message and problematic data."""
281
282
class ChecksumError(ParseError):
283
"""Raised when NMEA sentence checksum validation fails."""
284
285
class SentenceTypeError(ParseError):
286
"""Raised when sentence type is not recognized."""
287
```
288
289
### Error Handling Examples
290
291
```python
292
import pynmea2
293
294
# Handle parse errors
295
try:
296
msg = pynmea2.parse("invalid nmea data")
297
except pynmea2.ParseError as e:
298
print(f"Parse error: {e.args[0]}") # Error message
299
print(f"Bad data: {e.args[1]}") # Raw data that failed
300
301
# Handle checksum errors
302
try:
303
msg = pynmea2.parse("$GPGGA,184353.07,1929.045,S,02410.506,E,1,04,2.6,100.00,M,-33.9,M,,0000*FF")
304
except pynmea2.ChecksumError as e:
305
print(f"Checksum error: {e}")
306
307
# Handle unknown sentence types
308
try:
309
msg = pynmea2.parse("$GPXYZ,some,unknown,sentence,type*12")
310
except pynmea2.SentenceTypeError as e:
311
print(f"Unknown sentence type: {e}")
312
```