telemetry-server 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- telemetry_server-0.1.0/PKG-INFO +58 -0
- telemetry_server-0.1.0/README.md +50 -0
- telemetry_server-0.1.0/pyproject.toml +146 -0
- telemetry_server-0.1.0/setup.cfg +4 -0
- telemetry_server-0.1.0/src/app.py +6 -0
- telemetry_server-0.1.0/src/autoboat_telemetry_server/__init__.py +44 -0
- telemetry_server-0.1.0/src/autoboat_telemetry_server/routes/__init__.py +29 -0
- telemetry_server-0.1.0/src/autoboat_telemetry_server/routes/autopilot_parameters.py +176 -0
- telemetry_server-0.1.0/src/autoboat_telemetry_server/routes/boat_status.py +108 -0
- telemetry_server-0.1.0/src/autoboat_telemetry_server/routes/waypoints.py +108 -0
- telemetry_server-0.1.0/src/instance/config.py +5 -0
- telemetry_server-0.1.0/src/telemetry_server.egg-info/PKG-INFO +58 -0
- telemetry_server-0.1.0/src/telemetry_server.egg-info/SOURCES.txt +14 -0
- telemetry_server-0.1.0/src/telemetry_server.egg-info/dependency_links.txt +1 -0
- telemetry_server-0.1.0/src/telemetry_server.egg-info/requires.txt +2 -0
- telemetry_server-0.1.0/src/telemetry_server.egg-info/top_level.txt +3 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: telemetry_server
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Project-URL: repository, https://github.com/autoboat-vt/telemetry_server
|
|
5
|
+
Description-Content-Type: text/markdown
|
|
6
|
+
Requires-Dist: flask
|
|
7
|
+
Requires-Dist: gunicorn
|
|
8
|
+
|
|
9
|
+
# Autoboat Telemetry Server
|
|
10
|
+
|
|
11
|
+
A lightweight Flask-based web server to collect, display, and manage telemetry data from the Virginia Tech Autoboat project.
|
|
12
|
+
|
|
13
|
+
## 📦 Project Structure
|
|
14
|
+
|
|
15
|
+
```txt
|
|
16
|
+
autoboat_telemetry_server/
|
|
17
|
+
├── __init__.py # App factory
|
|
18
|
+
├── routes
|
|
19
|
+
├── __init__.py # Routes initialization
|
|
20
|
+
├── autopilot_parameters.py # Autopilot parameters routes
|
|
21
|
+
├── boat_status.py # Boat status routes
|
|
22
|
+
├── waypoints.py # Waypoints management routes
|
|
23
|
+
|
|
24
|
+
instance/
|
|
25
|
+
├── config.py # Configuration file
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## 🚀 Quick Start
|
|
29
|
+
|
|
30
|
+
### Installation
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install -e .
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Running the server
|
|
37
|
+
|
|
38
|
+
1. Production ([Gunicorn](https://gunicorn.org/)):
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
gunicorn "autoboat_telemetry_server:create_app()"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
2. Development (Flask):
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
flask run
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Server (Long term)
|
|
51
|
+
|
|
52
|
+
### Installation
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
git clone https://github.com/autoboat-vt/telemetry_server
|
|
56
|
+
cd telemetry_server
|
|
57
|
+
./server_files/install.sh
|
|
58
|
+
```
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Autoboat Telemetry Server
|
|
2
|
+
|
|
3
|
+
A lightweight Flask-based web server to collect, display, and manage telemetry data from the Virginia Tech Autoboat project.
|
|
4
|
+
|
|
5
|
+
## 📦 Project Structure
|
|
6
|
+
|
|
7
|
+
```txt
|
|
8
|
+
autoboat_telemetry_server/
|
|
9
|
+
├── __init__.py # App factory
|
|
10
|
+
├── routes
|
|
11
|
+
├── __init__.py # Routes initialization
|
|
12
|
+
├── autopilot_parameters.py # Autopilot parameters routes
|
|
13
|
+
├── boat_status.py # Boat status routes
|
|
14
|
+
├── waypoints.py # Waypoints management routes
|
|
15
|
+
|
|
16
|
+
instance/
|
|
17
|
+
├── config.py # Configuration file
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## 🚀 Quick Start
|
|
21
|
+
|
|
22
|
+
### Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install -e .
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Running the server
|
|
29
|
+
|
|
30
|
+
1. Production ([Gunicorn](https://gunicorn.org/)):
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
gunicorn "autoboat_telemetry_server:create_app()"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
2. Development (Flask):
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
flask run
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Server (Long term)
|
|
43
|
+
|
|
44
|
+
### Installation
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
git clone https://github.com/autoboat-vt/telemetry_server
|
|
48
|
+
cd telemetry_server
|
|
49
|
+
./server_files/install.sh
|
|
50
|
+
```
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "telemetry_server"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
readme = "README.md"
|
|
5
|
+
dependencies = ["flask", "gunicorn"]
|
|
6
|
+
|
|
7
|
+
[project.urls]
|
|
8
|
+
repository = "https://github.com/autoboat-vt/telemetry_server"
|
|
9
|
+
|
|
10
|
+
[build-system]
|
|
11
|
+
requires = ["setuptools", "wheel"]
|
|
12
|
+
build-backend = "setuptools.build_meta"
|
|
13
|
+
|
|
14
|
+
[tool.ruff]
|
|
15
|
+
# Exclude a variety of commonly ignored directories.
|
|
16
|
+
exclude = [
|
|
17
|
+
".bzr",
|
|
18
|
+
".direnv",
|
|
19
|
+
".eggs",
|
|
20
|
+
".git",
|
|
21
|
+
".git-rewrite",
|
|
22
|
+
".hg",
|
|
23
|
+
".ipynb_checkpoints",
|
|
24
|
+
".mypy_cache",
|
|
25
|
+
".nox",
|
|
26
|
+
".pants.d",
|
|
27
|
+
"**/.pyenv/**",
|
|
28
|
+
".pyenv",
|
|
29
|
+
".pytest_cache",
|
|
30
|
+
".pytype",
|
|
31
|
+
".ruff_cache",
|
|
32
|
+
".svn",
|
|
33
|
+
".tox",
|
|
34
|
+
".venv",
|
|
35
|
+
".vscode",
|
|
36
|
+
"__pypackages__",
|
|
37
|
+
"_build",
|
|
38
|
+
"buck-out",
|
|
39
|
+
"build",
|
|
40
|
+
"dist",
|
|
41
|
+
"node_modules",
|
|
42
|
+
"site-packages",
|
|
43
|
+
"venv",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
# Same as Black.
|
|
47
|
+
line-length = 135
|
|
48
|
+
indent-width = 4
|
|
49
|
+
|
|
50
|
+
# Assume Python 3.12
|
|
51
|
+
target-version = "py312"
|
|
52
|
+
|
|
53
|
+
# Also format files in .gitignore
|
|
54
|
+
respect-gitignore = false
|
|
55
|
+
|
|
56
|
+
[tool.ruff.lint]
|
|
57
|
+
# Enable all rules, then selectively ignore some below.
|
|
58
|
+
select = ["ALL"]
|
|
59
|
+
|
|
60
|
+
ignore = [
|
|
61
|
+
"BLE001", # Do not catch blind exception: `Exception`
|
|
62
|
+
"CPY001", # Missing copyright notice at top of file
|
|
63
|
+
"COM812", # Trailing comma missing
|
|
64
|
+
"S101", # Use of `assert` detected
|
|
65
|
+
"S113", # Probable use of `requests` call without timeout
|
|
66
|
+
"SIM115", # Use a context manager for opening files
|
|
67
|
+
"SLF001", # Private member accessed
|
|
68
|
+
"I001", # Import block is un-sorted or un-formatted
|
|
69
|
+
"INP001", # implicit-namespace-package
|
|
70
|
+
"D100", # undocumented-public-module
|
|
71
|
+
"D101", # undocumented-public-class
|
|
72
|
+
"D102", # undocumented-public-method
|
|
73
|
+
"D107", # undocumented-public-init
|
|
74
|
+
"D202", # blank-line-after-function
|
|
75
|
+
"D205", # missing-blank-line-after-summary
|
|
76
|
+
"D400", # missing-trailing-period
|
|
77
|
+
"D401", # non-imperative-mood
|
|
78
|
+
"C901", # Method is too complex
|
|
79
|
+
"E401", # multiple-imports-on-one-line
|
|
80
|
+
"E501", # line-too-long
|
|
81
|
+
"E741", # ambiguous-variable-name
|
|
82
|
+
"E711", # Comparison to `None` should be `if cond is None:`
|
|
83
|
+
"E712", # Comparison to `True` or `False` should use `is`
|
|
84
|
+
"EM101", # Exception must not use a string literal, assign to variable first
|
|
85
|
+
"ERA001", # commented-out-code
|
|
86
|
+
"EXE002", # The file is executable but no shebang is present
|
|
87
|
+
"EM102", # Exception must not use an f-string literal, assign to variable first
|
|
88
|
+
"F403", # undefined-local-with-import-star
|
|
89
|
+
"F405", # undefined-local-with-import-star-usage
|
|
90
|
+
"FA100", # future-rewritable-type-annotation
|
|
91
|
+
"FBT001", # Boolean positional value in function definition
|
|
92
|
+
"FBT002", # Boolean positional value in function definition with default value
|
|
93
|
+
"FBT003", # Boolean positional value in function call
|
|
94
|
+
"N802", # checks for functions names that do not follow the snake_case naming convention.
|
|
95
|
+
"N813", # checks for variable names that do not follow the snake_case naming convention.
|
|
96
|
+
"PLR0904", # Too many public methods (... > 20)
|
|
97
|
+
"PLR0912", # Too many branches
|
|
98
|
+
"PLR0913", # Too many arguments for function (... > 5)
|
|
99
|
+
"PLR0915", # too-many-statements
|
|
100
|
+
"PLR2004", # Magic value used in comparison
|
|
101
|
+
"PTH", # use of functions that can be replaced by pathlib module.
|
|
102
|
+
"T201", # Checks for print statements.
|
|
103
|
+
"TD002", # Missing author in TODO `# TODO(<author_name>): ...`
|
|
104
|
+
"TD003", # missing-todo-link
|
|
105
|
+
"TD004", # todo missing colon
|
|
106
|
+
"TRY002", # Create your own exception
|
|
107
|
+
"TRY003", # Avoid specifying long messages outside the exception class
|
|
108
|
+
"TRY301", # raise-within-try
|
|
109
|
+
"RET504", # Unnecessary assignment of `return` value to a variable
|
|
110
|
+
"RET505", # Unnecessary `else` after `return` statement
|
|
111
|
+
"G004", # logging-f-string
|
|
112
|
+
"UP015", # Unnecessary mode argument for `open` function
|
|
113
|
+
"W293", # Blank line contains whitespace
|
|
114
|
+
"Q000", # Single quotes found but double quotes preferred
|
|
115
|
+
]
|
|
116
|
+
|
|
117
|
+
unfixable = [
|
|
118
|
+
"F401", # Module imported but unused
|
|
119
|
+
]
|
|
120
|
+
|
|
121
|
+
# Allow unused variables when underscore-prefixed.
|
|
122
|
+
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
|
|
123
|
+
|
|
124
|
+
[tool.ruff.lint.pydocstyle]
|
|
125
|
+
convention = "pep257"
|
|
126
|
+
|
|
127
|
+
[tool.ruff.format]
|
|
128
|
+
# Like Black, use double quotes for strings.
|
|
129
|
+
quote-style = "double"
|
|
130
|
+
|
|
131
|
+
# Like Black, indent with spaces, rather than tabs.
|
|
132
|
+
indent-style = "space"
|
|
133
|
+
|
|
134
|
+
# Like Black, respect magic trailing commas.
|
|
135
|
+
skip-magic-trailing-comma = false
|
|
136
|
+
|
|
137
|
+
# Like Black, automatically detect the appropriate line ending.
|
|
138
|
+
line-ending = "auto"
|
|
139
|
+
|
|
140
|
+
# Enable auto-formatting of code examples in docstrings. Markdown,
|
|
141
|
+
# reStructuredText code/literal blocks and doctests are all supported.
|
|
142
|
+
docstring-code-format = true
|
|
143
|
+
|
|
144
|
+
# Set the line length limit used when formatting code snippets in
|
|
145
|
+
# docstrings (only has an effect when docstring-code-format is enabled).
|
|
146
|
+
docstring-code-line-length = "dynamic"
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""Telemetry server for Autoboat at Virginia Tech."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from flask import Flask as _flask
|
|
5
|
+
from autoboat_telemetry_server.routes import AutopilotParametersEndpoint, BoatStatusEndpoint, WaypointEndpoint
|
|
6
|
+
|
|
7
|
+
__all__ = ["create_app"]
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def create_app() -> _flask:
|
|
11
|
+
"""
|
|
12
|
+
Create and configure the Flask application instance.
|
|
13
|
+
|
|
14
|
+
Returns
|
|
15
|
+
-------
|
|
16
|
+
_flask
|
|
17
|
+
Configured Flask application instance.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
app = _flask(__name__)
|
|
21
|
+
|
|
22
|
+
instance_dir = "/home/ubuntu/telemetry_server/src/instance"
|
|
23
|
+
config_path = os.path.join(instance_dir, "config.py")
|
|
24
|
+
|
|
25
|
+
app.config.from_pyfile(config_path)
|
|
26
|
+
|
|
27
|
+
app.register_blueprint(AutopilotParametersEndpoint().blueprint)
|
|
28
|
+
app.register_blueprint(BoatStatusEndpoint().blueprint)
|
|
29
|
+
app.register_blueprint(WaypointEndpoint().blueprint)
|
|
30
|
+
|
|
31
|
+
@app.route("/")
|
|
32
|
+
def index() -> str:
|
|
33
|
+
"""
|
|
34
|
+
Root route for the telemetry server.
|
|
35
|
+
|
|
36
|
+
Returns
|
|
37
|
+
-------
|
|
38
|
+
str
|
|
39
|
+
Confirmation message indicating which server is running.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
return "This is the production telemetry server. It is running!"
|
|
43
|
+
|
|
44
|
+
return app
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module containing the routes for the Autoboat telemetry server.
|
|
3
|
+
|
|
4
|
+
Autopilot Routes:
|
|
5
|
+
- `/autopilot_parameters/test`: Test route for autopilot parameters.
|
|
6
|
+
- `/autopilot_parameters/get`: Get the current autopilot parameters.
|
|
7
|
+
- `/autopilot_parameters/get_new`: Get the latest autopilot parameters if they haven't been seen yet.
|
|
8
|
+
- `/autopilot_parameters/get_default`: Get the default autopilot parameters.
|
|
9
|
+
- `/autopilot_parameters/set`: Set the autopilot parameters from the request data.
|
|
10
|
+
- `/autopilot_parameters/set_default`: Set the default autopilot parameters from the request data.
|
|
11
|
+
|
|
12
|
+
Boat Status Routes:
|
|
13
|
+
- `/boat_status/test`: Test route for boat status.
|
|
14
|
+
- `/boat_status/get`: Get the current boat status.
|
|
15
|
+
- `/boat_status/get_new`: Get the latest boat status if it hasn't been seen yet.
|
|
16
|
+
- `/boat_status/set`: Set the boat status from the request data.
|
|
17
|
+
|
|
18
|
+
Waypoint Routes:
|
|
19
|
+
- `/waypoints/test`: Test route for waypoints.
|
|
20
|
+
- `/waypoints/get`: Get the current waypoints.
|
|
21
|
+
- `/waypoints/get_new`: Get the latest waypoints if they haven't been seen yet.
|
|
22
|
+
- `/waypoints/set`: Set the waypoints from the request data.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
__all__ = ["AutopilotParametersEndpoint", "BoatStatusEndpoint", "WaypointEndpoint"]
|
|
26
|
+
|
|
27
|
+
from .autopilot_parameters import AutopilotParametersEndpoint
|
|
28
|
+
from .boat_status import BoatStatusEndpoint
|
|
29
|
+
from .waypoints import WaypointEndpoint
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
from flask import Blueprint, Response, jsonify, request
|
|
2
|
+
from typing import Literal, Any
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class AutopilotParametersEndpoint:
|
|
6
|
+
"""Endpoint for handling autopilot parameters."""
|
|
7
|
+
|
|
8
|
+
def __init__(self) -> None:
|
|
9
|
+
self._blueprint = Blueprint("autopilot_parameters_page", __name__, url_prefix="/autopilot_parameters")
|
|
10
|
+
self.autopilot_parameters: dict[str, Any] = {}
|
|
11
|
+
self.default_autopilot_parameters: dict[str, Any] = {}
|
|
12
|
+
self.new_flag: bool = False
|
|
13
|
+
self._register_routes()
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def blueprint(self) -> Blueprint:
|
|
17
|
+
"""Returns the Flask blueprint for autopilot parameters."""
|
|
18
|
+
|
|
19
|
+
return self._blueprint
|
|
20
|
+
|
|
21
|
+
def _register_routes(self) -> str:
|
|
22
|
+
"""
|
|
23
|
+
Registers the routes for the autopilot parameters endpoint.
|
|
24
|
+
|
|
25
|
+
Returns
|
|
26
|
+
-------
|
|
27
|
+
str
|
|
28
|
+
Confirmation message indicating the routes have been registered successfully.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
@self._blueprint.route("/test", methods=["GET"])
|
|
32
|
+
def test_route() -> Literal["autopilot_parameters route testing!"]:
|
|
33
|
+
"""
|
|
34
|
+
Test route for autopilot parameters.
|
|
35
|
+
|
|
36
|
+
Method: GET
|
|
37
|
+
|
|
38
|
+
Returns
|
|
39
|
+
-------
|
|
40
|
+
Literal["autopilot_parameters route testing!"]
|
|
41
|
+
Confirmation message for testing the autopilot parameters route.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
return "autopilot_parameters route testing!"
|
|
45
|
+
|
|
46
|
+
@self._blueprint.route("/get", methods=["GET"])
|
|
47
|
+
def get_route() -> tuple[Response, int]:
|
|
48
|
+
"""
|
|
49
|
+
Get the current autopilot parameters.
|
|
50
|
+
|
|
51
|
+
Method: GET
|
|
52
|
+
|
|
53
|
+
Returns
|
|
54
|
+
-------
|
|
55
|
+
tuple[Response, int]
|
|
56
|
+
A tuple containing the JSON response of the autopilot parameters and the HTTP status code.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
return jsonify(self.autopilot_parameters), 200
|
|
60
|
+
|
|
61
|
+
@self._blueprint.route("/get_new", methods=["GET"])
|
|
62
|
+
def get_new_route() -> tuple[Response, int]:
|
|
63
|
+
"""
|
|
64
|
+
Get the latest autopilot parameters if they haven't been seen yet.
|
|
65
|
+
|
|
66
|
+
Method: GET
|
|
67
|
+
|
|
68
|
+
Returns
|
|
69
|
+
-------
|
|
70
|
+
tuple[Response, int]
|
|
71
|
+
A tuple containing the JSON response of the autopilot parameters if new,
|
|
72
|
+
otherwise an empty JSON object, along with the HTTP status code.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
if self.new_flag:
|
|
76
|
+
self.new_flag = False
|
|
77
|
+
return jsonify(self.autopilot_parameters), 200
|
|
78
|
+
|
|
79
|
+
else:
|
|
80
|
+
return jsonify({}), 200
|
|
81
|
+
|
|
82
|
+
@self._blueprint.route("/get_default", methods=["GET"])
|
|
83
|
+
def get_default_route() -> tuple[Response, int]:
|
|
84
|
+
"""
|
|
85
|
+
Get the default autopilot parameters.
|
|
86
|
+
|
|
87
|
+
Method: GET
|
|
88
|
+
|
|
89
|
+
Returns
|
|
90
|
+
-------
|
|
91
|
+
tuple[Response, int]
|
|
92
|
+
A tuple containing the JSON response of the default autopilot parameters and the HTTP status code.
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
return jsonify(self.default_autopilot_parameters), 200
|
|
96
|
+
|
|
97
|
+
@self._blueprint.route("/set", methods=["POST"])
|
|
98
|
+
def set_route() -> tuple[Response, int]:
|
|
99
|
+
"""
|
|
100
|
+
Set the autopilot parameters from the request data.
|
|
101
|
+
|
|
102
|
+
Method: POST
|
|
103
|
+
|
|
104
|
+
Returns
|
|
105
|
+
-------
|
|
106
|
+
tuple[Response, int]
|
|
107
|
+
A tuple containing a success message or error message and the corresponding HTTP status code.
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
try:
|
|
111
|
+
new_parameters = request.json
|
|
112
|
+
if not isinstance(new_parameters, dict):
|
|
113
|
+
raise TypeError("Invalid autopilot parameters format. Expected a dictionary.")
|
|
114
|
+
|
|
115
|
+
if self.default_autopilot_parameters != {}:
|
|
116
|
+
new_parameters_keys = list(new_parameters.keys())
|
|
117
|
+
if len(new_parameters_keys) == 1 and new_parameters_keys[0] in self.default_autopilot_parameters:
|
|
118
|
+
self.autopilot_parameters[new_parameters_keys[0]] = new_parameters[new_parameters_keys[0]]
|
|
119
|
+
|
|
120
|
+
elif new_parameters_keys == list(self.default_autopilot_parameters.keys()):
|
|
121
|
+
self.autopilot_parameters = new_parameters
|
|
122
|
+
|
|
123
|
+
else:
|
|
124
|
+
raise ValueError("Invalid keys in autopilot parameters.")
|
|
125
|
+
|
|
126
|
+
else:
|
|
127
|
+
self.autopilot_parameters = new_parameters
|
|
128
|
+
|
|
129
|
+
self.new_flag = True
|
|
130
|
+
return jsonify("Autopilot parameters updated successfully."), 200
|
|
131
|
+
|
|
132
|
+
except TypeError as e:
|
|
133
|
+
return jsonify(str(e)), 400
|
|
134
|
+
|
|
135
|
+
except ValueError as e:
|
|
136
|
+
return jsonify(str(e)), 400
|
|
137
|
+
|
|
138
|
+
except Exception as e:
|
|
139
|
+
return jsonify(str(e)), 500
|
|
140
|
+
|
|
141
|
+
@self._blueprint.route("/set_default", methods=["POST"])
|
|
142
|
+
def set_default_route() -> tuple[Response, int]:
|
|
143
|
+
"""
|
|
144
|
+
Set the default autopilot parameters from the request data.
|
|
145
|
+
|
|
146
|
+
Method: POST
|
|
147
|
+
|
|
148
|
+
Returns
|
|
149
|
+
-------
|
|
150
|
+
tuple[Response, int]
|
|
151
|
+
A tuple containing a success message or error message and the corresponding HTTP status code.
|
|
152
|
+
"""
|
|
153
|
+
|
|
154
|
+
try:
|
|
155
|
+
new_default_parameters = request.json
|
|
156
|
+
if not isinstance(new_default_parameters, dict):
|
|
157
|
+
raise TypeError("Invalid default autopilot parameters format. Expected a dictionary.")
|
|
158
|
+
|
|
159
|
+
if new_default_parameters != {}:
|
|
160
|
+
filtered_autopilot_parameters = {}
|
|
161
|
+
for key in new_default_parameters:
|
|
162
|
+
if key in self.default_autopilot_parameters:
|
|
163
|
+
filtered_autopilot_parameters[key] = new_default_parameters[key]
|
|
164
|
+
|
|
165
|
+
self.autopilot_parameters = filtered_autopilot_parameters
|
|
166
|
+
|
|
167
|
+
self.default_autopilot_parameters = new_default_parameters
|
|
168
|
+
return jsonify("Default autopilot parameters updated successfully."), 200
|
|
169
|
+
|
|
170
|
+
except TypeError as e:
|
|
171
|
+
return jsonify(str(e)), 400
|
|
172
|
+
|
|
173
|
+
except Exception as e:
|
|
174
|
+
return jsonify(str(e)), 500
|
|
175
|
+
|
|
176
|
+
return f"autopilot_parameters paths registered successfully: {self._blueprint.url_prefix}"
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
from flask import Blueprint, Response, jsonify, request
|
|
2
|
+
from typing import Literal, Any
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class BoatStatusEndpoint:
|
|
6
|
+
"""Endpoint for handling boat status."""
|
|
7
|
+
|
|
8
|
+
def __init__(self) -> None:
|
|
9
|
+
self._blueprint = Blueprint("boat_status_page", __name__, url_prefix="/boat_status")
|
|
10
|
+
self.boat_status: dict[str, Any] = {}
|
|
11
|
+
self.new_flag: bool = False
|
|
12
|
+
self._register_routes()
|
|
13
|
+
|
|
14
|
+
@property
|
|
15
|
+
def blueprint(self) -> Blueprint:
|
|
16
|
+
"""Returns the Flask blueprint for autopilot parameters."""
|
|
17
|
+
return self._blueprint
|
|
18
|
+
|
|
19
|
+
def _register_routes(self) -> str:
|
|
20
|
+
"""
|
|
21
|
+
Registers the routes for the boat status endpoint.
|
|
22
|
+
|
|
23
|
+
Returns
|
|
24
|
+
-------
|
|
25
|
+
str
|
|
26
|
+
Confirmation message indicating the routes have been registered successfully.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
@self._blueprint.route("/test", methods=["GET"])
|
|
30
|
+
def test_route() -> Literal["boat_status route testing!"]:
|
|
31
|
+
"""
|
|
32
|
+
Test route for boat status.
|
|
33
|
+
|
|
34
|
+
Method: GET
|
|
35
|
+
|
|
36
|
+
Returns
|
|
37
|
+
-------
|
|
38
|
+
Literal["boat_status route testing!"]
|
|
39
|
+
Confirmation message for testing the boat status route.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
return "boat_status route testing!"
|
|
43
|
+
|
|
44
|
+
@self._blueprint.route("/get", methods=["GET"])
|
|
45
|
+
def get_route() -> tuple[Response, int]:
|
|
46
|
+
"""
|
|
47
|
+
Get the current boat status.
|
|
48
|
+
|
|
49
|
+
Method: GET
|
|
50
|
+
|
|
51
|
+
Returns
|
|
52
|
+
-------
|
|
53
|
+
tuple[Response, int]
|
|
54
|
+
A tuple containing the JSON response of the boat status and the HTTP status code.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
return jsonify(self.boat_status)
|
|
58
|
+
|
|
59
|
+
@self._blueprint.route("/get_new", methods=["GET"])
|
|
60
|
+
def get_new_route() -> tuple[Response, int]:
|
|
61
|
+
"""
|
|
62
|
+
Get the latest boat status if it hasn't been seen yet.
|
|
63
|
+
|
|
64
|
+
Method: GET
|
|
65
|
+
|
|
66
|
+
Returns
|
|
67
|
+
-------
|
|
68
|
+
tuple[Response, int]
|
|
69
|
+
A tuple containing the JSON response of the new boat status (or empty if none) and the HTTP status code.
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
if self.new_flag:
|
|
73
|
+
self.new_flag = False
|
|
74
|
+
return jsonify(self.boat_status), 200
|
|
75
|
+
|
|
76
|
+
else:
|
|
77
|
+
return jsonify({}), 200
|
|
78
|
+
|
|
79
|
+
@self._blueprint.route("/set", methods=["POST"])
|
|
80
|
+
def set_route() -> tuple[Response, int]:
|
|
81
|
+
"""
|
|
82
|
+
Set the boat status from the request data.
|
|
83
|
+
|
|
84
|
+
Method: POST
|
|
85
|
+
|
|
86
|
+
Returns
|
|
87
|
+
-------
|
|
88
|
+
tuple[Response, int]
|
|
89
|
+
A tuple containing a confirmation message and the HTTP status code.
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
try:
|
|
93
|
+
new_status = request.json
|
|
94
|
+
if not isinstance(new_status, dict):
|
|
95
|
+
raise TypeError("Invalid boat status format. Expected a dictionary.")
|
|
96
|
+
|
|
97
|
+
self.boat_status = new_status
|
|
98
|
+
self.new_flag = True
|
|
99
|
+
|
|
100
|
+
return jsonify("Boat status updated successfully."), 200
|
|
101
|
+
|
|
102
|
+
except TypeError as e:
|
|
103
|
+
return jsonify(str(e)), 400
|
|
104
|
+
|
|
105
|
+
except Exception as e:
|
|
106
|
+
return jsonify(str(e)), 500
|
|
107
|
+
|
|
108
|
+
return f"boat_status paths registered successfully: {self._blueprint.url_prefix}"
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
from flask import Blueprint, Response, jsonify, request
|
|
2
|
+
from typing import Literal
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class WaypointEndpoint:
|
|
6
|
+
"""Endpoint for handling waypoints."""
|
|
7
|
+
|
|
8
|
+
def __init__(self) -> None:
|
|
9
|
+
self._blueprint = Blueprint("waypoints_page", __name__, url_prefix="/waypoints")
|
|
10
|
+
self.waypoints: list[list[float]] = []
|
|
11
|
+
self.new_flag: bool = False
|
|
12
|
+
self._register_routes()
|
|
13
|
+
|
|
14
|
+
@property
|
|
15
|
+
def blueprint(self) -> Blueprint:
|
|
16
|
+
"""Returns the Flask blueprint for autopilot parameters."""
|
|
17
|
+
return self._blueprint
|
|
18
|
+
|
|
19
|
+
def _register_routes(self) -> str:
|
|
20
|
+
"""
|
|
21
|
+
Registers the routes for the waypoints endpoint.
|
|
22
|
+
|
|
23
|
+
Returns
|
|
24
|
+
-------
|
|
25
|
+
str
|
|
26
|
+
Confirmation message indicating the routes have been registered successfully.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
@self._blueprint.route("/test", methods=["GET"])
|
|
30
|
+
def test_route() -> Literal["waypoints route testing!"]:
|
|
31
|
+
"""
|
|
32
|
+
Test route for waypoints.
|
|
33
|
+
|
|
34
|
+
Method: GET
|
|
35
|
+
|
|
36
|
+
Returns
|
|
37
|
+
-------
|
|
38
|
+
Literal["waypoints route testing!"]
|
|
39
|
+
Confirmation message for testing the waypoints route.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
return "waypoints route testing!"
|
|
43
|
+
|
|
44
|
+
@self._blueprint.route("/get", methods=["GET"])
|
|
45
|
+
def get_route() -> tuple[Response, int]:
|
|
46
|
+
"""
|
|
47
|
+
Get the current waypoints.
|
|
48
|
+
|
|
49
|
+
Method: GET
|
|
50
|
+
|
|
51
|
+
Returns
|
|
52
|
+
-------
|
|
53
|
+
tuple[Response, int]
|
|
54
|
+
A tuple containing the JSON response of the waypoints and the HTTP status code.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
return jsonify(self.waypoints), 200
|
|
58
|
+
|
|
59
|
+
@self._blueprint.route("/get_new", methods=["GET"])
|
|
60
|
+
def get_new_route() -> tuple[Response, int]:
|
|
61
|
+
"""
|
|
62
|
+
Get the latest waypoints if they haven't been seen yet.
|
|
63
|
+
|
|
64
|
+
Method: GET
|
|
65
|
+
|
|
66
|
+
Returns
|
|
67
|
+
-------
|
|
68
|
+
tuple[Response, int]
|
|
69
|
+
A tuple containing the JSON response of the new waypoints (or empty if none) and the HTTP status code.
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
if self.new_flag:
|
|
73
|
+
self.new_flag = False
|
|
74
|
+
return jsonify(self.waypoints), 200
|
|
75
|
+
|
|
76
|
+
else:
|
|
77
|
+
return jsonify({}), 200
|
|
78
|
+
|
|
79
|
+
@self._blueprint.route("/set", methods=["POST"])
|
|
80
|
+
def set_route() -> tuple[Response, int]:
|
|
81
|
+
"""
|
|
82
|
+
Set the waypoints from the request data.
|
|
83
|
+
|
|
84
|
+
Method: POST
|
|
85
|
+
|
|
86
|
+
Returns
|
|
87
|
+
-------
|
|
88
|
+
tuple[Response, int]
|
|
89
|
+
A tuple containing a confirmation message and the HTTP status code.
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
try:
|
|
93
|
+
new_waypoints = request.json
|
|
94
|
+
if not isinstance(new_waypoints, list):
|
|
95
|
+
raise TypeError("Invalid waypoints format. Expected a list of lists of floats.")
|
|
96
|
+
|
|
97
|
+
self.waypoints = new_waypoints
|
|
98
|
+
self.new_flag = True
|
|
99
|
+
|
|
100
|
+
return jsonify("Waypoints updated successfully."), 200
|
|
101
|
+
|
|
102
|
+
except TypeError as e:
|
|
103
|
+
return jsonify(str(e)), 400
|
|
104
|
+
|
|
105
|
+
except Exception as e:
|
|
106
|
+
return jsonify(str(e)), 500
|
|
107
|
+
|
|
108
|
+
return f"waypoints paths registered successfully: {self._blueprint.url_prefix}"
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: telemetry_server
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Project-URL: repository, https://github.com/autoboat-vt/telemetry_server
|
|
5
|
+
Description-Content-Type: text/markdown
|
|
6
|
+
Requires-Dist: flask
|
|
7
|
+
Requires-Dist: gunicorn
|
|
8
|
+
|
|
9
|
+
# Autoboat Telemetry Server
|
|
10
|
+
|
|
11
|
+
A lightweight Flask-based web server to collect, display, and manage telemetry data from the Virginia Tech Autoboat project.
|
|
12
|
+
|
|
13
|
+
## 📦 Project Structure
|
|
14
|
+
|
|
15
|
+
```txt
|
|
16
|
+
autoboat_telemetry_server/
|
|
17
|
+
├── __init__.py # App factory
|
|
18
|
+
├── routes
|
|
19
|
+
├── __init__.py # Routes initialization
|
|
20
|
+
├── autopilot_parameters.py # Autopilot parameters routes
|
|
21
|
+
├── boat_status.py # Boat status routes
|
|
22
|
+
├── waypoints.py # Waypoints management routes
|
|
23
|
+
|
|
24
|
+
instance/
|
|
25
|
+
├── config.py # Configuration file
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## 🚀 Quick Start
|
|
29
|
+
|
|
30
|
+
### Installation
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install -e .
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Running the server
|
|
37
|
+
|
|
38
|
+
1. Production ([Gunicorn](https://gunicorn.org/)):
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
gunicorn "autoboat_telemetry_server:create_app()"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
2. Development (Flask):
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
flask run
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Server (Long term)
|
|
51
|
+
|
|
52
|
+
### Installation
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
git clone https://github.com/autoboat-vt/telemetry_server
|
|
56
|
+
cd telemetry_server
|
|
57
|
+
./server_files/install.sh
|
|
58
|
+
```
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
src/app.py
|
|
4
|
+
src/autoboat_telemetry_server/__init__.py
|
|
5
|
+
src/autoboat_telemetry_server/routes/__init__.py
|
|
6
|
+
src/autoboat_telemetry_server/routes/autopilot_parameters.py
|
|
7
|
+
src/autoboat_telemetry_server/routes/boat_status.py
|
|
8
|
+
src/autoboat_telemetry_server/routes/waypoints.py
|
|
9
|
+
src/instance/config.py
|
|
10
|
+
src/telemetry_server.egg-info/PKG-INFO
|
|
11
|
+
src/telemetry_server.egg-info/SOURCES.txt
|
|
12
|
+
src/telemetry_server.egg-info/dependency_links.txt
|
|
13
|
+
src/telemetry_server.egg-info/requires.txt
|
|
14
|
+
src/telemetry_server.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|