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