Skip to content

Commit

Permalink
Improved telemetry retry
Browse files Browse the repository at this point in the history
  • Loading branch information
connervieira committed Jan 18, 2025
1 parent 6d3d93b commit 6754db2
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 39 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -599,3 +599,5 @@ November 20th, 2024
- `ext` is replaced by the file extension.
- Added `--help` commmand line option.
- Fixed GPS demo mode.
- Improved the reliability of file copying and erasing via management.
- Previously, this functionality might have behaved unexpected when the file path involved spaces.
1 change: 1 addition & 0 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ These are the features actively planned for Predator and are likely to be added
- [X] Validate multi-channel recording.
- [ ] Add sound effect for parking mode.
- [ ] Add management mode option to manually upload telemetry back-log.
- [ ] Fix management mode for dashcam video (main.py:452 and 550)


## Issues
Expand Down
36 changes: 19 additions & 17 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@
clear()
print(style.bold + style.red + "Privacy" + style.end)
print("Predator does not share telemetry or usage data with V0LT, or any other entity. However, by default, Predator will attach a random identifier to requests made to remote license plate list sources (as configured under `general>alerts>databases`). This identifier allows administrators of servers hosting license plate lists to roughly count how many clients are using their lists. If you're concerned about the administrator of one of your remote license plate lists using this unique identifier to derive information about how often you use Predator (based on when you fetch their lists), you can disable this functionality using the `developer>identify_to_remote_sources` configuration value.")
print("Additionally, by default, Predator will fetch a hardcoded ignore list from the V0LT website. Once again, this functionality does not send any identifiable information or telemetry data. To disable this functionality, either enable the `developer>offline` configuration value to disable all network requests, or remove the hardcoded ignore list from `ignore.py`.")
print("Additionally, by default, Predator will fetch a hardcoded ignore list from the V0LT website. This functionality does not send any identifiable information or telemetry data (even when identify_to_remote_sources is enabled). To disable this functionality, either enable the `developer>offline` configuration value to disable all network requests, or remove the hardcoded ignore list from `ignore.py`.")
print("For more information, see the `docs/CONFIGURE.md` document.")
input(style.faint + "Press enter to continue..." + style.end)

Expand Down Expand Up @@ -430,26 +430,28 @@

# Prompt the user for the copying destination.
copy_destination = "" # Set the copy_destination as a blank placeholder.
while os.path.exists(copy_destination) == False: # Repeatedly ask the user for a valid copy destination until they enter one that is valid.
copy_destination = prompt("Destination path: ", optional=False, input_type=str) # Prompt the user for a destination path.
while os.path.isdir(copy_destination) == False: # Repeatedly ask the user for a valid copy destination until they enter one that is valid.
copy_destination = prompt("Destination directory: ", optional=False, input_type=str) # Prompt the user for a destination path.
if (os.path.isdir(copy_destination) == False):
display_message("The specified destination is not a valid directory.", 2)


# Copy the files as per the user's inputs.
print("Copying files...")
if (copy_management_configuration):
os.system("cp " + predator_root_directory + "/config.json " + copy_destination)
os.system("cp \"" + predator_root_directory + "/config.json\" \"" + copy_destination + "\"")
if (copy_prerecorded_processed_frames):
os.system("cp -r " + config["general"]["working_directory"] + "/frames " + copy_destination)
os.system("cp -r \"" + config["general"]["working_directory"] + "/frames\" \"" + copy_destination + "\"")
if (copy_prerecorded_gpx_files):
os.system("cp " + config["general"]["working_directory"] + "/*.gpx " + copy_destination)
os.system("cp \"" + config["general"]["working_directory"] + "/*.gpx\" \"" + copy_destination + "\"")
if (copy_prerecorded_license_plate_analysis_data):
os.system("cp " + config["general"]["working_directory"] + "/pre_recorded_license_plate_export.* " + copy_destination)
os.system("cp \"" + config["general"]["working_directory"] + "/pre_recorded_license_plate_export.*\" \"" + copy_destination + "\"")
if (copy_prerecorded_license_plate_location_data):
os.system("cp " + config["general"]["working_directory"] + "/pre_recorded_location_data_export.* " + copy_destination)
os.system("cp \"" + config["general"]["working_directory"] + "/pre_recorded_location_data_export.*\" \"" + copy_destination + "\"")
if (copy_realtime_license_plate_recognition_data):
os.system("cp " + config["general"]["working_directory"] + "/real_time_plates* " + copy_destination)
os.system("cp \"" + config["general"]["working_directory"] + "/real_time_plates*\" \"" + copy_destination + "\"")
if (copy_dashcam_video):
os.system("cp " + config["general"]["working_directory"] + "/predator_dashcam* " + copy_destination)
os.system("cp \"" + os.path.join(config["general"]["working_directory"], "*Predator*." + config["dashcam"]["saving"]["file"]["extension"]) + "\" \"" + copy_destination + "\"")

