Commit e113878b authored by Trishna Saeharaseelan's avatar Trishna Saeharaseelan
Browse files

refactor: all messages from flask model to json schema definitions

parent 3a41f4a2
......@@ -3,7 +3,7 @@ This project repository is a collaborative workspace. It consists of all message
# Message Types
Each message below will be treated as the `payload` that are wrapped in a `full_message_format` that includes a `message_header`:
Each message below will be wrapped in a `message_wrapper`:
* `mission_plan`: these would be two message types, i. encoded (platform-specific serialized message) and ii. parsed, human-readable message.
* `platform_status`: these would be two message types, i. encoded (platform-specific serialized message) and ii. parsed, human-readable message.
* `observation`: this would be desired scientific data sent by the platform
......
......@@ -11,4 +11,3 @@ __all__ = [
]
app = Flask(__name__)
api = Api(app)
# api = Marshmallow(app)
import os
__all__ = [
os.path.splitext(os.path.basename(x))[0]
for x in os.listdir(os.path.dirname(__file__))
if x.endswith(".py") and x != "__init__.py"
]
......@@ -5,7 +5,7 @@
"source": "ecosub_c2",
"destination": "autonomy_engine",
"encoded": false,
"type": "platform_status",
"type": "observation",
"payload": {
"platform_serial":"ecosub-3",
"points_of_interest": [],
......
from flask_restx import fields
from . import api
# from flask_restx import fields
# from . import api
import os
......@@ -11,99 +11,99 @@ __all__ = [
# 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
# 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="{}",
),
},
)
# 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,
),
},
)
# 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),
},
)
# 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),
# },
# )
......@@ -2,29 +2,44 @@
schemas: Acknowledgement status sent by the surface platform to report
receipt of message.
"""
from . import api, full_message_schema
from flask_restx import fields
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 "
acknowledgement_schema = {
"properties": {
"message_ID": {
"type": "string",
"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`:"
"example": "b427003c-7bc8-11ed-a1eb-0242ac999999",
},
"status": {
"type": "string",
"description": "Highest level of acknowledgement. I.e. `c2_received`:"
+ " Received by C2, `c2_sent`: Sent from C2->Platform, `executed`:"
+ " Executed by platform",
),
"example": "executed by platform",
},
},
)
"required": ["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",
# ),
# },
# )
"""
schemas: Message Wrapper is used to wrap all message types that contain
details of where the message is coming from, which end client is its destination
and the type of message.
"""
message_wrapper_schema = {
"type": "object",
"discriminator": {
"propertyName": "message_type",
},
"properties": {
"message_ID": {
"type": "string",
"description": "An identifier for the type of " + "message received.",
"example": "PlatformStatus",
},
"timestamp": {
"type": "date-time",
"description": "Timestamp of message",
"example": "2022-11-16T00:00:00Z",
},
"message_type": {
"type": "Type of message",
"description": "Type of message",
"example": "platform_status",
},
"version": {
"type": "string",
"description": "Version of comms bacbone messaging format protocol",
"example": 2.0,
},
"source": {
"type": "string",
"description": "The sender; Where is this message from",
"example": "autonomy_engine",
},
"destination": {
"type": "string",
"description": "Publisher topic; What is the destination of this message",
"example": "ah1",
},
"encoded": {
"type": "boolean",
"description": "Indicate that message raw (encoded) or decoded. "
+ "Options: encoded=True, decoded=False",
"example": False,
},
"delivery_type": {
"type": "string",
"description": "To publish or broadcast this message.",
"enum": ["broadcast", "publish"],
"example": "publish",
"default": "publish",
},
},
"required": ["message_type"],
}
......@@ -3,83 +3,151 @@
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
# from . import api, full_message_schema
# from flask_restx import fields
action_schema = api.model(
"AutonomyEngineAction",
{
"action": fields.String(
required=True,
description="Autonomy Engine's action from `move`, `payload`,"
action_schema = {
"type": "object",
"properties": {
"action": {
"type": "string",
"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"
"example": "move",
},
"flight_style": {
"type": "string",
"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 "
"example": "orbit",
},
"latitude_waypoint": {
"type": "number",
"description": "Next waypoint, x-coordinate",
"example": -4.187143188645706,
},
"longitude_waypoint": {
"type": "number",
"description": "Next waypoint, y-coordinate",
"example": 50.37072283932642,
},
"altitude": {
"type": "number",
"description": "Altitude of next action",
"example": 15.0,
},
"depth": {
"type": "number",
"description": "Depth of next action",
"example": 15.0,
},
"activate_payload": {
"type": "boolean",
"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"
"example": True,
},
"send_environmental_data": {
"type": "boolean",
"description": "To trigger the platform to send list of observations"
+ " if any found",
example=False,
),
"example": False,
},
},
)
"required": [
"action",
"latitude_waypoint",
"longitude_waypoint",
],
}
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.",
),
mission_plan_schema = {
"allOf": [{"$ref": "#/components/schemas/Message"}],
"type": "object",
"properties": {
"plan_ID": {"type": "integer"},
"platform_serial": {"type": "string"},
"plan": {
"type": "array",
"items": action_schema,
},
},
)
"required": ["plan_ID", "platform_serial", "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.",
# ),
# },
# )
"""
schema: platform-specific decoded status message (DRAFT)
"""
from . import full_message_schema, api
from flask_restx import fields
# from . import full_message_schema, api
# from flask_restx import fields
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_schema = {
"allOf": [{"$ref": "#/components/schemas/Message"}],
"type": "object",
"properties": {
"platform_serial": {
"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"
"points_of_interest": {
"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."
"example": "",
},
"region_surveyed": {
"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"
"example": "",
},
"quality_of_points": {
"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},
),
"example": 0.98,
},
"additional_data": {
"description": "Placeholder field for any additional data",
"example": {"sensor_payload": False},
},
},
)
"required": ["platform_serial"],
}
# 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},
# ),
# },
# )
......@@ -2,102 +2,230 @@
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
# from . import api, full_message_schema, platform_schema
# from flask_restx import fields
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",
},
}
],
},
),
constraints_schema = {
"type": "object",
"properties": {
"min_altitude": {
"type": "number",
"description": "Minimum altitude set for squad.",
"example": 15.2,
},
"min_velocity": {
"type": "number",
"description": "Minimum velocity set for squad.",
"example": 0.1,
},
"max_velocity": {
"type": "number",
"description": "Maximum altitude set for squad.",
"example": 0.9,
},
},
)
"required": ["min_altitude", "min_velocity", "max_velocity"],
}
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.",
),
platform_schema = {
"type": "object",
"properties": {
"platform_ID": {
"type": "integer",
"description": "Identifier for platform",
"example": 23,
},
"serial": {
"type": "string",
"description": "platform serial number",
"example": "reav-60",
},
"model": {
"type": "string",
"example": "reav",
},
"constraints": constraints_schema,
},
"required": ["platform_ID", "serial", "model", "constraints"],
}
region_schema = {
"type": "object",
"properties": {
"geometry_coordinates": {
"type": "array", # TODO: Check if config defn is right.
"example": [
[
[-4.187143188645706, 50.37072283932642],
[-4.202697005964865, 50.368816892405874],
[-4.203156724702808, 50.365640144076906],
[-4.19449868846155, 50.362267670845654],
]
],
},
},
)
"description": "Using GEOJSON, exact 4-point region (rectangle shaped)",
"required": ["geometry_coordinates"],
}
squad_metadata_schema = {
"type": "object",
"properties": {
"squad_ID": {
"type": "integer",
"description": "Identifier of given squad",
"example": 23,
},
"no_of_platforms": {
"type": "integer",
"description": "Number of platforms",
"example": 3,
},
"platforms": {
"type": "array",
"items": platform_schema,
"description": "Squad consists of these platforms",
},
"squad_mission_type": {
"type": "string",
"enum": ["tracking", "survey", "inspection"],
"description": "Mission of given squad: `tracking`, `survey`"
+ ", `inspection`",
"example": "survey",
},
"squad_state": {
"type": "string",
"description": "In execution, Waiting.. <define further>",
"example": False,
},
"region_of_interest": region_schema,
"exclusion_zones": {
"type": "array",
"items": region_schema,
"description": "Exclusion zones per squad.",
},
},
"required": [
"squad_ID",
"no_of_platforms",
"platforms",
"squad_mission_type",
"squad_state",
"exclusion_zones",
],
}
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"
planning_configuration_schema = {
"allOf": [{"$ref": "#/components/schemas/Message"}],
"type": "object",
"properties": {
"config_ID": {
"type": "integer",
"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",
),
"example": 3,
},
"squads": {
"type": "array",
"items": squad_metadata_schema,
},
},
)
"required": ["config_ID", "squads"],
}
# 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",
# ),
# },
# )
"""
schema: platform-specific decoded status message (DRAFT)
schema: platform-specific decoded status message
"""
from . import full_message_schema, api
from flask_restx import fields
# from . import full_message_schema, api
# from flask_restx import fields
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",
),
gps_schema = {
"type": "object",
"properties": {
"gps_source": {
"type": "string",
"description": "Source of gps position. E.g. USBL (external),"
+ "platform itself (internal)",
"example": "internal",
},
"latitude_type": {
"type": "string",
"description": "TODO: Add description",
},
"longitude_type": {
"type": "string",
"description": "TODO: Add description",
},
"latitude": {
"type": "number",
"description": "Latitude in decimal degrees.",
"example": 178.2,
},
"longitude": {
"type": "number",
"description": "Longitude in decimal degrees.",
"example": -10.122,
},
"depth": {
"type": "number",
"description": "Target depth in metres",
"example": 50,
"default": 0,
},
"altitude": {
"type": "number",
"description": "Target altitude in metres",
"example": 20,
},
},
)
"required": [
"gps_source",
"latitude",
"longitude",
],
}
sensor_schema = {
"type": "object",
"description": "Scanning sensor on platform available to be controlled by the Autonomy Engine",
"properties": {
"sensor_serial": {
"type": "string",
"description": "serial number of sensor",
"example": "mbes-002a",
},
"sensor_status": {
"type": "boolean",
"description": "Sensor switched on (True) or off (False)",
"example": True,
},
"additional_data": {
"type": "null",
"description": "Any addition fields/data to be added here",
"example": {"payload": [1.2, 434]},
},
},
"required": [],
}
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"
platform_status_message_schema = {
"allOf": [{"$ref": "#/components/schemas/Message"}],
"type": "object",
"properties": {
"platform_ID": {
"type": "integer",
"description": "Identifier for platform",
"example": 1,
},
"platform_timestamp": {
"type": "date-time",
"decription": "Timestamp for onboard platform status message",
"example": "2022-12-21T00:00:00Z",
},
"active": {
"type": "boolean",
"description": "When a platform is in deployment (executing a"
+ " mission plan) this should be True",
example=True,
),
"platform_state": fields.String(
"example": True,
},
"platform_state": {
# TODO: Define dictionary with potential STATES of each platform
required=False,
description="Current state executed by platform. E.g. "
"type": "string",
"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"
"example": "ABORT",
},
"autonomy_plan_ID": {
"type": "integer",
"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
"example": 1,
},
"mission_track_ID": {
"type": "integer",
"description": "Track number - stage in mission (e.g. "
+ "4 --> Waypoint 3 to Waypoint 4)",
"example": 4,
},
"mission_action_ID": {
"type": "integer",
"description": "TODO: add description",
"example": 1,
},
"range_to_go": {
"type": "number",
"description": "Estimated distance to reach next waypoint",
"example": 124.3,
},
"speed_over_ground": {
"type": "number",
"description": "TODO: add description",
"example": 124.3,
},
"water_current_velocity": {
"type": "number",
"description": "TODO: add description",
"example": 124.3,
},
"thrust_applied": {
"type": "number",
"description": "TODO: Needs further consideration",
"example": 124.3,
},
"health_status": {
"type": "string",
"description": "Health status extracted by respective platform "
+ "if any diagnosis is available to check sensors",
"example": "Warning",
},
"gps_data": {
"type": "array",
"description": "position of platform",
"items": gps_schema,
},
"localisation_error": {
"type": "number",
"description": "Localisation error at last USBL update.",
"example": 0.000129,
},
"usbl_fix_seconds_ago": {
"type": "number",
"description": "USBL Fix received x second ago.",
"example": 10.0,
},
"battery_remaining_capacity": {
"type": "number",
"description": "Battery remaining capacity % provided by respective",
"example": 80.2,
},
"sensor_config": sensor_schema,
},
)
"required": [
"platform_ID",
"platform_timestamp",
"gps_data",
"battery_remaining_capacity",
],
}
# 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?
# # TBD: Do we append beacon positions with platform positions?
from flask import Flask
from flasgger import Swagger
# from . import properties
from formats.message_wrapper import message_wrapper_schema
from formats.mission_plan import mission_plan_schema
from formats.observation import observation_schema
from formats.planning_configuration import planning_configuration_schema
from formats.platform_status import platform_status_message_schema
app = Flask(__name__)
swagger_config = {
......@@ -23,96 +30,15 @@ swagger_config = {
],
"components": {
"schemas": {
"Message": {
"type": "object",
"required": ["message_type"],
"properties": {
"message_type": {
"type": "string",
},
"source": {
"type": "string",
"description": "The sender.",
"example": "autonomy-engine",
},
"destination": {
"type": "string",
"description": "Publisher topic.",
"example": "soar.noc.autosub.ah1.status",
},
"delivery_type": {
"type": "string",
"description": "Published or broadcast",
"enum": ["broadcast", "publish"],
"example": "2.0.0",
},
"message_ID": {
"type": "string",
"description": "An identifier for the type of "
+ "message received.",
"example": "PlatformStatus",
},
},
"discriminator": {
"propertyName": "message_type",
},
},
"Coordinate": {
"allOf": [{"$ref": "#/components/schemas/Message"}],
"type": "object",
"properties": {
"latitude": {
"type": "integer",
"description": "Latitude in decimal degrees.",
"example": 54.234,
},
"longitude": {
"type": "integer",
"description": "Longitude in decimal degrees.",
"example": -1.432,
},
"depth": {
"type": "integer",
"description": "Target depth",
"default": 0,
"example": 50,
},
"projection": {
"type": "integer",
"description": "EPSG Projection Code",
"example": 4326,
"default": 4326,
},
},
},
"PlatformStatus": {
"allOf": [
{"$ref": "#/components/schemas/Message"},
],
"type": "object",
"properties": {
"partner_ID": {
"type": "string",
"description": "An identifier for the partner "
+ "owning/operating the platform.",
"example": "noc",
},
"platform_ID": {
"type": "string",
"description": "An identifier for the platform.",
"example": "noc_ah1",
},
"state": {
"type": "string",
"description": "Status of platform.",
"example": "idle",
},
},
},
"Message": message_wrapper_schema,
"MissionPlan": mission_plan_schema,
"Observation": observation_schema,
"PlanningConfiguration": planning_configuration_schema,
"PlatformStatus": platform_status_message_schema,
},
},
"paths": {
"/messages": {
"/all_messages": {
"get": {
"description": "Returns all messages from the system.",
"responses": {
......@@ -130,30 +56,21 @@ swagger_config = {
"$ref": "#/components/"
+ "schemas/PlatformStatus"
},
],
"discriminator": {
"propertyName": "message_type",
},
}
}
},
}
},
}
},
"/platformstatus": {
"get": {
"description": "Returns platform status message",
"responses": {
"200": {
"description": "Platform status message.",
"content": {
"application/json": {
"schema": {
"allOf": [
{
"$ref": "#/components/schemas"
+ "/PlatformStatus"
"$ref": "#/components/"
+ "schemas/MissionPlan"
},
{
"$ref": "#/components/"
+ "schemas/Observation"
},
{
"$ref": "#/components/"
+ "schemas/PlanningConfiguration"
},
{
"$ref": "#/components/"
+ "schemas/PlatformStatus"
},
],
"discriminator": {
......@@ -170,6 +87,40 @@ swagger_config = {
"produces": ["application/json"],
"consumes": ["application/json"],
}
message_types = [
"Message",
"Acknowledgement",
"MissionPlan",
"Observation",
"PlanningConfiguration",
"PlatformStatus",
]
for item in message_types:
swagger_config["paths"]["/" + str(item.lower())] = {
"get": {
"description": "Returns message for " + item,
"responses": {
"200": {
"description": item + " message.",
"content": {
"application/json": {
"schema": {
"allOf": [
{
"$ref": "#/components/schemas"
+ "/" + item,
},
],
"discriminator": {
"propertyName": "message_type",
},
}
}
},
}
},
}
}
swag = Swagger(app, config=swagger_config, merge=True)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment