diff --git a/examples/ecosub_c2/mission_plan.json b/examples/ecosub_c2/mission_plan.json index 14256ffd7dd08f0216c29d7292a7ef37bc6bcb4f..322a08f223294f9eab0c98cb9617320bd8b8106e 100644 --- a/examples/ecosub_c2/mission_plan.json +++ b/examples/ecosub_c2/mission_plan.json @@ -7,7 +7,7 @@ "delivery_type": "publish", "encoded": false, "message_type": "mission_plan", - "platform_serial": "reav-60", + "platform_ID": 1, "autonomy_engine_mission_plan_ID": 1, "plan": [ { diff --git a/examples/hydrosurv_adapter/mission_plan.json b/examples/hydrosurv_adapter/mission_plan.json index 81a6ff71a426f0c5ff72b50a56fa178013ce764b..f10b821ec15011177b4ff42a99844d652b7e750d 100644 --- a/examples/hydrosurv_adapter/mission_plan.json +++ b/examples/hydrosurv_adapter/mission_plan.json @@ -7,7 +7,7 @@ "delivery_type": "publish", "encoded": false, "message_type": "mission_plan", - "platform_serial": "reav-60", + "platform_ID": 5, "autonomy_engine_plan_ID": 1, "plan": [ { diff --git a/formats/__init__.py b/formats/__init__.py index 446108fa662b373a1619beb67bbc64fbe3543579..2253a07952dc605ffa662b625265c4b68b841e53 100644 --- a/formats/__init__.py +++ b/formats/__init__.py @@ -1,5 +1,3 @@ -# from flask_restx import fields -# from . import api import os @@ -8,102 +6,3 @@ __all__ = [ for x in os.listdir(os.path.dirname(__file__)) if x.endswith(".py") and x != "__init__.py" ] - -# TODO: Define units for all schemas - -# message_types = [ -# "platform_status", -# "mission_plan_ecosub", -# "mission_plan_reav", -# "mission_plan_autosub", -# ] # TODO: Add full range of message types once scoped out - -# full_message_schema = api.model( -# "FullMessageSchema", -# { -# "message_ID": fields.String( -# required=True, -# description="UUID assigned to this message", -# example="b427003c-7bc8-11ed-a1eb-0242ac120002", -# ), -# "timestamp": fields.DateTime( -# required=True, -# description="Timestamp of message", -# example="2022-11-16T00:00:00Z", -# ), -# "version": fields.Float( -# required=True, -# description="Version of comms bacbone messaging format protocol", -# example=2.0, -# ), -# "source": fields.String( -# required=True, -# description="Where is this message from", -# example="autonomy_engine", -# ), -# "destination": fields.String( -# required=True, -# description="What is the destination of this message", -# example="ah-1", -# ), -# "encoded": fields.Boolean( -# required=True, -# description="Indicate that message raw (encoded) or decoded. " -# + "Options: encoded=True, decoded=False", -# example=False, -# ), -# "type": fields.String( -# required=True, -# description="Type of message", -# example="platform_status", -# ), -# "payload": fields.Raw( -# required=True, -# description="Content of Message", -# # example="{}", -# ), -# }, -# ) - -# constraints_schema = api.model( -# "ConstraintsSchema", -# { -# "min_altitude": fields.Float( -# required=True, -# description="Minimum altitude set for squad.", -# example=15.2, -# ), -# "min_velocity": fields.Float( -# required=True, -# description="Minimum velocity set for squad.", -# example=0.1, -# ), -# "max_velocity": fields.Float( -# required=True, -# description="Maximum altitude set for squad.", -# example=0.9, -# ), -# }, -# ) - -# platform_schema = api.model( -# "PlatformSchema", -# { -# "platform_ID": fields.Integer( -# required=True, -# description="unique identifier for platform", -# example=1, -# ), -# "serial": fields.String( -# required=True, -# description="platform serial number", -# example="reav-60", -# ), -# "model": fields.String( -# required=True, -# description="platform serial number", -# example="reav", -# ), -# "constraints": fields.Nested(constraints_schema), -# }, -# ) diff --git a/formats/acknowledgement.py b/formats/acknowledgement.py index 4f3352cfc21b138c46dfe9bab64ca2ea504617fb..70f89a3290cc3324a03caca25275602028ff96fb 100644 --- a/formats/acknowledgement.py +++ b/formats/acknowledgement.py @@ -14,34 +14,13 @@ acknowledgement_schema = { }, "status": { "type": "string", + "enum": ["c2_received", "operator_approved_and_sent", "executed"], "description": "Highest level of acknowledgement. I.e." - + " `c2_received`: Received by C2, `c2_sent`: Sent from" - + " C2->Platform, `executed`: Executed by platform", + + " `c2_received`: Received by C2, `operator_approved_and_sent`" + + " : Approved by operator and sent from C2->Platform," + + " `executed`: Executed by platform", "example": "executed by platform", }, }, "required": ["acknowledged_message_ID", "status"], } - -# acknowledgement_schema = api.model( -# "Acknowledgement", -# { -# "message": fields.Nested( -# full_message_schema, -# required=True, -# description="Message header", -# ), -# "message_ID": fields.Integer( -# required=True, -# description="Identifier of message received and executed with " -# + "success for mission plans sent by the Autonomy Engine.", -# example=202, -# ), -# "status": fields.String( -# required=True, -# description="Highest level of acknowledgement. " -# + " I.e. `c2_received`: Received by C2, `c2_sent`:" -# + " Sent from C2->Platform, `executed`: Executed by platform", -# ), -# }, -# ) diff --git a/formats/message_wrapper.py b/formats/message_wrapper.py index ead7cf1102d2dd32bff39bf5a4ddb7ee9788e2e3..a7a92d0197663fe53b00135e67642b6aeab1eb41 100644 --- a/formats/message_wrapper.py +++ b/formats/message_wrapper.py @@ -16,18 +16,20 @@ message_wrapper_schema = { "example": "b427003c-0000-11aa-a1eb-bvcdfghjgfdd", }, "timestamp": { - "type": "date-time", + "type": "string", + "format": "date-time", "description": "Timestamp of message", "example": "2022-11-16T00:00:00Z", }, "message_type": { - "type": "Type of message", + "type": "string", "description": "Type of message", "example": "platform_status", }, "version": { - "type": "string", - "description": "Version of comms bacbone message format protocol", + "type": "number", + "format": "float", + "description": "Version of comms backbone message format protocol", "example": 2.0, }, "source": { diff --git a/formats/mission_plan.py b/formats/mission_plan.py index e46096c2f3c35fb25137d01ea7ef914a22aecdff..0e6c975c7b2318ab5bcd6478a2e36c89296446c8 100644 --- a/formats/mission_plan.py +++ b/formats/mission_plan.py @@ -1,10 +1,8 @@ """ - schemas: Mission plan (un-compiled) geenrated by the Autonomy Engine + schemas: Mission plan (un-compiled) generated by the Autonomy Engine sent to the respective platform's C2 to compile into a platform-specific mission plan. """ -# from . import api, full_message_schema -# from flask_restx import fields action_schema = { "type": "object", @@ -23,21 +21,25 @@ action_schema = { }, "latitude_waypoint": { "type": "number", + "format": "float", "description": "Next waypoint, x-coordinate", "example": -4.187143188645706, }, "longitude_waypoint": { "type": "number", + "format": "float", "description": "Next waypoint, y-coordinate", "example": 50.37072283932642, }, "altitude": { "type": "number", + "format": "float", "description": "Altitude of next action", "example": 15.0, }, "depth": { "type": "number", + "format": "float", "description": "Depth of next action", "example": 15.0, }, @@ -64,90 +66,21 @@ mission_plan_schema = { "allOf": [{"$ref": "#/components/schemas/Message"}], "type": "object", "properties": { - "autonomy_engine_plan_ID": {"type": "integer"}, - "platform_serial": {"type": "string"}, + "autonomy_engine_plan_ID": { + "type": "integer", + "description": "Unique identifier for this plan" + + "generated by the Autonomy Engine", + "example": 3, + }, + "platform_ID": { + "type": "integer", + "description": "Unique identifier for this platform", + "example": 1, + }, "plan": { "type": "array", "items": action_schema, }, }, - "required": ["plan_ID", "platform_serial", "plan"], + "required": ["plan_ID", "platform_ID", "plan"], } - -# action_schema = api.model( -# "AutonomyEngineAction", -# { -# "action": fields.String( -# required=True, -# description="Autonomy Engine's action from `move`, `payload`," -# + " `dive`, `send_hits`, `scanline`, `scanpoint`.", -# example="move", -# ), -# "flight_style": fields.String( -# required=False, -# description="Platform-specific modes/flight styles to perform" -# + " next action", -# example="orbit", -# ), -# "latitude_waypoint": fields.Float( -# required=True, -# description="Next waypoint, x-coordinate", -# example=-4.187143188645706, -# ), -# "longitude_waypoint": fields.Float( -# required=True, -# description="Next waypoint, y-coordinate", -# example=50.37072283932642, -# ), -# "altitude": fields.Float( -# required=False, -# description="Altitude of next action", -# example=15.0, -# ), -# "depth": fields.Float( -# required=False, -# description="Depth of next action", -# example=15.0, -# ), -# "activate_payload": fields.Boolean( -# required=False, -# description="To activate/deactivate sensor for Autosub " -# + "Hover-1 --> `MBES` sensor and for EcoSUB --> `Sidescan`", -# example=True, -# ), -# "send_environmental_data": fields.Boolean( -# required=False, -# description="To trigger the platform to send list of" -# + " observations if any found", -# example=False, -# ), -# }, -# ) - -# mission_plan_schema = api.model( -# "MissionPlan", -# { -# "message": fields.Nested( -# full_message_schema, -# required=True, -# description="Message header", -# ), -# "plan_ID": fields.Integer( -# required=True, -# description="Identifier of given mission sequence planned", -# example=1, -# ), -# "platform_serial": fields.String( -# required=True, -# description="Serial of target platform to send mission to", -# example="reav-60", -# ), -# "plan": fields.List( -# fields.Nested(action_schema), -# required=True, -# description="Sequence of actions/instructions generated by the" -# + " Autonomy Engine that should be compiled by the", -# + " respective C2.", -# ), -# }, -# ) diff --git a/formats/observation.py b/formats/observation.py index 8d0097a246b494b560196d8850b9b8a5f056c023..d67ff3839eea5ab7a884a6e99ca48294c4cf3f03 100644 --- a/formats/observation.py +++ b/formats/observation.py @@ -2,30 +2,31 @@ schema: Observation Message sent by platforms when points of interest are found. """ -# from . import full_message_schema, api -# from flask_restx import fields hits_schema = { "type": "object", "properties": { "latitude": { "type": "number", + "format": "float", "description": "Identified x-coordinate of point of interest", "example": 178.2, }, "longitude": { "type": "number", + "format": "float", "description": "Identified y-coordinate of point of interest", "example": -10.122, }, "quality_of_point": { "type": "number", + "format": "float", "description": "Quality/strength of points from features of" - + " interest identified by platform. TODO: DEFINE FORMAT.", + + " interest identified by platform.", # TODO: DEFINE FORMAT. "example": 0.98, }, }, - "required": [], + "required": ["latitude", "longitude"], } observation_schema = { @@ -35,19 +36,18 @@ observation_schema = { "platform_ID": { "type": "integer", "description": "ID of platform to sending observations", - "example": "ecosub-3", + "example": 2, }, - # "observation_type" ==> payloads tied to different types maybe? - # properties of each observation? "points_of_interest": { "type": "array", "items": hits_schema, "description": "Points from features of interest identified by" - + " platform if any found. DEFINE FORMAT.", + + " platform if any found.", # TODO: DEFINE FORMAT. }, "region_surveyed": { - "description": "Region surveyed by given platform. DEFINE FORMAT." - + " GEOJSON", + "type": "null", + "description": "Region surveyed by given platform." + + " GEOJSON", # TODO: DEFINE FORMAT. "example": "", }, "additional_data": { @@ -55,46 +55,5 @@ observation_schema = { "example": {"sensor_payload": False}, }, }, - "required": ["platform_serial"], + "required": ["platform_ID"], } - -# observation_schema = api.model( -# "Observation", -# { -# "message": fields.Nested( -# full_message_schema, -# required=True, -# description="Message header", -# ), -# "platform_serial": fields.String( -# required=True, -# description="Serial of platform to sendign observations", -# example="ecosub-3", -# ), -# # "observation_type" ==> payloads tied to different types maybe? -# # properties of each observation? -# "points_of_interest": fields.Float( -# required=False, -# description="Points from features of interest identified by" -# + " platform if any found. DEFINE FORMAT.", -# example="", -# ), -# "region_surveyed": fields.Float( -# required=False, -# description="Region surveyed by given platform. DEFINE FORMAT." -# + " GEOJSON?", -# example="", -# ), -# "quality_of_points": fields.Float( -# required=False, -# description="Quality/strength of points from features of" -# + " interest identified by platform. DEFINE FORMAT.", -# example=0.98, -# ), -# "additional_data": fields.Raw( -# required=False, -# description="Placeholder field for any additional data", -# example={"sensor_payload": False}, -# ), -# }, -# ) diff --git a/formats/planning_configuration.py b/formats/planning_configuration.py index 4e008a924493b721392310ae08e7ddca2aab900c..50da1848b9611622c6a4bdb216db689d652855af 100644 --- a/formats/planning_configuration.py +++ b/formats/planning_configuration.py @@ -2,8 +2,6 @@ schemas: configuration sent to Autonomy Engine (i.e. during an emergency, if a platform needs to be removed from the mission planning) """ -# from . import api, full_message_schema, platform_schema -# from flask_restx import fields emergency_schema = { "type": "object", @@ -17,16 +15,19 @@ emergency_schema = { }, "latitude_waypoint": { "type": "number", + "format": "float", "description": "X-coordinate safe place for respective platform", "example": -7.432, }, "longitude_waypoint": { "type": "number", + "format": "float", "description": "Y-coordinate safe place for respective platform", "example": 50.365, }, "target_depth": { "type": "number", + "format": "float", "description": "Z-coordinate safe place for respective platform" + " . If platform to NOT stay at depth, key in `0.0`", "example": 10, @@ -61,16 +62,19 @@ platform_schema = { "emergency": emergency_schema, "min_altitude": { "type": "number", + "format": "float", "description": "Minimum altitude set for squad.", "example": 15.2, }, "min_velocity": { "type": "number", + "format": "float", "description": "Minimum velocity set for squad.", "example": 0.1, }, "max_velocity": { "type": "number", + "format": "float", "description": "Maximum altitude set for squad.", "example": 0.9, }, @@ -178,99 +182,3 @@ planning_configuration_schema = { "exclusion_zones", ], } - -# region_schema = api.model( -# "RegionSchema", -# { -# "region": fields.Raw( -# required=True, -# description="Using GEOJSON, exact region of " -# + "interest in rectangle format polygon", -# example={ -# "type": "FeatureCollection", -# "features": [ -# { -# "type": "Feature", -# "properties": {}, -# "geometry": { -# "coordinates": [ -# [ -# [-4.187143188645706, 50.37072283932642], -# [-4.202697005964865, 50.368816892405874], -# [-4.203156724702808, 50.365640144076906], -# [-4.19449868846155, 50.362267670845654], -# ] -# ], -# "type": "Polygon", -# }, -# } -# ], -# }, -# ), -# }, -# ) - -# squad_metadata_schema = api.model( -# "SquadMetadataSchema", -# { -# "squad_ID": fields.Integer( -# required=True, -# description="Identifier of given squad", -# example=23, -# ), -# "no_of_platforms": fields.Integer( -# required=True, -# description="Number of platforms", -# example=3, -# ), -# "platforms": fields.List( -# fields.Nested(platform_schema), -# required=True, -# description="Squad consists of these platforms", -# ), -# "squad_mission_type": fields.String( -# required=True, -# description="Mission of given squad: `tracking`, `survey`" -# + ", `inspection`", -# example="survey", -# ), -# "squad_state": fields.Boolean( -# required=True, -# description="In execution, Waiting.. <define further>", -# example=False, -# ), -# "region_of_interest": fields.List( -# fields.Nested(region_schema), -# required=False, -# description="Region of interest and exclusion zones per squad.", -# ), -# "exclusion_zones": fields.List( -# fields.Nested(region_schema), -# required=True, -# description="Exclusion zones exclusion zones per squad.", -# ), -# }, -# ) - - -# planning_configuration_schema = api.model( -# "PlanningConfigurationSchema", -# { -# "message": fields.Nested( -# full_message_schema, -# required=True, -# description="Message header", -# ), -# "ID": fields.Integer( -# required=True, -# description="Unique identifier tagged to version of this" -# + " configuration plan", -# example=3, -# ), -# "squads": fields.Nested( -# squad_metadata_schema, -# required=False, -# description="Details of each squad", -# ), -# }, -# ) diff --git a/formats/platform_status.py b/formats/platform_status.py index 9d08620b096243473b30a0c51825babab09a2540..87853c67f443394775becf2b9083226cd10151e9 100644 --- a/formats/platform_status.py +++ b/formats/platform_status.py @@ -42,7 +42,8 @@ platform_status_message_schema = { "example": "usbl", }, "platform_timestamp": { - "type": "date-time", + "type": "string", + "format": "date-time", "decription": "Timestamp for onboard platform status message", "example": "2022-12-21T00:00:00Z", }, @@ -53,7 +54,7 @@ platform_status_message_schema = { "example": True, }, "platform_state": { - # TODO: Define dictionary with potential STATES of each platform + # TODO: Define enum with potential STATES of each platform "type": "string", "description": "Current state executed by platform. E.g. " + "STOP, IDLE, ABORT.", @@ -67,22 +68,26 @@ platform_status_message_schema = { }, "latitude": { "type": "number", + "format": "float", "description": "Latitude in decimal degrees.", "example": 178.2, }, "longitude": { "type": "number", + "format": "float", "description": "Longitude in decimal degrees.", "example": -10.122, }, "depth": { "type": "number", + "format": "float", "description": "Target depth in metres", "example": 50, "default": 0, }, "altitude": { "type": "number", + "format": "float", "description": "Target altitude in metres", "example": 20, }, @@ -94,31 +99,36 @@ platform_status_message_schema = { }, "mission_action_ID": { "type": "integer", - "description": "TODO: add description", + "description": "", # TODO: Add description "example": 1, }, "range_to_go": { "type": "number", + "format": "float", "description": "Estimated distance to reach next waypoint", "example": 124.3, }, "speed_over_ground": { "type": "number", - "description": "TODO: add description", + "format": "float", + "description": "", # TODO: Add description "example": 124.3, }, "water_current_velocity": { "type": "number", - "description": "TODO: add description", + "format": "float", + "description": "", # TODO: Add description "example": 124.3, }, "thrust_applied": { "type": "number", - "description": "TODO: Needs further consideration", + "format": "float", + "description": "", # TODO: Add description "example": 124.3, }, "heading": { "type": "number", + "format": "float", "description": "Angular distance relative to north, usually 000°" + " at north, clockwise through 359°, in degrees", "example": 124.3, @@ -131,21 +141,25 @@ platform_status_message_schema = { }, "localisation_error": { "type": "number", + "format": "float", "description": "Localisation error at last USBL update.", "example": 0.000129, }, "usbl_fix_seconds_ago": { "type": "number", + "format": "float", "description": "USBL Fix received x second ago.", "example": 10.0, }, "battery_remaining_capacity": { "type": "number", + "format": "float", "description": "Battery remaining % provided by respective C2", "example": 80.2, }, "current_pitch": { "type": "number", + "format": "float", "description": "Current pitch of platform", "example": -4.0, }, @@ -159,175 +173,3 @@ platform_status_message_schema = { "longitude", ], } - -# gps_schema = api.model( -# "GPS", -# { -# "gps_source": fields.Float( # TODO: TBD with partners -# required=False, -# description=( -# "Source of gps position. E.g. USBL (external)," -# + "platform itself (internal)" -# ), -# example="internal", -# ), -# "latitude_type": fields.String( -# required=False, -# description="", -# example="", -# ), -# "longitude_type": fields.String( -# required=False, -# description="", -# example="", -# ), -# "latitude": fields.Float( -# required=False, -# description="Latitude in <DEFINE UNITS>", -# example="", -# ), -# "longitude": fields.Float( -# required=False, -# description="Longitude in <DEFINE UNITS>", -# example="", -# ), -# "depth": fields.Float( -# required=False, -# description="Depth in <DEFINE UNITS>", -# example="", -# ), -# "altitude": fields.Float( -# required=False, -# description="Altitude in <DEFINE UNITS>", -# example="", -# ), -# # "gps_fix_seconds_ago" -# }, -# ) - -# sensor_schema = api.model( -# "SensorSchema", -# { -# "sensor_ID": fields.Integer( -# required=True, -# description="unique identifier for platform", -# example=2, -# ), -# "serial": fields.String( -# required=False, -# description="serial number of sensor", -# example="mbes-001", -# ), -# "sensor_status": fields.Boolean( -# required=False, -# description="Sensor switched on (True) or off (False)", -# example=True, -# ), -# "additional_data": fields.Raw( -# required=False, -# description="Any addition fields/data to be added here", -# ), -# }, -# ) - -# platform_status_message_schema = api.model( -# "platformStatusMessage", -# { -# "message": fields.Nested( -# full_message_schema, -# required=True, -# description="Message header", -# ), -# "platform_ID": fields.Integer( -# required=True, -# description="unique identifier for platform", -# example=1, -# ), -# "active": fields.Boolean( -# required=False, -# description="When a platform is in deployment (executing a" -# + " mission plan) this should be True", -# example=True, -# ), -# "platform_state": fields.String( -# # TODO: Define dictionary with potential STATES of each platform -# required=False, -# description="Current state executed by platform. E.g. " -# + "STOP, IDLE, ABORT.", -# example="IDLE", -# ), -# "autonomy_plan_ID": fields.Integer( -# required=False, -# description="Last mission plan ID ( -# + "according to Autonomy Engine's" -# + " mission plan number) executed by platform", -# example=1, -# ), -# "mission_track_ID": fields.Integer( -# required=False, -# description=( -# "Track number - stage in mission (e.g. " -# + "4 --> Waypoint 3 to Waypoint 4)" -# ), -# example=4, -# ), -# "mission_action_ID": fields.Integer( -# required=False, -# description="to add description", -# example=1, -# ), -# "range_to_go": fields.Float( -# required=False, -# description="Estimated distance to reach next waypoint", -# example=124.3, -# ), -# "speed_over_ground": fields.Float( -# required=False, -# description="", -# example=124.3, -# ), -# "water_current_velocity": fields.Float( -# required=False, -# description="", -# example=124.3, -# ), -# "thrust_applied": fields.Float( -# required=False, -# description="TODO: Needs further consideration", -# example=124.3, -# ), -# "health_status": fields.String( -# required=False, -# description="Health status extracted by respective platform " -# + "if any diagnosis available checks on sensors", -# example="Warning", -# ), -# "gps_data": fields.List( -# fields.Nested(gps_schema), # TODO: TBD Do we want a list of -# # gps readings to allow > 1 reading i.e. platform + usbl -# required=True, -# description="Metadata pf each platform", -# ), -# "localisation_error": fields.Float( -# required=False, -# description="Localisation error at last USBL update.", -# example="", -# ), -# "usbl_fix_seconds_ago": fields.Float( -# required=False, -# description="", -# example="", -# ), -# "battery_remaining_capacity": fields.Float( -# required=True, -# description="Battery remaining capacity % provided by respective" -# + " platform/C2.", -# example=80.0, -# ), -# "sensor_config": fields.Nested( -# sensor_schema -# ), # TODO: TBD Do we want a list of sensors to allow > 1 sensor -# }, -# ) - -# # TBD: Do we append beacon positions with platform positions?