mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2025-04-17 07:55:15 +00:00
227 lines
7.8 KiB
Python
227 lines
7.8 KiB
Python
import numpy as np
|
|
import pytest
|
|
from pendulum import datetime, duration
|
|
|
|
from akkudoktoreos.config.config import SettingsEOS
|
|
from akkudoktoreos.measurement.measurement import (
|
|
MeasurementCommonSettings,
|
|
MeasurementDataRecord,
|
|
get_measurement,
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def measurement_eos():
|
|
"""Fixture to create a Measurement instance."""
|
|
measurement = get_measurement()
|
|
measurement.records = [
|
|
MeasurementDataRecord(
|
|
date_time=datetime(2023, 1, 1, hour=0),
|
|
load0_mr=100,
|
|
load1_mr=200,
|
|
),
|
|
MeasurementDataRecord(
|
|
date_time=datetime(2023, 1, 1, hour=1),
|
|
load0_mr=150,
|
|
load1_mr=250,
|
|
),
|
|
MeasurementDataRecord(
|
|
date_time=datetime(2023, 1, 1, hour=2),
|
|
load0_mr=200,
|
|
load1_mr=300,
|
|
),
|
|
MeasurementDataRecord(
|
|
date_time=datetime(2023, 1, 1, hour=3),
|
|
load0_mr=250,
|
|
load1_mr=350,
|
|
),
|
|
MeasurementDataRecord(
|
|
date_time=datetime(2023, 1, 1, hour=4),
|
|
load0_mr=300,
|
|
load1_mr=400,
|
|
),
|
|
MeasurementDataRecord(
|
|
date_time=datetime(2023, 1, 1, hour=5),
|
|
load0_mr=350,
|
|
load1_mr=450,
|
|
),
|
|
]
|
|
return measurement
|
|
|
|
|
|
def test_interval_count(measurement_eos):
|
|
"""Test interval count calculation."""
|
|
start = datetime(2023, 1, 1, 0)
|
|
end = datetime(2023, 1, 1, 3)
|
|
interval = duration(hours=1)
|
|
|
|
assert measurement_eos._interval_count(start, end, interval) == 3
|
|
|
|
|
|
def test_interval_count_invalid_end_before_start(measurement_eos):
|
|
"""Test interval count raises ValueError when end_datetime is before start_datetime."""
|
|
start = datetime(2023, 1, 1, 3)
|
|
end = datetime(2023, 1, 1, 0)
|
|
interval = duration(hours=1)
|
|
|
|
with pytest.raises(ValueError, match="end_datetime must be after start_datetime"):
|
|
measurement_eos._interval_count(start, end, interval)
|
|
|
|
|
|
def test_interval_count_invalid_non_positive_interval(measurement_eos):
|
|
"""Test interval count raises ValueError when interval is non-positive."""
|
|
start = datetime(2023, 1, 1, 0)
|
|
end = datetime(2023, 1, 1, 3)
|
|
|
|
with pytest.raises(ValueError, match="interval must be positive"):
|
|
measurement_eos._interval_count(start, end, duration(hours=0))
|
|
|
|
|
|
def test_energy_from_meter_readings_valid_input(measurement_eos):
|
|
"""Test _energy_from_meter_readings with valid inputs and proper alignment of load data."""
|
|
key = "load0_mr"
|
|
start_datetime = datetime(2023, 1, 1, 0)
|
|
end_datetime = datetime(2023, 1, 1, 5)
|
|
interval = duration(hours=1)
|
|
|
|
load_array = measurement_eos._energy_from_meter_readings(
|
|
key, start_datetime, end_datetime, interval
|
|
)
|
|
|
|
expected_load_array = np.array([50, 50, 50, 50, 50]) # Differences between consecutive readings
|
|
np.testing.assert_array_equal(load_array, expected_load_array)
|
|
|
|
|
|
def test_energy_from_meter_readings_empty_array(measurement_eos):
|
|
"""Test _energy_from_meter_readings with no data (empty array)."""
|
|
key = "load0_mr"
|
|
start_datetime = datetime(2023, 1, 1, 0)
|
|
end_datetime = datetime(2023, 1, 1, 5)
|
|
interval = duration(hours=1)
|
|
|
|
# Use empyt records array
|
|
measurement_eos.records = []
|
|
|
|
load_array = measurement_eos._energy_from_meter_readings(
|
|
key, start_datetime, end_datetime, interval
|
|
)
|
|
|
|
# Expected: an array of zeros with one less than the number of intervals
|
|
expected_size = (
|
|
measurement_eos._interval_count(start_datetime, end_datetime + interval, interval) - 1
|
|
)
|
|
expected_load_array = np.zeros(expected_size)
|
|
np.testing.assert_array_equal(load_array, expected_load_array)
|
|
|
|
|
|
def test_energy_from_meter_readings_misaligned_array(measurement_eos):
|
|
"""Test _energy_from_meter_readings with misaligned array size."""
|
|
key = "load1_mr"
|
|
start_datetime = measurement_eos.min_datetime
|
|
end_datetime = measurement_eos.max_datetime
|
|
interval = duration(hours=1)
|
|
|
|
# Use misaligned array, latest interval set to 2 hours (instead of 1 hour)
|
|
measurement_eos.records[-1].date_time = datetime(2023, 1, 1, 6)
|
|
|
|
load_array = measurement_eos._energy_from_meter_readings(
|
|
key, start_datetime, end_datetime, interval
|
|
)
|
|
|
|
expected_load_array = np.array([50, 50, 50, 50, 25]) # Differences between consecutive readings
|
|
np.testing.assert_array_equal(load_array, expected_load_array)
|
|
|
|
|
|
def test_energy_from_meter_readings_partial_data(measurement_eos, caplog):
|
|
"""Test _energy_from_meter_readings with partial data (misaligned but empty array)."""
|
|
key = "load2_mr"
|
|
start_datetime = datetime(2023, 1, 1, 0)
|
|
end_datetime = datetime(2023, 1, 1, 5)
|
|
interval = duration(hours=1)
|
|
|
|
with caplog.at_level("DEBUG"):
|
|
load_array = measurement_eos._energy_from_meter_readings(
|
|
key, start_datetime, end_datetime, interval
|
|
)
|
|
|
|
expected_size = (
|
|
measurement_eos._interval_count(start_datetime, end_datetime + interval, interval) - 1
|
|
)
|
|
expected_load_array = np.zeros(expected_size)
|
|
np.testing.assert_array_equal(load_array, expected_load_array)
|
|
|
|
|
|
def test_energy_from_meter_readings_negative_interval(measurement_eos):
|
|
"""Test _energy_from_meter_readings with a negative interval."""
|
|
key = "load3_mr"
|
|
start_datetime = datetime(2023, 1, 1, 0)
|
|
end_datetime = datetime(2023, 1, 1, 5)
|
|
interval = duration(hours=-1)
|
|
|
|
with pytest.raises(ValueError, match="interval must be positive"):
|
|
measurement_eos._energy_from_meter_readings(key, start_datetime, end_datetime, interval)
|
|
|
|
|
|
def test_load_total(measurement_eos):
|
|
"""Test total load calculation."""
|
|
start = datetime(2023, 1, 1, 0)
|
|
end = datetime(2023, 1, 1, 2)
|
|
interval = duration(hours=1)
|
|
|
|
result = measurement_eos.load_total(start_datetime=start, end_datetime=end, interval=interval)
|
|
|
|
# Expected total load per interval
|
|
expected = np.array([100, 100]) # Differences between consecutive meter readings
|
|
np.testing.assert_array_equal(result, expected)
|
|
|
|
|
|
def test_load_total_no_data(measurement_eos):
|
|
"""Test total load calculation with no data."""
|
|
measurement_eos.records = []
|
|
start = datetime(2023, 1, 1, 0)
|
|
end = datetime(2023, 1, 1, 3)
|
|
interval = duration(hours=1)
|
|
|
|
result = measurement_eos.load_total(start_datetime=start, end_datetime=end, interval=interval)
|
|
expected = np.zeros(3) # No data, so all intervals are zero
|
|
np.testing.assert_array_equal(result, expected)
|
|
|
|
|
|
def test_name_to_key(measurement_eos):
|
|
"""Test name_to_key functionality."""
|
|
settings = SettingsEOS(
|
|
measurement=MeasurementCommonSettings(
|
|
load0_name="Household",
|
|
load1_name="Heat Pump",
|
|
)
|
|
)
|
|
measurement_eos.config.merge_settings(settings)
|
|
|
|
assert measurement_eos.name_to_key("Household", "load") == "load0_mr"
|
|
assert measurement_eos.name_to_key("Heat Pump", "load") == "load1_mr"
|
|
assert measurement_eos.name_to_key("Unknown", "load") is None
|
|
|
|
|
|
def test_name_to_key_invalid_topic(measurement_eos):
|
|
"""Test name_to_key with an invalid topic."""
|
|
settings = SettingsEOS(
|
|
MeasurementCommonSettings(
|
|
load0_name="Household",
|
|
load1_name="Heat Pump",
|
|
)
|
|
)
|
|
measurement_eos.config.merge_settings(settings)
|
|
|
|
assert measurement_eos.name_to_key("Household", "invalid_topic") is None
|
|
|
|
|
|
def test_load_total_partial_intervals(measurement_eos):
|
|
"""Test total load calculation with partial intervals."""
|
|
start = datetime(2023, 1, 1, 0, 30) # Start in the middle of an interval
|
|
end = datetime(2023, 1, 1, 1, 30) # End in the middle of another interval
|
|
interval = duration(hours=1)
|
|
|
|
result = measurement_eos.load_total(start_datetime=start, end_datetime=end, interval=interval)
|
|
expected = np.array([100]) # Only one complete interval covered
|
|
np.testing.assert_array_equal(result, expected)
|