From 8aac30268245e3b82480f4c78435348cf74333e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20S=C3=A1nchez-Gallego?= Date: Mon, 11 Nov 2024 18:12:01 -0800 Subject: [PATCH 1/3] Stub for transparency route --- src/lvmapi/routers/transparency.py | 40 ++++++++++++++++++++++++++++++ src/lvmapi/tools/transparency.py | 27 ++++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 src/lvmapi/routers/transparency.py create mode 100644 src/lvmapi/tools/transparency.py diff --git a/src/lvmapi/routers/transparency.py b/src/lvmapi/routers/transparency.py new file mode 100644 index 0000000..8f36b28 --- /dev/null +++ b/src/lvmapi/routers/transparency.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# @Author: José Sánchez-Gallego (gallegoj@uw.edu) +# @Date: 2024-11-11 +# @Filename: transparency.py +# @License: BSD 3-clause (http://www.opensource.org/licenses/BSD-3-Clause) + +from __future__ import annotations + +from time import time + +from typing import Annotated + +from fastapi import APIRouter, Query + + +router = APIRouter(prefix="/transparency", tags=["transparency"]) + + +@router.get("/", summary="Transparency measurements") +async def route_get_transparency( + start_time: Annotated[ + float | None, + Query(description="Start time as a UNIX timestamp"), + ] = None, + end_time: Annotated[ + float | None, + Query(description="End time as a UNIX timestamp"), + ] = None, +): + """Returns transparency measurements. + + Without any parameters, returns the transparency measurements for the last hour. + + """ + + if start_time is None or end_time is None: + end_time = time() + start_time = end_time - 3600 diff --git a/src/lvmapi/tools/transparency.py b/src/lvmapi/tools/transparency.py new file mode 100644 index 0000000..7073320 --- /dev/null +++ b/src/lvmapi/tools/transparency.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# @Author: José Sánchez-Gallego (gallegoj@uw.edu) +# @Date: 2024-11-11 +# @Filename: transparency.py +# @License: BSD 3-clause (http://www.opensource.org/licenses/BSD-3-Clause) + +from __future__ import annotations + +from lvmapi.tools.influxdb import query_influxdb + + +async def get_transparency(start_time: float, end_time: float): + """Returns transparency measurements.""" + + query = rf""" +from(bucket: "actors") + |> range(start: {start_time*1000}, stop: {end_time*1000}) + |> filter(fn: (r) => (r["_measurement"] =~ /lvm\.[a-z]+\.guider/) and + (r["_field"] == "measured_pointing.zero_point")) + |> yield(name: "mean") +""" + + data = await query_influxdb(query) + + return data From 3850a7c17c359b2c5df23875939c0b5e02c5b8f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20S=C3=A1nchez-Gallego?= Date: Tue, 12 Nov 2024 03:30:16 +0000 Subject: [PATCH 2/3] Complete code --- src/lvmapi/app.py | 2 ++ src/lvmapi/routers/transparency.py | 39 +++++++++++++++++++++++++++++- src/lvmapi/tools/transparency.py | 11 ++++++++- 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/lvmapi/app.py b/src/lvmapi/app.py index d0e6ea4..6210328 100644 --- a/src/lvmapi/app.py +++ b/src/lvmapi/app.py @@ -29,6 +29,7 @@ spectrographs, tasks, telescopes, + transparency, weather, ) from lvmapi.tools.kubernetes import Kubernetes @@ -51,6 +52,7 @@ app.include_router(actors.router) app.include_router(logs.router) app.include_router(notifications.router) +app.include_router(transparency.router) @app.get("/id") diff --git a/src/lvmapi/routers/transparency.py b/src/lvmapi/routers/transparency.py index 8f36b28..2ea6aca 100644 --- a/src/lvmapi/routers/transparency.py +++ b/src/lvmapi/routers/transparency.py @@ -8,16 +8,45 @@ from __future__ import annotations +from datetime import datetime from time import time from typing import Annotated from fastapi import APIRouter, Query +from pydantic import BaseModel, Field + +from lvmapi.tools.transparency import get_transparency router = APIRouter(prefix="/transparency", tags=["transparency"]) +class TransparencyResponse(BaseModel): + """Response model for transparency measurements.""" + + start_time: Annotated[ + float, + Field(description="Start time of the measurements as a UNIX timestamp"), + ] + end_time: Annotated[ + float, + Field(description="End time of the measurements as a UNIX timestamp"), + ] + data: Annotated[ + list[TransparencyData], + Field(description="Transparency data"), + ] + + +class TransparencyData(BaseModel): + """Model for transparency data.""" + + time: Annotated[datetime, Field(description="Time of the measurement")] + telescope: Annotated[str, Field(description="Telescope name")] + zero_point: Annotated[float, Field(description="Zero-point value")] + + @router.get("/", summary="Transparency measurements") async def route_get_transparency( start_time: Annotated[ @@ -28,7 +57,7 @@ async def route_get_transparency( float | None, Query(description="End time as a UNIX timestamp"), ] = None, -): +) -> TransparencyResponse: """Returns transparency measurements. Without any parameters, returns the transparency measurements for the last hour. @@ -38,3 +67,11 @@ async def route_get_transparency( if start_time is None or end_time is None: end_time = time() start_time = end_time - 3600 + + data = await get_transparency(start_time, end_time) + + return TransparencyResponse( + start_time=start_time, + end_time=end_time, + data=[TransparencyData(**row) for row in data.to_dicts()], + ) diff --git a/src/lvmapi/tools/transparency.py b/src/lvmapi/tools/transparency.py index 7073320..174c871 100644 --- a/src/lvmapi/tools/transparency.py +++ b/src/lvmapi/tools/transparency.py @@ -8,6 +8,8 @@ from __future__ import annotations +import polars + from lvmapi.tools.influxdb import query_influxdb @@ -16,7 +18,7 @@ async def get_transparency(start_time: float, end_time: float): query = rf""" from(bucket: "actors") - |> range(start: {start_time*1000}, stop: {end_time*1000}) + |> range(start: {int(start_time)}, stop: {int(end_time)}) |> filter(fn: (r) => (r["_measurement"] =~ /lvm\.[a-z]+\.guider/) and (r["_field"] == "measured_pointing.zero_point")) |> yield(name: "mean") @@ -24,4 +26,11 @@ async def get_transparency(start_time: float, end_time: float): data = await query_influxdb(query) + # Clean up the dataframe. + data = data.select( + time=polars.col._time, + telescope=polars.col._measurement.str.extract(r"lvm\.([a-z]+)\.guider"), + zero_point=polars.col._value, + ) + return data From e617021f097a6b861fa8b5873c25c02626cd7043 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20S=C3=A1nchez-Gallego?= Date: Tue, 12 Nov 2024 03:38:47 +0000 Subject: [PATCH 3/3] Update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 15b16ee..71aeed9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Next version +### 🚀 New + +* [#14](https://github.com/sdss/lvmapi/pull/14) Add `/transparency` endpoint to retrieve transparency data. + ### 🔧 Fixed * Correctly calculate time lost in night metrics while the night is ongoing.