Skip to content

[change] Add mobile 5g rssi signal data#782

Open
asmodehn wants to merge 2 commits into
openwisp:masterfrom
asmodehn:add_mobile_5g_rssi_signal_data
Open

[change] Add mobile 5g rssi signal data#782
asmodehn wants to merge 2 commits into
openwisp:masterfrom
asmodehn:add_mobile_5g_rssi_signal_data

Conversation

@asmodehn
Copy link
Copy Markdown
Member

Checklist

  • I have read the OpenWISP Contributing Guidelines.
  • I have manually tested the changes proposed in this pull request.
  • I have written new test cases for new code and/or updated existing tests for changes to existing code.
  • I have updated the documentation.

Reference to Existing Issue

Address parts of #779

Description of Changes

This adds rssi to 5g metrics. Also requires one metric only for lte and 5g signal data

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 29, 2026

📝 Walkthrough

Walkthrough

The changes extend OpenWISP monitoring to support 5G mobile signal metrics. The JSON schema for mobile signal validation was updated to relax strict field requirements, replacing all-fields-required lists with anyOf constructs that accept objects containing at least one signal metric (RSSI, RSRP, RSRQ, or SNR) for both LTE and 5G. A template was modified to render 5G signal values (RSSI, RSRP, RSRQ, SNR) in the device admin interface when available. Test coverage was extended with an admin UI test for 5G signal rendering and API tests for 5G signal metric persistence, precision validation, and chart API behavior.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description check ✅ Passed The pull request description is largely complete with checked guidelines, issue reference, and change description, though manual testing and documentation updates remain incomplete.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Bug Fixes ✅ Passed This PR adds 5G signal metric support and adjusts validation rules; it is a feature addition, not a bug fix.
Title check ✅ Passed The title '[change] Add mobile 5g rssi signal data' clearly and specifically describes the main changes in the pull request: adding RSSI signal data support for 5G mobile signals, which aligns with all four modified files and matches the commit messages.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@openwisp_monitoring/device/tests/test_api.py`:
- Around line 808-857: The current test_5g_mobile_properties only exercises the
full signal.5g payload; add a minimal-payload case to assert the new "at least
one metric" validation path succeeds: after creating org/device, call _post_data
with a DeviceMonitoring payload where interfaces[0].mobile.signal contains "5g"
with a single metric (e.g., {"rsrp": -75}) and assert response.status_code ==
200, then load DeviceData(pk=device.pk).data and check that
mobile.signal["5g"]["rsrp"] is stored as float and that other metrics are absent
or not required; use the existing helpers (_create_org, _create_device,
_post_data, DeviceData, device.id/device.key/device.pk) and either add this as a
new test function or a subTest inside test_5g_mobile_properties.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 7071a885-5f75-45cf-aaa7-24123cb75415

📥 Commits

Reviewing files that changed from the base of the PR and between 7712351 and ce44896.

📒 Files selected for processing (4)
  • openwisp_monitoring/device/schema.py
  • openwisp_monitoring/device/templates/admin/monitoring/device/change_form.html
  • openwisp_monitoring/device/tests/test_admin.py
  • openwisp_monitoring/device/tests/test_api.py
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: Python==3.12 | django~=4.2.0
  • GitHub Check: Python==3.12 | django~=5.2.0
  • GitHub Check: Python==3.11 | django~=5.1.0
  • GitHub Check: Python==3.13 | django~=5.2.0
  • GitHub Check: Python==3.12 | django~=5.1.0
  • GitHub Check: Python==3.11 | django~=4.2.0
  • GitHub Check: Python==3.11 | django~=5.2.0
  • GitHub Check: Python==3.13 | django~=5.1.0
  • GitHub Check: Python==3.10 | django~=5.1.0
  • GitHub Check: Python==3.10 | django~=5.2.0
  • GitHub Check: Python==3.10 | django~=4.2.0
🧰 Additional context used
📓 Path-based instructions (1)
{**/*.sh,**/*.{js,ts,tsx,jsx},**/*.py,**/*.rb,**/*.go,**/*.java,**/*.cs,**/*.cpp,**/*.c}

📄 CodeRabbit inference engine (Custom checks)

Cryptic or non-obvious code (regex, complex bash commands, or hard-to-read code) must include a concise comment explaining why it is needed and why the complexity is acceptable

Files:

  • openwisp_monitoring/device/tests/test_api.py
  • openwisp_monitoring/device/schema.py
  • openwisp_monitoring/device/tests/test_admin.py
🧠 Learnings (6)
📚 Learning: 2026-03-24T21:28:33.379Z
Learnt from: CR
Repo: openwisp/openwisp-monitoring PR: 0
File: coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt:0-0
Timestamp: 2026-03-24T21:28:33.379Z
Learning: Changes: Tests must be updated to cover non-trivial changes and ensure proper validation of modified behavior

Applied to files:

  • openwisp_monitoring/device/tests/test_api.py
📚 Learning: 2026-02-21T01:03:37.822Z
Learnt from: nemesifier
Repo: openwisp/openwisp-monitoring PR: 738
File: openwisp_monitoring/tests/test_selenium.py:827-859
Timestamp: 2026-02-21T01:03:37.822Z
Learning: In Selenium tests (e.g., in openwisp_monitoring/tests/test_selenium.py and similar test files), when testing JS animations on dashboards or elements driven by JavaScript (such as real-time location updates), insert a short sleep (e.g., sleep(0.3)) before WebDriverWait assertions to allow animations to complete and reduce flakiness. Note: use this as a targeted workaround and prefer explicit waits or animation-end checks where possible to avoid relying on fixed delays.

Applied to files:

  • openwisp_monitoring/device/tests/test_api.py
  • openwisp_monitoring/device/tests/test_admin.py
📚 Learning: 2026-02-21T18:44:28.852Z
Learnt from: dee077
Repo: openwisp/openwisp-monitoring PR: 738
File: openwisp_monitoring/device/api/views.py:263-281
Timestamp: 2026-02-21T18:44:28.852Z
Learning: In openwisp-monitoring, MonitoringIndoorCoordinatesList inherits organization scoping from the parent IndoorCoordinatesList (from openwisp-controller), which uses FilterByParentManaged mixin and filters by location_id in get_queryset(). The child class only overrides the queryset attribute to add monitoring-specific select_related fields; this pattern is safe as long as get_queryset() from the parent is not bypassed. During reviews, verify that MonitoringIndoorCoordinatesList continues to rely on the parent's get_queryset() and that any added select_related fields in the child do not alter the parent's filtering logic.

Applied to files:

  • openwisp_monitoring/device/tests/test_api.py
  • openwisp_monitoring/device/schema.py
  • openwisp_monitoring/device/tests/test_admin.py
📚 Learning: 2026-02-25T18:42:08.825Z
Learnt from: dee077
Repo: openwisp/openwisp-monitoring PR: 738
File: openwisp_monitoring/tests/test_selenium.py:309-317
Timestamp: 2026-02-25T18:42:08.825Z
Learning: In Selenium tests that use ChannelsLiveServerTestCase (e.g., openwisp_monitoring/tests/test_selenium.py), override settings to configure CHANNEL_LAYERS with channels_redis.core.RedisChannelLayer instead of InMemoryChannelLayer. This is required because the live server runs in a separate process from the test process, and InMemoryChannelLayer is per-process only and cannot handle cross-process WebSocket broadcasting needed for real-time location update tests.

Applied to files:

  • openwisp_monitoring/device/tests/test_api.py
  • openwisp_monitoring/device/tests/test_admin.py
📚 Learning: 2026-03-14T18:39:04.626Z
Learnt from: UltraBot05
Repo: openwisp/openwisp-monitoring PR: 766
File: openwisp_monitoring/utils.py:59-68
Timestamp: 2026-03-14T18:39:04.626Z
Learning: In this repository (openwisp/openwisp-monitoring), the project targets Python 3.10–3.13 as defined by CI. Do not flag backports.zoneinfo as a missing dependency; zoneinfo is a built-in module in all supported Python versions. When reviewing Python code, assume zoneinfo is available and avoid suggesting installation of backports.zoneinfo. If a file imports zoneinfo or uses it for time zone handling, treat it as standard library usage compatible with the supported CI matrix.

Applied to files:

  • openwisp_monitoring/device/tests/test_api.py
  • openwisp_monitoring/device/schema.py
  • openwisp_monitoring/device/tests/test_admin.py
📚 Learning: 2026-03-14T18:39:04.626Z
Learnt from: UltraBot05
Repo: openwisp/openwisp-monitoring PR: 766
File: openwisp_monitoring/utils.py:59-68
Timestamp: 2026-03-14T18:39:04.626Z
Learning: In the openwisp-monitoring project, targets are Linux-based environments. Do not flag a Windows-specific tzdata package as a missing dependency in code reviews for Python files (e.g., openwisp_monitoring/utils.py). If a platform-specific dependency is truly required, document the exception in review guidelines and ensure CI/packaging checks enforce platform constraints rather than manual review.

Applied to files:

  • openwisp_monitoring/device/tests/test_api.py
  • openwisp_monitoring/device/schema.py
  • openwisp_monitoring/device/tests/test_admin.py
🔇 Additional comments (6)
openwisp_monitoring/device/tests/test_admin.py (1)

504-542: Looks good.

This covers the new 5G admin rendering path end-to-end and matches the existing LTE-style assertions.

openwisp_monitoring/device/templates/admin/monitoring/device/change_form.html (1)

327-352: Looks good.

The 5G block is consistent with the existing LTE rendering and is gated correctly on the signal object.

openwisp_monitoring/device/schema.py (1)

335-363: Looks good.

The relaxed anyOf validation matches the new one-metric requirement for both LTE and 5G without changing the surrounding schema shape.

openwisp_monitoring/device/tests/test_api.py (3)

918-919: Good update to the negative validation case.

Switching this payload to unknown_metric keeps the regression test invalid now that partial lte/5g payloads are accepted.


1004-1043: Looks good.

This covers the 5G-only chart path and verifies the new access-tech mapping behaves as expected.


1044-1085: Looks good.

The mixed LTE/5G case is a good regression check for 5G-NSA precedence and chart summaries.

Comment on lines +808 to +857
def test_5g_mobile_properties(self):
org = self._create_org()
device = self._create_device(organization=org)
data = {
"type": "DeviceMonitoring",
"interfaces": [
{
"name": "mobile0",
"mac": "00:00:00:00:00:00",
"mtu": 1900,
"multicast": True,
"txqueuelen": 1000,
"type": "modem-manager",
"up": True,
"mobile": {
"connection_status": "connected",
"imei": "300000001234567",
"manufacturer": "Sierra Wireless, Incorporated",
"model": "MC7430",
"operator_code": "50502",
"operator_name": "YES OPTUS",
"power_status": "on",
"signal": {
"5g": {"rsrp": -75, "rsrq": -8, "rssi": -52.00, "snr": 13}
},
},
}
],
}
response = self._post_data(device.id, device.key, data)
self.assertEqual(response.status_code, 200)
mobile_data = DeviceData(pk=device.pk).data["interfaces"][0]["mobile"]
with self.subTest("check mobile interface static properties"):
self.assertEqual(mobile_data["connection_status"], "connected")
self.assertEqual(mobile_data["imei"], "300000001234567")
self.assertEqual(mobile_data["model"], "MC7430")
self.assertEqual(mobile_data["operator_code"], "50502")
self.assertEqual(mobile_data["operator_name"], "YES OPTUS")
self.assertEqual(mobile_data["power_status"], "on")
with self.subTest("ensure signal data is converted to float"):
# ensure numbers are stored as floats,
# lua cannot be forced to send floats so we need to force it
self.assertIsInstance(mobile_data["signal"]["5g"]["rsrp"], float)
self.assertIsInstance(mobile_data["signal"]["5g"]["rsrq"], float)
self.assertIsInstance(mobile_data["signal"]["5g"]["rssi"], float)
self.assertIsInstance(mobile_data["signal"]["5g"]["snr"], float)
self.assertDictEqual(
mobile_data["signal"],
{"5g": {"rsrp": -75.00, "rsrq": -8.00, "rssi": -52.00, "snr": 13.00}},
)
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Cover the new relaxed 5G validation with a minimal payload.

This test still posts a fully populated signal.5g object, so it doesn't prove the new "at least one metric" schema path that this PR introduces.

♻️ Suggested addition
         with self.subTest("ensure signal data is converted to float"):
             # ensure numbers are stored as floats,
             # lua cannot be forced to send floats so we need to force it
             self.assertIsInstance(mobile_data["signal"]["5g"]["rsrp"], float)
             self.assertIsInstance(mobile_data["signal"]["5g"]["rsrq"], float)
             self.assertIsInstance(mobile_data["signal"]["5g"]["rssi"], float)
             self.assertIsInstance(mobile_data["signal"]["5g"]["snr"], float)
             self.assertDictEqual(
                 mobile_data["signal"],
                 {"5g": {"rsrp": -75.00, "rsrq": -8.00, "rssi": -52.00, "snr": 13.00}},
             )
+
+        with self.subTest("accept a minimal 5G signal payload"):
+            minimal_data = deepcopy(data)
+            minimal_data["interfaces"][0]["mobile"]["signal"] = {"5g": {"rssi": -52}}
+            response = self._post_data(device.id, device.key, minimal_data)
+            self.assertEqual(response.status_code, 200)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@openwisp_monitoring/device/tests/test_api.py` around lines 808 - 857, The
current test_5g_mobile_properties only exercises the full signal.5g payload; add
a minimal-payload case to assert the new "at least one metric" validation path
succeeds: after creating org/device, call _post_data with a DeviceMonitoring
payload where interfaces[0].mobile.signal contains "5g" with a single metric
(e.g., {"rsrp": -75}) and assert response.status_code == 200, then load
DeviceData(pk=device.pk).data and check that mobile.signal["5g"]["rsrp"] is
stored as float and that other metrics are absent or not required; use the
existing helpers (_create_org, _create_device, _post_data, DeviceData,
device.id/device.key/device.pk) and either add this as a new test function or a
subTest inside test_5g_mobile_properties.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we want to check with this level of detail, wont we need to check each of the metrics one by one ?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@asmodehn — Not necessarily. The goal of the suggested minimal-payload subTest is narrower than full per-metric coverage: it just needs to confirm that sending a single metric no longer triggers a 400 (i.e., the anyOf gate in the schema is working at all). One metric is sufficient to prove that path.

