• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

openwisp / openwisp-monitoring / 27715225473

17 Jun 2026 07:44PM UTC coverage: 98.596% (+0.02%) from 98.574%
27715225473

push

github

nemesifier
[feature] Device list: allowed inspecting and filtering problematic metrics #774

Added support for inspecting unhealthy metrics directly from the
device list page through an inline accordion and filtering devices
by specific problem types when the health status is PROBLEM.

This makes it easier to identify and triage problematic devices
without leaving the list view.

Closes #774

Co-authored-by: Federico Capoano <f.capoano@openwisp.io>

3933 of 3989 relevant lines covered (98.6%)

10.84 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.68
openwisp_monitoring/device/api/serializers.py
1
from rest_framework import serializers
11✔
2
from swapper import load_model
11✔
3

4
from openwisp_controller.config.api.serializers import DeviceListSerializer
11✔
5
from openwisp_controller.geo.api.serializers import (
11✔
6
    GeoJsonLocationSerializer,
7
    IndoorCoordinatesSerializer,
8
    LocationDeviceSerializer,
9
)
10
from openwisp_users.api.mixins import FilterSerializerByOrgManaged
11✔
11

12
Device = load_model("config", "Device")
11✔
13
DeviceMonitoring = load_model("device_monitoring", "DeviceMonitoring")
11✔
14
DeviceData = load_model("device_monitoring", "DeviceData")
11✔
15
Metric = load_model("monitoring", "Metric")
11✔
16
WifiSession = load_model("device_monitoring", "WifiSession")
11✔
17
WifiClient = load_model("device_monitoring", "WifiClient")
11✔
18

19

20
class BaseDeviceMonitoringSerializer(serializers.ModelSerializer):
11✔
21
    class Meta:
11✔
22
        model = DeviceMonitoring
11✔
23
        fields = ("status",)
11✔
24

25

26
class DeviceMonitoringLocationSerializer(BaseDeviceMonitoringSerializer):
11✔
27
    status_label = serializers.SerializerMethodField()
11✔
28

29
    def get_status_label(self, obj):
11✔
30
        return obj.get_status_display()
11✔
31

32
    class Meta(BaseDeviceMonitoringSerializer.Meta):
11✔
33
        fields = BaseDeviceMonitoringSerializer.Meta.fields + ("status_label",)
11✔
34

35

36
class DeviceMonitoringSerializer(BaseDeviceMonitoringSerializer):
11✔
37
    related_metrics = serializers.SerializerMethodField()
11✔
38

39
    def get_related_metrics(self, obj):
11✔
40
        return obj.related_metrics.values("name", "is_healthy").order_by("name")
11✔
41

42
    class Meta(BaseDeviceMonitoringSerializer.Meta):
11✔
43
        fields = BaseDeviceMonitoringSerializer.Meta.fields + ("related_metrics",)
11✔
44

45

46
class MonitoringLocationDeviceSerializer(LocationDeviceSerializer):
11✔
47
    monitoring = DeviceMonitoringLocationSerializer()
11✔
48

49

50
class MonitoringIndoorCoordinatesSerializer(IndoorCoordinatesSerializer):
11✔
51
    monitoring = DeviceMonitoringLocationSerializer(
11✔
52
        source="content_object.monitoring", read_only=True
53
    )
54

55
    class Meta(IndoorCoordinatesSerializer.Meta):
11✔
56
        fields = IndoorCoordinatesSerializer.Meta.fields + ["monitoring"]
11✔
57

58

59
class MonitoringNearbyDeviceSerializer(
11✔
60
    FilterSerializerByOrgManaged, serializers.ModelSerializer
61
):
62
    monitoring_status = serializers.CharField(source="monitoring.status")
11✔
63
    distance = serializers.SerializerMethodField("get_distance")
11✔
64
    monitoring_data = serializers.SerializerMethodField("get_monitoring_data")
11✔
65

66
    class Meta(DeviceListSerializer.Meta):
11✔
67
        model = Device
11✔
68
        fields = [
11✔
69
            "id",
70
            "name",
71
            "organization",
72
            "group",
73
            "mac_address",
74
            "management_ip",
75
            "model",
76
            "os",
77
            "system",
78
            "notes",
79
            "distance",
80
            "monitoring_status",
81
            "monitoring_data",
82
        ]
83

84
    def get_distance(self, obj):
11✔
85
        return obj.distance.m
11✔
86

87
    def get_monitoring_data(self, obj):
11✔
88
        return DeviceData.objects.only("id").get(id=obj.id).data
11✔
89

90

91
class DeviceMetricSerializer(serializers.ModelSerializer):
11✔
92
    class Meta:
11✔
93
        model = Metric
11✔
94
        fields = ["name", "key", "is_healthy"]
11✔
95

96

97
class MonitoringDeviceListSerializer(DeviceListSerializer):
11✔
98
    monitoring = BaseDeviceMonitoringSerializer(read_only=True)
11✔
99

100
    def get_status(self, obj):
11✔
101
        return obj.get_status_display()
×
102

103
    class Meta:
11✔
104
        model = Device
11✔
105
        fields = [
11✔
106
            "id",
107
            "name",
108
            "organization",
109
            "group",
110
            "mac_address",
111
            "key",
112
            "last_ip",
113
            "management_ip",
114
            "model",
115
            "os",
116
            "system",
117
            "notes",
118
            "config",
119
            "monitoring",
120
            "created",
121
            "modified",
122
        ]
123

124

125
class MonitoringDeviceDetailSerializer(MonitoringDeviceListSerializer):
11✔
126
    monitoring = DeviceMonitoringSerializer(read_only=True)
11✔
127

128

129
class MonitoringGeoJsonLocationSerializer(GeoJsonLocationSerializer):
11✔
130
    ok_count = serializers.IntegerField()
11✔
131
    problem_count = serializers.IntegerField()
11✔
132
    critical_count = serializers.IntegerField()
11✔
133
    unknown_count = serializers.IntegerField()
11✔
134

135

136
class WifiClientSerializer(serializers.ModelSerializer):
11✔
137
    wifi6 = serializers.CharField(source="he", read_only=True)
11✔
138
    wifi5 = serializers.CharField(source="vht", read_only=True)
11✔
139
    wifi4 = serializers.CharField(source="ht", read_only=True)
11✔
140

141
    class Meta:
11✔
142
        model = WifiClient
11✔
143
        fields = [
11✔
144
            "mac_address",
145
            "vendor",
146
            "wifi6",
147
            "wifi5",
148
            "wifi4",
149
            "wmm",
150
            "wds",
151
            "wps",
152
        ]
153

154

155
class WifiSessionSerializer(serializers.ModelSerializer):
11✔
156
    client = WifiClientSerializer(source="wifi_client")
11✔
157
    organization = serializers.CharField(source="device.organization", read_only=True)
11✔
158
    device = serializers.CharField(source="device.name", read_only=True)
11✔
159

160
    class Meta:
11✔
161
        model = WifiSession
11✔
162
        fields = [
11✔
163
            "id",
164
            "organization",
165
            "device",
166
            "ssid",
167
            "interface_name",
168
            "client",
169
            "start_time",
170
            "stop_time",
171
            "modified",
172
        ]
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc