Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Faraday-APRS Persistent Across Network Failures #271

Merged
merged 28 commits into from
Sep 10, 2017
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
dad1f90
Initial addition of APRS BASE91 Code
kb1lqc Sep 5, 2017
62263c5
ADC0, ADC1, ADC3, ADC6, and BOARDTEMP BASE91
kb1lqc Sep 5, 2017
5ccd19a
Added telemetry sequence to sendPosition
kb1lqc Sep 5, 2017
74212a3
Working telemetry and some hacked in telemetry seq
kb1lqc Sep 5, 2017
eb55358
Per @rossengeorgiev there is a width for BASE91
kb1lqc Sep 5, 2017
d132474
Cleaned up APRS Position Telemetry Code
kb1lqc Sep 5, 2017
0a57a3b
Added IO to position comment data
kb1lqc Sep 7, 2017
7ead5f3
Only send Parameters, Labels, and Equations once
kb1lqc Sep 7, 2017
b82e2fd
Fixed up pytest PEP8 Failures
kb1lqc Sep 8, 2017
161145c
Updated comments for sendPosition() function
kb1lqc Sep 8, 2017
541f10c
Reversed 4095 hardcoded values in sendTelemetry
kb1lqc Sep 8, 2017
e68b408
Just got reconnection working!
kb1lqc Sep 8, 2017
4db85fb
Removed unnecessary comment in sendPositions
kb1lqc Sep 8, 2017
8eafdf5
Simplified packet sending with sendAPRSPacket
kb1lqc Sep 8, 2017
041a922
Removed commented out code and added documentation
kb1lqc Sep 8, 2017
bf2a6f1
Send all packets on 10th loop
kb1lqc Sep 8, 2017
0565340
Implemented sendAPRSPacket() on all packets
kb1lqc Sep 8, 2017
982b169
Updated sendAPRSPacket documenation
kb1lqc Sep 8, 2017
ffe768d
Fixed pytest errors/warnings
kb1lqc Sep 8, 2017
5c47607
Updated parameter names
kb1lqc Sep 8, 2017
83ae953
Fixed reconnection issue on extended network loss
kb1lqc Sep 9, 2017
799b61f
Removed development code/comments
kb1lqc Sep 10, 2017
ac65bd6
Removed extra line under if statement
kb1lqc Sep 10, 2017
b354512
Replaced return status with reture sendAPRSPacket
kb1lqc Sep 10, 2017
a0e6d73
Removed useless break statement after return
kb1lqc Sep 10, 2017
ddcb2ff
Cleaned up commented code and sock initialization
kb1lqc Sep 10, 2017
75d6930
Removed passing of sock variable to threads
kb1lqc Sep 10, 2017
f529c01
Updated reconnect comment and BASE91 comment add
kb1lqc Sep 10, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions etc/faraday/aprs.sample.ini
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ BLABEL7=IO

ADC0PARAM=ADC0
ADC1PARAM=ADC1
ADC2PARAM=ADC2
ADC3PARAM=ADC7
ADC4PARAM=ADC8
ADC2PARAM=ADC3
ADC3PARAM=ADC6
ADC4PARAM=TEMP
IO0PARAM=IO
IO1PARAM=IO
IO2PARAM=IO
Expand All @@ -65,4 +65,4 @@ EQ3B=1
EQ3C=0
EQ4A=0
EQ4B=1
EQ4C=0
EQ4C=0
171 changes: 98 additions & 73 deletions faraday/aprs.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from time import sleep
import sys
import argparse
from aprslib import base91

from classes import helper

Expand Down Expand Up @@ -103,6 +104,11 @@ def aprs_worker(config, sock):
# Local variable initialization
telemSequence = 0

#dev
sock = ''
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is unnecessary.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed, conn=False now used in the initialization just above to force it to initialize on first loop. Thanks for catching this!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: This statement is unnecessary.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

sock = connectAPRSIS()
conn = True

# Start infinite loop to send station data to APRS-IS
while True:
# Query telemetry database for station data
Expand All @@ -114,11 +120,21 @@ def aprs_worker(config, sock):
logger.info(str.format(len(stations)))

