Skip to content

Commit

Permalink
Merge branch 'master' of github.com:M0r13n/pyais
Browse files Browse the repository at this point in the history
* 'master' of github.com:M0r13n/pyais:
  chore: adds an example for tag blocks (#126)
  • Loading branch information
M0r13n committed Dec 23, 2023
2 parents 7e7eb29 + 2f2a7a8 commit a9ac5a9
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 4 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
====================
pyais CHANGELOG
====================
-------------------------------------------------------------------------------
Version 2.5.9 26 Nov 2023
-------------------------------------------------------------------------------
* adds `decode_nmea_and_ais`
* use this method to get a tuple of NMEASentence and AIS payload
* chore: also adds another example regarding tag blocks
-------------------------------------------------------------------------------
Version 2.5.8 01 Oct 2023
-------------------------------------------------------------------------------
Expand Down
4 changes: 3 additions & 1 deletion examples/sample.ais
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@
!AIVDM,1,1,,A,15MrVH0000KH<:V:NtBLoqFP2H9:,0*2F
# Lines with a leading `#` are ignored
# Also invalid lines or invalid messages are ignored
IamNotAnAisMessage1111
IamNotAnAisMessage1111
# Tag blocks are also supported
\g:1-2-73874,n:157036,s:r003669945,c:12415440354*A\!AIVDM,1,1,,B,15N4cJ005Jrek0H@9nDW5608EP,013
31 changes: 31 additions & 0 deletions examples/tag_block.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""How to work with optional tag blocks?"""
import pathlib
from pyais.decode import decode_nmea_and_ais
from pyais.stream import FileReaderStream

# Tag blocks for single messages
msg = b'\\g:1-2-73874,n:157036,s:r003669945,c:12415440354*A\\!AIVDM,1,1,,B,15N4cJ005Jrek0H@9nDW5608EP,013'

# The regular `decode()` function only returns decoded AIS messages.
# Thus, use `decode_nmea_and_ais` to get both: the NMEA sentence and the AIS payload
nmea, ais = decode_nmea_and_ais(msg)
if nmea.tag_block:
# not all messages contain a tag block
# also it is evaluated lazily
nmea.tag_block.init()

print(nmea)
print(nmea.tag_block.asdict())

# Tag blocks for streams
# All streaming interfaces support tag blocks

filename = pathlib.Path(__file__).parent.joinpath('sample.ais')

for nmea in FileReaderStream(filename):
if nmea.tag_block:
# again: not all messages have a tag block
nmea.tag_block.init()
print(nmea.tag_block.asdict())

decoded = nmea.decode()
2 changes: 1 addition & 1 deletion pyais/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from pyais.tracker import AISTracker, AISTrack

__license__ = 'MIT'
__version__ = '2.5.8'
__version__ = '2.5.9'
__author__ = 'Leon Morten Richter'

__all__ = (
Expand Down
11 changes: 11 additions & 0 deletions pyais/decode.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,17 @@ def decode(*args: typing.Union[str, bytes], error_if_checksum_invalid: bool = Fa
return nmea.decode()


def decode_nmea_and_ais(
*args: typing.Union[str, bytes], error_if_checksum_invalid: bool = False
) -> typing.Tuple[NMEASentence, ANY_MESSAGE]:
"""Behaves just like `decode`.
But it returns both: the NMEASentence and the AIS payload.
Useful, if the NMEA sentence layer is of interest."""
parts = tuple(msg.encode('utf-8') if isinstance(msg, str) else msg for msg in args)
nmea = _assemble_messages(*parts, error_if_checksum_invalid=error_if_checksum_invalid)
return nmea, nmea.decode()


def decode_nmea_line(line: bytes) -> NMEASentence:
"""
Decode a single NMEA line/sentence.
Expand Down
16 changes: 15 additions & 1 deletion tests/test_decode.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
TransmitMode,
TurnRate,
)
from pyais.decode import decode, decode_nmea_line
from pyais.decode import decode, decode_nmea_and_ais, decode_nmea_line
from pyais.exceptions import (
InvalidNMEAChecksum,
InvalidNMEAMessageException,
Expand Down Expand Up @@ -1488,6 +1488,10 @@ def test_get_comm_state_type_18_sotdma_utc_direct(self):
assert comm_state["slot_increment"] is None
assert comm_state["num_slots"] is None

# Also test decode_nmea_and_ais
_, decoded_2 = decode_nmea_and_ais(msg)
self.assertEqual(decoded_2, decoded)

def test_get_comm_state_type_18_sotdma_base_inidrect(self):
msg = "!AIVDM,1,1,,A,B69Gk3h071tpI02lT2ek?wg61P06,0*1F"
decoded = decode(msg)
Expand Down Expand Up @@ -1682,3 +1686,13 @@ def test_that_lat_and_long_are_rounded_correctly(self):
second_decode = decode(encoded)

self.assertEqual(first_decode, second_decode)

def test_that_decode_nmea_and_ais_works_with_proprietary_messages(self):
msg = "!AIVDM,1,1,,B,181:Kjh01ewHFRPDK1s3IRcn06sd,0*08,raishub,1342569600"
nmea, decoded = decode_nmea_and_ais(msg)

self.assertIsInstance(nmea, NMEAMessage)
self.assertEqual(decoded.course, 87.0)
self.assertEqual(decoded.msg_type, 1)
self.assertEqual(decoded.mmsi, 538090443)
self.assertEqual(decoded.speed, 10.9)
2 changes: 1 addition & 1 deletion tests/test_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ def test_run_every_file(self):
if csv_file.exists():
csv_file.unlink()

assert i == 16
assert i == 17

0 comments on commit a9ac5a9

Please sign in to comment.