diff --git a/apps/counter/api/serializers.py b/apps/counter/api/serializers.py index d3204d8..4bd8cf6 100644 --- a/apps/counter/api/serializers.py +++ b/apps/counter/api/serializers.py @@ -1,12 +1,19 @@ import time +from typing import Optional from django.db.models import Q, Min, Max from django.core.cache import cache from rest_framework import serializers from counter.models import DeviceCount, DeviceInfo -from mosquito.models import DeviceInfo as CelexDeviceInfo +from mosquito.models import DeviceInfo as MosquitoDeviceInfo from mosquito.models import MosqPostStatistic, DevicePostStatistic +class DeviceSourceException(Exception): + """ + source should be counter | mosquito + """ + + def get_vol(device_id, cur_vol): vol_min_key = '{}_vol_min'.format(device_id) vol_max_key = '{}_vol_max'.format(device_id) @@ -35,27 +42,59 @@ def get_latest(device_id): return data -def get_device(device_id): - device_key = 'device_lon_{}'.format(device_id) - device = cache.get(device_key) - if device: - return device - qs = DeviceCount.objects.filter(~Q(longitude=0), device_id=device_id).order_by('-data_time') - if qs.count() == 0: - return None - device = qs.first() - s = DeviceCountBaseSerializer(device) - data = s.data - cache.set(device_key, data, 60 * 10) - return data - - class DeviceCountBaseSerializer(serializers.ModelSerializer): class Meta: model = DeviceCount fields = '__all__' +class DeviceInfoBaseSerializer(serializers.ModelSerializer): + class Meta: + model = MosquitoDeviceInfo + fields = '__all__' + + +device_source_map = { + 'counter': DeviceCountBaseSerializer, + 'mosquito': DeviceInfoBaseSerializer, +} + + +def get_device(device_id: str, source: str) -> Optional[dict]: + """ + Get device data serialized by DeviceCountBaseSerializer (counter) or DeviceInfoBaseSerializer (mosquito), + For source 'counter', we get device from device_counter table not device_info, because + the [lon, lat] info is located in device_counter. + For source 'mosquito', we get device from mosquito/DeviceInfo model, + due to the [point_x, point_y] is what we want. + + params: device_id, + params: source, counter | mosquito + return: dict + """ + device_key = 'device_lon_{}'.format(device_id) + device = cache.get(device_key) + if device: + return device + + if source == 'counter': + qs = DeviceCount.objects.filter(~Q(longitude=0), + device_id=device_id).order_by('-data_time') + elif source == 'mosquito': + qs = MosquitoDeviceInfo.objects.filter(device_id=device_id) + else: + raise DeviceSourceException("source should be counter or mosquito") + + if qs.count() == 0: + return None + + device = qs.first() + s = device_source_map[source](device) + data = s.data + cache.set(device_key, data, 60 * 10) + return data + + class DeviceCountSerializer(serializers.ModelSerializer): device_name = serializers.SerializerMethodField() mosq_count = serializers.SerializerMethodField() @@ -103,7 +142,7 @@ class DeviceCountSerializer(serializers.ModelSerializer): if device: self.device = device return device.device_name - qs = CelexDeviceInfo.objects.filter(device_id=device_id) + qs = MosquitoDeviceInfo.objects.filter(device_id=device_id) if qs.count() > 0: device = qs[0] self.device = device @@ -126,6 +165,50 @@ class DeviceCountSerializer(serializers.ModelSerializer): return obj.latitude +class DeviceCountWithInfoSerializer(DeviceCountSerializer): + location_id = serializers.SerializerMethodField() + point_x = serializers.SerializerMethodField() + point_y = serializers.SerializerMethodField() + + class Meta: + model = DeviceCount + fields = [ + 'id', + 'device_id', + 'device_name', + 'signal', + 'mosq_count', + 'energy', + 'calc_time', + 'longitude', + 'latitude', + 'location_id', + 'point_x', + 'point_y', + ] + + def get_location_id(self, obj): + device = self.device + if device: + if device.location_id: + return device.location_id + return None + + def get_point_x(self, obj): + device = self.device + if device: + if device.point_x: + return device.point_x + return None + + def get_point_y(self, obj): + device = self.device + if device: + if device.point_y: + return device.point_y + return None + + class DeviceInfoSerializer(serializers.ModelSerializer): device_name = serializers.SerializerMethodField() status = serializers.SerializerMethodField() @@ -154,7 +237,7 @@ class DeviceInfoSerializer(serializers.ModelSerializer): self.cur_device = None def get_device_name(self, obj): - qs = CelexDeviceInfo.objects.filter(device_id=obj.device_id) + qs = MosquitoDeviceInfo.objects.filter(device_id=obj.device_id) if qs.count() > 0: device = qs[0] self.cur_device = device @@ -164,7 +247,7 @@ class DeviceInfoSerializer(serializers.ModelSerializer): def get_status(self, obj): return obj.online - def get_count(self, obj) ->str: + def get_count(self, obj) -> str: try: # self.latest = DeviceCount.objects.filter(device_id=obj.device_id).order_by('-data_time')[0] self.latest = get_latest(obj.device_id) @@ -174,12 +257,12 @@ class DeviceInfoSerializer(serializers.ModelSerializer): return self.latest['count'] return '0' - def get_signal(self, obj) ->str: + def get_signal(self, obj) -> str: if self.latest: return self.latest['csq'] return '0' - def get_energy(self, obj) ->str: + def get_energy(self, obj) -> str: if self.latest: if float(self.latest['vol']) <= 100: return '{}{}'.format(round(float(self.latest['vol']), 1), '%') @@ -193,7 +276,7 @@ class DeviceInfoSerializer(serializers.ModelSerializer): return [lon, lat] # query = DeviceCount.objects.filter(~Q(longitude=0), device_id=obj.device_id).order_by('-data_time') - device = get_device(obj.device_id) + device = get_device(obj.device_id, source='counter') if device: return [device['longitude'], device['latitude']] return None @@ -205,7 +288,6 @@ class DeviceInfoSerializer(serializers.ModelSerializer): class LatestDailySerializer(serializers.ModelSerializer): - class Meta: model = MosqPostStatistic fields = [ @@ -216,7 +298,6 @@ class LatestDailySerializer(serializers.ModelSerializer): class DeviceLogHistorySerializer(serializers.ModelSerializer): - class Meta: model = DevicePostStatistic fields = [ diff --git a/apps/counter/api/views.py b/apps/counter/api/views.py index 9ceef32..4f6ee73 100644 --- a/apps/counter/api/views.py +++ b/apps/counter/api/views.py @@ -21,6 +21,7 @@ from mosquito.api.pagination import ( ) from .serializers import ( DeviceCountSerializer, + DeviceCountWithInfoSerializer, DeviceInfoSerializer, LatestDailySerializer, DeviceLogHistorySerializer, @@ -32,12 +33,18 @@ from mosquito.models import DeviceInfo as CelexDeviceInfo class DeviceLogListAPIView(ListAPIView, RoleMixin, DeviceListMixin): - serializer_class = DeviceCountSerializer + # serializer_class = DeviceCountSerializer permission_classes = [IsAuthenticated] filter_backends = [SearchFilter, OrderingFilter] pagination_class = DeviceLogListPagination search_fields = ['device_id'] + def get_serializer_class(self): + with_device = self.request.GET.get('with_device') + if with_device == 'true': + return DeviceCountWithInfoSerializer + return DeviceCountSerializer + def get_queryset(self, *args, **kwargs): user_roles = self.get_role() device = self.request.GET.get('device') diff --git a/apps/mosquito/api/serializers.py b/apps/mosquito/api/serializers.py index e0b75a8..8965314 100644 --- a/apps/mosquito/api/serializers.py +++ b/apps/mosquito/api/serializers.py @@ -1,3 +1,6 @@ +import time +from typing import Optional +from django.db.models import Q, Min, Max from rest_framework import serializers from django.core.cache import cache from mosquito.models import Mosquito, MosqPost, DeviceTempLog, WeatherLog, WeatherStationInfo, DeviceInfo @@ -50,6 +53,66 @@ class DeviceTempLogSerializer(serializers.ModelSerializer): return obj.last_time.strftime('%Y-%m-%d %H:%M:%S') +class DeviceSourceException(Exception): + """ + source should be counter | mosquito + """ + + +class WeatherLogBaseSerializer(serializers.ModelSerializer): + class Meta: + model = WeatherLog + fields = '__all__' + + +class WeatherStationInfoBaseSerializer(serializers.ModelSerializer): + class Meta: + model = WeatherStationInfo + fields = '__all__' + + +device_source_map = { + 'counter': WeatherLogBaseSerializer, + 'mosquito': WeatherStationInfoBaseSerializer, +} + + +def get_device(device_id: str, source: str) -> Optional[dict]: + """ + Get device data serialized by DeviceCountBaseSerializer (counter) or DeviceInfoBaseSerializer (mosquito), + For source 'counter', we get device from device_counter table not device_info, because + the [lon, lat] info is located in device_counter. + For source 'mosquito', we get device from mosquito/DeviceInfo model, + due to the [point_x, point_y] is what we want. + + params: device_id, + params: source, counter | mosquito + return: dict + """ + device_key = 'device_lon_{}'.format(device_id) + device = cache.get(device_key) + if device: + return device + + if source == 'counter': + qs = WeatherLog.objects.filter(~Q(longitude=0), + device_id=device_id).order_by('-data_time') + elif source == 'mosquito': + qs = WeatherStationInfo.objects.filter(device_id=device_id) + else: + raise DeviceSourceException("source should be counter or mosquito") + + if qs.count() == 0: + return None + + device = qs.first() + s = device_source_map[source](device) + data = s.data + cache.set(device_key, data, 60 * 10) + print(data) + return data + + class WeatherLogSerializer(serializers.ModelSerializer): power = serializers.SerializerMethodField() data_time = serializers.SerializerMethodField() @@ -88,10 +151,90 @@ class WeatherLogSerializer(serializers.ModelSerializer): def get_data_time(self, obj): return obj.data_time.strftime('%Y-%m-%d %H:%M:%S') - def get_create_time(self, obj): + def get_create_time(self, obj): return obj.data_time.strftime('%Y-%m-%d %H:%M:%S') +class WeatherLogWithInfoSerializer(WeatherLogSerializer): + longitude = serializers.SerializerMethodField() + latitude = serializers.SerializerMethodField() + location_id = serializers.SerializerMethodField() + point_x = serializers.SerializerMethodField() + point_y = serializers.SerializerMethodField() + + class Meta: + model = WeatherLog + fields = [ + 'data_time', + 'device_id', + 'device_name', + 'env_temp', + 'temperature1', 'temperature2', 'temperature3', 'temperature4', 'temperature5', 'dew_point_temp', + 'env_humi', 'soil_humi1', 'soil_humi2', 'soil_humi3', + 'co2', 'evaporation', 'air_pressure', + 'total_radiation_1_ins', 'scat_radiation_ins', 'direct_radiation_ins', 'total_radiation_2_ins', + 'net_radiation_ins', 'pho_radiation_ins', 'uv_radiation_ins', + 'wind_direction', 'wind_speed_ins', 'wind_speed_2mins', 'wind_speed_10mins', + 'rainfall_interval_cum', 'sunshine_time_interval_cum', 'total_radiation_1_interval_cum', + 'scat_radiation_interval_cum', 'direct_radiation_interval_cum', 'total_radiation_2_interval_cum', + 'net_radiation_interval_cum', 'pho_radiation_interval_cum', 'uv_radiation_interval_cum', + 'rainfall_daily_cum', 'sunshine_time_daily_cum', 'total_radiation_1_daily_cum', + 'scat_radiation_daily_cum', 'direct_radiation_daily_cum', 'total_radiation_2_daily_cum', + 'net_radiation_daily_cum', 'pho_radiation_daily_cum', 'uv_radiation_daily_cum', + 'light_intensity', + 'power', + 'pm25', + 'create_time', + 'longitude', + 'latitude', + 'location_id', + 'point_x', + 'point_y', + ] + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.device = None + + def get_longitude(self, obj): + device = self.device + print(device) + if device: + if device.longitude: + return device.longitude + return None + + def get_latitude(self, obj): + device = self.device + print(device) + if device: + if device.latitude: + return device.latitude + return None + + def get_location_id(self, obj): + device = self.device + print(device) + if device: + if device.location_id: + return device.location_id + return None + + def get_point_x(self, obj): + device = self.device + if device: + if device.point_x: + return device.point_x + return None + + def get_point_y(self, obj): + device = self.device + if device: + if device.point_y: + return device.point_y + return None + + class WeatherStationInfoSerializer(serializers.ModelSerializer): class Meta: diff --git a/apps/mosquito/api/views.py b/apps/mosquito/api/views.py index 15b484b..cabab51 100644 --- a/apps/mosquito/api/views.py +++ b/apps/mosquito/api/views.py @@ -28,6 +28,7 @@ from .serializers import ( MosqPostListSerializer, DeviceTempLogSerializer, WeatherLogSerializer, + WeatherLogWithInfoSerializer, DeviceInfoSerializer, WeatherStationInfoSerializer, ) @@ -115,7 +116,7 @@ class DeviceTempLogListAPIView(ListAPIView, RoleMixin, DeviceListMixin): class WeatherLogListAPIView(ListAPIView, RoleMixin, WeatherStationListMixin): - serializer_class = WeatherLogSerializer + #serializer_class = WeatherLogSerializer permission_classes = [IsAuthenticated] filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter) pagination_class = WeatherlogHistoryPagination @@ -123,6 +124,12 @@ class WeatherLogListAPIView(ListAPIView, RoleMixin, WeatherStationListMixin): filterset_fields = ['device_id'] ordering_fields = ['data_time'] + def get_serializer_class(self): + with_device = self.request.GET.get('with_device') + if with_device == 'true': + return WeatherLogWithInfoSerializer + return WeatherLogSerializer + def get_queryset(self, *args, **kwargs): user_roles = self.get_role() device = self.request.GET.get('device')