# Iterate through all stations sending telemetry and position data
sendPositions(stationData, sock)
telemSequence = sendtelemetry(stationData, telemSequence, sock)
sendTelemLabels(stationData, sock)
sendParameters(stationData, sock)
sendEquations(stationData, sock)
if not conn:
sock = connectAPRSIS()
try:
conn = sendPositions(telemSequence, stationData, sock)

# Just send labels, Parameters, and Equations every 10th loop
if telemSequence % 10 == 0:

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Extra blank line.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed

sendTelemLabels(stationData, sock)
sendParameters(stationData, sock)
sendEquations(stationData, sock)
telemSequence += 1

except StandardError as e:
logger.error(e)

# Sleep for intended update rate (seconds)
sleep(rate)
Expand Down Expand Up @@ -231,10 +247,33 @@ def nmeaToDegDecMin(latitude, longitude):
return [latString, lonString]


def sendPositions(stations, socket):
def sendAPRSPacket(socket, packet):
"""
Sends an APRS packet (just a string) to the socket specified. If an
error occurs a False is returned while a True is returned if successful.
On an error, the socket is closed as it is no longer useful.

:param socket: APRS-IS server internet socket
:param packet: String to be sent to APRS-IS
:return: Boolean
"""

try:
socket.sendall(packet)
return True

except IOError as e:
logger.error(e)
socket.close()
return False


