OceanDataTools / openrvdas

An open source data acquisition system designed for use on research vessels and other scientific installations
http://openrvdas.org
Other
39 stars 20 forks source link

Data-driven logger control #359

Closed davidpablocohn closed 9 months ago

davidpablocohn commented 10 months ago

What: Allow the system to change logger state/mode depending on the values of data read.

Why: Most ubiquitous reason is geofencing. Inside a country's EEZ, we may not be allowed to record certain forms of data, but we'd like the system to automatically start recording once lat/lon indicate we are outside. And off once we approach it again. Or maybe we'd like to turn a logger off if it starts showing out-of-band data.

How: A couple of new transforms and writers. The crucial one would be a LoggerManagerWriter which sends commands to the LoggerManager:

# Send commands to logger manager. Records will be split at newlines and sent sequentially.
# Special string 'sleep [n]' will sleep for n (default 1) seconds before sending next command.
LoggerManagerWriter(
    database=django,
    path_to_credential_file=None,
    allowed_command_prefixes = [],    # which messages we'll allow - 
)

The way we can use this for geofencing is to have a GeoFenceTransform that takes in lat/lon and outputs one pre-specified string when we exit the fence, and another when we enter it.

GeoFenceTransform(
    latitude_field_name, longitude_field_name,  # what fields to listen to for lat/lon values
    boundary_file_name,    # GML file?
    country_name=None,  # if GML has more than one
    distance_from_boundary_in_m=0,    # negative means inside
    leaving_boundary_message=None,
    entering_boundary_message=None,
    seconds_between_checks=0  # do computation no more frequently than this, to limit computation overhead
    data_points_before_message=1  #  number of sequential data points that are inside/outside boundary before sending message
)

Question: should we add 'sleep' command to API to add time for previous commands to take effect? Is it needed? Could also just have it be a special command that LoggerManagerWriter() recognizes.

Some sample geofencing code generated by ChatGPT, but seems to work:

#Get EEZ GML file using http://www.marineregions.org/Test whether within (or within N mile buffer of) EEZ.
# Can also test distance to boundary - maybe return as a DASRecord of lat/lon, distance_to_eez (negative if inside),
# inside/outside, buffer width, distance_to_buffer, inside/outside_buffer).
import geopandas as gpd
from shapely.geometry import Point

# Load the EEZ data from the GML file
eez_data = gpd.read_file("path_to_eez_gml_file.gml")

# Filter the EEZ for a specific country if necessary
country_eez = eez_data[eez_data['SOVEREIGNT'] == 'Name of the Country']

# Convert the GeoDataFrame to a UTM projection suitable for the area
# Note: You might need to adjust the zone and/or hemisphere based on your EEZ's location
country_eez = country_eez.to_crs(f"EPSG:326XX")  # Replace XX with the appropriate UTM zone

# Buffer the country's EEZ by N nautical miles (1 nautical mile is approx. 1852 meters)
N = your_value_for_N
buffered_eez = country_eez.buffer(N * 1852)

# Define a function to check if a point is within N nautical miles of the geofenced area
def is_within_buffered_eez(lon, lat):
    point = Point(lon, lat).to_crs(f"EPSG:326XX")  # Convert point to same UTM CRS
    return buffered_eez.contains(point).any()

# Test the function
longitude = your_longitude
latitude = your_latitude
if is_within_buffered_eez(longitude, latitude):
    print(f"The point is within {N} nautical miles of the EEZ!")
else:
    print(f"The point is outside {N} nautical miles of the EEZ!")
davidpablocohn commented 9 months ago

Merged to dev