@@ -95,7 +95,7 @@ def _parse_degrees(nmea_data: str) -> int:
95
95
degrees = int (raw [0 ]) // 100 * 1000000 # the ddd
96
96
minutes = int (raw [0 ]) % 100 # the mm.
97
97
minutes += int (f"{ raw [1 ][:4 ]:0<4} " ) / 10000
98
- minutes = int (minutes / 60 * 1000000 )
98
+ minutes = int (( minutes * 1000000 ) / 60 )
99
99
return degrees + minutes
100
100
101
101
@@ -125,12 +125,26 @@ def _read_degrees(data: List[float], index: int, neg: str) -> float:
125
125
return x
126
126
127
127
128
- def _read_int_degrees (data : List [float ], index : int , neg : str ) -> Tuple [int , float ]:
129
- deg = data [index ] // 1000000
130
- minutes = data [index ] % 1000000 / 10000
128
+ def _read_deg_mins (data : List [str ], index : int , neg : str ) -> Tuple [int , float ]:
129
+ # the degrees come in different formats and vary between latitudes and
130
+ # longitudes, which makes parsing tricky:
131
+ # for latitudes: ddmm,mmmm (0 - 7 decimal places, not zero padded)
132
+ # for longitudes: dddmm,mmmm (0 - 7 decimal places, not zero padded)
133
+ if "." in data [index ]:
134
+ int_part , minutes_decimal = data [index ].split ("." )
135
+ else :
136
+ int_part , minutes_decimal = data [index ], 0
137
+
138
+ # we need to parse from right to left, minutes can only have 2 digits
139
+ minutes_int = int_part [- 2 :]
140
+ # the rest must be degrees which are either 2 or 3 digits
141
+ deg = int (int_part [:- 2 ])
142
+ # combine the parts of the minutes, this also works when there are no
143
+ # decimal places specified in the sentence
144
+ minutes = float (f"{ minutes_int } .{ minutes_decimal } " )
131
145
if data [index + 1 ].lower () == neg :
132
146
deg *= - 1
133
- return ( deg , minutes )
147
+ return deg , minutes
134
148
135
149
136
150
def _parse_talker (data_type : bytes ) -> Tuple [bytes , bytes ]:
@@ -490,26 +504,30 @@ def _parse_gll(self, data: List[str]) -> bool:
490
504
491
505
if data is None or len (data ) != 7 :
492
506
return False # Unexpected number of params.
493
- data = _parse_data (_GLL , data )
507
+ parsed_data = _parse_data (_GLL , data )
494
508
if data is None :
495
509
return False # Params didn't parse
496
510
497
511
# Latitude
498
- self .latitude = _read_degrees (data , 0 , "s" )
499
- self .latitude_degrees , self .latitude_minutes = _read_int_degrees (data , 0 , "s" )
512
+ self .latitude = _read_degrees (parsed_data , 0 , "s" )
513
+ self .latitude_degrees , self .latitude_minutes = _read_deg_mins (
514
+ data = data , index = 0 , neg = "s"
515
+ )
500
516
501
517
# Longitude
502
- self .longitude = _read_degrees (data , 2 , "w" )
503
- self .longitude_degrees , self .longitude_minutes = _read_int_degrees (data , 2 , "w" )
518
+ self .longitude = _read_degrees (parsed_data , 2 , "w" )
519
+ self .longitude_degrees , self .longitude_minutes = _read_deg_mins (
520
+ data = data , index = 2 , neg = "w"
521
+ )
504
522
505
523
# UTC time of position
506
- self ._update_timestamp_utc (data [4 ])
524
+ self ._update_timestamp_utc (parsed_data [4 ])
507
525
508
526
# Status Valid(A) or Invalid(V)
509
- self .isactivedata = data [5 ]
527
+ self .isactivedata = parsed_data [5 ]
510
528
511
529
# Parse FAA mode indicator
512
- self ._mode_indicator = data [6 ]
530
+ self ._mode_indicator = parsed_data [6 ]
513
531
514
532
return True
515
533
@@ -518,44 +536,48 @@ def _parse_rmc(self, data: List[str]) -> bool:
518
536
519
537
if data is None or len (data ) not in (12 , 13 ):
520
538
return False # Unexpected number of params.
521
- data = _parse_data ({12 : _RMC , 13 : _RMC_4_1 }[len (data )], data )
522
- if data is None :
539
+ parsed_data = _parse_data ({12 : _RMC , 13 : _RMC_4_1 }[len (data )], data )
540
+ if parsed_data is None :
523
541
self .fix_quality = 0
524
542
return False # Params didn't parse
525
543
526
544
# UTC time of position and date
527
- self ._update_timestamp_utc (data [0 ], data [8 ])
545
+ self ._update_timestamp_utc (parsed_data [0 ], parsed_data [8 ])
528
546
529
547
# Status Valid(A) or Invalid(V)
530
- self .isactivedata = data [1 ]
531
- if data [1 ].lower () == "a" :
548
+ self .isactivedata = parsed_data [1 ]
549
+ if parsed_data [1 ].lower () == "a" :
532
550
if self .fix_quality == 0 :
533
551
self .fix_quality = 1
534
552
else :
535
553
self .fix_quality = 0
536
554
537
555
# Latitude
538
- self .latitude = _read_degrees (data , 2 , "s" )
539
- self .latitude_degrees , self .latitude_minutes = _read_int_degrees (data , 2 , "s" )
556
+ self .latitude = _read_degrees (parsed_data , 2 , "s" )
557
+ self .latitude_degrees , self .latitude_minutes = _read_deg_mins (
558
+ data = data , index = 2 , neg = "s"
559
+ )
540
560
541
561
# Longitude
542
- self .longitude = _read_degrees (data , 4 , "w" )
543
- self .longitude_degrees , self .longitude_minutes = _read_int_degrees (data , 4 , "w" )
562
+ self .longitude = _read_degrees (parsed_data , 4 , "w" )
563
+ self .longitude_degrees , self .longitude_minutes = _read_deg_mins (
564
+ data = data , index = 4 , neg = "w"
565
+ )
544
566
545
567
# Speed over ground, knots
546
- self .speed_knots = data [6 ]
568
+ self .speed_knots = parsed_data [6 ]
547
569
548
570
# Track made good, degrees true
549
- self .track_angle_deg = data [7 ]
571
+ self .track_angle_deg = parsed_data [7 ]
550
572
551
573
# Magnetic variation
552
- if data [9 ] is None or data [10 ] is None :
574
+ if parsed_data [9 ] is None or parsed_data [10 ] is None :
553
575
self ._magnetic_variation = None
554
576
else :
555
- self ._magnetic_variation = _read_degrees (data , 9 , "w" )
577
+ self ._magnetic_variation = _read_degrees (parsed_data , 9 , "w" )
556
578
557
579
# Parse FAA mode indicator
558
- self ._mode_indicator = data [11 ]
580
+ self ._mode_indicator = parsed_data [11 ]
559
581
560
582
return True
561
583
@@ -564,37 +586,41 @@ def _parse_gga(self, data: List[str]) -> bool:
564
586
565
587
if data is None or len (data ) != 14 :
566
588
return False # Unexpected number of params.
567
- data = _parse_data (_GGA , data )
568
- if data is None :
589
+ parsed_data = _parse_data (_GGA , data )
590
+ if parsed_data is None :
569
591
self .fix_quality = 0
570
592
return False # Params didn't parse
571
593
572
594
# UTC time of position
573
- self ._update_timestamp_utc (data [0 ])
595
+ self ._update_timestamp_utc (parsed_data [0 ])
574
596
575
597
# Latitude
576
- self .latitude = _read_degrees (data , 1 , "s" )
577
- self .latitude_degrees , self .latitude_minutes = _read_int_degrees (data , 1 , "s" )
598
+ self .latitude = _read_degrees (parsed_data , 1 , "s" )
599
+ self .longitude_degrees , self .longitude_minutes = _read_deg_mins (
600
+ data = data , index = 3 , neg = "w"
601
+ )
578
602
579
603
# Longitude
580
- self .longitude = _read_degrees (data , 3 , "w" )
581
- self .longitude_degrees , self .longitude_minutes = _read_int_degrees (data , 3 , "w" )
604
+ self .longitude = _read_degrees (parsed_data , 3 , "w" )
605
+ self .latitude_degrees , self .latitude_minutes = _read_deg_mins (
606
+ data = data , index = 1 , neg = "s"
607
+ )
582
608
583
609
# GPS quality indicator
584
- self .fix_quality = data [5 ]
610
+ self .fix_quality = parsed_data [5 ]
585
611
586
612
# Number of satellites in use, 0 - 12
587
- self .satellites = data [6 ]
613
+ self .satellites = parsed_data [6 ]
588
614
589
615
# Horizontal dilution of precision
590
- self .horizontal_dilution = data [7 ]
616
+ self .horizontal_dilution = parsed_data [7 ]
591
617
592
618
# Antenna altitude relative to mean sea level
593
- self .altitude_m = _parse_float (data [8 ])
619
+ self .altitude_m = _parse_float (parsed_data [8 ])
594
620
# data[9] - antenna altitude unit, always 'M' ???
595
621
596
622
# Geoidal separation relative to WGS 84
597
- self .height_geoid = _parse_float (data [10 ])
623
+ self .height_geoid = _parse_float (parsed_data [10 ])
598
624
# data[11] - geoidal separation unit, always 'M' ???
599
625
600
626
# data[12] - Age of differential GPS data, can be null
0 commit comments