def sendPositions(telemSequence, stations, socket):
"""
Constructs an APRS position string for station and sends to a socket
Constructs an APRS position string for station and sends to a socket.
Includes BASE91 comment telemetry functionality as well.

:param telemSequence: Telemetry sequence number
:param stations: List of dictionary organized station data
:param socket: APRS-IS server internet socket
:return: None
Expand Down Expand Up @@ -268,11 +307,37 @@ def sendPositions(stations, socket):
altSymbol = aprsConfig.get('APRS', 'ALTSYMBOL')
comment = aprsConfig.get('APRS', 'COMMENT')
altComment = aprsConfig.get('APRS', 'ALTCOMMENT')
ioSource = aprsConfig.get('APRS', 'IOSOURCE').upper()

# Create nodes from GPS data
node = sourceCallsign + "-" + str(sourceID)
destNode = destinationCallsign + "-" + str(destinationID)

#Obtain GPIO data
gpioValues = station["GPIOSTATE"]
rfValues = station["RFSTATE"]

# Extract IO data
if ioSource == 'GPIO':
ioList = gpioValues
elif ioSource == 'RF':
ioList = rfValues

# Generate BASE91 telemetry with aprslib using a width of 2
b91seq = base91.from_decimal(telemSequence, 2)
b91a = base91.from_decimal(station["ADC0"], 2)
b91b = base91.from_decimal(station["ADC1"], 2)
b91c = base91.from_decimal(station["ADC3"], 2)
b91d = base91.from_decimal(station["ADC6"], 2)
b91e = base91.from_decimal(station["BOARDTEMP"], 2)
b91f = base91.from_decimal(ioList, 2)

b91Tlm = "|{0}{1}{2}{3}{4}{5}{6}|".format(b91seq, b91a, b91b, b91c, b91d, b91e, b91f)

# add telemetry to comments
comment = comment + b91Tlm
altComment = altComment + b91Tlm
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment += b91Tlm
altComment += b91Tlm

a += b is more efficient than a = a + b.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated


# Convert position to APRS-IS compliant string
latString, lonString = nmeaToDegDecMin(latitude, longitude)

Expand Down Expand Up @@ -317,11 +382,8 @@ def sendPositions(stations, socket):

logger.debug(positionString)

try:
socket.sendall(positionString)

except IOError as e:
logger.error(e)
status = sendAPRSPacket(socket, positionString)
return status
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return sendAPRSPacket(socket, positionString)

Here and below.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All return status lines replaced with obviously better return sendAPRSPacket(). Thanks for observing this unnecessary addition of variables!


elif node == destNode:
# APRS string is for local node
Expand All @@ -342,12 +404,8 @@ def sendPositions(stations, socket):
altComment)
logger.debug(positionString)

try:
socket.sendall(positionString)

except IOError as e:
logger.error("SendPosition")
logger.error(e)
status = sendAPRSPacket(socket, positionString)
return status


def sendtelemetry(stations, telemSequence, socket):
Expand Down Expand Up @@ -403,12 +461,8 @@ def sendtelemetry(stations, telemSequence, socket):

logger.debug(telemetry)

try:
socket.sendall(telemetry)

except IOError as e:
logger.error("SendTelemetry")
logger.error(e)
status = sendAPRSPacket(socket, telemetry)
return status

elif node == destNode:
# APRS string is for local node
Expand All @@ -425,12 +479,8 @@ def sendtelemetry(stations, telemSequence, socket):

logger.debug(telemetry)

try:
socket.sendall(telemetry)

except IOError as e:
logger.error("Sendtelemetry")
logger.error(e)
status = sendAPRSPacket(socket, telemetry)
return status

# Check for telemetry sequence rollover
if telemSequence >= 999:
Expand Down Expand Up @@ -493,25 +543,16 @@ def sendTelemLabels(stations, socket):
node, destAddress, qConstruct, destNode, node, unitsAndLabels)
logger.debug(labels)

try:
socket.sendall(labels)

except IOError as e:
logger.error("SendTelemLabels")
logger.error(e)
status = sendAPRSPacket(socket, labels)
return status

elif node == destNode:
# APRS string is for local node
labels = '{}>{}::{} :UNIT.{}\r'.format(
node, destAddress, node, unitsAndLabels)

logger.debug(labels)
try:
socket.sendall(labels)

except IOError as e:
logger.error("SendTelemLabels")
logger.error(e)
status = sendAPRSPacket(socket, labels)
return status


def sendParameters(stations, socket):
Expand Down Expand Up @@ -564,26 +605,16 @@ def sendParameters(stations, socket):
parameters = '{}>{},{},{}::{} :PARM.{}\r'.format(
node, destAddress, qConstruct, destNode, node, adcAndIoParams)

logger.debug(parameters)
try:
socket.sendall(parameters)

except IOError as e:
logger.error("SendParameters")
logger.error(e)
status = sendAPRSPacket(socket, parameters)
return status

elif node == destNode:
# APRS string is for local node
parameters = '{}>{}::{} :PARM.{}\r'.format(
node, destAddress, node, adcAndIoParams)

logger.debug(parameters)
try:
socket.sendall(parameters)

except IOError as e:
logger.error("SendParameters")
logger.error(e)
status = sendAPRSPacket(socket, parameters)
return status


def sendEquations(stations, socket):
Expand Down Expand Up @@ -636,26 +667,16 @@ def sendEquations(stations, socket):
equations = '{}>{},{},{}::{} :EQNS.{}\r'.format(
node, destAddress, qConstruct, destNode, node, equationConfig)

logger.debug(equations)
try:
socket.sendall(equations)

except IOError as e:
logger.error("SendEquations")
logger.error(e)
status = sendAPRSPacket(socket, equations)
return status

elif node == destNode:
# APRS string is for local node
equations = '{}>{}::{} :EQNS.{}\r'.format(
node, destAddress, node, equationConfig)

logger.debug(equations)
try:
socket.sendall(equations)

except IOError as e:
logger.error("SendEquations")
logger.error(e)
status = sendAPRSPacket(socket, equations)
return status


def connectAPRSIS():
Expand Down Expand Up @@ -693,14 +714,17 @@ def connectAPRSIS():
aprssock.sendall(logon_string)

except IOError as e:
# Close socket and setup for next connection attempt
logger.error(e)
aprssock.close()
aprssock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

else:
logger.info("Connection successful!")
return aprssock
break
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not this change, but break after return does nothing.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed


sleep(10) # Try to reconnect every 10 seconds
sleep(2) # Try to reconnect every 10 seconds
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update the comment?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

return aprssock
else:
while True:
Expand Down Expand Up @@ -762,7 +786,8 @@ def main():
"""

logger.info('Starting Faraday APRS-IS application')
sock = connectAPRSIS()
#sock = connectAPRSIS()
sock = ''
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why pass sock to aprs_worker at all if it calls connectAPRSIS() itself?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I used to need this but with the current implementation of the socket connections I do not. Removed!


# Initialize local variables
threads = []
Expand Down