diff --git a/kuksa-client/kuksa_client/grpc/__init__.py b/kuksa-client/kuksa_client/grpc/__init__.py index 873db21..5421a9c 100644 --- a/kuksa-client/kuksa_client/grpc/__init__.py +++ b/kuksa-client/kuksa_client/grpc/__init__.py @@ -322,11 +322,23 @@ def from_message(cls, message: types_pb2.Datapoint): if message.WhichOneof('value') is None: logger.warning("No value provided in datapoint!") return None + + if message.HasField('timestamp'): + # Sanity check, is date before year 2500 + # Technically up to 9999 is allowed + if message.timestamp.seconds > 16725225600: + logger.error("Timestamp %d out of accepted range, value ignored!", + message.timestamp.seconds) + return None + timestamp = message.timestamp.ToDatetime( + tzinfo=datetime.timezone.utc, + ) + else: + timestamp = None + return cls( value=getattr(message, message.WhichOneof('value')), - timestamp=message.timestamp.ToDatetime( - tzinfo=datetime.timezone.utc, - ) if message.HasField('timestamp') else None, + timestamp=timestamp, ) def cast_array_values(cast, array): diff --git a/kuksa-client/tests/test_datapoint.py b/kuksa-client/tests/test_datapoint.py index 737f7cb..36a663c 100644 --- a/kuksa-client/tests/test_datapoint.py +++ b/kuksa-client/tests/test_datapoint.py @@ -14,6 +14,7 @@ import pytest from kuksa_client.grpc import Datapoint from kuksa.val.v1 import types_pb2 +from google.protobuf import timestamp_pb2 # # Client rules: @@ -195,3 +196,20 @@ def test_from_message_uint32(): msg = types_pb2.Datapoint(uint32=456) datapoint = Datapoint.from_message(msg) assert datapoint.value == 456 + + +def test_from_message_time(): + """ + Make sure that we can handle values out of range (by discarding them) + """ + timestamp = timestamp_pb2.Timestamp(seconds=1705485747) + msg = types_pb2.Datapoint(uint32=456, timestamp=timestamp) + datapoint = Datapoint.from_message(msg) + assert datapoint.timestamp.year == 2024 + + # Checking that we return None if timestamp is out of range + # Test with year 3000 + timestamp = timestamp_pb2.Timestamp(seconds=32503680000) + msg = types_pb2.Datapoint(uint32=456, timestamp=timestamp) + datapoint = Datapoint.from_message(msg) + assert datapoint is None