clear()
print("Files have finished copying.")
Expand Down Expand Up @@ -535,19 +537,19 @@
if (prompt("Are you sure you want to delete the selected files permanently? (y/n): ").lower() == "y"):
print("Deleting files...")
if (delete_management_custom):
os.system("rm -r " + config["general"]["working_directory"] + "/" + delete_custom_file_name)
os.system("rm -r \"" + config["general"]["working_directory"] + "/" + delete_custom_file_name + "\"")
if (delete_prerecorded_processed_frames):
os.system("rm -r " + config["general"]["working_directory"] + "/frames")
os.system("rm -r \"" + config["general"]["working_directory"] + "/frames\"")
if (delete_prerecorded_gpx_files):
os.system("rm " + config["general"]["working_directory"] + "/*.gpx")
os.system("rm \"" + config["general"]["working_directory"] + "/*.gpx\"")
if (delete_prerecorded_license_plate_analysis_data):
os.system("rm " + config["general"]["working_directory"] + "/pre_recorded_license_plate_export.*")
os.system("rm \"" + config["general"]["working_directory"] + "/pre_recorded_license_plate_export.*\"")
if (delete_prerecorded_license_plate_location_data):
os.system("rm " + config["general"]["working_directory"] + "/pre_recorded_location_data_export.*")
os.system("rm \"" + config["general"]["working_directory"] + "/pre_recorded_location_data_export.*\"")
if (delete_realtime_license_plate_recognition_data):
os.system("rm " + config["general"]["working_directory"] + "/real_time_plates*")
os.system("rm \"" + config["general"]["working_directory"] + "/real_time_plates*\"")
if (delete_dashcam_video):
os.system("rm " + config["general"]["working_directory"] + "/predator_dashcam*")
os.system("rm \"" + os.path.join(config["general"]["working_directory"], "*Predator*." + config["dashcam"]["saving"]["file"]["extension"]) + "\"")
clear()
print("Files have finished deleting.")
else:
Expand Down
36 changes: 14 additions & 22 deletions utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -918,25 +918,6 @@ def send_telemetry(data):
data["system"] = {}
data["system"]["timezone"] = timezone_offset_stamp # Add the system timezone to the data.

# Format:
# data = {
# "system": { # Must be present
# "timezone": "UTC+00:00" # Must be present and valid.
# },
# "image": { # Can be omitted if no image data is present.
# "main": [OpenCV image],
# "rear": "[OpenCV image]",
# ...
# },
# "location": { # Must be present, but can be set to all zeros.
# "time": 0.0,
# "lat": 0.0,
# "lon": 0.0,
# "alt": 0.0,
# "spd": 0.0,
# "head": 0.0
# }
# }
if (time.time() - last_telemetry_sent >= 10): # Check to see if it has been at least 10 seconds since the last telemetry update. Note: most external receivers (such as V0LT Portal) will reject any data within 10 seconds of a previous datapoint.
for device in data["image"]:
# Rescale the image to 720p:
Expand Down Expand Up @@ -968,29 +949,40 @@ def send_telemetry(data):
else:
display_message("The remote telemetry provider responded with an unknown error.", 2)
else:
display_message("The response from the remote telemetry provider was not valid JSON.", 2)
display_message("The response from the remote telemetry provider was not valid JSON. (" + str(response) + ")", 2)
success = False
except Exception as exception:
display_message("The telemetry upload process failed with the following exception:", 2)
print(exception)
success = False

if (success == True):
if (success == True): # Check to see if the current submission was successful.
if (len(telemetry_backlog) > 0): # Check to see if there is at least one request in the back-log.
consecutive_failures = 0 # This will count consecutive failures to we can tell if we should abort.
for timestamp in list(telemetry_backlog.keys()): # Iterate over each entry in the telemetry back-log.
try:
request = requests.post(config["dashcam"]["telemetry"]["target"], data={"identifier": config["dashcam"]["telemetry"]["vehicle_identifier"], "data": json.dumps(telemetry_backlog[timestamp])}, timeout=8) # Submit the data.
response = json.loads(request.content)
if ("success" in response and response["success"] == True):
success = True
else:
if ("code" in response): # Check to see if an error code was returned.
if (response["code"] in ["timezone_offset_invalid"]): # Check to see if the error code matches a type that would cause all of the other points to fail as well.
break
elif (response["code"] in ["timestamp_invalid"]): # Check to see if the error code matches a type that would cause this entry to fail forever.
del telemetry_backlog[timestamp] # Delete this point from the back-log.
success = False
except Exception as e:
success = False
if (success == True): # Check to see if the data submission was successful.
consecutive_failures = 0 # Reset the consecutive failure counter.
del telemetry_backlog[timestamp] # Delete this point from the back-log.
else:
consecutive_failures += 1
if (consecutive_failures >= 10): # Check to see if we have had several consecutive failures.
break # Exit the loop (give up on the remaining
save_to_file(telemetry_backlog_file_location, json.dumps(telemetry_backlog)) # Save the updated back-log file.
else:
else: # Otherwise, the current submission failed.
del data["image"] # Delete the image data before adding it to the backlog.
telemetry_backlog[data["location"]["time"]] = data # Add this datapoint to the back-log.
save_to_file(telemetry_backlog_file_location, json.dumps(telemetry_backlog)) # Save the updated back-log file.
Expand Down

0 comments on commit 6754db2

Please sign in to comment.