From 88a7503a50ad702db84de05e000a67506dc178be Mon Sep 17 00:00:00 2001 From: marcel Date: Fri, 31 Jan 2025 14:29:21 +0100 Subject: [PATCH] First commit --- README.md | 2 +- __pycache__/decimaldegrees.cpython-311.pyc | Bin 0 -> 6487 bytes __pycache__/decimaldegrees.cpython-37.pyc | Bin 0 -> 4816 bytes __pycache__/geo_util.cpython-311.pyc | Bin 0 -> 3156 bytes __pycache__/geo_util.cpython-37.pyc | Bin 0 -> 2432 bytes decimaldegrees.py | 160 +++++++++++++++++++++ geo_util.py | 108 ++++++++++++++ get_position.py | 54 +++++++ gps_port.txt | 4 + send_beacon_aprs_1200bd.sh | 23 +++ send_beacon_aprs_lora.sh | 23 +++ 11 files changed, 373 insertions(+), 1 deletion(-) create mode 100644 __pycache__/decimaldegrees.cpython-311.pyc create mode 100644 __pycache__/decimaldegrees.cpython-37.pyc create mode 100644 __pycache__/geo_util.cpython-311.pyc create mode 100644 __pycache__/geo_util.cpython-37.pyc create mode 100644 decimaldegrees.py create mode 100644 geo_util.py create mode 100644 get_position.py create mode 100755 gps_port.txt create mode 100755 send_beacon_aprs_1200bd.sh create mode 100755 send_beacon_aprs_lora.sh diff --git a/README.md b/README.md index 55c80ee..876f384 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ # get_gps_position -Reads GPS position from gpds on Linux systems \ No newline at end of file +Reads GPS position from gpds on Linux systems. This program is used in the PE1RXF Reticulum Portable Server from Mees Electronics. diff --git a/__pycache__/decimaldegrees.cpython-311.pyc b/__pycache__/decimaldegrees.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0e68c2aba2abab6061773cc66be8c56f9577d96f GIT binary patch literal 6487 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 literal 0 HcmV?d00001 diff --git a/__pycache__/geo_util.cpython-311.pyc b/__pycache__/geo_util.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f9fe4555f68de6fd855a39f54a90b3dccb423004 GIT binary patch literal 3156 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 BSL*-( literal 0 HcmV?d00001 diff --git a/decimaldegrees.py b/decimaldegrees.py new file mode 100644 index 0000000..4f2bff6 --- /dev/null +++ b/decimaldegrees.py @@ -0,0 +1,160 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +PyDecimalDegrees - geographic coordinates conversion utility. + +Copyright (C) 2006-2013 by Mateusz Łoskot +Copyright (C) 2010-2013 by Evan Wheeler + +This file is part of PyDecimalDegrees module. + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from +the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + +DESCRIPTION + +DecimalDegrees module provides functions to convert between +degrees/minutes/seconds and decimal degrees. + +Original source distribution: +http://mateusz.loskot.net/software/gis/pydecimaldegrees/ + +Inspired by Walter Mankowski's Geo::Coordinates::DecimalDegrees module +for Perl, originally located in CPAN Archives: +http://search.cpan.org/~waltman/Geo-Coordinates-DecimalDegrees-0.05/ + +doctest examples are based following coordinates: +DMS: 121 8' 6" +DM: 121 8.1' +DD: 121.135 + +To run doctest units just execut this module script as follows +(-v instructs Python to run script in verbose mode): + +$ python decimaldegrees.py [-v] + +""" + +import decimal as libdecimal + +from decimal import Decimal as D + +__revision__ = '$Revision: 1.1 $' + + +def decimal2dms(decimal_degrees): + """ Converts a floating point number of degrees to the equivalent + number of degrees, minutes, and seconds, which are returned + as a 3-element tuple of decimals. If 'decimal_degrees' is negative, + only degrees (1st element of returned tuple) will be negative, + minutes (2nd element) and seconds (3rd element) will always be positive. + + Example: + + >>> decimal2dms(121.135) + (Decimal('121'), Decimal('8'), Decimal('6.000')) + >>> decimal2dms(-121.135) + (Decimal('-121'), Decimal('8'), Decimal('6.000')) + + """ + + degrees = D(int(decimal_degrees)) + decimal_minutes = libdecimal.getcontext().multiply( + (D(str(decimal_degrees)) - degrees).copy_abs(), D(60)) + minutes = D(int(decimal_minutes)) + seconds = libdecimal.getcontext().multiply( + (decimal_minutes - minutes), D(60)) + return (degrees, minutes, seconds) + + +def decimal2dm(decimal_degrees): + """ + Converts a floating point number of degrees to the degress & minutes. + + Returns a 2-element tuple of decimals. + + If 'decimal_degrees' is negative, only degrees (1st element of returned + tuple) will be negative, minutes (2nd element) will always be positive. + + Example: + + >>> decimal2dm(121.135) + (Decimal('121'), Decimal('8.100')) + >>> decimal2dm(-121.135) + (Decimal('-121'), Decimal('8.100')) + + """ + degrees = D(int(decimal_degrees)) + + minutes = libdecimal.getcontext().multiply( + (D(str(decimal_degrees)) - degrees).copy_abs(), D(60)) + + return (degrees, minutes) + + +def dms2decimal(degrees, minutes, seconds): + """ Converts degrees, minutes, and seconds to the equivalent + number of decimal degrees. If parameter 'degrees' is negative, + then returned decimal-degrees will also be negative. + + NOTE: this method returns a decimal.Decimal + + Example: + + >>> dms2decimal(121, 8, 6) + Decimal('121.135') + >>> dms2decimal(-121, 8, 6) + Decimal('-121.135') + + """ + decimal = D(0) + degs = D(str(degrees)) + mins = libdecimal.getcontext().divide(D(str(minutes)), D(60)) + secs = libdecimal.getcontext().divide(D(str(seconds)), D(3600)) + + if degrees >= D(0): + decimal = degs + mins + secs + else: + decimal = degs - mins - secs + + return libdecimal.getcontext().normalize(decimal) + + +def dm2decimal(degrees, minutes): + """ Converts degrees and minutes to the equivalent number of decimal + degrees. If parameter 'degrees' is negative, then returned decimal-degrees + will also be negative. + + Example: + + >>> dm2decimal(121, 8.1) + Decimal('121.135') + >>> dm2decimal(-121, 8.1) + Decimal('-121.135') + + """ + return dms2decimal(degrees, minutes, 0) + + +def run_doctest(): # pragma: no cover + """Runs doctests for this module.""" + import doctest + return doctest.testmod() + + +if __name__ == '__main__': + run_doctest() # pragma: no cover + diff --git a/geo_util.py b/geo_util.py new file mode 100644 index 0000000..0b20fb3 --- /dev/null +++ b/geo_util.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +"""Python APRS Module Geo Utility Function Definitions.""" + +import decimaldegrees + +__author__ = 'Greg Albrecht W2GMD ' # NOQA pylint: disable=R0801 +__copyright__ = 'Copyright 2017 Greg Albrecht and Contributors' # NOQA pylint: disable=R0801 +__license__ = 'Apache License, Version 2.0' # NOQA pylint: disable=R0801 + + +def dec2dm_lat(dec: float) -> str: + """ + Converts DecDeg to APRS Coord format. + + See: http://ember2ash.com/lat.htm + + Source: http://stackoverflow.com/questions/2056750 + + Example: + >>> test_lat = 37.7418096 + >>> aprs_lat = dec2dm_lat(test_lat) + >>> aprs_lat + '3744.51N' + >>> test_lat = -8.01 + >>> aprs_lat = dec2dm_lat(test_lat) + >>> aprs_lat + '0800.60S' + """ + dec_min = decimaldegrees.decimal2dm(dec) + + deg = dec_min[0] + abs_deg = abs(deg) + + if not deg == abs_deg: + suffix = 'S' + else: + suffix = 'N' + + return "%02d%05.2f%s" % (abs_deg, dec_min[1], suffix) + + +def dec2dm_lng(dec: float) -> str: + """ + Converts DecDeg to APRS Coord format. + + See: http://ember2ash.com/lat.htm + + Example: + >>> test_lng = 122.38833 + >>> aprs_lng = dec2dm_lng(test_lng) + >>> aprs_lng + '12223.30E' + >>> test_lng = -99.01 + >>> aprs_lng = dec2dm_lng(test_lng) + >>> aprs_lng + '09900.60W' + """ + dec_min = decimaldegrees.decimal2dm(dec) + + deg = dec_min[0] + abs_deg = abs(deg) + + if not deg == abs_deg: + suffix = 'W' + else: + suffix = 'E' + + return "%03d%05.2f%s" % (abs_deg, dec_min[1], suffix) + + +def ambiguate(pos: float, ambiguity: int) -> str: + """ + Adjust ambiguity of position. + + Derived from @asdil12's `process_ambiguity()`. + + >>> pos = '12345.67N' + >>> ambiguate(pos, 0) + '12345.67N' + >>> ambiguate(pos, 1) + '12345.6 N' + >>> ambiguate(pos, 2) + '12345. N' + >>> ambiguate(pos, 3) + '1234 . N' + """ + num = bytearray(pos, 'UTF-8') + for i in range(0, ambiguity): + if i > 1: + # skip the dot + i += 1 + # skip the direction + i += 2 + num[-i] = ord(' ') + return num.decode() + + +def run_doctest(): # pragma: no cover + """Runs doctests for this module.""" + import doctest + return doctest.testmod() + + +if __name__ == '__main__': + run_doctest() # pragma: no cover + diff --git a/get_position.py b/get_position.py new file mode 100644 index 0000000..b7686b9 --- /dev/null +++ b/get_position.py @@ -0,0 +1,54 @@ +# +# Simple program to read gpsd and return the APRS formatted position string including the APRS symbol. +# Can be used to generate position beacons +# +# (C)2025 M.T. Konstapel https://meezenest.nl/mees +# +# get_position.oy is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# PE1RXF-APRS-server is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +import gpsd2 + +import geo_util + +# Define APRS symbol, camp ground = /; +SymbolTableIdentifier = '/' +SymbolCode = ';' + +try: + # Connect to the local gpsd + gpsd2.connect() + + # Connect somewhere else + gpsd2.connect(host="127.0.0.1", port=2947) + + # Get gps position + packet = gpsd2.get_current() + + # See the inline docs for GpsResponse for the available data + aprs_position = packet.position() +except: + aprs_position = (0,0) + + +# Translate the gps location data to the APRS location standard +aprs_lat = geo_util.dec2dm_lat(aprs_position[0]) +aprs_lng = geo_util.dec2dm_lng(aprs_position[1]) +aprs_location='!'+aprs_lat+SymbolTableIdentifier+aprs_lng+SymbolCode + +aprs_beacon = aprs_location + 'Portable HAM station' + +print(aprs_location) +#print(aprs_beacon) diff --git a/gps_port.txt b/gps_port.txt new file mode 100755 index 0000000..ac53981 --- /dev/null +++ b/gps_port.txt @@ -0,0 +1,4 @@ +Serial port gps module: + +serial_port=$(readlink -f /dev/serial/by-path/platform-20980000.usb-usb-0:1.3:1.0-port0) + diff --git a/send_beacon_aprs_1200bd.sh b/send_beacon_aprs_1200bd.sh new file mode 100755 index 0000000..2e91994 --- /dev/null +++ b/send_beacon_aprs_1200bd.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +POSITION="$(/usr/bin/python /home/marcel/ham/gps/get_position.py)" +INFO="Portable HAM Station" + +if [ "$POSITION" != "!0000.00N/00000.00E;" ]; then + + # Set arguments for beacon program + args[0]=-d + args[1]="APRX29 $Path" + args[2]=-s + args[3]=aprs_1200bd + args[4]="$POSITION$INFO" + + # Send position beacon + /usr/sbin/beacon "${args[@]}" + + echo "Position beacon send." + + #/usr/sbin/beacon -d "APRX29" -s aprs_lora $BEACON +else + echo "No GPS signal found. Nothing to do." +fi diff --git a/send_beacon_aprs_lora.sh b/send_beacon_aprs_lora.sh new file mode 100755 index 0000000..e2adfaf --- /dev/null +++ b/send_beacon_aprs_lora.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +POSITION="$(/usr/bin/python /home/marcel/ham/gps/get_position.py)" +INFO="Portable HAM Station" + +if [ "$POSITION" != "!0000.00N/00000.00E;" ]; then + + # Set arguments for beacon program + args[0]=-d + args[1]="APRX29 $Path" + args[2]=-s + args[3]=aprs_lora + args[4]="$POSITION$INFO" + + # Send position beacon + /usr/sbin/beacon "${args[@]}" + + echo "Position beacon send." + + #/usr/sbin/beacon -d "APRX29" -s aprs_lora $BEACON +else + echo "No GPS signal found. Nothing to do." +fi