diff --git a/ogn_lib/parser.py b/ogn_lib/parser.py
index f3b51ae..5842f01 100644
--- a/ogn_lib/parser.py
+++ b/ogn_lib/parser.py
@@ -778,3 +778,44 @@ class Capturs(Parser):
     @staticmethod
     def _preprocess_message(message):
         return message.strip('/')
+
+
+class Fanet(Parser):
+    """
+    Parser for Fanet-formatted APRS messages.
+    """
+
+    __destto__ = ['OGNFNT', 'OGNFNT-1']
+
+    @staticmethod
+    def _parse_protocol_specific(comment):
+        """
+        Parses the comment string from Fanet's APRS messages.
+        :param str comment: comment string
+        :return: parsed comment
+        :rtype: dict
+        """
+
+        fields = comment.split(' ')
+
+        if len(fields) != 3:
+            raise exceptions.ParseError('Fanet comment incorrectly formatted:'
+                                        ' received {}'.format(comment))
+
+        lat_dig = int(fields[0][2])
+        lon_dig = int(fields[0][3])
+        update_position = [
+            {
+                'target': 'latitude',
+                'function': Parser._get_location_update_func(lat_dig)
+            }, {
+                'target': 'longitude',
+                'function': Parser._get_location_update_func(lon_dig)
+            }
+        ]
+
+        return {
+            '_update': update_position,
+            'id': fields[1],
+            'vertical_speed': Parser._convert_fpm_to_ms(fields[2])
+        }

Add support for Fanet (OGNFNT)
See https://github.com/glidernet/ogn-aprs-protocol/pull/5/commits/1be92993c4d50db4329371d18385a29782ddc4fa for detailed message format.
diff --git a/tests/messages.txt b/tests/messages.txt
index 72b0c93..18ce385 100644
--- a/tests/messages.txt
+++ b/tests/messages.txt
@@ -80,3 +80,8 @@ FLRDDF944>OGSPID,qAS,SPIDER:/213930h3322.17S/07033.97W'332/028/A=003428 id300234
 ICA3E7540>OGSPOT,qAS,SPOT:/161427h1448.35S/04610.86W'000/000/A=008677 id0-2860357 SPOT3 GOOD
 ICA3E7540>OGSPOT,qAS,SPOT:/162923h1431.99S/04604.33W'000/000/A=006797 id0-2860357 SPOT3 GOOD
 ICA3E7540>OGSPOT,qAS,SPOT:/163421h1430.38S/04604.43W'000/000/A=007693 id0-2860357 SPOT3 GOOD
+FNT1103CE>OGNFNT,qAS,FNB1103CE:/183727h5057.94N/00801.00Eg355/002/A=001042 !W10! id1E1103CE +03fpm
+FNT1103CE>OGNFNT,qAS,FNB1103CE:/183729h5057.94N/00801.00Eg354/001/A=001042 !W10! id1E1103CE +07fpm
+FNT1103CE>OGNFNT,qAS,FNB1103CE:/183731h5057.94N/00801.00Eg354/001/A=001042 !W10! id1E1103CE +05fpm
+FNT1103CE>OGNFNT,qAS,FNB1103CE:/183734h5057.94N/00801.00Eg354/001/A=001042 !W30! id1E1103CE -10fpm
+FNT1103CE>OGNFNT,qAS,FNB1103CE:/183736h5057.94N/00801.00Eg354/001/A=001042 !W40! id1E1103CE -02fpm
diff --git a/tests/test_parser.py b/tests/test_parser.py
index 937c193..ca88c62 100644
--- a/tests/test_parser.py
+++ b/tests/test_parser.py
@@ -580,6 +580,32 @@ class TestCapturs:
         parser.Capturs._preprocess_message.assert_called_once_with(msg)
 
 
+class TestFanet:
+
+    def test_parse_protocol_specific(self):
+        data = parser.Fanet._parse_protocol_specific('!W30! id1E1103CE 180fpm')
+
+        assert data['id'] == 'id1E1103CE'
+        assert abs(data['vertical_speed'] - 0.9144) < 0.01
+        assert (list(map(lambda x: x['target'], data['_update'])) ==
+                ['latitude', 'longitude'])
+
+    def test_parse_protocol_specific_fail(self):
+        with pytest.raises(exceptions.ParseError):
+            parser.Fanet._parse_protocol_specific('id1E1103CE')
+
+        with pytest.raises(exceptions.ParseError):
+            parser.Fanet._parse_protocol_specific(
+                '!W30! id1E1103CE -02fpm x')
+
+    def test_registered(self, mocker):
+        mocker.spy(parser.Fanet, '_parse_protocol_specific')
+        parser.Parser('FNT1103CE>OGNFNT,qAS,FNB1103CE:/183734h5057.94N/'
+                      '00801.00Eg354/001/A=001042 !W30! id1E1103CE -10fpm')
+        parser.Fanet._parse_protocol_specific.assert_called_once_with(
+            '!W30! id1E1103CE -10fpm')
+
+
 class TestServerParser:
 
     def test_parse_message_beacon(self, mocker):

