parent
40c241f40f
commit
88a7503a50
11 changed files with 373 additions and 1 deletions
@ -1,3 +1,3 @@ |
|||||||
# get_gps_position |
# get_gps_position |
||||||
|
|
||||||
Reads GPS position from gpds on Linux systems |
Reads GPS position from gpds on Linux systems. This program is used in the PE1RXF Reticulum Portable Server from Mees Electronics. |
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,160 @@ |
|||||||
|
#!/usr/bin/env python |
||||||
|
# -*- coding: utf-8 -*- |
||||||
|
|
||||||
|
""" |
||||||
|
PyDecimalDegrees - geographic coordinates conversion utility. |
||||||
|
|
||||||
|
Copyright (C) 2006-2013 by Mateusz Łoskot <mateusz@loskot.net> |
||||||
|
Copyright (C) 2010-2013 by Evan Wheeler <ewheeler@unicef.org> |
||||||
|
|
||||||
|
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 |
||||||
|
|
@ -0,0 +1,108 @@ |
|||||||
|
#!/usr/bin/env python |
||||||
|
# -*- coding: utf-8 -*- |
||||||
|
|
||||||
|
"""Python APRS Module Geo Utility Function Definitions.""" |
||||||
|
|
||||||
|
import decimaldegrees |
||||||
|
|
||||||
|
__author__ = 'Greg Albrecht W2GMD <oss@undef.net>' # 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 |
||||||
|
|
@ -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 <https://www.gnu.org/licenses/>. |
||||||
|
# |
||||||
|
|
||||||
|
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) |
@ -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) |
||||||
|
|
@ -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 |
@ -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 |
Loading…
Reference in new issue