First commit
This commit is contained in:
@@ -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.
|
||||||
|
BIN
__pycache__/decimaldegrees.cpython-311.pyc
Normal file
BIN
__pycache__/decimaldegrees.cpython-311.pyc
Normal file
Binary file not shown.
BIN
__pycache__/decimaldegrees.cpython-37.pyc
Normal file
BIN
__pycache__/decimaldegrees.cpython-37.pyc
Normal file
Binary file not shown.
BIN
__pycache__/geo_util.cpython-311.pyc
Normal file
BIN
__pycache__/geo_util.cpython-311.pyc
Normal file
Binary file not shown.
BIN
__pycache__/geo_util.cpython-37.pyc
Normal file
BIN
__pycache__/geo_util.cpython-37.pyc
Normal file
Binary file not shown.
160
decimaldegrees.py
Normal file
160
decimaldegrees.py
Normal file
@@ -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
|
||||||
|
|
108
geo_util.py
Normal file
108
geo_util.py
Normal file
@@ -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
|
||||||
|
|
54
get_position.py
Normal file
54
get_position.py
Normal file
@@ -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)
|
4
gps_port.txt
Executable file
4
gps_port.txt
Executable file
@@ -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)
|
||||||
|
|
23
send_beacon_aprs_1200bd.sh
Executable file
23
send_beacon_aprs_1200bd.sh
Executable file
@@ -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
|
23
send_beacon_aprs_lora.sh
Executable file
23
send_beacon_aprs_lora.sh
Executable file
@@ -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
|
Reference in New Issue
Block a user