M0r13n / pyais

AIS message decoding and encoding in Python (AIVDM/AIVDO)
MIT License
176 stars 61 forks source link

pyais fails to decode type 5 messages #112

Closed sv1 closed 1 year ago

sv1 commented 1 year ago

While testing pyais i get the following issue

Traceback (most recent call last): File "/srv/software/pyais/readsock.py", line 18, in <module> dec = pyais.decode(p) File "/srv/software/pyais/pyais/decode.py", line 78, in decode nmea = _assemble_messages(*parts, error_if_checksum_invalid=error_if_checksum_invalid) File "/srv/software/pyais/pyais/decode.py", line 43, in _assemble_messages raise MissingMultipartMessageException(f"Missing fragment numbers: {diff}") pyais.exceptions.MissingMultipartMessageException: Missing fragment numbers: [2]

This happens every time I try to decode AIS type 5 messages like these:

!AIVDM,2,2,0,,0000000000,255' !AIVDM,2,2,0,,8888888880,25D' !AIVDM,2,2,9,,8888888880,2*54'

Thanks

mihermans commented 1 year ago

Hi You're not defining the first part of the multipart message.

Xxvdm,2,1,5, ...... Xxvdm,2,2,5, ......

Something like this.

sv1 commented 1 year ago

Since I am feeding pyais with live data over RF I do not have control over all messages.

I think that pyais should handle missing message more gracefully.

sv1 commented 1 year ago

Maybe handle these messages as gnuais does:

ch A type 5 mmsi 636022096: name "LARA I" destination "PIRAEUS" type 80 length 274 width 50 draught 9.0 (!AIVDM,2,2,3,,8888888880,2*5E)

mihermans commented 1 year ago

Maybe handle these messages as gnuais does:

ch A type 5 mmsi 636022096: name "LARA I" destination "PIRAEUS" type 80 length 274 width 50 draught 9.0 (!AIVDM,2,2,3,,8888888880,2*5E)

Also in this case a !AIVDM,2,1,3,, ...... should be present. Otherwise the message is not complete and should give an error or warning (in my opinion), but should not stop the program.

M0r13n commented 1 year ago

There's a lot going on here. I will try my best to respond to the issue and your comments as good as I can.

The error that you encountered is expected. You are missing one or more parts of a multipart message. Thus, the message can not be correctly decoded. There is simply no way around that. As long as there is at least one part missing, the decoded values will always be wrong. And because I value correctness, the lib won't even attempt to decode the invalid message.

But there are quite a few possible solutions to your case:

The easiest option would be to catch the error in your code:

try:
    decode(...)
except MissingMultipartMessageException:
    pass

But because you are receiving a stream of messages, a more elegant solution would be to use one of the provided streaming classes. By doing so, missing messages will be properly handled. The lib tries to assemble them by keeping the last recently received messages in a buffer. Feel free to look at this example.

In case that none of the provided streaming classes fit your need (which I doubt), you can easily implement your own. Just inherit from AssembleMessages and implement self._iter_messages() with whatever logic is necessary to receive the raw encoded messages. The class will then handle the rest like assembling of multi-part messages.

M0r13n commented 1 year ago

@sv1 Let me know if you have further questions.