def test_bad_values(self): # packet expresses longitude of 221.8539, which is crazy, so no location should be available m = simpleais.parse('!AIVDM,1,1,,A,2C2ILGC4oRgoT?r1fdC3wcvi26;8,0*33') self.assertEqual('203840605', m['mmsi']) self.assertIsNone(m['lon']) self.assertAlmostEquals(3.0226, m['lat']) self.assertIsNone(m.location()) # packet is too short, so no location should be available m = simpleais.parse('1452655664.394 !AIVDM,1,1,,A,ECgb9OI9R@106jh`8@7Q3wmTkP06,0*3A') self.assertEqual('251300221', m['mmsi']) self.assertIsNone(m['lon']) self.assertIsNone(m['lat']) self.assertIsNone(m.location())
def test_checksum_filter(self): good = parse("!AIVDM,1,1,,B,3;hw29cc6<<1qABsuhLN>=5ws`Qo,0*4C") bad = parse("!AIVDM,1,1,,B,3;hw29cc6<<1qABsuhLN>=5ws`Qo,0*4B") taster = Taster(checksum=None) self.assertTrue(taster.likes(good)) self.assertTrue(taster.likes(bad)) taster = Taster(checksum=True) self.assertTrue(taster.likes(good)) self.assertFalse(taster.likes(bad)) taster = Taster(checksum=False) self.assertFalse(taster.likes(good)) self.assertTrue(taster.likes(bad))
def test_bad_values(self): # packet expresses longitude of 221.8539, which is crazy, so no location should be available m = simpleais.parse('!AIVDM,1,1,,A,2C2ILGC4oRgoT?r1fdC3wcvi26;8,0*33') self.assertEqual('203840605', m['mmsi']) self.assertIsNone(m['lon']) self.assertAlmostEquals(3.0226, m['lat']) self.assertIsNone(m.location()) # packet is too short, so no location should be available m = simpleais.parse( '1452655664.394 !AIVDM,1,1,,A,ECgb9OI9R@106jh`8@7Q3wmTkP06,0*3A') self.assertEqual('251300221', m['mmsi']) self.assertIsNone(m['lon']) self.assertIsNone(m['lat']) self.assertIsNone(m.location())
def test_basics(self): m = simpleais.parse(['!AIVDM,2,1,0,B,55QEQ`42Cktc<IL?J20@tpNl61A8U@tr2222221@BhQ,0*45', '!AIVDM,2,2,0,B,H86tl0PDSlhDRE3p3F8888888880,2*57'])[0] self.assertEqual(5, m.type_id()) self.assertEqual('370500000', m['mmsi']) self.assertEqual('DONG-A TRITON', m['shipname']) self.assertEqual('ROSARITO MX', m['destination'])
def test_basic_sentence(self): sentence = simpleais.parse('!ABVDM,1,1,,A,15NaEPPP01oR`R6CC?<j@gvr0<1C,0*1F') self.assertIsInstance(sentence, Sentence) self.assertEqual('AB', sentence.talker) self.assertEqual('VDM', sentence.sentence_type) self.assertEqual('A', sentence.radio_channel) self.assertEqual(1, sentence.type_id())
def test_fragment_assembly(self): raw = fragmented_message_type_8 sentences = simpleais.parse(raw) self.assertEqual(1, len(sentences)) message_bytes = sum([len(m) - len('!AIVDM,3,1,3,A,') - len(',2*34') for m in raw]) message_bits = message_bytes * 6 - 2 # where 2 is padding on last fragment self.assertEquals(message_bits, len(sentences[0].message_bits()))
def test_basic_sentence(self): sentence = simpleais.parse( '!ABVDM,1,1,,A,15NaEPPP01oR`R6CC?<j@gvr0<1C,0*1F') self.assertIsInstance(sentence, Sentence) self.assertEqual('AB', sentence.talker) self.assertEqual('VDM', sentence.sentence_type) self.assertEqual('A', sentence.radio_channel) self.assertEqual(1, sentence.type_id())
def test_fragment_assembly(self): raw = fragmented_message_type_8 sentences = simpleais.parse(raw) self.assertEqual(1, len(sentences)) message_bytes = sum( [len(m) - len('!AIVDM,3,1,3,A,') - len(',2*34') for m in raw]) message_bits = message_bytes * 6 - 2 # where 2 is padding on last fragment self.assertEquals(message_bits, len(sentences[0].message_bits()))
def test_time_filter(self): early, late = parse(["1456572038.584 !AIVDM,1,1,,A,35DQ`v100211@E:GFlh=6To<P000pJw>`<,0*59", "1463812839.417 !AIVDM,1,1,,A,15DQ`v001P005W4EqMD`DVW>0>`<,0*62"]) taster = Taster(before=1460000000) self.assertTrue(taster.likes(early)) self.assertFalse(taster.likes(late)) taster = Taster(after=1460000000) self.assertFalse(taster.likes(early)) self.assertTrue(taster.likes(late))
def test_time_filter(self): early, late = parse([ "1456572038.584 !AIVDM,1,1,,A,35DQ`v100211@E:GFlh=6To<P000pJw>`<,0*59", "1463812839.417 !AIVDM,1,1,,A,15DQ`v001P005W4EqMD`DVW>0>`<,0*62" ]) taster = Taster(before=1460000000) self.assertTrue(taster.likes(early)) self.assertFalse(taster.likes(late)) taster = Taster(after=1460000000) self.assertFalse(taster.likes(early)) self.assertTrue(taster.likes(late))
def AISDecode(): print("AIS Decoded Started..") fInput = open("Test.csv", "r", newline='') fOutput = open('AISDecoded.csv', "w", newline='') AISReader = csv.reader(fInput, delimiter=',') AISWriter = csv.writer(fOutput, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL) for row in AISReader: message = row[0] decodedMsg = simpleais.parse(message) if decodedMsg is None: continue AISWriter.writerow([ decodedMsg['mmsi'], decodedMsg['lat'], decodedMsg['lon'], decodedMsg['course'], decodedMsg['speed'], row[1] ]) print("AIS Decoded")
def test_fields_for_sentence(self): m = simpleais.parse('!ABVDM,1,1,,A,15NaEPPP01oR`R6CC?<j@gvr0<1C,0*1F') self.assertEqual(16, len(m.fields())) self.assertEqual("Message Type", m.fields()[0].description()) self.assertEqual("Message Type", m.field('type').description()) message_type = m.field(0) self.assertEqual("type", message_type.name()) self.assertEqual("Message Type", message_type.description()) self.assertEqual(1, message_type.value()) self.assertEqual(Bits('000001'), message_type.bits()) raim = m.field(14) self.assertEqual("raim", raim.name()) self.assertEqual("RAIM flag", raim.description()) self.assertEqual(False, raim.value()) self.assertEqual(Bits('0'), raim.bits()) radio_status = m.field(15) self.assertEqual("radio", radio_status.name()) self.assertEqual("Radio status", radio_status.description()) self.assertEqual(49235, radio_status.value()) self.assertEqual(Bits('0001100000001010011'), radio_status.bits())
def AISDecode(path): print("AIS Decoding Started..") fInput = open(path, "r", newline='') fOutput = open('AISDecoded.csv', "w", newline='') AISReader = csv.reader(fInput, delimiter=',') AISWriter = csv.writer(fOutput, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL) AISWriter.writerow(["MMSI", "Latitude", "Longitude", "COG", "SOG", "Time"]) for row in AISReader: message = row[0] decodedMsg = simpleais.parse(message) if decodedMsg is None: continue if isinstance(decodedMsg, simpleais.SentenceFragment) == True: continue AISWriter.writerow([ decodedMsg['mmsi'], decodedMsg['lat'], decodedMsg['lon'], decodedMsg['course'], decodedMsg['speed'], row[1] ]) print("AIS Decoded")
def test_single_fragment(self): body = '85NoHR1KfI99t:BHBI3sWpAoS7VHRblW8McQtR3lsFR' padding = 0 fragment = simpleais.parse('!AIVDM,3,1,3,A,%s,%s*5A' % (body, padding)) self.assertIsInstance(fragment, SentenceFragment) self.assertEqual(len(body) * 6 - padding, len(fragment.bits()))
def test_optional_date(self): text = "1454124838.633\t!ABVDM,1,1,,A,15NaEPPP01oR`R6CC?<j@gvr0<1C,0*1F" sentence = simpleais.parse(text) self.assertEqual(1454124838.633, sentence.time)
def test_known_and_unknown_fields(self): m = simpleais.parse('!ABVDM,1,1,,A,15NaEPPP01oR`R6CC?<j@gvr0<1C,0*1F') self.assertTrue(m['type']) self.assertFalse(m['unknown'])
def test_as_location(self): m = simpleais.parse('!ABVDM,1,1,,A,15NaEPPP01oR`R6CC?<j@gvr0<1C,0*1F') location = m.location() self.assertAlmostEquals(-118.2634, location[0]) self.assertAlmostEquals(33.7302, location[1])
def test_round_trip_for_multiple_fragments(self): sentence = simpleais.parse(fragmented_message_type_8)[0] self.assertEqual(fragmented_message_type_8, sentence.text)
def test_basic_lists(self): sentences = simpleais.parse([ '!AIVDM,1,1,,B,H52R9E1<D<tpB1LTp@000000000,2*5C', '!ABVDM,1,1,,A,15MqdBP001GRT>>CCUu360Lr041d,0*69' ]) self.assertEqual(2, len(sentences))
def test_has_zero_speed(self): m = simpleais.parse('!AIVDM,1,1,,A,39NSH1U000GND`LCRQc;WpM`P>`<,0*6C') self.assertTrue('speed' in m) self.assertEqual(0, m['speed'])
def test_has_speed(self): m = simpleais.parse('!AIVDM,1,1,,B,19NSH1P02QG?:MjE`?qBFApb0>`<,0*41') self.assertTrue('speed' in m) self.assertEqual(16.1, m['speed'])
def test_no_lat_or_lon(self): m = simpleais.parse('!ABVDM,1,1,,A,152MQ1qP?w<tSF0l4Q@>4?wp1p7G,0*78') self.assertEqual('338125063', m['mmsi']) self.assertIsNone(m['lon']) self.assertIsNone(m['lat'])
def test_basics(self): m = simpleais.parse('!ABVDM,1,1,,A,15NaEPPP01oR`R6CC?<j@gvr0<1C,0*1F') self.assertEqual(1, m.type_id()) self.assertEqual('367678850', m['mmsi']) self.assertAlmostEquals(-118.2634, m['lon']) self.assertAlmostEquals(33.7302, m['lat'])
def test_round_trip_for_single_fragment(self): text = '!ABVDM,1,1,,A,15NaEPPP01oR`R6CC?<j@gvr0<1C,0*1F' sentence = simpleais.parse(text) self.assertEqual(text, sentence.text[0])
class TestTaster(TestCase): type_1_la = parse( ["1452468552.938 !AIVDM,1,1,,B,14Wtnn002SGLde:BbrBmdTLF0Vql,0*6E"])[0] type_1_sf = parse(["!AIVDM,1,1,,A,15Mw0GP01SG?W>PE`laU<TJj0L20,0*67"])[0] type_5 = parse([ "!WSVDM,2,1,0,A,5=JklSl00003UHDs:20l4E9<f04i@4U:22222217,0*4C", "!WSVDM,2,2,0,A,05B0dl0HtS000000000000000000008,2*00" ])[0] type_17 = parse( ["!AIVDM,1,1,,A,Auju3sUbv8u`:JBCIf?vOeCSWmp:JOGeRN@?iD=I,0*61"])[0] def test_location_filtering(self): taster = Taster(lat=(32, 35)) # LA self.assertTrue(taster.likes(self.type_1_la)) self.assertFalse(taster.likes(self.type_1_sf)) taster = Taster(lon=(-121, -117)) # LA self.assertTrue(taster.likes(self.type_1_la)) self.assertFalse(taster.likes(self.type_1_sf)) def test_type_filtering(self): taster = Taster(sentence_type=[1]) self.assertTrue(taster.likes(self.type_1_la)) self.assertTrue(taster.likes(self.type_1_sf)) self.assertFalse(taster.likes(self.type_5)) self.assertFalse(taster.likes(self.type_17)) taster = Taster(sentence_type=[5, 17]) self.assertFalse(taster.likes(self.type_1_la)) self.assertFalse(taster.likes(self.type_1_sf)) self.assertTrue(taster.likes(self.type_5)) self.assertTrue(taster.likes(self.type_17)) def test_field_filtering(self): taster = Taster(field=['shiptype']) self.assertFalse(taster.likes(self.type_1_la)) self.assertTrue(taster.likes(self.type_5)) self.assertFalse(taster.likes(self.type_17)) def test_value_filtering(self): taster = Taster(value=[('mmsi', '366985310')]) self.assertTrue(taster.likes(self.type_1_sf)) self.assertFalse(taster.likes(self.type_1_la)) self.assertFalse(taster.likes(self.type_5)) self.assertFalse(taster.likes(self.type_17)) def test_packets_without_locations_are_rejected_when_filtering_for_location( self): taster = Taster(lat=(0, 90)) self.assertFalse(taster.likes(self.type_5)) def test_checksum_filter(self): good = parse("!AIVDM,1,1,,B,3;hw29cc6<<1qABsuhLN>=5ws`Qo,0*4C") bad = parse("!AIVDM,1,1,,B,3;hw29cc6<<1qABsuhLN>=5ws`Qo,0*4B") taster = Taster(checksum=None) self.assertTrue(taster.likes(good)) self.assertTrue(taster.likes(bad)) taster = Taster(checksum=True) self.assertTrue(taster.likes(good)) self.assertFalse(taster.likes(bad)) taster = Taster(checksum=False) self.assertFalse(taster.likes(good)) self.assertTrue(taster.likes(bad)) def test_time_filter(self): early, late = parse([ "1456572038.584 !AIVDM,1,1,,A,35DQ`v100211@E:GFlh=6To<P000pJw>`<,0*59", "1463812839.417 !AIVDM,1,1,,A,15DQ`v001P005W4EqMD`DVW>0>`<,0*62" ]) taster = Taster(before=1460000000) self.assertTrue(taster.likes(early)) self.assertFalse(taster.likes(late)) taster = Taster(after=1460000000) self.assertFalse(taster.likes(early)) self.assertTrue(taster.likes(late)) def test_invert_match(self): taster = Taster(lat=(32, 35), invert_match=True) # LA self.assertFalse(taster.likes(self.type_1_la)) self.assertTrue(taster.likes(self.type_1_sf))
def test_decoder_decodes(self): d = MESSAGE_DECODERS[1] m = simpleais.parse('!ABVDM,1,1,,A,15NaEPPP01oR`R6CC?<j@gvr0<1C,0*1F') self.assertEqual('367678850', d.decode('mmsi', m)) self.assertAlmostEquals(33.7302, d.decode('lat', m)) self.assertAlmostEquals(-118.2634, d.decode('lon', m))
def test_convenience_parse(self): self.assertEqual(None, simpleais.parse('')) self.assertEqual([], simpleais.parse([]))