pip install -e .
parse_log_pytest
pytest
pytest
3.6
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs @ file:///opt/conda/conda-bld/attrs_1642510447205/work
certifi==2021.5.30
importlib-metadata @ file:///tmp/build/80754af9/importlib-metadata_1631916693255/work
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
more-itertools @ file:///tmp/build/80754af9/more-itertools_1637733554872/work
-e git+https://github.com/akolar/ogn-lib.git@695f77174bd5a1ef7bdba53c03e3e905aaaec521#egg=ogn_lib
packaging @ file:///tmp/build/80754af9/packaging_1637314298585/work
pluggy @ file:///tmp/build/80754af9/pluggy_1615976315926/work
py @ file:///opt/conda/conda-bld/py_1644396412707/work
pyparsing @ file:///tmp/build/80754af9/pyparsing_1635766073266/work
pytest==6.2.4
toml @ file:///tmp/build/80754af9/toml_1616166611790/work
typing_extensions @ file:///opt/conda/conda-bld/typing_extensions_1647553014482/work
zipp @ file:///tmp/build/80754af9/zipp_1633618647012/work

name: ogn-lib
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - attrs=21.4.0=pyhd3eb1b0_0
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - importlib-metadata=4.8.1=py36h06a4308_0
  - importlib_metadata=4.8.1=hd3eb1b0_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - more-itertools=8.12.0=pyhd3eb1b0_0
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - packaging=21.3=pyhd3eb1b0_0
  - pip=21.2.2=py36h06a4308_0
  - pluggy=0.13.1=py36h06a4308_0
  - py=1.11.0=pyhd3eb1b0_0
  - pyparsing=3.0.4=pyhd3eb1b0_0
  - pytest=6.2.4=py36h06a4308_2
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - toml=0.10.2=pyhd3eb1b0_0
  - typing_extensions=4.1.1=pyh06a4308_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zipp=3.6.0=pyhd3eb1b0_0
  - zlib=1.2.13=h5eee18b_1
prefix: /opt/conda/envs/ogn-lib

tests/test_parser.py::TestFanet::test_parse_protocol_specific tests/test_parser.py::TestFanet::test_parse_protocol_specific_fail
tests/test_parser.py::TestParserBase::test_new_no_id tests/test_parser.py::TestParserBase::test_new_single_id tests/test_parser.py::TestParserBase::test_new_multi_id tests/test_parser.py::TestParserBase::test_no_destto tests/test_parser.py::TestParserBase::test_new_wrong_id tests/test_parser.py::TestParserBase::test_set_default tests/test_parser.py::TestParserBase::test_call_no_parser tests/test_parser.py::TestParser::test_pattern_header tests/test_parser.py::TestParser::test_pattern_header_matches_all tests/test_parser.py::TestParser::test_pattern_location tests/test_parser.py::TestParser::test_pattern_location_matches_all tests/test_parser.py::TestParser::test_pattern_comment_common tests/test_parser.py::TestParser::test_pattern_comment_common_matches_all tests/test_parser.py::TestParser::test_pattern_all tests/test_parser.py::TestParser::test_pattern_all_matches_all tests/test_parser.py::TestParser::test_parse_msg_no_match tests/test_parser.py::TestParser::test_preprocess_message tests/test_parser.py::TestParser::test_parse_digipeaters tests/test_parser.py::TestParser::test_parse_digipeaters_relayed tests/test_parser.py::TestParser::test_parse_digipeaters_unknown_format tests/test_parser.py::TestParser::test_parse_heading_speed tests/test_parser.py::TestParser::test_parse_heading_speed_both_missing tests/test_parser.py::TestParser::test_parse_heading_speed_null_input tests/test_parser.py::TestParser::test_parse_altitude tests/test_parser.py::TestParser::test_parse_altitude_missing tests/test_parser.py::TestParser::test_parse_attrs tests/test_parser.py::TestParser::test_parse_time_past tests/test_parser.py::TestParser::test_parse_time_future tests/test_parser.py::TestParser::test_parse_datetime tests/test_parser.py::TestParser::test_parse_location_sign tests/test_parser.py::TestParser::test_parse_location_value tests/test_parser.py::TestParser::test_parse_protocol_specific tests/test_parser.py::TestParser::test_conv_fpm_to_ms tests/test_parser.py::TestParser::test_conv_fpm_to_ms_sign tests/test_parser.py::TestParser::test_get_location_update_func tests/test_parser.py::TestParser::test_update_location_decimal_same tests/test_parser.py::TestParser::test_update_location_decimal_positive tests/test_parser.py::TestParser::test_update_location_decimal_negative tests/test_parser.py::TestParser::test_update_data tests/test_parser.py::TestParser::test_update_data_missing tests/test_parser.py::TestAPRS::test_parse_protocol_specific tests/test_parser.py::TestAPRS::test_parse_id_string tests/test_parser.py::TestNaviter::test_parse_protocol_specific tests/test_parser.py::TestNaviter::test_parse_id_string tests/test_parser.py::TestSpot::test_parse_protocol_specific tests/test_parser.py::TestSpot::test_parse_protocol_specific_fail tests/test_parser.py::TestSpider::test_parse_protocol_specific tests/test_parser.py::TestSpider::test_parse_protocol_specific_fail tests/test_parser.py::TestSkylines::test_parse_protocol_specific tests/test_parser.py::TestSkylines::test_parse_protocol_specific_fail tests/test_parser.py::TestLT24::test_parse_protocol_specific tests/test_parser.py::TestLT24::test_parse_protocol_specific_fail tests/test_parser.py::TestCapturs::test_process tests/test_parser.py::TestCapturs::test_preprocess
ogn_lib/parser.py
ogn_lib/parser.py