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 0000000..0e68c2a Binary files /dev/null and b/__pycache__/decimaldegrees.cpython-311.pyc differ diff --git a/__pycache__/decimaldegrees.cpython-37.pyc b/__pycache__/decimaldegrees.cpython-37.pyc new file mode 100644 index 0000000..3f92955 Binary files /dev/null and b/__pycache__/decimaldegrees.cpython-37.pyc differ diff --git a/__pycache__/geo_util.cpython-311.pyc b/__pycache__/geo_util.cpython-311.pyc new file mode 100644 index 0000000..f9fe455 Binary files /dev/null and b/__pycache__/geo_util.cpython-311.pyc differ diff --git a/__pycache__/geo_util.cpython-37.pyc b/__pycache__/geo_util.cpython-37.pyc new file mode 100644 index 0000000..39b7f4a Binary files /dev/null and b/__pycache__/geo_util.cpython-37.pyc differ 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