aprsd 4.0.1__tar.gz → 4.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. {aprsd-4.0.1 → aprsd-4.1.0}/.github/workflows/release_build.yml +3 -2
  2. {aprsd-4.0.1 → aprsd-4.1.0}/ChangeLog.md +56 -17
  3. {aprsd-4.0.1 → aprsd-4.1.0}/PKG-INFO +1 -1
  4. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/client/drivers/aprsis.py +87 -35
  5. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/client/drivers/fake.py +5 -0
  6. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/client/drivers/kiss.py +45 -20
  7. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/client/kiss.py +29 -25
  8. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/cmds/listen.py +84 -91
  9. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/cmds/server.py +1 -1
  10. aprsd-4.1.0/aprsd/conf/common.py +237 -0
  11. aprsd-4.1.0/aprsd/conf/log.py +68 -0
  12. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/log/log.py +24 -14
  13. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/packets/__init__.py +6 -0
  14. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/packets/core.py +5 -2
  15. aprsd-4.1.0/aprsd/packets/filter.py +58 -0
  16. aprsd-4.1.0/aprsd/packets/filters/dupe_filter.py +68 -0
  17. aprsd-4.1.0/aprsd/packets/filters/packet_type.py +53 -0
  18. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/packets/packet_list.py +33 -27
  19. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/plugins/fortune.py +21 -15
  20. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/threads/__init__.py +1 -2
  21. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/threads/rx.py +83 -75
  22. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/threads/stats.py +4 -9
  23. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/utils/objectstore.py +12 -13
  24. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd.egg-info/PKG-INFO +1 -1
  25. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd.egg-info/SOURCES.txt +5 -0
  26. {aprsd-4.0.1 → aprsd-4.1.0}/docker/Dockerfile +2 -1
  27. aprsd-4.1.0/tests/plugins/__init__.py +0 -0
  28. aprsd-4.1.0/uv.lock +1340 -0
  29. aprsd-4.0.1/aprsd/conf/common.py +0 -238
  30. aprsd-4.0.1/aprsd/conf/log.py +0 -63
  31. {aprsd-4.0.1 → aprsd-4.1.0}/.coveragerc +0 -0
  32. {aprsd-4.0.1 → aprsd-4.1.0}/.github/workflows/authors.yml +0 -0
  33. {aprsd-4.0.1 → aprsd-4.1.0}/.github/workflows/codeql.yml +0 -0
  34. {aprsd-4.0.1 → aprsd-4.1.0}/.github/workflows/manual_build.yml +0 -0
  35. {aprsd-4.0.1 → aprsd-4.1.0}/.github/workflows/master-build.yml +0 -0
  36. {aprsd-4.0.1 → aprsd-4.1.0}/.github/workflows/python.yml +0 -0
  37. {aprsd-4.0.1 → aprsd-4.1.0}/.mailmap +0 -0
  38. {aprsd-4.0.1 → aprsd-4.1.0}/.pre-commit-config.yaml +0 -0
  39. {aprsd-4.0.1 → aprsd-4.1.0}/.readthedocs.yaml +0 -0
  40. {aprsd-4.0.1 → aprsd-4.1.0}/AUTHORS +0 -0
  41. {aprsd-4.0.1 → aprsd-4.1.0}/CONTRIBUTING.md +0 -0
  42. {aprsd-4.0.1 → aprsd-4.1.0}/INSTALL.txt +0 -0
  43. {aprsd-4.0.1 → aprsd-4.1.0}/LICENSE +0 -0
  44. {aprsd-4.0.1 → aprsd-4.1.0}/MANIFEST.in +0 -0
  45. {aprsd-4.0.1 → aprsd-4.1.0}/Makefile +0 -0
  46. {aprsd-4.0.1 → aprsd-4.1.0}/README.md +0 -0
  47. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/__init__.py +0 -0
  48. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/cli_helper.py +0 -0
  49. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/client/__init__.py +0 -0
  50. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/client/aprsis.py +0 -0
  51. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/client/base.py +0 -0
  52. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/client/drivers/__init__.py +0 -0
  53. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/client/factory.py +0 -0
  54. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/client/fake.py +0 -0
  55. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/client/stats.py +0 -0
  56. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/cmds/__init__.py +0 -0
  57. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/cmds/completion.py +0 -0
  58. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/cmds/dev.py +0 -0
  59. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/cmds/fetch_stats.py +0 -0
  60. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/cmds/healthcheck.py +0 -0
  61. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/cmds/list_plugins.py +0 -0
  62. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/cmds/send_message.py +0 -0
  63. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/conf/__init__.py +0 -0
  64. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/conf/client.py +0 -0
  65. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/conf/opts.py +0 -0
  66. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/conf/plugin_common.py +0 -0
  67. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/exception.py +0 -0
  68. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/log/__init__.py +0 -0
  69. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/main.py +0 -0
  70. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/packets/collector.py +0 -0
  71. {aprsd-4.0.1/aprsd/plugins → aprsd-4.1.0/aprsd/packets/filters}/__init__.py +0 -0
  72. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/packets/log.py +0 -0
  73. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/packets/seen_list.py +0 -0
  74. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/packets/tracker.py +0 -0
  75. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/packets/watch_list.py +0 -0
  76. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/plugin.py +0 -0
  77. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/plugin_utils.py +0 -0
  78. {aprsd-4.0.1/examples → aprsd-4.1.0/aprsd}/plugins/__init__.py +0 -0
  79. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/plugins/notify.py +0 -0
  80. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/plugins/ping.py +0 -0
  81. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/plugins/time.py +0 -0
  82. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/plugins/version.py +0 -0
  83. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/plugins/weather.py +0 -0
  84. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/stats/__init__.py +0 -0
  85. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/stats/app.py +0 -0
  86. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/stats/collector.py +0 -0
  87. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/threads/aprsd.py +0 -0
  88. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/threads/keepalive.py +0 -0
  89. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/threads/registry.py +0 -0
  90. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/threads/tx.py +0 -0
  91. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/utils/__init__.py +0 -0
  92. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/utils/counter.py +0 -0
  93. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/utils/fuzzyclock.py +0 -0
  94. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/utils/json.py +0 -0
  95. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/utils/keepalive_collector.py +0 -0
  96. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/utils/ring_buffer.py +0 -0
  97. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd/utils/trace.py +0 -0
  98. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd-lnav.json +0 -0
  99. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd.egg-info/dependency_links.txt +0 -0
  100. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd.egg-info/entry_points.txt +0 -0
  101. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd.egg-info/requires.txt +0 -0
  102. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd.egg-info/top_level.txt +0 -0
  103. {aprsd-4.0.1 → aprsd-4.1.0}/aprsd_logo.png +0 -0
  104. {aprsd-4.0.1 → aprsd-4.1.0}/docker/bin/admin.sh +0 -0
  105. {aprsd-4.0.1 → aprsd-4.1.0}/docker/bin/healthcheck.sh +0 -0
  106. {aprsd-4.0.1 → aprsd-4.1.0}/docker/bin/listen.sh +0 -0
  107. {aprsd-4.0.1 → aprsd-4.1.0}/docker/bin/run.sh +0 -0
  108. {aprsd-4.0.1 → aprsd-4.1.0}/docker/bin/setup.sh +0 -0
  109. {aprsd-4.0.1 → aprsd-4.1.0}/docker/build.sh +0 -0
  110. {aprsd-4.0.1 → aprsd-4.1.0}/docker/docker-compose.yml +0 -0
  111. {aprsd-4.0.1 → aprsd-4.1.0}/docs/_static/.keep +0 -0
  112. {aprsd-4.0.1 → aprsd-4.1.0}/docs/_static/aprsd_overview.png +0 -0
  113. {aprsd-4.0.1 → aprsd-4.1.0}/docs/_static/aprsd_overview.svg +0 -0
  114. {aprsd-4.0.1 → aprsd-4.1.0}/docs/_templates/.keep +0 -0
  115. {aprsd-4.0.1 → aprsd-4.1.0}/docs/apidoc/aprsd.client.drivers.rst +0 -0
  116. {aprsd-4.0.1 → aprsd-4.1.0}/docs/apidoc/aprsd.client.rst +0 -0
  117. {aprsd-4.0.1 → aprsd-4.1.0}/docs/apidoc/aprsd.cmds.rst +0 -0
  118. {aprsd-4.0.1 → aprsd-4.1.0}/docs/apidoc/aprsd.conf.rst +0 -0
  119. {aprsd-4.0.1 → aprsd-4.1.0}/docs/apidoc/aprsd.log.rst +0 -0
  120. {aprsd-4.0.1 → aprsd-4.1.0}/docs/apidoc/aprsd.packets.rst +0 -0
  121. {aprsd-4.0.1 → aprsd-4.1.0}/docs/apidoc/aprsd.plugins.rst +0 -0
  122. {aprsd-4.0.1 → aprsd-4.1.0}/docs/apidoc/aprsd.rst +0 -0
  123. {aprsd-4.0.1 → aprsd-4.1.0}/docs/apidoc/aprsd.stats.rst +0 -0
  124. {aprsd-4.0.1 → aprsd-4.1.0}/docs/apidoc/aprsd.threads.rst +0 -0
  125. {aprsd-4.0.1 → aprsd-4.1.0}/docs/apidoc/aprsd.utils.rst +0 -0
  126. {aprsd-4.0.1 → aprsd-4.1.0}/docs/apidoc/modules.rst +0 -0
  127. {aprsd-4.0.1 → aprsd-4.1.0}/docs/aprsd.drawio +0 -0
  128. {aprsd-4.0.1 → aprsd-4.1.0}/docs/changelog.rst +0 -0
  129. {aprsd-4.0.1 → aprsd-4.1.0}/docs/clean_docs.py +0 -0
  130. {aprsd-4.0.1 → aprsd-4.1.0}/docs/conf.py +0 -0
  131. {aprsd-4.0.1 → aprsd-4.1.0}/docs/configure.rst +0 -0
  132. {aprsd-4.0.1 → aprsd-4.1.0}/docs/index.rst +0 -0
  133. {aprsd-4.0.1 → aprsd-4.1.0}/docs/install.rst +0 -0
  134. {aprsd-4.0.1 → aprsd-4.1.0}/docs/links.rst +0 -0
  135. {aprsd-4.0.1 → aprsd-4.1.0}/docs/plugin.rst +0 -0
  136. {aprsd-4.0.1 → aprsd-4.1.0}/docs/readme.rst +0 -0
  137. {aprsd-4.0.1 → aprsd-4.1.0}/docs/server.rst +0 -0
  138. {aprsd-4.0.1/tests → aprsd-4.1.0/examples/plugins}/__init__.py +0 -0
  139. {aprsd-4.0.1 → aprsd-4.1.0}/examples/plugins/example_plugin.py +0 -0
  140. {aprsd-4.0.1 → aprsd-4.1.0}/gray.conf +0 -0
  141. {aprsd-4.0.1 → aprsd-4.1.0}/pyproject.toml +0 -0
  142. {aprsd-4.0.1 → aprsd-4.1.0}/requirements-dev.in +0 -0
  143. {aprsd-4.0.1 → aprsd-4.1.0}/requirements-dev.txt +0 -0
  144. {aprsd-4.0.1 → aprsd-4.1.0}/requirements.in +0 -0
  145. {aprsd-4.0.1 → aprsd-4.1.0}/requirements.txt +0 -0
  146. {aprsd-4.0.1 → aprsd-4.1.0}/setup.cfg +0 -0
  147. {aprsd-4.0.1 → aprsd-4.1.0}/setup.py +0 -0
  148. {aprsd-4.0.1/tests/cmds → aprsd-4.1.0/tests}/__init__.py +0 -0
  149. {aprsd-4.0.1 → aprsd-4.1.0}/tests/client/test_aprsis.py +0 -0
  150. {aprsd-4.0.1 → aprsd-4.1.0}/tests/client/test_client_base.py +0 -0
  151. {aprsd-4.0.1 → aprsd-4.1.0}/tests/client/test_factory.py +0 -0
  152. {aprsd-4.0.1/tests/plugins → aprsd-4.1.0/tests/cmds}/__init__.py +0 -0
  153. {aprsd-4.0.1 → aprsd-4.1.0}/tests/cmds/test_send_message.py +0 -0
  154. {aprsd-4.0.1 → aprsd-4.1.0}/tests/fake.py +0 -0
  155. {aprsd-4.0.1 → aprsd-4.1.0}/tests/plugins/test_fortune.py +0 -0
  156. {aprsd-4.0.1 → aprsd-4.1.0}/tests/plugins/test_notify.py +0 -0
  157. {aprsd-4.0.1 → aprsd-4.1.0}/tests/plugins/test_ping.py +0 -0
  158. {aprsd-4.0.1 → aprsd-4.1.0}/tests/plugins/test_time.py +0 -0
  159. {aprsd-4.0.1 → aprsd-4.1.0}/tests/plugins/test_version.py +0 -0
  160. {aprsd-4.0.1 → aprsd-4.1.0}/tests/plugins/test_weather.py +0 -0
  161. {aprsd-4.0.1 → aprsd-4.1.0}/tests/test_packets.py +0 -0
  162. {aprsd-4.0.1 → aprsd-4.1.0}/tests/test_plugin.py +0 -0
  163. {aprsd-4.0.1 → aprsd-4.1.0}/tools/fast8.sh +0 -0
  164. {aprsd-4.0.1 → aprsd-4.1.0}/tox.ini +0 -0
