{ "cells": [ { "cell_type": "markdown", "id": "c5066026", "metadata": {}, "source": [ "# Using TimeDB API\n", "\n", "This notebook demonstrates how to use the TimeDB REST API to read and write time series data.\n", "\n", "**Note**: This example assumes no user authentication (users_table is not created). In production, you would typically use authentication with API keys.\n", "\n", "## What we'll cover:\n", "1. Setting up the database schema (using SDK - admin task)\n", "2. Starting the API server\n", "3. Inserting time series data using the REST API\n", "4. Reading time series data using the REST API\n", "5. Updating records using the REST API\n" ] }, { "cell_type": "code", "execution_count": 6, "id": "c951cc83", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "✓ Imports successful\n" ] } ], "source": [ "import timedb as td\n", "import pandas as pd\n", "import requests\n", "import json\n", "from datetime import datetime, timezone, timedelta\n", "from typing import Dict, Any\n", "\n", "# API base URL (adjust if your API is running on a different host/port)\n", "API_BASE_URL = \"http://127.0.0.1:8000\"\n", "API_BASE_URL = \"https://rebase-energy--timedb-api-fastapi-app-dev.modal.run\"\n", "API_BASE_URL = \"https://sebaheg--timedb-api-fastapi-app.modal.run\"\n", "print(\"✓ Imports successful\")\n" ] }, { "cell_type": "markdown", "id": "cf1860a3", "metadata": {}, "source": [ "## Part 1: Setup Database Schema\n", "\n", "First, we'll use the SDK to create the database schema. This is typically done once by an administrator. The API cannot create or delete the database schema - this must be done through the SDK or CLI.\n" ] }, { "cell_type": "code", "execution_count": 3, "id": "e7d798a4", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Creating database schema...\n", "✓ Schema created successfully\n" ] } ], "source": [ "# Delete existing schema (optional - only if you want to start fresh)\n", "# Uncomment the line below if you want to start with a clean database\n", "td.delete()\n", "\n", "# Create database schema\n", "td.create()\n" ] }, { "cell_type": "markdown", "id": "cd50c230", "metadata": {}, "source": [ "## Part 2: Start the API Server\n", "\n", "Before we can use the API, we need to start the API server. \n", "\n", "**Note**: The API server runs in a blocking manner. In a notebook, we'll start it in a background thread so we can continue using the notebook.\n" ] }, { "cell_type": "code", "execution_count": 3, "id": "5a264e58", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "INFO: Started server process [73573]\n", "INFO: Waiting for application startup.\n", "INFO: Application startup complete.\n", "INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Starting API server in background thread on http://127.0.0.1:8000...\n", "Starting TimeDB API server on http://127.0.0.1:8000\n", "API docs available at http://127.0.0.1:8000/docs\n", "Press Ctrl+C to stop the server\n", "INFO: 127.0.0.1:60092 - \"GET / HTTP/1.1\" 200 OK\n", "✓ API is running\n", " Name: TimeDB API\n", " Version: 0.1.1\n", "\n", "Available endpoints:\n", " - read_values: GET /values - Read time series values\n", " - upload_timeseries: POST /upload - Upload time series data (create a new run with values)\n", " - create_series: POST /series - Create a new time series\n", " - list_timeseries: GET /list_timeseries - List all time series (series_id -> series_key mapping)\n", " - update_records: PUT /values - Update existing time series records\n", "✓ API server started successfully\n", " Server running at http://127.0.0.1:8000\n", " API docs available at http://127.0.0.1:8000/docs\n" ] }, { "data": { "text/plain": [ "True" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Start the API server in the background\n", "# This will start the server in a daemon thread so we can continue using the notebook\n", "td.start_api_background()\n" ] }, { "cell_type": "code", "execution_count": 4, "id": "93bf1ba9", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "❌ API is not running!\n", " Please start it by running: td.start_api_background()\n", " Or in a terminal: timedb api\n" ] }, { "data": { "text/plain": [ "False" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Verify API is running and get API information\n", "td.check_api()\n" ] }, { "cell_type": "markdown", "id": "4ae14808", "metadata": {}, "source": [ "## Part 3: Insert Data Using the API\n", "\n", "Now let's create some sample time series data and insert it using the REST API.\n" ] }, { "cell_type": "code", "execution_count": 14, "id": "0dbd79a3", "metadata": {}, "outputs": [], "source": [ "headers={\"Content-Type\": \"application/json\",\n", " \"X-API-Key\": \"OekXZaRjQDxdQ-3NfX_Y0p7SzgRWSkd2q32VxUkJbTs\"}" ] }, { "cell_type": "code", "execution_count": 8, "id": "efc22941", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "✓ Created series 'temperature': 49c45b07-7910-4f85-add4-1d77bf80d487\n", " Message: Series created successfully\n", "✓ Created series 'humidity': 79e63af8-b0e0-4372-b0db-cee9b975c600\n", " Message: Series created successfully\n", "\n", "✓ Created 2 time series\n", "\n", "Prepared 48 value rows to insert\n", "Time range: 2025-01-01 00:00:00+00:00 to 2025-01-01 23:00:00+00:00\n", "Series: temperature, humidity\n" ] } ], "source": [ "# First, create the time series using the /create_series endpoint\n", "series_to_create = [\n", " {\n", " \"name\": \"temperature\",\n", " \"description\": \"Temperature measurements in Celsius\",\n", " \"unit\": \"celsius\"\n", " },\n", " {\n", " \"name\": \"humidity\",\n", " \"description\": \"Relative humidity percentage\",\n", " \"unit\": \"percent\"\n", " }\n", "]\n", "\n", "created_series = {}\n", "for series_info in series_to_create:\n", " response = requests.post(\n", " f\"{API_BASE_URL}/series\",\n", " json=series_info,\n", " headers={\"Content-Type\": \"application/json\",\n", " \"X-API-Key\": \"OekXZaRjQDxdQ-3NfX_Y0p7SzgRWSkd2q32VxUkJbTs\"\n", " }\n", " )\n", " response.raise_for_status()\n", " result = response.json()\n", " series_key = series_info[\"name\"]\n", " created_series[series_key] = result[\"series_id\"]\n", " print(f\"✓ Created series '{series_key}': {result['series_id']}\")\n", " print(f\" Message: {result['message']}\")\n", "\n", "print(f\"\\n✓ Created {len(created_series)} time series\")\n", "\n", "# Create sample time series data\n", "base_time = datetime(2025, 1, 1, 0, 0, tzinfo=timezone.utc)\n", "dates = [base_time + timedelta(hours=i) for i in range(24)]\n", "\n", "# Prepare request payload for API\n", "# Now we use the series_key from the created series\n", "value_rows = []\n", "for i, date in enumerate(dates):\n", " # Add temperature value using the created series_key\n", " value_rows.append({\n", " \"valid_time\": date.isoformat(),\n", " \"value_key\": \"temperature\", # Use the series_key from created series\n", " \"value\": 20.0 + i * 0.3 # Temperature rising\n", " })\n", " # Add humidity value using the created series_key\n", " value_rows.append({\n", " \"valid_time\": date.isoformat(),\n", " \"value_key\": \"humidity\", # Use the series_key from created series\n", " \"value\": 60.0 - i * 0.5 # Humidity decreasing\n", " })\n", "\n", "# Note: workflow_id defaults to \"api-workflow\" if not provided\n", "create_run_request = {\n", " \"run_start_time\": datetime.now(timezone.utc).isoformat(),\n", " \"value_rows\": value_rows\n", "}\n", "\n", "print(f\"\\nPrepared {len(value_rows)} value rows to insert\")\n", "print(f\"Time range: {dates[0]} to {dates[-1]}\")\n", "print(f\"Series: {', '.join(created_series.keys())}\")\n" ] }, { "cell_type": "markdown", "id": "d68fad34", "metadata": {}, "source": [ "### 3.1: Upload the Data\n", "\n", "Now let's upload the time series data using the series_keys from the series we just created.\n" ] }, { "cell_type": "code", "execution_count": 10, "id": "fab8523c", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "✓ Created run with ID: c5c7b465-1a9f-4605-a801-c51b8de0e73e\n", " Message: Run created successfully\n", "\n", "Series IDs returned:\n", " temperature: 4b7f4c69-6898-406e-9d6d-78d7a9096214\n", " humidity: 715583c0-1d9e-4012-b938-013d0f5dc563\n" ] } ], "source": [ "# Upload data via API\n", "response = requests.post(\n", " f\"{API_BASE_URL}/upload\",\n", " json=create_run_request,\n", " headers={\"Content-Type\": \"application/json\",\n", " \"X-API-Key\": \"OekXZaRjQDxdQ-3NfX_Y0p7SzgRWSkd2q32VxUkJbTs\"\n", " }\n", ")\n", "response.raise_for_status()\n", "\n", "result = response.json()\n", "print(f\"✓ Created run with ID: {result['run_id']}\")\n", "print(f\" Message: {result['message']}\")\n", "print(f\"\\nSeries IDs returned:\")\n", "for series_key, series_id in result['series_ids'].items():\n", " print(f\" {series_key}: {series_id}\")\n", "\n", "# Store run_id and series_ids for later use\n", "run_id = result['run_id']\n", "series_ids = result['series_ids'] # Maps series_key -> series_id\n" ] }, { "cell_type": "markdown", "id": "5fc21dd0", "metadata": {}, "source": [ "### 3.2: List All Time Series\n", "\n", "After uploading data, you can list all available time series to get the series_id -> series_key mapping. This is useful for subsequent API calls.\n" ] }, { "cell_type": "code", "execution_count": 13, "id": "09f69fd7", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "✓ Found 2 time series\n", "\n", "Series information:\n", " 715583c0-1d9e-4012-b938-013d0f5dc563:\n", " Series Key: humidity\n", " Description: None\n", " Unit: dimensionless\n", " 4b7f4c69-6898-406e-9d6d-78d7a9096214:\n", " Series Key: temperature\n", " Description: None\n", " Unit: dimensionless\n" ] } ], "source": [ "# List all time series\n", "response = requests.get(f\"{API_BASE_URL}/list_timeseries\",\n", " headers={\"Content-Type\": \"application/json\",\n", " \"X-API-Key\": \"OekXZaRjQDxdQ-3NfX_Y0p7SzgRWSkd2q32VxUkJbTs\"\n", " })\n", "response.raise_for_status()\n", "\n", "timeseries_list = response.json()\n", "print(f\"✓ Found {len(timeseries_list)} time series\")\n", "print(\"\\nSeries information:\")\n", "for series_id, series_info in timeseries_list.items():\n", " print(f\" {series_id}:\")\n", " print(f\" Series Key: {series_info['series_key']}\")\n", " print(f\" Description: {series_info.get('description', 'N/A')}\")\n", " print(f\" Unit: {series_info['unit']}\")\n", "\n", "# Store for later use\n", "all_series_ids = timeseries_list\n" ] }, { "cell_type": "markdown", "id": "ee28ad3c", "metadata": {}, "source": [ "## Part 4: Read Data Using the API\n", "\n", "Let's read the time series data we just inserted using the API.\n" ] }, { "cell_type": "code", "execution_count": 15, "id": "06ea2260", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "✓ Retrieved 48 records via API\n", "\n", "First few rows:\n", " valid_time series_id value \\\n", "0 2025-01-01 00:00:00+00:00 4b7f4c69-6898-406e-9d6d-78d7a9096214 20.0 \n", "1 2025-01-01 00:00:00+00:00 715583c0-1d9e-4012-b938-013d0f5dc563 60.0 \n", "2 2025-01-01 01:00:00+00:00 4b7f4c69-6898-406e-9d6d-78d7a9096214 20.3 \n", "3 2025-01-01 01:00:00+00:00 715583c0-1d9e-4012-b938-013d0f5dc563 59.5 \n", "4 2025-01-01 02:00:00+00:00 4b7f4c69-6898-406e-9d6d-78d7a9096214 20.6 \n", "5 2025-01-01 02:00:00+00:00 715583c0-1d9e-4012-b938-013d0f5dc563 59.0 \n", "6 2025-01-01 03:00:00+00:00 4b7f4c69-6898-406e-9d6d-78d7a9096214 20.9 \n", "7 2025-01-01 03:00:00+00:00 715583c0-1d9e-4012-b938-013d0f5dc563 58.5 \n", "8 2025-01-01 04:00:00+00:00 4b7f4c69-6898-406e-9d6d-78d7a9096214 21.2 \n", "9 2025-01-01 04:00:00+00:00 715583c0-1d9e-4012-b938-013d0f5dc563 58.0 \n", "\n", " series_key series_unit \n", "0 temperature dimensionless \n", "1 humidity dimensionless \n", "2 temperature dimensionless \n", "3 humidity dimensionless \n", "4 temperature dimensionless \n", "5 humidity dimensionless \n", "6 temperature dimensionless \n", "7 humidity dimensionless \n", "8 temperature dimensionless \n", "9 humidity dimensionless \n", "\n", "DataFrame shape: (48, 5)\n", "Columns: ['valid_time', 'series_id', 'value', 'series_key', 'series_unit']\n" ] } ], "source": [ "# Read data via API\n", "# Note: Since we're not using authentication, we can read all data\n", "params = {\n", " \"start_valid\": base_time.isoformat(),\n", " \"end_valid\": (base_time + timedelta(hours=24)).isoformat(),\n", " \"mode\": \"flat\", # \"flat\" returns latest known_time per valid_time, \"overlapping\" returns all revisions\n", " \"all_versions\": False # Set to True to include historical versions\n", "}\n", "\n", "response = requests.get(f\"{API_BASE_URL}/values\", params=params, headers=headers)\n", "response.raise_for_status()\n", "\n", "data = response.json()\n", "print(f\"✓ Retrieved {data['count']} records via API\")\n", "\n", "# Convert to DataFrame for easier viewing\n", "if data['count'] > 0:\n", " df_api = pd.DataFrame(data['data'])\n", " # Convert ISO strings back to datetime\n", " df_api['valid_time'] = pd.to_datetime(df_api['valid_time'])\n", " print(\"\\nFirst few rows:\")\n", " print(df_api.head(10))\n", " print(f\"\\nDataFrame shape: {df_api.shape}\")\n", " print(f\"Columns: {list(df_api.columns)}\")\n", "else:\n", " print(\"No data found\")\n" ] }, { "cell_type": "code", "execution_count": 16, "id": "0b6c7120", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
| \n", " | valid_time | \n", "series_id | \n", "value | \n", "series_key | \n", "series_unit | \n", "
|---|---|---|---|---|---|
| 0 | \n", "2025-01-01 00:00:00+00:00 | \n", "4b7f4c69-6898-406e-9d6d-78d7a9096214 | \n", "20.0 | \n", "temperature | \n", "dimensionless | \n", "
| 1 | \n", "2025-01-01 00:00:00+00:00 | \n", "715583c0-1d9e-4012-b938-013d0f5dc563 | \n", "60.0 | \n", "humidity | \n", "dimensionless | \n", "
| 2 | \n", "2025-01-01 01:00:00+00:00 | \n", "4b7f4c69-6898-406e-9d6d-78d7a9096214 | \n", "20.3 | \n", "temperature | \n", "dimensionless | \n", "
| 3 | \n", "2025-01-01 01:00:00+00:00 | \n", "715583c0-1d9e-4012-b938-013d0f5dc563 | \n", "59.5 | \n", "humidity | \n", "dimensionless | \n", "
| 4 | \n", "2025-01-01 02:00:00+00:00 | \n", "4b7f4c69-6898-406e-9d6d-78d7a9096214 | \n", "20.6 | \n", "temperature | \n", "dimensionless | \n", "
| 5 | \n", "2025-01-01 02:00:00+00:00 | \n", "715583c0-1d9e-4012-b938-013d0f5dc563 | \n", "59.0 | \n", "humidity | \n", "dimensionless | \n", "
| 6 | \n", "2025-01-01 03:00:00+00:00 | \n", "4b7f4c69-6898-406e-9d6d-78d7a9096214 | \n", "20.9 | \n", "temperature | \n", "dimensionless | \n", "
| 7 | \n", "2025-01-01 03:00:00+00:00 | \n", "715583c0-1d9e-4012-b938-013d0f5dc563 | \n", "58.5 | \n", "humidity | \n", "dimensionless | \n", "
| 8 | \n", "2025-01-01 04:00:00+00:00 | \n", "4b7f4c69-6898-406e-9d6d-78d7a9096214 | \n", "21.2 | \n", "temperature | \n", "dimensionless | \n", "
| 9 | \n", "2025-01-01 04:00:00+00:00 | \n", "715583c0-1d9e-4012-b938-013d0f5dc563 | \n", "58.0 | \n", "humidity | \n", "dimensionless | \n", "
| 10 | \n", "2025-01-01 05:00:00+00:00 | \n", "4b7f4c69-6898-406e-9d6d-78d7a9096214 | \n", "21.5 | \n", "temperature | \n", "dimensionless | \n", "
| 11 | \n", "2025-01-01 05:00:00+00:00 | \n", "715583c0-1d9e-4012-b938-013d0f5dc563 | \n", "57.5 | \n", "humidity | \n", "dimensionless | \n", "
| 12 | \n", "2025-01-01 06:00:00+00:00 | \n", "4b7f4c69-6898-406e-9d6d-78d7a9096214 | \n", "21.8 | \n", "temperature | \n", "dimensionless | \n", "
| 13 | \n", "2025-01-01 06:00:00+00:00 | \n", "715583c0-1d9e-4012-b938-013d0f5dc563 | \n", "57.0 | \n", "humidity | \n", "dimensionless | \n", "
| 14 | \n", "2025-01-01 07:00:00+00:00 | \n", "4b7f4c69-6898-406e-9d6d-78d7a9096214 | \n", "22.1 | \n", "temperature | \n", "dimensionless | \n", "
| 15 | \n", "2025-01-01 07:00:00+00:00 | \n", "715583c0-1d9e-4012-b938-013d0f5dc563 | \n", "56.5 | \n", "humidity | \n", "dimensionless | \n", "
| 16 | \n", "2025-01-01 08:00:00+00:00 | \n", "4b7f4c69-6898-406e-9d6d-78d7a9096214 | \n", "22.4 | \n", "temperature | \n", "dimensionless | \n", "
| 17 | \n", "2025-01-01 08:00:00+00:00 | \n", "715583c0-1d9e-4012-b938-013d0f5dc563 | \n", "56.0 | \n", "humidity | \n", "dimensionless | \n", "
| 18 | \n", "2025-01-01 09:00:00+00:00 | \n", "4b7f4c69-6898-406e-9d6d-78d7a9096214 | \n", "22.7 | \n", "temperature | \n", "dimensionless | \n", "
| 19 | \n", "2025-01-01 09:00:00+00:00 | \n", "715583c0-1d9e-4012-b938-013d0f5dc563 | \n", "55.5 | \n", "humidity | \n", "dimensionless | \n", "
| 20 | \n", "2025-01-01 10:00:00+00:00 | \n", "4b7f4c69-6898-406e-9d6d-78d7a9096214 | \n", "23.0 | \n", "temperature | \n", "dimensionless | \n", "
| 21 | \n", "2025-01-01 10:00:00+00:00 | \n", "715583c0-1d9e-4012-b938-013d0f5dc563 | \n", "55.0 | \n", "humidity | \n", "dimensionless | \n", "
| 22 | \n", "2025-01-01 11:00:00+00:00 | \n", "4b7f4c69-6898-406e-9d6d-78d7a9096214 | \n", "23.3 | \n", "temperature | \n", "dimensionless | \n", "
| 23 | \n", "2025-01-01 11:00:00+00:00 | \n", "715583c0-1d9e-4012-b938-013d0f5dc563 | \n", "54.5 | \n", "humidity | \n", "dimensionless | \n", "
| 24 | \n", "2025-01-01 12:00:00+00:00 | \n", "4b7f4c69-6898-406e-9d6d-78d7a9096214 | \n", "23.6 | \n", "temperature | \n", "dimensionless | \n", "
| 25 | \n", "2025-01-01 12:00:00+00:00 | \n", "715583c0-1d9e-4012-b938-013d0f5dc563 | \n", "54.0 | \n", "humidity | \n", "dimensionless | \n", "
| 26 | \n", "2025-01-01 13:00:00+00:00 | \n", "4b7f4c69-6898-406e-9d6d-78d7a9096214 | \n", "23.9 | \n", "temperature | \n", "dimensionless | \n", "
| 27 | \n", "2025-01-01 13:00:00+00:00 | \n", "715583c0-1d9e-4012-b938-013d0f5dc563 | \n", "53.5 | \n", "humidity | \n", "dimensionless | \n", "
| 28 | \n", "2025-01-01 14:00:00+00:00 | \n", "4b7f4c69-6898-406e-9d6d-78d7a9096214 | \n", "24.2 | \n", "temperature | \n", "dimensionless | \n", "
| 29 | \n", "2025-01-01 14:00:00+00:00 | \n", "715583c0-1d9e-4012-b938-013d0f5dc563 | \n", "53.0 | \n", "humidity | \n", "dimensionless | \n", "
| 30 | \n", "2025-01-01 15:00:00+00:00 | \n", "4b7f4c69-6898-406e-9d6d-78d7a9096214 | \n", "24.5 | \n", "temperature | \n", "dimensionless | \n", "
| 31 | \n", "2025-01-01 15:00:00+00:00 | \n", "715583c0-1d9e-4012-b938-013d0f5dc563 | \n", "52.5 | \n", "humidity | \n", "dimensionless | \n", "
| 32 | \n", "2025-01-01 16:00:00+00:00 | \n", "4b7f4c69-6898-406e-9d6d-78d7a9096214 | \n", "24.8 | \n", "temperature | \n", "dimensionless | \n", "
| 33 | \n", "2025-01-01 16:00:00+00:00 | \n", "715583c0-1d9e-4012-b938-013d0f5dc563 | \n", "52.0 | \n", "humidity | \n", "dimensionless | \n", "
| 34 | \n", "2025-01-01 17:00:00+00:00 | \n", "4b7f4c69-6898-406e-9d6d-78d7a9096214 | \n", "25.1 | \n", "temperature | \n", "dimensionless | \n", "
| 35 | \n", "2025-01-01 17:00:00+00:00 | \n", "715583c0-1d9e-4012-b938-013d0f5dc563 | \n", "51.5 | \n", "humidity | \n", "dimensionless | \n", "
| 36 | \n", "2025-01-01 18:00:00+00:00 | \n", "4b7f4c69-6898-406e-9d6d-78d7a9096214 | \n", "25.4 | \n", "temperature | \n", "dimensionless | \n", "
| 37 | \n", "2025-01-01 18:00:00+00:00 | \n", "715583c0-1d9e-4012-b938-013d0f5dc563 | \n", "51.0 | \n", "humidity | \n", "dimensionless | \n", "
| 38 | \n", "2025-01-01 19:00:00+00:00 | \n", "4b7f4c69-6898-406e-9d6d-78d7a9096214 | \n", "25.7 | \n", "temperature | \n", "dimensionless | \n", "
| 39 | \n", "2025-01-01 19:00:00+00:00 | \n", "715583c0-1d9e-4012-b938-013d0f5dc563 | \n", "50.5 | \n", "humidity | \n", "dimensionless | \n", "
| 40 | \n", "2025-01-01 20:00:00+00:00 | \n", "4b7f4c69-6898-406e-9d6d-78d7a9096214 | \n", "26.0 | \n", "temperature | \n", "dimensionless | \n", "
| 41 | \n", "2025-01-01 20:00:00+00:00 | \n", "715583c0-1d9e-4012-b938-013d0f5dc563 | \n", "50.0 | \n", "humidity | \n", "dimensionless | \n", "
| 42 | \n", "2025-01-01 21:00:00+00:00 | \n", "4b7f4c69-6898-406e-9d6d-78d7a9096214 | \n", "26.3 | \n", "temperature | \n", "dimensionless | \n", "
| 43 | \n", "2025-01-01 21:00:00+00:00 | \n", "715583c0-1d9e-4012-b938-013d0f5dc563 | \n", "49.5 | \n", "humidity | \n", "dimensionless | \n", "
| 44 | \n", "2025-01-01 22:00:00+00:00 | \n", "4b7f4c69-6898-406e-9d6d-78d7a9096214 | \n", "26.6 | \n", "temperature | \n", "dimensionless | \n", "
| 45 | \n", "2025-01-01 22:00:00+00:00 | \n", "715583c0-1d9e-4012-b938-013d0f5dc563 | \n", "49.0 | \n", "humidity | \n", "dimensionless | \n", "
| 46 | \n", "2025-01-01 23:00:00+00:00 | \n", "4b7f4c69-6898-406e-9d6d-78d7a9096214 | \n", "26.9 | \n", "temperature | \n", "dimensionless | \n", "
| 47 | \n", "2025-01-01 23:00:00+00:00 | \n", "715583c0-1d9e-4012-b938-013d0f5dc563 | \n", "48.5 | \n", "humidity | \n", "dimensionless | \n", "