That said, if you did want to be thorough, you could do something compact like:

with self.subTest("accept each single 5G metric on its own"):
    for metric, value in [("rssi", -52), ("rsrp", -75), ("rsrq", -8), ("snr", 13)]:
        minimal_data = deepcopy(data)
        minimal_data["interfaces"][0]["mobile"]["signal"] = {"5g": {metric: value}}
        response = self._post_data(device.id, device.key, minimal_data)
        self.assertEqual(response.status_code, 200, f"Failed for single metric: {metric}")

But for this PR's scope, a single-metric check (especially for rssi, which is the new addition) is enough to cover the relaxed-validation path without requiring four separate checks.


🧠 Learnings used
Learnt from: CR
Repo: openwisp/openwisp-monitoring PR: 0
File: coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt:0-0
Timestamp: 2026-03-24T21:28:33.379Z
Learning: Changes: Tests must be updated to cover non-trivial changes and ensure proper validation of modified behavior

Learnt from: CR
Repo: openwisp/openwisp-monitoring PR: 0
File: coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt:0-0
Timestamp: 2026-03-24T21:28:33.379Z
Learning: Features: Tests must be added and coverage must not decrease significantly; if the feature impacts UI, Selenium browser tests are preferred

Learnt from: nemesifier
Repo: openwisp/openwisp-monitoring PR: 738
File: openwisp_monitoring/tests/test_selenium.py:827-859
Timestamp: 2026-02-21T01:03:37.822Z
Learning: In Selenium tests (e.g., in openwisp_monitoring/tests/test_selenium.py and similar test files), when testing JS animations on dashboards or elements driven by JavaScript (such as real-time location updates), insert a short sleep (e.g., sleep(0.3)) before WebDriverWait assertions to allow animations to complete and reduce flakiness. Note: use this as a targeted workaround and prefer explicit waits or animation-end checks where possible to avoid relying on fixed delays.