@@ -6,7 +6,7 @@ on:
6
6
  aprsd_version:
7
7
  required: true
8
8
  options:
9
- - 3.0.0
9
+ - 4.0.0
10
10
  logLevel:
11
11
  description: 'Log level'
12
12
  required: true
@@ -41,9 +41,10 @@ jobs:
41
41
  platforms: linux/amd64,linux/arm64
42
42
  file: ./Dockerfile
43
43
  build-args: |
44
+ INSTALL_TYPE=pypi
44
45
  VERSION=${{ inputs.aprsd_version }}
45
46
  BUILDX_QEMU_ENV=true
46
47
  push: true
47
48
  tags: |
48
- hemna6969/aprsd:v${{ inputs.aprsd_version }}
49
+ hemna6969/aprsd:${{ inputs.aprsd_version }}
49
50
  hemna6969/aprsd:latest
@@ -4,17 +4,72 @@ All notable changes to this project will be documented in this file. Dates are d
4
4
 
5
5
  Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
6
6
 
7
+ #### [4.1.0](https://github.com/craigerl/aprsd/compare/4.0.2...4.1.0)
8
+
9
+ > 20 February 2025
10
+
11
+ - Added new PacketFilter mechanism [`#184`](https://github.com/craigerl/aprsd/pull/184)
12
+ - Update to build from pypi [`3b57e75`](https://github.com/craigerl/aprsd/commit/3b57e7597d77303ffc03b082370283bb2fea2838)
13
+ - Updated APRSIS driver [`1606585`](https://github.com/craigerl/aprsd/commit/1606585d41f69133192199d139b53344bb320fa9)
14
+ - Updated packet_list to allow infinit max store [`19c12e7`](https://github.com/craigerl/aprsd/commit/19c12e70f30a6f1f7d223a2f0fd3bf1182579fa4)
15
+ - Update StatsStore to use existing lock [`227ddbf`](https://github.com/craigerl/aprsd/commit/227ddbf148be2e14d4b4f27e48a4b091a98f15df)
16
+ - Try and stop chardet logging! [`101904c`](https://github.com/craigerl/aprsd/commit/101904ca77d816ae9e70bc7d22e6d8516fc3c5ce)
17
+ - Fixed some pep8 failures. [`e9e7e6b`](https://github.com/craigerl/aprsd/commit/e9e7e6b59f9f93f3f09142e56407bc87603a44cb)
18
+ - updated gitignore [`fd517b3`](https://github.com/craigerl/aprsd/commit/fd517b32188fdf15835a74fbd515ce417e7ef1f5)
19
+ - Remove sleep in main RX thread [`6cd7e99`](https://github.com/craigerl/aprsd/commit/6cd7e997139e8f2687bee753d9e0d2b22b1c42a3)
20
+ - Changed Objectstore log to debug [`361663e`](https://github.com/craigerl/aprsd/commit/361663e7d2cf43bd2fd53da0d8c5205bb848dbc2)
21
+ - fix for None packet in rx thread [`d82a81a`](https://github.com/craigerl/aprsd/commit/d82a81a2c3c1a7f50177a0a6435a555daeb858aa)
22
+ - Fix runaway KISS driver on failed connnection [`b6da0eb`](https://github.com/craigerl/aprsd/commit/b6da0ebb0d2f4d7078dbbf91d8c03715412d89ea)
23
+ - CONF.logging.enable_color option added [`06bdb34`](https://github.com/craigerl/aprsd/commit/06bdb34642640d91ea96e3c6e8d8b5a4b8230611)
24
+
25
+ #### [4.0.2](https://github.com/craigerl/aprsd/compare/4.0.1...4.0.2)
26
+
27
+ > 25 January 2025
28
+
29
+ - Fix for KISS/Fake client drivers [`edeba7f`](https://github.com/craigerl/aprsd/commit/edeba7f5141c3197a3ddff5fe45127894c861e07)
30
+ - Trap for failed parsing of packets on KISS [`9501a63`](https://github.com/craigerl/aprsd/commit/9501a63bd61a681daf9eb9e41704e31570b7b385)
31
+ - Pass branch in github release_build [`1f65bbe`](https://github.com/craigerl/aprsd/commit/1f65bbe13a33c1fffad650c87c949bbe844d27f6)
32
+ - Removed some verbose output from KISS [`c1319c3`](https://github.com/craigerl/aprsd/commit/c1319c3ab8822f24c0e3b2c74d151d4e13a0039a)
33
+ - Look in multiple places for fortune bin [`97ffffc`](https://github.com/craigerl/aprsd/commit/97ffffc10dd05bd785134877ddb94437cf9b7f97)
34
+ - Added uv.lock [`2f26eb8`](https://github.com/craigerl/aprsd/commit/2f26eb86f44625547f72f7c3612494b1bc44bc99)
35
+ - Fix the testing of fortune path [`3c4e200`](https://github.com/craigerl/aprsd/commit/3c4e200d700c24125479bb754b5f68bdf35b85a6)
36
+ - update the install from github in Dockerfile [`bea4815`](https://github.com/craigerl/aprsd/commit/bea481555bc1270ab371a22c69973d648e526d54)
37
+ - Prep for 4.0.2 [`000adef`](https://github.com/craigerl/aprsd/commit/000adef6d4f2792d33980d59d37f4b139e0c693c)
38
+
7
39
  #### [4.0.1](https://github.com/craigerl/aprsd/compare/4.0.0...4.0.1)
8
40
 
9
41
  > 24 January 2025
10
42
 
11
43
  - Update pyproject for README.rst -> md [`e080394`](https://github.com/craigerl/aprsd/commit/e08039431ebde92a162ab422c05391dc55d3d3fa)
44
+ - Updated Changelog [`24f5672`](https://github.com/craigerl/aprsd/commit/24f567224cf8ecdebd51f49804425565883acb94)
12
45
 
13
- ### [4.0.0](https://github.com/craigerl/aprsd/compare/3.4.4...4.0.0)
46
+ ### [4.0.0](https://github.com/craigerl/aprsd/compare/3.5.0...4.0.0)
14
47
 
15
48
  > 24 January 2025
16
49
 
17
50
  - Migrate admin web out of aprsd. [`#183`](https://github.com/craigerl/aprsd/pull/183)
51
+ - Enable packet stats for listen command in Docker [`e5d8796`](https://github.com/craigerl/aprsd/commit/e5d8796cda1a007aa868c760b96b50b364351519)
52
+ - Added activity to README [`cdd297c`](https://github.com/craigerl/aprsd/commit/cdd297c5bbc8b93f4739f5850a3e5971ce8baeba)
53
+ - Added star history to readme [`02e2940`](https://github.com/craigerl/aprsd/commit/02e29405ce2f8310e4f87f68498dfd6575c2e43b)
54
+ - removed pytest from README [`1cba31f`](https://github.com/craigerl/aprsd/commit/1cba31f0ac9bd5ee532721a909fc752f023f3b06)
55
+ - Updated Docker for using alpine and uv [`24db814`](https://github.com/craigerl/aprsd/commit/24db814c82c9bb6634566d7428603bf7a9ae37d1)
56
+ - Update the admin and setup.sh for container [`044ea4c`](https://github.com/craigerl/aprsd/commit/044ea4cc9a0059101851d6e722e986ee236833e8)
57
+ - added healthcheck.sh [`1054999`](https://github.com/craigerl/aprsd/commit/10549995686b08e4c166f780efdec5bdae496cab)
58
+ - updated healthcheck.sh [`dabb48c`](https://github.com/craigerl/aprsd/commit/dabb48c6f64062c1fed8f83a4f0b8ffba0c206a5)
59
+ - try making image for webchat [`ba8acdc`](https://github.com/craigerl/aprsd/commit/ba8acdc5849fc7b2d8a1ee11af6f5e317cf30f45)
60
+ - Added APRSD logo [`0ed648f`](https://github.com/craigerl/aprsd/commit/0ed648f8f8a961dbbd9e22bcebadcde525ee41ae)
61
+ - Added plugin and extension links [`447451c`](https://github.com/craigerl/aprsd/commit/447451c6c97e1f2d3d0bf580db21ecd176690258)
62
+ - reduced logo size 50% [`cf4a29f`](https://github.com/craigerl/aprsd/commit/cf4a29f0cb3ed366b21ec3120a189614e0955180)
63
+ - Updated README.md TOC [`375a5e5`](https://github.com/craigerl/aprsd/commit/375a5e5b34718cadc6ee8a51484fc91441440a61)
64
+ - chore: update AUTHORS [skip ci] [`c556f51`](https://github.com/craigerl/aprsd/commit/c556f5126f725904822a75427475d46986f8e9f3)
65
+ - Updated requirements [`4a7a902`](https://github.com/craigerl/aprsd/commit/4a7a902a337759a352560d4d92dc314b1726412a)
66
+ - Updated ChangeLog for 4.0.0 [`934ebd2`](https://github.com/craigerl/aprsd/commit/934ebd236d044625b911dd8ca45293f6c5680a68)
67
+
68
+ #### [3.5.0](https://github.com/craigerl/aprsd/compare/3.4.4...3.5.0)
69
+
70
+ > 10 January 2025
71
+
72
+ - Migrate admin web out of aprsd. [`c48ff8d`](https://github.com/craigerl/aprsd/commit/c48ff8dfd4bd4ce2f95b36e71dce13da5446a658)
18
73
  - Remove webchat as a built in command. [`8f8887f`](https://github.com/craigerl/aprsd/commit/8f8887f0e496d960b0e71275893b75408a40fdb2)
19
74
  - Remove email plugin [`0880a35`](https://github.com/craigerl/aprsd/commit/0880a356e6df1a0924cbf6e815e68cba5f5c6cf1)
20
75
  - Fixed make clean [`ae28dbb`](https://github.com/craigerl/aprsd/commit/ae28dbb0e6bc216bf78c0bd9d7804f57b39091d1)
@@ -23,7 +78,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
23
78
  - Removed LocationPlugin from aprsd core [`3bba8a1`](https://github.com/craigerl/aprsd/commit/3bba8a19da88b0912064cea786bc9f8203038946)
24
79
  - Include haversine library [`bbdbb9a`](https://github.com/craigerl/aprsd/commit/bbdbb9aba189d536497ea3cd7d30911fe3d9d706)
25
80
  - Update Makefile [`caa4bb8`](https://github.com/craigerl/aprsd/commit/caa4bb8bd01cbd2e02024d75e1c8af97acf6c657)
26
- - Enable packet stats for listen command in Docker [`e5d8796`](https://github.com/craigerl/aprsd/commit/e5d8796cda1a007aa868c760b96b50b364351519)
27
81
  - Added new KeepAliveCollector [`30d1eb5`](https://github.com/craigerl/aprsd/commit/30d1eb57dd249c609f5b092d8084c40cadda7bd9)
28
82
  - Changed to ruff [`72d068c`](https://github.com/craigerl/aprsd/commit/72d068c0b8944c8c9eed494fc23de8d7179ee09b)
29
83
  - Changed README.rst -> README.md [`b1a830d`](https://github.com/craigerl/aprsd/commit/b1a830d54e9dec473074b34f9566f161bdec0030)
@@ -44,21 +98,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
44
98
  - Added .mailmap [`8d98546`](https://github.com/craigerl/aprsd/commit/8d9854605584fa35117af888fe219df610fb7cb4)
45
99
  - updated tools in pre-commit [`e4f82d6`](https://github.com/craigerl/aprsd/commit/e4f82d6054d4d859023423bccdd5c402d7a83494)
46
100
  - some cleanup [`e332d7c`](https://github.com/craigerl/aprsd/commit/e332d7c9d046066e2686ea0522ae06b86d2f162d)
47
- - Added activity to README [`cdd297c`](https://github.com/craigerl/aprsd/commit/cdd297c5bbc8b93f4739f5850a3e5971ce8baeba)
48
- - Added star history to readme [`02e2940`](https://github.com/craigerl/aprsd/commit/02e29405ce2f8310e4f87f68498dfd6575c2e43b)
49
- - removed pytest from README [`1cba31f`](https://github.com/craigerl/aprsd/commit/1cba31f0ac9bd5ee532721a909fc752f023f3b06)
50
- - Updated Docker for using alpine and uv [`24db814`](https://github.com/craigerl/aprsd/commit/24db814c82c9bb6634566d7428603bf7a9ae37d1)
51
- - Update the admin and setup.sh for container [`044ea4c`](https://github.com/craigerl/aprsd/commit/044ea4cc9a0059101851d6e722e986ee236833e8)
52
- - added healthcheck.sh [`1054999`](https://github.com/craigerl/aprsd/commit/10549995686b08e4c166f780efdec5bdae496cab)
53
- - updated healthcheck.sh [`dabb48c`](https://github.com/craigerl/aprsd/commit/dabb48c6f64062c1fed8f83a4f0b8ffba0c206a5)
54
- - try making image for webchat [`ba8acdc`](https://github.com/craigerl/aprsd/commit/ba8acdc5849fc7b2d8a1ee11af6f5e317cf30f45)
55
- - Added APRSD logo [`0ed648f`](https://github.com/craigerl/aprsd/commit/0ed648f8f8a961dbbd9e22bcebadcde525ee41ae)
56
- - Added plugin and extension links [`447451c`](https://github.com/craigerl/aprsd/commit/447451c6c97e1f2d3d0bf580db21ecd176690258)
57
- - reduced logo size 50% [`cf4a29f`](https://github.com/craigerl/aprsd/commit/cf4a29f0cb3ed366b21ec3120a189614e0955180)
58
- - Updated README.md TOC [`375a5e5`](https://github.com/craigerl/aprsd/commit/375a5e5b34718cadc6ee8a51484fc91441440a61)
59
- - chore: update AUTHORS [skip ci] [`c556f51`](https://github.com/craigerl/aprsd/commit/c556f5126f725904822a75427475d46986f8e9f3)
60
- - Updated requirements [`4a7a902`](https://github.com/craigerl/aprsd/commit/4a7a902a337759a352560d4d92dc314b1726412a)
61
- - Updated ChangeLog for 4.0.0 [`934ebd2`](https://github.com/craigerl/aprsd/commit/934ebd236d044625b911dd8ca45293f6c5680a68)
62
101
 
63
102
  #### [3.4.4](https://github.com/craigerl/aprsd/compare/3.4.3...3.4.4)
64
103
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: aprsd
3
- Version: 4.0.1
3
+ Version: 4.1.0
4
4
  Summary: APRSd is a APRS-IS server that can be used to connect to APRS-IS and send and receive APRS packets.
5
5
  Author-email: Craig Lamparter <craig@craiger.org>, "Walter A. Boring IV" <waboring@hemna.com>, Emre Saglam <emresaglam@gmail.com>, Jason Martin <jhmartin@toger.us>, John <johng42@users.noreply.github.com>, Martiros Shakhzadyan <vrzh@vrzh.net>, Zoe Moore <zoenb@mailbox.org>, ranguli <hello@joshmurphy.ca>
6
6
  Maintainer-email: Craig Lamparter <craig@craiger.org>, "Walter A. Boring IV" <waboring@hemna.com>
@@ -1,6 +1,7 @@
1
1
  import datetime
2
2
  import logging
3
3
  import select
4
+ import socket
4
5
  import threading
5
6
 
6
7
  import aprslib
@@ -18,7 +19,7 @@ from aprslib.exceptions import (
18
19
  import aprsd
19
20
  from aprsd.packets import core
20
21
 
21
- LOG = logging.getLogger("APRSD")
22
+ LOG = logging.getLogger('APRSD')
22
23
 
23
24
 
24
25
  class Aprsdis(aprslib.IS):
@@ -31,7 +32,7 @@ class Aprsdis(aprslib.IS):
31
32
  aprsd_keepalive = datetime.datetime.now()
32
33
 
33
34
  # Which server we are connected to?
34
- server_string = "None"
35
+ server_string = 'None'
35
36
 
36
37
  # timeout in seconds
37
38
  select_timeout = 1
@@ -39,10 +40,10 @@ class Aprsdis(aprslib.IS):
39
40
 
40
41
  def stop(self):
41
42
  self.thread_stop = True
42
- LOG.warning("Shutdown Aprsdis client.")
43
+ LOG.warning('Shutdown Aprsdis client.')
43
44
 
44
45
  def close(self):
45
- LOG.warning("Closing Aprsdis client.")
46
+ LOG.warning('Closing Aprsdis client.')
46
47
  super().close()
47
48
 
48
49
  @wrapt.synchronized(lock)
@@ -54,6 +55,57 @@ class Aprsdis(aprslib.IS):
54
55
  """If the connection is alive or not."""
55
56
  return self._connected
56
57
 
58
+ def _connect(self):
59
+ """
60
+ Attemps connection to the server
61
+ """
62
+
63
+ self.logger.info(
64
+ 'Attempting connection to %s:%s', self.server[0], self.server[1]
65
+ )
66
+
67
+ try:
68
+ self._open_socket()
69
+
70
+ peer = self.sock.getpeername()
71
+
72
+ self.logger.info('Connected to %s', str(peer))
73
+
74
+ # 5 second timeout to receive server banner
75
+ self.sock.setblocking(1)
76
+ self.sock.settimeout(5)
77
+
78
+ self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
79
+ # MACOS doesn't have TCP_KEEPIDLE
80
+ if hasattr(socket, 'TCP_KEEPIDLE'):
81
+ self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 1)
82
+ self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 3)
83
+ self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 5)
84
+
85
+ banner = self.sock.recv(512)
86
+ if is_py3:
87
+ banner = banner.decode('latin-1')
88
+
89
+ if banner[0] == '#':
90
+ self.logger.debug('Banner: %s', banner.rstrip())
91
+ else:
92
+ raise ConnectionError('invalid banner from server')
93
+
94
+ except ConnectionError as e:
95
+ self.logger.error(str(e))
96
+ self.close()
97
+ raise
98
+ except (socket.error, socket.timeout) as e:
99
+ self.close()
100
+
101
+ self.logger.error('Socket error: %s' % str(e))
102
+ if str(e) == 'timed out':
103
+ raise ConnectionError('no banner from server') from e
104
+ else:
105
+ raise ConnectionError(e) from e
106
+
107
+ self._connected = True
108
+
57
109
  def _socket_readlines(self, blocking=False):
58
110
  """
59
111
  Generator for complete lines, received from the server
@@ -61,12 +113,12 @@ class Aprsdis(aprslib.IS):
61
113
  try:
62
114
  self.sock.setblocking(0)
63
115
  except OSError as e:
64
- self.logger.error(f"socket error when setblocking(0): {str(e)}")
65
- raise aprslib.ConnectionDrop("connection dropped")
116
+ self.logger.error(f'socket error when setblocking(0): {str(e)}')
117
+ raise aprslib.ConnectionDrop('connection dropped') from e
66
118
 
67
119
  while not self.thread_stop:
68
- short_buf = b""
69
- newline = b"\r\n"
120
+ short_buf = b''
121
+ newline = b'\r\n'
70
122
 
71
123
  # set a select timeout, so we get a chance to exit
72
124
  # when user hits CTRL-C
@@ -91,11 +143,11 @@ class Aprsdis(aprslib.IS):
91
143
  # We could just not be blocking, so empty is expected
92
144
  continue
93
145
  else:
94
- self.logger.error("socket.recv(): returned empty")
95
- raise aprslib.ConnectionDrop("connection dropped")
146
+ self.logger.error('socket.recv(): returned empty')
147
+ raise aprslib.ConnectionDrop('connection dropped')
96
148
  except OSError as e:
97
149
  # self.logger.error("socket error on recv(): %s" % str(e))
98
- if "Resource temporarily unavailable" in str(e):
150
+ if 'Resource temporarily unavailable' in str(e):
99
151
  if not blocking:
100
152
  if len(self.buf) == 0:
101
153
  break
@@ -111,22 +163,22 @@ class Aprsdis(aprslib.IS):
111
163
  """
112
164
  Sends login string to server
113
165
  """
114
- login_str = "user {0} pass {1} vers github.com/craigerl/aprsd {3}{2}\r\n"
166
+ login_str = 'user {0} pass {1} vers Python-APRSD {3}{2}\r\n'
115
167
  login_str = login_str.format(
116
168
  self.callsign,
117
169
  self.passwd,
118
- (" filter " + self.filter) if self.filter != "" else "",
170
+ (' filter ' + self.filter) if self.filter != '' else '',
119
171
  aprsd.__version__,
120
172
  )
121
173
 
122
- self.logger.debug("Sending login information")
174
+ self.logger.debug('Sending login information')
123
175
 
124
176
  try:
125
177
  self._sendall(login_str)
126
178
  self.sock.settimeout(5)
127
179
  test = self.sock.recv(len(login_str) + 100)
128
180
  if is_py3:
129
- test = test.decode("latin-1")
181
+ test = test.decode('latin-1')
130
182
  test = test.rstrip()
131
183
 
132
184
  self.logger.debug("Server: '%s'", test)
@@ -134,26 +186,26 @@ class Aprsdis(aprslib.IS):
134
186
  if not test:
135
187
  raise LoginError(f"Server Response Empty: '{test}'")
136
188
 
137
- _, _, callsign, status, e = test.split(" ", 4)
138
- s = e.split(",")
189
+ _, _, callsign, status, e = test.split(' ', 4)
190
+ s = e.split(',')
139
191
  if len(s):
140
- server_string = s[0].replace("server ", "")
192
+ server_string = s[0].replace('server ', '')
141
193
  else:
142
- server_string = e.replace("server ", "")
194
+ server_string = e.replace('server ', '')
143
195
 
144
- if callsign == "":
145
- raise LoginError("Server responded with empty callsign???")
196
+ if callsign == '':
197
+ raise LoginError('Server responded with empty callsign???')
146
198
  if callsign != self.callsign:
147
- raise LoginError(f"Server: {test}")
148
- if status != "verified," and self.passwd != "-1":
149
- raise LoginError("Password is incorrect")
199
+ raise LoginError(f'Server: {test}')
200
+ if status != 'verified,' and self.passwd != '-1':
201
+ raise LoginError('Password is incorrect')
150
202
 
151
- if self.passwd == "-1":
152
- self.logger.info("Login successful (receive only)")
203
+ if self.passwd == '-1':
204
+ self.logger.info('Login successful (receive only)')
153
205
  else:
154
- self.logger.info("Login successful")
206
+ self.logger.info('Login successful')
155
207
 
156
- self.logger.info(f"Connected to {server_string}")
208
+ self.logger.info(f'Connected to {server_string}')
157
209
  self.server_string = server_string
158
210
 
159
211
  except LoginError as e:
@@ -164,7 +216,7 @@ class Aprsdis(aprslib.IS):
164
216
  self.close()
165
217
  self.logger.error(f"Failed to login '{e}'")
166
218
  self.logger.exception(e)
167
- raise LoginError("Failed to login")
219
+ raise LoginError('Failed to login') from e
168
220
 
169
221
  def consumer(self, callback, blocking=True, immortal=False, raw=False):
170
222
  """
@@ -180,21 +232,21 @@ class Aprsdis(aprslib.IS):
180
232
  """
181
233
 
182
234
  if not self._connected:
183
- raise ConnectionError("not connected to a server")
235
+ raise ConnectionError('not connected to a server')
184
236
 
185
- line = b""
237
+ line = b''
186
238
 
187
239
  while True and not self.thread_stop:
188
240
  try:
189
241
  for line in self._socket_readlines(blocking):
190
- if line[0:1] != b"#":
242
+ if line[0:1] != b'#':
191
243
  self.aprsd_keepalive = datetime.datetime.now()
192
244
  if raw:
193
245
  callback(line)
194
246
  else:
195
247
  callback(self._parse(line))
196
248
  else:
197
- self.logger.debug("Server: %s", line.decode("utf8"))
249
+ self.logger.debug('Server: %s', line.decode('utf8'))
198
250
  self.aprsd_keepalive = datetime.datetime.now()
199
251
  except ParseError as exp:
200
252
  self.logger.log(
@@ -211,7 +263,7 @@ class Aprsdis(aprslib.IS):
211
263
  exp.packet,
212
264
  )
213
265
  except LoginError as exp:
214
- self.logger.error("%s: %s", exp.__class__.__name__, exp)
266
+ self.logger.error('%s: %s', exp.__class__.__name__, exp)
215
267
  except (KeyboardInterrupt, SystemExit):
216
268
  raise
217
269
  except (ConnectionDrop, ConnectionError):
@@ -227,7 +279,7 @@ class Aprsdis(aprslib.IS):
227
279
  except StopIteration:
228
280
  break
229
281
  except Exception:
230
- self.logger.error("APRS Packet: %s", line)
282
+ self.logger.error('APRS Packet: %s', line)
231
283
  raise
232
284
 
233
285
  if not blocking:
@@ -1,3 +1,4 @@
1
+ import datetime
1
2
  import logging
2
3
  import threading
3
4
  import time
@@ -20,6 +21,9 @@ class APRSDFakeClient(metaclass=trace.TraceWrapperMetaclass):
20
21
  # flag to tell us to stop
21
22
  thread_stop = False
22
23
 
24
+ # date for last time we heard from the server
25
+ aprsd_keepalive = datetime.datetime.now()
26
+
23
27
  lock = threading.Lock()
24
28
  path = []
25
29
 
@@ -63,6 +67,7 @@ class APRSDFakeClient(metaclass=trace.TraceWrapperMetaclass):
63
67
  raw = 'GTOWN>APDW16,WIDE1-1,WIDE2-1:}KM6LYW-9>APZ100,TCPIP,GTOWN*::KM6LYW :KM6LYW: 19 Miles SW'
64
68
  pkt_raw = aprslib.parse(raw)
65
69
  pkt = core.factory(pkt_raw)
70
+ self.aprsd_keepalive = datetime.datetime.now()
66
71
  callback(packet=pkt)
67
72
  LOG.debug(f'END blocking FAKE consumer {self}')
68
73
  time.sleep(8)
@@ -1,32 +1,36 @@
1
+ import datetime
1
2
  import logging
2
3
 
3
- from ax253 import Frame
4
4
  import kiss
5
+ from ax253 import Frame
5
6
  from oslo_config import cfg
6
7
 
7
8
  from aprsd import conf # noqa
8
9
  from aprsd.packets import core
9
10
  from aprsd.utils import trace
10
11
 
11
-
12
12
  CONF = cfg.CONF
13
- LOG = logging.getLogger("APRSD")
13
+ LOG = logging.getLogger('APRSD')
14
14
 
15
15
 
16
16
  class KISS3Client:
17
17
  path = []
18
18
 
19
+ # date for last time we heard from the server
20
+ aprsd_keepalive = datetime.datetime.now()
21
+ _connected = False
22
+
19
23
  def __init__(self):
20
24
  self.setup()
21
25
 
22
26
  def is_alive(self):
23
- return True
27
+ return self._connected
24
28
 
25
29
  def setup(self):
26
30
  # we can be TCP kiss or Serial kiss
27
31
  if CONF.kiss_serial.enabled:
28
32
  LOG.debug(
29
- "KISS({}) Serial connection to {}".format(
33
+ 'KISS({}) Serial connection to {}'.format(
30
34
  kiss.__version__,
31
35
  CONF.kiss_serial.device,
32
36
  ),
@@ -39,7 +43,7 @@ class KISS3Client:
39
43
  self.path = CONF.kiss_serial.path
40
44
  elif CONF.kiss_tcp.enabled:
41
45
  LOG.debug(
42
- "KISS({}) TCP Connection to {}:{}".format(
46
+ 'KISS({}) TCP Connection to {}:{}'.format(
43
47
  kiss.__version__,
44
48
  CONF.kiss_tcp.host,
45
49
  CONF.kiss_tcp.port,
@@ -52,18 +56,34 @@ class KISS3Client:
52
56
  )
53
57
  self.path = CONF.kiss_tcp.path
54
58
 
55
- LOG.debug("Starting KISS interface connection")
56
- self.kiss.start()
59
+ LOG.debug('Starting KISS interface connection')
60
+ try:
61
+ self.kiss.start()
62
+ if self.kiss.protocol.transport.is_closing():
63
+ LOG.warning('KISS transport is closing, not setting consumer callback')
64
+ self._connected = False
65
+ else:
66
+ self._connected = True
67
+ except Exception:
68
+ LOG.error('Failed to start KISS interface.')
69
+ self._connected = False
57
70
 
58
71
  @trace.trace
59
72
  def stop(self):
73
+ if not self._connected:
74
+ # do nothing since we aren't connected
75
+ return
76
+
60
77
  try:
61
78
  self.kiss.stop()
62
79
  self.kiss.loop.call_soon_threadsafe(
63
80
  self.kiss.protocol.transport.close,
64
81
  )
65
- except Exception as ex:
66
- LOG.exception(ex)
82
+ except Exception:
83
+ LOG.error('Failed to stop KISS interface.')
84
+
85
+ def close(self):
86
+ self.stop()
67
87
 
68
88
  def set_filter(self, filter):
69
89
  # This does nothing right now.
@@ -74,18 +94,23 @@ class KISS3Client:
74
94
  frame = Frame.from_bytes(frame_bytes)
75
95
  # Now parse it with aprslib
76
96
  kwargs = {
77
- "frame": frame,
97
+ 'frame': frame,
78
98
  }
79
99
  self._parse_callback(**kwargs)
100
+ self.aprsd_keepalive = datetime.datetime.now()
80
101
  except Exception as ex:
81
- LOG.error("Failed to parse bytes received from KISS interface.")
102
+ LOG.error('Failed to parse bytes received from KISS interface.')
82
103
  LOG.exception(ex)
83
104
 
84
105
  def consumer(self, callback):
85
- LOG.debug("Start blocking KISS consumer")
106
+ if not self._connected:
107
+ raise Exception('KISS transport is not connected')
108
+
86
109
  self._parse_callback = callback
87
- self.kiss.read(callback=self.parse_frame, min_frames=None)
88
- LOG.debug(f"END blocking KISS consumer {self.kiss}")
110
+ if not self.kiss.protocol.transport.is_closing():
111
+ self.kiss.read(callback=self.parse_frame, min_frames=1)
112
+ else:
113
+ self._connected = False
89
114
 
90
115
  def send(self, packet):
91
116
  """Send an APRS Message object."""
@@ -94,24 +119,24 @@ class KISS3Client:
94
119
  path = self.path
95
120
  if isinstance(packet, core.Packet):
96
121
  packet.prepare()
97
- payload = packet.payload.encode("US-ASCII")
122
+ payload = packet.payload.encode('US-ASCII')
98
123
  if packet.path:
99
124
  path = packet.path
100
125
  else:
101
- msg_payload = f"{packet.raw}{{{str(packet.msgNo)}"
126
+ msg_payload = f'{packet.raw}{{{str(packet.msgNo)}'
102
127
  payload = (
103
- ":{:<9}:{}".format(
128
+ ':{:<9}:{}'.format(
104
129
  packet.to_call,
105
130
  msg_payload,
106
131
  )
107
- ).encode("US-ASCII")
132
+ ).encode('US-ASCII')
108
133
 
109
134
  LOG.debug(
110
135
  f"KISS Send '{payload}' TO '{packet.to_call}' From "
111
136
  f"'{packet.from_call}' with PATH '{path}'",
112
137
  )
113
138
  frame = Frame.ui(
114
- destination="APZ100",
139
+ destination='APZ100',
115
140
  source=packet.from_call,
116
141
  path=path,
117
142
  info=payload,