added graph endpoint
This commit is contained in:
parent
9783501744
commit
6f13e5bf3b
@ -1,4 +1,5 @@
|
||||
from rest_framework import serializers
|
||||
from django.db import models
|
||||
from .models import WeatherStats
|
||||
|
||||
class WeatherStatSerializer(serializers.ModelSerializer):
|
||||
@ -8,9 +9,6 @@ class WeatherStatSerializer(serializers.ModelSerializer):
|
||||
model = WeatherStats
|
||||
fields = ('humidity_air', 'humidity_ground', 'temperature', 'light', 'created_at')
|
||||
|
||||
|
||||
|
||||
|
||||
class OpenWeatherAPISerializer(serializers.Serializer):
|
||||
date = serializers.DateField()
|
||||
temp_night = serializers.FloatField()
|
||||
@ -18,3 +16,25 @@ class OpenWeatherAPISerializer(serializers.Serializer):
|
||||
humidity = serializers.FloatField()
|
||||
wind_speed = serializers.FloatField()
|
||||
precip_probability = serializers.FloatField()
|
||||
|
||||
class WeatherPeriods(models.TextChoices):
|
||||
min_10 = 'min_10', '10 Minutes'
|
||||
min_30 = 'min_30', '30 Minutes'
|
||||
hour = 'hour', '1 Hour'
|
||||
hour_6 = 'hour_6', '6 Hours'
|
||||
hour_12 = 'hour_12', '12 Hours'
|
||||
hour_24 = 'hour_24', '24 Hours'
|
||||
|
||||
@classmethod
|
||||
def only_values(cls):
|
||||
return [value for value, label in cls.choices]
|
||||
|
||||
class WeatherByPeriodRequestSerializer(serializers.Serializer):
|
||||
period = serializers.ChoiceField(WeatherPeriods.choices, required=True)
|
||||
|
||||
class WeatherByPeriodSerializer(serializers.Serializer):
|
||||
date = serializers.DateTimeField(required=True)
|
||||
humidity_air = serializers.FloatField(required=True)
|
||||
humidity_ground = serializers.FloatField(required=True)
|
||||
temperature = serializers.FloatField(required=True)
|
||||
light = serializers.FloatField(required=True)
|
||||
@ -6,4 +6,5 @@ urlpatterns = [
|
||||
path('last/', LastStatAPI.as_view()),
|
||||
path('history/', StatsHistoryAPI.as_view()),
|
||||
path('open-meteo/', OpenMeteoWeatherAPI.as_view()),
|
||||
path('stats-by-period/', StatsByPeriodAPI.as_view())
|
||||
]
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
import time
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views.decorators.cache import cache_page
|
||||
from django.utils import timezone
|
||||
from django.db.models import Avg
|
||||
from django.db.models.functions import TruncMinute, TruncHour
|
||||
from datetime import timedelta
|
||||
from django.core.cache import cache
|
||||
from rest_framework.generics import CreateAPIView, ListAPIView
|
||||
from rest_framework.views import APIView
|
||||
@ -11,7 +15,7 @@ from drf_spectacular.utils import extend_schema, OpenApiParameter, OpenApiRespon
|
||||
|
||||
from project.serializers import MessageSerializer
|
||||
from .models import WeatherStats
|
||||
from .serializers import WeatherStatSerializer, OpenWeatherAPISerializer
|
||||
from .serializers import *
|
||||
from .utils import IsMikrokontroller, PageNumberPagination, get_weather_api_data
|
||||
|
||||
CACHE_SAVE_CONTROL = 'stats_latest_saved_control'
|
||||
@ -76,6 +80,90 @@ class StatsHistoryAPI(ListAPIView):
|
||||
queryset = WeatherStats.objects.order_by('-created_at')
|
||||
pagination_class = PageNumberPagination
|
||||
|
||||
class StatsByPeriodAPI(APIView):
|
||||
|
||||
@extend_schema(tags=['Weather'],
|
||||
description="Weather data for graph by period",
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name='period',
|
||||
type=str,
|
||||
location=OpenApiParameter.QUERY,
|
||||
description='Period',
|
||||
required=True,
|
||||
enum=WeatherPeriods.only_values()
|
||||
)
|
||||
],
|
||||
responses={
|
||||
200: WeatherByPeriodSerializer(many=True),
|
||||
400: MessageSerializer
|
||||
}
|
||||
)
|
||||
def get(self, request: Request, format=None):
|
||||
serializer = WeatherByPeriodRequestSerializer(data=request.query_params)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
period = serializer.validated_data['period']
|
||||
|
||||
now = timezone.now()
|
||||
if period == WeatherPeriods.min_10:
|
||||
start_time = now - timedelta(minutes=10)
|
||||
trunc_func = TruncMinute
|
||||
step = 1
|
||||
elif period == WeatherPeriods.min_30:
|
||||
start_time = now - timedelta(minutes=30)
|
||||
trunc_func = TruncMinute
|
||||
step = 1
|
||||
elif period == WeatherPeriods.hour:
|
||||
start_time = now - timedelta(hours=1)
|
||||
trunc_func = TruncMinute
|
||||
step = 10
|
||||
elif period == WeatherPeriods.hour_6:
|
||||
start_time = now - timedelta(hours=6)
|
||||
trunc_func = TruncHour
|
||||
elif period == WeatherPeriods.hour_12:
|
||||
start_time = now - timedelta(hours=12)
|
||||
trunc_func = TruncHour
|
||||
elif period == WeatherPeriods.hour_24:
|
||||
start_time = now - timedelta(hours=24)
|
||||
trunc_func = TruncHour
|
||||
|
||||
qs = (
|
||||
WeatherStats.objects
|
||||
.filter(created_at__gte=start_time)
|
||||
.annotate(time_slot=trunc_func('created_at'))
|
||||
.values('time_slot')
|
||||
.annotate(
|
||||
humidity_air=Avg('humidity_air'),
|
||||
humidity_ground=Avg('humidity_ground'),
|
||||
temperature=Avg('temperature'),
|
||||
light=Avg('light')
|
||||
)
|
||||
.order_by('-time_slot')
|
||||
)
|
||||
|
||||
data_dict = {entry['date']: entry for entry in qs}
|
||||
|
||||
slots = []
|
||||
current = start_time
|
||||
while current <= now:
|
||||
|
||||
if trunc_func == TruncMinute:
|
||||
slot = current.replace(second=0, microsecond=0, minute=(current.minute // step) * step)
|
||||
else:
|
||||
slot = current.replace(minute=0, second=0, microsecond=0)
|
||||
|
||||
entry = data_dict.get(slot, {
|
||||
"date": slot,
|
||||
"humidity_air": 0,
|
||||
"humidity_ground": 0,
|
||||
"temperature": 0,
|
||||
"light": 0
|
||||
})
|
||||
slots.append(entry)
|
||||
current += timedelta(minutes=step if trunc_func == TruncMinute else 60)
|
||||
|
||||
serializer = WeatherByPeriodSerializer(slots, many=True)
|
||||
return Response(serializer.data)
|
||||
|
||||
|
||||
@method_decorator(cache_page(CACHE_TIMEOUT_WEATHER), name='dispatch')
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user