Learnt from: dee077
Repo: openwisp/openwisp-monitoring PR: 738
File: openwisp_monitoring/device/api/views.py:263-281
Timestamp: 2026-02-21T18:44:28.852Z
Learning: In openwisp-monitoring, MonitoringIndoorCoordinatesList inherits organization scoping from the parent IndoorCoordinatesList (from openwisp-controller), which uses FilterByParentManaged mixin and filters by location_id in get_queryset(). The child class only overrides the queryset attribute to add monitoring-specific select_related fields; this pattern is safe as long as get_queryset() from the parent is not bypassed. During reviews, verify that MonitoringIndoorCoordinatesList continues to rely on the parent's get_queryset() and that any added select_related fields in the child do not alter the parent's filtering logic.

Learnt from: dee077
Repo: openwisp/openwisp-monitoring PR: 738
File: openwisp_monitoring/tests/test_selenium.py:309-317
Timestamp: 2026-02-25T18:42:08.825Z
Learning: In Selenium tests that use ChannelsLiveServerTestCase (e.g., openwisp_monitoring/tests/test_selenium.py), override settings to configure CHANNEL_LAYERS with channels_redis.core.RedisChannelLayer instead of InMemoryChannelLayer. This is required because the live server runs in a separate process from the test process, and InMemoryChannelLayer is per-process only and cannot handle cross-process WebSocket broadcasting needed for real-time location update tests.

Learnt from: UltraBot05
Repo: openwisp/openwisp-monitoring PR: 766
File: openwisp_monitoring/utils.py:59-68
Timestamp: 2026-03-14T18:39:04.626Z
Learning: In this repository (openwisp/openwisp-monitoring), the project targets Python 3.10–3.13 as defined by CI. Do not flag backports.zoneinfo as a missing dependency; zoneinfo is a built-in module in all supported Python versions. When reviewing Python code, assume zoneinfo is available and avoid suggesting installation of backports.zoneinfo. If a file imports zoneinfo or uses it for time zone handling, treat it as standard library usage compatible with the supported CI matrix.

Learnt from: UltraBot05
Repo: openwisp/openwisp-monitoring PR: 766
File: openwisp_monitoring/utils.py:59-68
Timestamp: 2026-03-14T18:39:04.626Z
Learning: In the openwisp-monitoring project, targets are Linux-based environments. Do not flag a Windows-specific tzdata package as a missing dependency in code reviews for Python files (e.g., openwisp_monitoring/utils.py). If a platform-specific dependency is truly required, document the exception in review guidelines and ensure CI/packaging checks enforce platform constraints rather than manual review.

@asmodehn asmodehn marked this pull request as ready for review April 29, 2026 06:40
@openwisp-companion
Copy link
Copy Markdown

Multiple Test Failures Detected

Hello @asmodehn,
(Analysis for commit ce44896)

There are multiple test failures in the CI logs. Please address the following:

  1. test_device_custom_date_metrics: IndexError: list index out of range.
    The test is trying to access an index that does not exist in the rows list.
    This likely means the rows list is empty or too short.
    Fix: Review the test data and assertions in openwisp_monitoring/device/tests/test_api.py to ensure rows contains enough elements before accessing rows[-3].

  2. test_read_summary_top_fields: KeyError: 'summary'.
    The test expects a 'summary' key in the data dictionary, but it's not present.
    Fix: In openwisp_monitoring/monitoring/tests/test_charts.py, ensure that the data dictionary returned by the read method contains the 'summary' key, or adjust the test assertion to match the actual returned data.

  3. test_device_admin: AssertionError: 0 != 1.
    The test test_device_admin in openwisp_monitoring/device/tests/test_admin.py fails because it expects len(points) to be 1, but it is 0. This indicates that no points were created or retrieved when they were expected.
    Fix: Examine the create_test_data method in openwisp_monitoring/device/tests/test_api.py (which is likely used by test_device_admin via DeviceMonitoringTestCase) and ensure that test data is correctly set up to produce at least one point.

  4. test_200_multiple_measurements: AssertionError: 2 != 4.
    The test expects 4 data points but received 2. This suggests an issue with how the data is being generated or processed.
    Fix: In openwisp_monitoring/device/tests/test_api.py, review the test data setup and the _create_multiple_measurements method to ensure the correct number of measurements are generated or that the assertion accurately reflects the expected outcome.

  5. test_available_memory: AssertionError: 9.729419481797308 != 9.301032356920302.
    The calculated percent_used value does not match the expected value. This could be due to a change in how memory usage is calculated or a precision issue.
    Fix: In openwisp_monitoring/device/tests/test_api.py, adjust the expected value in the assertion or investigate the _write_memory method in openwisp_monitoring/device/writer.py to understand the discrepancy.

  6. test_get_device_metrics_200: AssertionError: 0 != 2.
    Similar to test_device_admin, this test expects 2 points but receives 0.
    Fix: In openwisp_monitoring/device/tests/test_api.py, ensure that the create_test_data method correctly populates the data to yield at least 2 points for the relevant metrics.

  7. test_get_device_metrics_list_200: AssertionError: 0 != 1.
    This test expects 1 point but receives 0.
    Fix: In openwisp_monitoring/device/tests/test_api.py, verify that create_test_data correctly generates at least 1 point for the test.

  8. test_get_device_status_200: AssertionError: 0 != 1.
    This test expects 1 data point but receives 0.
    Fix: In openwisp_monitoring/device/tests/test_api.py, ensure the test data setup results in at least one data point being available.

  9. test_device_offline_close_session: AssertionError: 1 != 0.
    The test expects 0 open WiFi sessions after a device goes offline, but

@asmodehn asmodehn changed the title Add mobile 5g rssi signal data [change] Add mobile 5g rssi signal data Apr 29, 2026
@asmodehn asmodehn requested a review from nemesifier April 29, 2026 06:43
Copy link
Copy Markdown
Member

@nemesifier nemesifier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Findings

  1. Low: admin renders empty metric rows for valid partial signal payloads

openwisp_monitoring/device/templates/admin/monitoring/device/change_form.html:327

The schema now accepts 5g payloads with any one of rssi, rsrp, rsrq, or snr, but the admin block renders all four rows whenever interface.mobile.signal.5g exists. For valid inputs like {"5g": {"rsrp": -70}}, the admin will show blank Signal Strength, Signal Quality, and Signal to noise ratio values with units. The same behavioral issue applies to LTE after relaxing its schema in schema.py:335. Consider guarding each metric row individually, or only displaying fields present in the payload.

@openwisp openwisp deleted a comment from openwisp-companion Bot May 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants