2026-09-13 18:14:19 +02:00
|
|
|
<!DOCTYPE html>
|
|
|
|
|
<html lang="en">
|
|
|
|
|
<head>
|
|
|
|
|
<meta charset="UTF-8">
|
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
2026-10-03 20:24:37 +02:00
|
|
|
<title>API Documentation - Yggdrasil</title>
|
|
|
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
|
|
|
<link href="https://fonts.googleapis.com/css2?family=VT323&display=swap" rel="stylesheet">
|
|
|
|
|
<link rel="stylesheet" href="{{ url_for('static', filename='retro.css') }}">
|
2026-09-13 18:14:19 +02:00
|
|
|
</head>
|
|
|
|
|
<body>
|
2026-10-03 20:24:37 +02:00
|
|
|
<nav>
|
|
|
|
|
<a href="{{ url_for('home') }}">Home</a>
|
|
|
|
|
<a href="{{ url_for('sensors_page') }}">Sensors</a>
|
2026-11-01 17:17:58 +01:00
|
|
|
<a href="{{ url_for('notes_page') }}">Notes</a>
|
2026-11-01 20:27:10 +01:00
|
|
|
<a href="{{ url_for('notifications_page') }}">Notifications{% if unread_notifications %} <span class="nav-badge">{{ unread_notifications }}</span>{% endif %}</a>
|
|
|
|
|
<a href="{{ url_for('api_docs') }}">API</a>
|
2026-10-03 20:24:37 +02:00
|
|
|
<a href="{{ url_for('logout') }}">Log out</a>
|
2026-10-23 11:37:55 +02:00
|
|
|
<img class="nav-logo" src="{{ url_for('static', filename='yggdrasil-logo.png') }}" alt="Yggdrasil logo">
|
2026-10-03 20:24:37 +02:00
|
|
|
</nav>
|
2026-09-13 18:14:19 +02:00
|
|
|
<h1>Sensor Readouts — API Documentation</h1>
|
|
|
|
|
|
|
|
|
|
<h2>Base URL</h2>
|
2026-11-01 12:07:04 +01:00
|
|
|
<p><code>{{ main_api_url }}</code></p>
|
|
|
|
|
<p>The main app proxies all requests to the sensors API service.</p>
|
2026-09-13 18:14:19 +02:00
|
|
|
|
|
|
|
|
<!-- GET /api/sensors -->
|
|
|
|
|
<h2>GET /api/sensors</h2>
|
|
|
|
|
<div class="endpoint">
|
|
|
|
|
<span class="method get">GET</span><span class="path">/api/sensors</span>
|
|
|
|
|
<p class="desc">Return a list of all sensors ordered by name.</p>
|
|
|
|
|
<p class="section-label">curl</p>
|
2026-11-01 12:07:04 +01:00
|
|
|
<pre><code>curl {{ main_api_url }}/sensors</code></pre>
|
2026-09-13 18:14:19 +02:00
|
|
|
<p class="section-label">Response 200</p>
|
|
|
|
|
<pre><code>[
|
|
|
|
|
{ "id": 1, "name": "outdoor-station" },
|
|
|
|
|
{ "id": 2, "name": "indoor-unit" }
|
|
|
|
|
]</code></pre>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- POST /api/sensors -->
|
|
|
|
|
<div class="endpoint">
|
|
|
|
|
<span class="method post">POST</span><span class="path">/api/sensors</span>
|
|
|
|
|
<p class="desc">Create a new sensor.</p>
|
|
|
|
|
<p class="section-label">curl</p>
|
2026-11-01 12:07:04 +01:00
|
|
|
<pre><code>curl -X POST {{ main_api_url }}/sensors \
|
2026-09-13 18:14:19 +02:00
|
|
|
-H "Content-Type: application/json" \
|
|
|
|
|
-d '{"name": "new-sensor"}'</code></pre>
|
|
|
|
|
<p class="section-label">Response 201</p>
|
|
|
|
|
<pre><code>{ "id": 5, "name": "new-sensor" }</code></pre>
|
|
|
|
|
<p><strong>Errors:</strong></p>
|
|
|
|
|
<table>
|
|
|
|
|
<tr><th>Code</th><th>Condition</th></tr>
|
|
|
|
|
<tr><td>400</td><td><code>name</code> is missing or empty</td></tr>
|
|
|
|
|
<tr><td>409</td><td>Sensor with this name already exists</td></tr>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- GET /api/sensors/:id/types -->
|
|
|
|
|
<h2>GET /api/sensors/:id/types</h2>
|
|
|
|
|
<div class="endpoint">
|
|
|
|
|
<span class="method get">GET</span><span class="path">/api/sensors/:id/types</span>
|
|
|
|
|
<p class="desc">Return distinct readout types available for a given sensor.</p>
|
|
|
|
|
<p class="section-label">curl</p>
|
2026-11-01 12:07:04 +01:00
|
|
|
<pre><code>curl {{ main_api_url }}/sensors/1/types</code></pre>
|
2026-09-13 18:14:19 +02:00
|
|
|
<p class="section-label">Response 200</p>
|
|
|
|
|
<pre><code>["humidity", "pressure", "temperature"]</code></pre>
|
|
|
|
|
<p><strong>Errors:</strong></p>
|
|
|
|
|
<table>
|
|
|
|
|
<tr><th>Code</th><th>Condition</th></tr>
|
|
|
|
|
<tr><td>404</td><td>Sensor not found</td></tr>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- GET /api/sensors/:id/readouts -->
|
|
|
|
|
<h2>GET /api/sensors/:id/readouts</h2>
|
|
|
|
|
<div class="endpoint">
|
|
|
|
|
<span class="method get">GET</span><span class="path">/api/sensors/:id/readouts</span>
|
|
|
|
|
<p class="desc">Return the latest readouts for a sensor. Optional <code>type</code> query parameter filters by readout type.</p>
|
|
|
|
|
<p><strong>Query parameters:</strong></p>
|
|
|
|
|
<table>
|
|
|
|
|
<tr><th>Param</th><th>Type</th><th>Description</th></tr>
|
|
|
|
|
<tr><td>type</td><td>string</td><td>Filter by type (e.g. <code>temperature</code>)</td></tr>
|
|
|
|
|
</table>
|
|
|
|
|
<p class="section-label">curl</p>
|
|
|
|
|
<pre><code># all types
|
2026-11-01 12:07:04 +01:00
|
|
|
curl {{ main_api_url }}/sensors/1/readouts
|
2026-09-13 18:14:19 +02:00
|
|
|
|
|
|
|
|
# filter by type
|
2026-11-01 12:07:04 +01:00
|
|
|
curl "{{ main_api_url }}/sensors/1/readouts?type=temperature"</code></pre>
|
2026-09-13 18:14:19 +02:00
|
|
|
<p class="section-label">Response 200</p>
|
|
|
|
|
<pre><code>[
|
|
|
|
|
{ "value": 24.31, "timestamp": "2026-09-11T10:30:00" },
|
|
|
|
|
{ "value": 24.15, "timestamp": "2026-09-11T10:29:30" }
|
|
|
|
|
]</code></pre>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- POST /api/sensors/:id/readouts -->
|
|
|
|
|
<div class="endpoint">
|
|
|
|
|
<span class="method post">POST</span><span class="path">/api/sensors/:id/readouts</span>
|
|
|
|
|
<p class="desc">Add a new readout to an existing sensor. Timestamp is generated server-side.</p>
|
|
|
|
|
<p class="section-label">curl</p>
|
2026-11-01 12:07:04 +01:00
|
|
|
<pre><code>curl -X POST {{ main_api_url }}/sensors/1/readouts \
|
2026-09-13 18:14:19 +02:00
|
|
|
-H "Content-Type: application/json" \
|
|
|
|
|
-d '{"type": "temperature", "value": 22.5}'</code></pre>
|
|
|
|
|
<p class="section-label">Response 201</p>
|
|
|
|
|
<pre><code>{
|
|
|
|
|
"id": 2702,
|
|
|
|
|
"sensor_id": 1,
|
|
|
|
|
"type": "temperature",
|
|
|
|
|
"value": 22.5,
|
|
|
|
|
"timestamp": "2026-09-11T17:00:00.123456"
|
|
|
|
|
}</code></pre>
|
|
|
|
|
<p><strong>Errors:</strong></p>
|
|
|
|
|
<table>
|
|
|
|
|
<tr><th>Code</th><th>Condition</th></tr>
|
|
|
|
|
<tr><td>400</td><td>Missing <code>type</code> or <code>value</code>, or <code>value</code> is not a number</td></tr>
|
|
|
|
|
<tr><td>404</td><td>Sensor not found</td></tr>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="note">
|
|
|
|
|
<strong>Note:</strong> All request and response bodies use <code>application/json</code>.
|
|
|
|
|
</div>
|
2026-10-03 20:24:37 +02:00
|
|
|
|
|
|
|
|
<footer class="statusbar">
|
|
|
|
|
<span>{{ user.username }}@yggdrasil:~/api$</span>
|
|
|
|
|
</footer>
|
2026-09-13 18:14:19 +02:00
|
|
|
</body>
|
|
|
|
|
</html>
|