Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion hub-server/hub_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
Efergy hub, logging incoming sensor data to a sqlite database.
"""
import logging
import math
import socket
import sys
from http.server import HTTPServer, SimpleHTTPRequestHandler
Expand All @@ -24,6 +25,14 @@
ENERGY_UNIT_OF_MEASUREMENT
)

INT32_MAX = 2_147_483_647


def is_valid_power_reading(value: float) -> bool:
"""Reject non-finite readings and the INT32_MAX emitted by faulty hubs."""
return math.isfinite(value) and value < INT32_MAX


class EfergyHTTPServer(HTTPServer):
"""
A custom HTTPServer subclass that holds the database instance.
Expand Down Expand Up @@ -287,7 +296,11 @@ def process_parsed_results(self, parsed_results: list[dict], hub_version: str, f
value = data["value"]
firmware_version = data.get("firmware_version", firmware_version)
timestamp = data.get("timestamp")


if not is_valid_power_reading(value):
logging.warning(f"Skipping invalid power reading for {label}: {value}")
continue

logging.debug(f"Logging sensor: {label}, raw: {value}")
database.log_data(label, value, firmware_version, timestamp=timestamp)

Expand Down
26 changes: 26 additions & 0 deletions hub-server/tests/test_hub_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,32 @@ def test_post_h2(test_server, mock_db, mock_mqtt):
assert mock_mqtt.publish_power.called


def test_post_h3_rejects_invalid_power_readings(test_server, mock_db, mock_mqtt):
host, port = test_server
payload = b"\r\n".join([
b"782792|1|EFCT|P1,12761.72|-61",
b"782792|1|EFCT|P1,2147483647.2147483647|-61",
b"782792|1|EFCT|P1,2147483647|-61",
b"782792|1|EFCT|P1,nan|-61",
b"782792|1|EFCT|P1,inf|-61",
b"782792|1|EFCT|P1,12285.65|-61",
])
headers = {
"Content-Type": "application/eh-data",
"Content-Length": str(len(payload)),
"X-Version": "3.7.1",
}

status, data = http_request(host, port, "POST", "/h3", body=payload, headers=headers)

assert status == 200
assert data == b"success"
assert mock_db.log_data.call_count == 2
assert [call.args[1] for call in mock_db.log_data.call_args_list] == [12761.72, 12285.65]
assert mock_mqtt.publish_power.call_count == 2
assert [call.args[4] for call in mock_mqtt.publish_power.call_args_list] == [12761.72, 12285.65]


def test_post_h3bulk(test_server, mock_db, mock_mqtt):
host, port = test_server
payload = bytes.fromhex(
Expand Down
Loading