# pynmeagps Release Notes

### RELEASE 1.1.7

1. Fix typo in release version (v1.1.6 rather than V1.1.6) for those using pkgsrc to deploy.

### RELEASE 1.1.6

1. Add fix for ALC message definition - thanks to @SoerenDittman for contribution #96.

### RELEASE 1.1.5

1. Add support for additional proprietary Quectel PQTM configuration messages from LG290/LG580 firmware version 1.3.

    - PQTMAIDINI: Inputs aiding position and time data
    - PQTMAIDPOS: Inputs aiding position data
    - PQTMAIDTIME: Inputs aiding time data
    - PQTMCFGANTENNA: Sets/gets GNSS antenna power supply
    - PQTMCFGCNRTHD: Sets/gets the CNR threshold for position engine
    - PQTMCFGEVENT: Sets/gets external interrupt event
    - PQTMCFGPINALT: Sets/gets the function of module's pin 14
    - PQTMCFGPPP: Sets/gets the PPP feature
    - PQTMCFGPPS2: Sets/gets the PPS extend feature
    - PQTMCFGRTKRL: Sets/gets the RTK reliability level
    - PQTMCFGSTANDALONE: Sets/gets the Standalone mode
    - PQTMCLRMSG: Disables serial message output. (2 variants)
    - PQTMENV: Outputs the environment information.
    - PQTMLSTMSG: Queries message output of serial port (2 variants)
    - PQTMPPPNAV: Outputs the PPP navigation information
    - PQTMRTCMIS: Outputs the RTCM input status

### RELEASE 1.1.4

1. Add `modwno` boolean argument to wnotow2utc and utc2wnotow helper functions - True => modular week number, False => continuous week number. The default is True (modular week no).

### RELEASE 1.1.3

1. Update wnotow2utc, utc2wnotow and leapsecond helper functions to accommodate all GNSS time systems. wnotow2utc method also adds an 'autoroll' argument which, if True, will automatically roll forward modular GNSS week numbers to the latest date less than the current date - see API docs for details.

### RELEASE 1.1.2

1. Add workaround for Unicore UM9* firmware error, which creates malformed NMEA GLL sentences (-ve latitude).

### RELEASE 1.1.1

1. Add helper methods `utc2wnotow` and `wnotow2utc` to convert between UTC datetime and GPS week number, time of week (in milliseconds) and leapsecond offset.
1. Helper methods `leapsecond` and `get_gpswnotow` will now accept timezone-aware or timezone-naive datetimes. If naive, UTC will be inferred.

### RELEASE 1.1.0

1. Add support for Unicore extended NMEA sentences:

   Secondary Antenna Data:
    - "GGAH": "Global Positioning System Fix Data (Secondary Antenna)",
    - "GLLH": "Geographic Position (Secondary Antenna)",
    - "GNSH": "GNSS Fix Data (Secondary Antenna)",
    - "GRSH": "GNSS Range Residuals (Secondary Antenna)",
    - "GSAH": "GNSS DOP and Active Satellites (Secondary Antenna)",
    - "GSTH": "GNSS Pseudorange Error Statistics (Secondary Antenna)",
    - "GSVH": "GNSS Satellites in View (Secondary Antenna)",
    - "RMCH": "Recommended Minimum Specific GNSS Data (Secondary Antenna)",
    - "VTGH": "Course over Ground and Ground Speed (Secondary Antenna)",

    Attitude Data:
    - "THS2": "True Heading and Status",
    - "HPR": "Attitude Parameters",
    - "HPR2": "Attitude Parameters",
    - "TRA2": "Heading, Pitch & Roll Information",
    - "ROT2": "Rate of Turn",
    - "HPD": "Positioning and Heading Information",

### RELEASE 1.0.57

1. Fix HDM definition - Fixes #89
1. Add NMEAReader encoding argument for chunked-encoded socket streams.
1. Type hints and docstrings updated
1. VSCode actions updated

### RELEASE 1.0.56

1. Cosmetic fix to GSV parsing - `elv` now rendered as `int` rather than `float`.
1. Add helper method `groupsize` to fix issue which prevented manual generation of messages with variable length groups (e.g. GSV, RTE)

### RELEASE 1.0.55

ENHANCEMENTS:

1. Add additional proprietary NMEA PQTM message definitions for Quectel LG290P / LG580P series.
1. Address what appear to be minor bugs in LG580P firmware (LG580P03AANR01A04S_SH 2025/06/06-10:08:42) relating to proprietary NMEA PQTM message output (*outputs differ from documented firmware specifications for PQTMSN and PQTMCFGRTKSRCTYPE*).
1. Add additional proprietary NMEA PSTM message definitions for Quectel LG69T (AA,AD,AF,AI,AJ,AR) series.

CHANGES:

1. Drop active support for Python 3.9 (EOL as at 31 October 2025)

### RELEASE 1.0.54

FIXES:

1. Fix PUBX040 payload definition (`id` = str, not int)

ENHANCEMENTS:

1. Add further Quectel proprietary PQTM message definitions for LC29H (BA,CA,DA,EA) DR series.
1. Add `get_leapseconds()` helper method to retrieve GPS leapsecond offset effective at given date.

### RELEASE 1.0.53

FIXES:

1. Fix PUBX040 message definition (id = str rather than int).

### RELEASE 1.0.53

FIXES:

1. Fix typo in Quectel PAIR650 GET message definition.
1. Allow string type (*as well as datetime.date/time type*) for NMEA DT, DTL, DM and TM attribute constructors. TM strings must be in format "hhmmss" (or "hh:mm:ss"). DT/DTL/DM strings must be "yyyymmdd" (or "yyyy-mm-dd"). See examples below:

```python
from datetime import datetime

from pynmeagps import SET, NMEAMessage

# NOTE THAT LAD/NS ("N"/"S") and LND/EW ("E"/"W") attributes do not need to be explicitly
# provided - these values will be derived from the sign of the decimal lat/lon values.

# NMEA Date (DM, DT, DTL) and Time (TM) attributes can be populated in any of the following ways:

# A) use formatted string types for TM and DT attributes
msg1 = NMEAMessage(
    "P",
    "GRMI",
    SET,
    lat=-115.81513,
    lon=37.23345,
    date="2025-09-12",  # "-" delimiters are optional
    time="12:15:34",  # ":" delimiters are optional
    rcvr_cmd="D",
)
# <NMEA(PGRMI, lat=-115.81513, NS=S, lon=37.23345, EW=E, date=2025-09-12, time=12:15:34, rcvr_cmd=D)>
# b'$PGRMI,11548.90780,S,03714.00700,E,120925,121534,D*3B\r\n'
print(msg1)
print(msg1.serialize())

# B) use datetime.date() and datetime.time() types for DT and TM attributes
msg2 = NMEAMessage(
    "P",
    "GRMI",
    SET,
    lat=-115.81513,
    lon=37.23345,
    date=datetime(2025, 9, 12).date(),
    time=datetime(2025, 9, 12, 12, 15, 34).time(),
    rcvr_cmd="D",
)
# <NMEA(PGRMI, lat=-115.81513, NS=S, lon=37.23345, EW=E, date=2025-09-12, time=12:15:34, rcvr_cmd=D)>
# b'$PGRMI,11548.90780,S,03714.00700,E,120925,121534.00,D*15\r\n'
print(msg2)
print(msg2.serialize())

# C) use default values
msg3 = NMEAMessage(
    "P",
    "GRMI",
    SET,
    lat=-115.81513,
    lon=37.23345,
    rcvr_cmd="D",
)
# <NMEA(PGRMI, lat=-115.81513, NS=S, lon=37.23345, EW=E, date=2025-09-18, time=14:37:20.373212, rcvr_cmd=D)>
# b'$PGRMI,11548.90780,S,03714.00700,E,180925,143720.37,D*18\r\n'
print(msg3)
print(msg3.serialize())
```

### RELEASE 1.0.52

ENHANCEMENTS

1. Add support for proprietary Quectel $PAIR message types (as used by Quectel LC29H and LC79H receivers).
1. Add support for additional proprietary Quectel $PQTM message types (as used by Quectel LC29H and LC79H receivers).
1. BSD 3-Clause license attribution clarified in all modules.

### RELEASE 1.0.51

ENHANCEMENTS

1. Add Python 3.14rc2 to workflow. No functional changes.

### RELEASE 1.0.50

ENHANCEMENTS

1. Add support for Feyman IM19 IMU NMEA sentence GPFMI.

### RELEASE 1.0.49

FIXES:

1. Minor updates to proprietary Quectel NMEA definitions to improve attribute name clarity - affects QTMCFGGEOFENCE and QTMCFGPPS.
1. SocketWrapper class updated to accommodate chunk and/or zip encoded socket streams.

### RELEASE 1.0.48

FIXES:

1. Fix for Conda build issue (`license = { file = "LICENSE" }` deprecated in latest Python build but still mandated by Conda).
1. No other functional changes.

### RELEASE 1.0.47

ENHANCEMENTS:

1. Add support for proprietary Quectel LG290P PQTM* NMEA sentences, as documented in https://quectel.com/content/uploads/2024/09/Quectel_LG290P03_GNSS_Protocol_Specification_V1.0.pdf. See /examples/quecteldemo.py for example usage.

### RELEASE 1.0.46

ENHANCEMENTS:

1. Add support for proprietary Septentrio X5 NMEA sentences.

### RELEASE 1.0.45

FIXES:

1. Fix NAK message talker attribute name - fixes #71

### RELEASE 1.0.44

ENHANCEMENTS:

1. dms2deg helper method added to convert d.m.s or d.m to d.dd format.

### RELEASE 1.0.43

ENHANCEMENTS:

1. Add provision for user-defined payload definition dictionary, supplementing the existing `NMEA_PAYLOADS_GET` and `NMEA_PAYLOADS_GET_PROP` dictionaries. Format should mirror that used in `NMEA_PAYLOADS_GET`. Can be used for proprietary product development purposes or for standard payload definitions which are not yet in the public domain.
1. Drop active support for Python 3.8 - now End of Life as at October 2024.

### RELEASE 1.0.42

ENHANCEMENTS:

1. Add additional maritime talker IDs and NMEA sentence definitions.
1. Add `DTL` date format ddmmyyyy.

### RELEASE 1.0.41

ENHANCEMENTS:

1. Enhance NMEAMessage to parse unrecognised* NMEA sentence types to a nominal `<NMEA(TTXXX, NOMINAL, field_01=x...)>` message structure if `VALMSGID` validation flag is *not* set, rather than raise a `NMEAParseMessage` error e.g.:

   A. with the `VALMSGID` flag *not* set (*the new default behaviour*):

   ```shell
   from pynmeagps import NMEAReader
   msg = NMEAReader.parse("$GNACN,103607.00,ECN,E,A,W,A,test,C*67\r\n")
   print(msg)
   ```
   ```
   <NMEA(GNACN, NOMINAL, field_01=103607.00, field_02=ECN, field_03=E, field_04=A, field_05=W, field_06=A, field_07=test, field_08=C)>
   ```

   B. with the `VALMSGID flag` set:

   ```shell
   from pynmeagps import NMEAReader, VALMSGID
   msg = NMEAReader.parse("$GNACN,103607.00,ECN,E,A,W,A,test,C*67\r\n", validate=VALMSGID)
   print(msg)
   ```
   ```
   pynmeagps.exceptions.NMEAParseError: Unknown msgID GNACN, msgmode GET.
   ```

   \* unrecognised message types include those with unknown or invalid NMEA msgIDs (*but valid payloads and checksums*), or valid NMEA sentences whose payload definitions are not yet in the public domain (e.g. those currently commented-out in [`NMEA_MSGIDS`](https://github.com/semuconsulting/pynmeagps/blob/master/src/pynmeagps/nmeatypes_core.py#L207)).

1. Add NMEA ALF sentence definition.
1. Add `validate` argument to `NMEAMessage` and carry forward from `NMEAReader`
1. Add logger to `NMEAMessage`.

### RELEASE 1.0.40

ENHANCEMENTS:

1. Add area() helper method to calculate spherical area of bounding box.
1. Sphinx documentation and docstrings enhanced to include global constants and decodes.
1. `socket_stream.SocketStream` class renamed to `socket_wrapper.SocketWrapper` class for clarity.

### RELEASE 1.0.39

ENHANCEMENTS:

1. Add support for NMEA streams with lower case hex checksums

### RELEASE 1.0.38

ENHANCEMENTS:

1. Add Locosys proprietary NMEA GET and SET messages:
   - $PINVCRES: Clear the NVM data
   - $PINVCSTR: Start session
   - $PINVMATTIT: ATTIT information
   - $PINVMIMU: MEMS RAW-DATA message information
   - $PINVMINR: Calibration status
   - $PINVMSTR: Session Status
   - $PINVMSLOPE: SLOPE information
   - $PLSC: Set status/poll version
   - $PLSR: Set status response
   - $PLSVD: Attitude yaw, pitch, roll
   
   NB: $PMTKnnn: proprietary command message sets not yet implemented

### RELEASE 1.0.37

ENHANCEMENTS:

1. Correct `planar()` helper function.
1. Internal logging & exception handling enhancements.

### RELEASE 1.0.36

ENHANCEMENTS:

1. Add further proprietary message definitions.

### RELEASE 1.0.35

FIXES:

1. Fixes & simplifies the derivation of NMEA `NS` and `EW` values when creating `NMEAMessage` objects (e.g. GNGLL) using individual keyword arguments. `NS` and `EW` will always be derived from the sign of the provided signed decimal `lat` and `lon` values and need not be provided explicitly. When creating an `NMEAMessage` using a single payload argument (_which is effectively what happens when parsing incoming serial data streams_), the value of `NS` and `EW` in the payload will determine the sign of the decimal `lat`/`lon` values in the `NMEAMessage` object.

### RELEASE 1.0.34

FIXES:

1. Add missing Trimble PASHR Proprietary Pitch and Roll sentence Fixes [#52](https://github.com/semuconsulting/pynmeagps/issues/52).

### RELEASE 1.0.33

ENHANCEMENTS:

1. Add planar formula in `nmeahelpers.py` to calculate approximate planar distance between two sets of coordinates. Complements the haversine formula at smaller scales.

### RELEASE 1.0.32

ENHANCEMENTS:

1. Cater for NMEA streams with LF (b"\x0a") rather than CRLF (b"\x0d\x0a") message terminators.

### RELEASE 1.0.31

ENHANCEMENTS:

1. Extend `NMEA_HDR` to include *all* known Talker IDs (*not just those relevant to GNSS*).
2. Minor Internal streamlining.

### RELEASE 1.0.30

ENHANCEMENTS:

1. Cater for 'IN' (Integrated Navigation) Talker ID.

### RELEASE 1.0.29

ENHANCEMENTS:

1. Cater for legacy "BD" (Beidou) NMEA Talker ID.

### RELEASE 1.0.28

ENHANCEMENTS:

1. Add 'NAVIC' to list of gnssId enumerations - reference only, no functional change.

### RELEASE 1.0.27

CHANGES:

1. Add write capability to socket_stream wrapper, allowing clients to write to NMEAReader socket stream (NMEAReader.datastream) as well as read from it.
1. Update constructor arguments and docstrings to clarify API (no functional changes).

### RELEASE 1.0.26

CHANGES:

1. Deprecated `NMEAReader.iterate()` method removed - use the standard iterator instead e.g. `nmr = NMEAReader(stream, **wkargs): for (raw,parse) in nmr: ...`, passing any `quitonerror` or `errorhandler` kwargs to the NMEAReader constructor.
1. Internal streamlining of helper methods.

### RELEASE 1.0.25

FIXES:

1. Add support for non-standard 3-digit degree latitude value, e.g.
   `'$GNGLL,02348.3822990,S,15313.5862807,E,040856.82,A,D*5F'`
1. NB: footprint of `dmm2ddd` helper method has changed - `att` argument no longer required.
1. Fixes #37

### RELEASE 1.0.24

1. Remove Python 3.7 from workflows.
1. Add proprietary POLL messages to nmeatypes_poll.py

### RELEASE 1.0.23

ENHANCEMENTS:

1. Add proprietary Trimble message definitions.
    - GMP   GNSS Map Projection Fix Data
    - LLQ 	Leica local position and quality
    - ROT 	Rate of turn
    - PASHR,ALR Alarms
    - PASHR,ARA True Heading
    - PASHR,ARR Vector & Accuracy
    - PASHR,ATT True Heading
    - PASHR,BTS Bluetooth Status
    - PASHR,CAP Parameters of Antenna Used at Received Base
    - PASHR,CPA Height of Antenna Used at Received Base
    - PASHR,CPO Position of Received Base
    - PASHR,DDM Differential Decoder Message
    - PASHR,DDS Differential Decoder Status
    - PASHR,HPR True Heading
    - PASHRHR Proprietary Roll and Pitch
    - PASHR,LTN Latency
    - PASHR,MDM Modem State and Parameter
    - PASHR,PBN Position and Velocity Information
    - PASHR,POS Position
    - PASHR,PTT PPS Time Tag
    - PASHR,PWR Power Status
    - PASHR,RCS Recording Status
    - PASHR,SBD BEIDOU Satellites Status
    - PASHR,SGA GALILEO Satellites Status (E1,E5a,E5b)
    - PASHR,SGL GLONASS Satellites Status
    - PASHR,SGO GALILEO Satellites Status (E1,E5a,E5b,E6)
    - PASHR,SGP GPS Satellites Status
    - PASHR,SIR IRNSS Satellites Status
    - PASHR,SLB L-Band Satellites Status
    - PASHR,SQZ QZSS Satellites Status
    - PASHR,SSB SBAS Satellites Status
    - PASHR,TEM Receiver Temperature
    - PASHR,THS True Heading and Status
    - PASHR,TTT Event Marker
    - PASHR,VCR Vector and Accuracy
    - PASHR,VCT Vector and Accuracy
    - PASHR,VEL Velocity
    - FUGDP Fugro Dynamic Positioning
    - GPPADV,110 Position and satellite information for RTK network operations 110
    - GPPADV,120 Position and satellite information for RTK network operations 120
    - PTNL,AVR 	Time, yaw, tilt, range, mode, PDOP, and number of SVs for Moving Baseline RTK
    - PTNL,BPQ 	Base station position and position quality indicator
    - PTNL,DG 	L-band corrections and beacon signal strength and related information
    - PTNL,EVT 	Event marker data
    - PTNL,GGK 	Time, position, position type, and DOP values
    - PTNL,PJK 	Time, position, position type, and DOP values
    - PTNL,PJT 	Projection type
    - PTNL,REX Rover Extended Output
    - PTNL,VGK 	Time, locator vector, type, and DOP values
    - PTNL,VHD 	Heading Information

### RELEASE 1.0.22

FIXES:

1. Rounding removed from `haversine` helper method.

### RELEASE 1.0.21

ENHANCEMENTS:

1. Add `bearing` helper method.

### RELEASE 1.0.20

CHANGES:

1. `quitonerror` and `errorhandler` kwargs added to NMEAReader constructor - see Sphinx documentation for details.
2. `NMEAReader.iterate()` method deprecated - use the standard iterator instead e.g. `nmr = NMEAReader(stream, **wkargs): for (raw,parse) in nmr: ...`, passing any `quitonerror` or `errorhandler` kwargs to the NMEAReader constructor.

### RELEASE 1.0.19

FIXES:

1. Fix typo in PUBX00 payload definition - PDOP is now TDOP. Thanks to @dbstf for issue report.
1. Fix handling of VALMSGID flag in NMEAReader. Thanks to @nmichaels-qualinx for issue report.

### RELEASE 1.0.18

ENHANCEMENTS:

1. Following utility methods added to nmeahelpers.py:

- `latlon2dms` - converts decimal lat/lon to degrees, minutes, decimal seconds format e.g. "53°20′45.6″N", "2°32′46.68″W"
- `latlon2dmm` - converts decimal lat/lon to degrees, decimal minutes format e.g. "53°20.76′N", "2°32.778′W"
- `llh2iso6709` - converts lat/lon and altitude (hMSL) to ISO6709 format e.g. "+27.5916+086.5640+8850CRSWGS_84/"
- `ecef2llh` - converts ECEF (X, Y, Z) coordinates to geodetic (lat, lon, ellipsoidal height) coordinates
- `llh2ecef` - converts geodetic (lat, lon, ellipsoidal height) coordinates to ECEF (X, Y, Z) coordinates
- `haversine` - finds spherical distance in km between two sets of (lat, lon) coordinates


### RELEASE 1.0.17

CHANGES:

1. shields.io build status badge URL updated.

No other functional changes.

### RELEASE 1.0.16

ENHANCEMENTS:

1. `time2utc` helper method enhanced to cater for proprietary NMEA messages containing timestamps in format hh.mm.ss rather than hh.mm.ss.ss (i.e. missing decimal seconds). Addresses PR #19.

### RELEASE 1.0.15

ENHANCEMENTS:

1. Enhancement to NMEAMessage constructor - will now automatically derive value of `NS` or `EW` attributes from provided lat/lon e.g. `lon` < 0 => `EW` = "W"
2. Enhancement to NMEAMessage constructor - optional keyword argument `hpnmeamode` added which allows NMEA position
message payloads to be constructed to 7dp decimal minutes rather than the standard 5dp (i.e. (d)ddmm.mmmmmmm rather than (d)ddmm.mmmm). **NB:** this is primarily for manually constructed messages. Messages parsed from a GNSS receiver data stream retain whatever level of precision is output by the receiver to a maximum 10dp of decimal degrees.

### RELEASE 1.0.14

CHANGES:

1. `nmeadump` CLI utility has been removed and replaced by the `gnssdump` utility available via the `pygnssutils` PyPi package.
2. Python 3.11 classifier added to setup.

### RELEASE 1.0.13.

FIXES:

1. When manually creating NMEA Messages, the nominal (default) value of time and date fields is now set to UTC time rather than local time. This is relevant, for example, when constructing NMEA GGA messages to send to NTRIP casters.

### RELEASE 1.0.12

CHANGES:

1. Add support for THS message type.
1. Extend test coverage for socket handler.

### RELEASE 1.0.11

ENHANCEMENTS:

1. Add capability to read from TCP/UDP socket as well as serial stream. Utilises a SocketStream utility class to allow sockets to be read using standard stream-like read(bytes) and readline() methods.


### RELEASE 1.0.10

FIXES:

1. GBS and GSA message definitions updated - `systemId` and `signalId` now correctly defined as HX rather than IN.

### RELEASE 1.0.9

FIXES:

1. GRS message definition updated - `systemId` and `signalId` now correctly defined as HX rather than IN.

### RELEASE 1.0.8

ENHANCEMENTS:

1. `identity` property added to NMEAMessage for consistency with companion `pyubx2` library - identity = (talker+msgID)
2. internal refactoring of error handling in `NMEAReader.read()` method to make it more consistent with `pyubx2` when processing corrupted data streams.

### RELEASE 1.0.7

FIXES:

1. HX attribute type processing corrected - will now parse HX values as hex strings rather than convert to/from integers.
2. GSV payload corrected - SignalId is now hex.

### RELEASE 1.0.6

ENHANCEMENTS:

1. Python 3.10 compatibility added
2. Minor pylint code tweaks

### RELEASE 1.0.5

ENHANCEMENTS:

1. Filter added to `nmeadump` cli utility to limit output to specified NMEA msgIDs. See README for usage.
2. Update `dmm2ddd()` helper method to increase conversion accuracy from 6 to 8 decimal places - thanks for Doradx for the contribution.

### RELEASE 1.0.4

ENHANCEMENTS:

1. The nmeadump.py example has been moved into the pynmeagpscli module and configured as a setup entry point. It is now available as a simple command line utility. See README for usage.

### RELEASE 1.0.3

FIXES:

1. Fixed diffAge field type in GGA payload definition.

### RELEASE 1.0.2

FIXES:

1. Fixed typo in VTG payload definition - `cogT` is now `cogt`. Test script updated.

### RELEASE 1.0.1

FIXES:

1. Fixed typo in GBS payload definition - `effLon` is now `errLon`. Test script updated.
2. Fixed cosmetic typo in nmeafile.py example - functionality not affected.

### RELEASE 1.0.0

CHANGES:

1. Marked to v1.0.0 Production/Stable. No other functional changes.
