388 lines
13 KiB
Python
388 lines
13 KiB
Python
"""Define test fixtures for Enphase Envoy."""
|
|
|
|
from unittest.mock import AsyncMock, Mock, patch
|
|
|
|
import jwt
|
|
from pyenphase import (
|
|
Envoy,
|
|
EnvoyData,
|
|
EnvoyInverter,
|
|
EnvoySystemConsumption,
|
|
EnvoySystemProduction,
|
|
EnvoyTokenAuth,
|
|
)
|
|
from pyenphase.const import PhaseNames, SupportedFeatures
|
|
from pyenphase.models.meters import (
|
|
CtMeterStatus,
|
|
CtState,
|
|
CtStatusFlags,
|
|
CtType,
|
|
EnvoyMeterData,
|
|
EnvoyPhaseMode,
|
|
)
|
|
import pytest
|
|
|
|
from homeassistant.components.enphase_envoy import DOMAIN
|
|
from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PASSWORD, CONF_USERNAME
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.setup import async_setup_component
|
|
|
|
from tests.common import MockConfigEntry
|
|
|
|
|
|
@pytest.fixture(name="config_entry")
|
|
def config_entry_fixture(hass: HomeAssistant, config, serial_number):
|
|
"""Define a config entry fixture."""
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
entry_id="45a36e55aaddb2007c5f6602e0c38e72",
|
|
title=f"Envoy {serial_number}" if serial_number else "Envoy",
|
|
unique_id=serial_number,
|
|
data=config,
|
|
)
|
|
entry.add_to_hass(hass)
|
|
return entry
|
|
|
|
|
|
@pytest.fixture(name="config")
|
|
def config_fixture():
|
|
"""Define a config entry data fixture."""
|
|
return {
|
|
CONF_HOST: "1.1.1.1",
|
|
CONF_NAME: "Envoy 1234",
|
|
CONF_USERNAME: "test-username",
|
|
CONF_PASSWORD: "test-password",
|
|
}
|
|
|
|
|
|
@pytest.fixture(name="mock_envoy")
|
|
def mock_envoy_fixture(
|
|
serial_number,
|
|
mock_authenticate,
|
|
mock_setup,
|
|
mock_auth,
|
|
):
|
|
"""Define a mocked Envoy fixture."""
|
|
mock_envoy = Mock(spec=Envoy)
|
|
mock_envoy.serial_number = serial_number
|
|
mock_envoy.firmware = "7.1.2"
|
|
mock_envoy.part_number = "123456789"
|
|
mock_envoy.envoy_model = "Envoy, phases: 3, phase mode: three, net-consumption CT, production CT, storage CT"
|
|
mock_envoy.authenticate = mock_authenticate
|
|
mock_envoy.setup = mock_setup
|
|
mock_envoy.auth = mock_auth
|
|
mock_envoy.supported_features = SupportedFeatures(
|
|
SupportedFeatures.INVERTERS
|
|
| SupportedFeatures.PRODUCTION
|
|
| SupportedFeatures.PRODUCTION
|
|
| SupportedFeatures.METERING
|
|
| SupportedFeatures.THREEPHASE
|
|
| SupportedFeatures.CTMETERS
|
|
)
|
|
mock_envoy.phase_mode = EnvoyPhaseMode.THREE
|
|
mock_envoy.phase_count = 3
|
|
mock_envoy.active_phase_count = 3
|
|
mock_envoy.ct_meter_count = 3
|
|
mock_envoy.consumption_meter_type = CtType.NET_CONSUMPTION
|
|
mock_envoy.production_meter_type = CtType.PRODUCTION
|
|
mock_envoy.storage_meter_type = CtType.STORAGE
|
|
mock_envoy.data = EnvoyData(
|
|
system_consumption=EnvoySystemConsumption(
|
|
watt_hours_last_7_days=1234,
|
|
watt_hours_lifetime=1234,
|
|
watt_hours_today=1234,
|
|
watts_now=1234,
|
|
),
|
|
system_production=EnvoySystemProduction(
|
|
watt_hours_last_7_days=1234,
|
|
watt_hours_lifetime=1234,
|
|
watt_hours_today=1234,
|
|
watts_now=1234,
|
|
),
|
|
system_consumption_phases={
|
|
PhaseNames.PHASE_1: EnvoySystemConsumption(
|
|
watt_hours_last_7_days=1321,
|
|
watt_hours_lifetime=1322,
|
|
watt_hours_today=1323,
|
|
watts_now=1324,
|
|
),
|
|
PhaseNames.PHASE_2: EnvoySystemConsumption(
|
|
watt_hours_last_7_days=2321,
|
|
watt_hours_lifetime=2322,
|
|
watt_hours_today=2323,
|
|
watts_now=2324,
|
|
),
|
|
PhaseNames.PHASE_3: EnvoySystemConsumption(
|
|
watt_hours_last_7_days=3321,
|
|
watt_hours_lifetime=3322,
|
|
watt_hours_today=3323,
|
|
watts_now=3324,
|
|
),
|
|
},
|
|
system_production_phases={
|
|
PhaseNames.PHASE_1: EnvoySystemProduction(
|
|
watt_hours_last_7_days=1231,
|
|
watt_hours_lifetime=1232,
|
|
watt_hours_today=1233,
|
|
watts_now=1234,
|
|
),
|
|
PhaseNames.PHASE_2: EnvoySystemProduction(
|
|
watt_hours_last_7_days=2231,
|
|
watt_hours_lifetime=2232,
|
|
watt_hours_today=2233,
|
|
watts_now=2234,
|
|
),
|
|
PhaseNames.PHASE_3: EnvoySystemProduction(
|
|
watt_hours_last_7_days=3231,
|
|
watt_hours_lifetime=3232,
|
|
watt_hours_today=3233,
|
|
watts_now=3234,
|
|
),
|
|
},
|
|
ctmeter_production=EnvoyMeterData(
|
|
eid="100000010",
|
|
timestamp=1708006110,
|
|
energy_delivered=11234,
|
|
energy_received=12345,
|
|
active_power=100,
|
|
power_factor=0.11,
|
|
voltage=111,
|
|
current=0.2,
|
|
frequency=50.1,
|
|
state=CtState.ENABLED,
|
|
measurement_type=CtType.PRODUCTION,
|
|
metering_status=CtMeterStatus.NORMAL,
|
|
status_flags=[
|
|
CtStatusFlags.PODUCTION_IMBALANCE,
|
|
CtStatusFlags.POWER_ON_UNUSED_PHASE,
|
|
],
|
|
),
|
|
ctmeter_consumption=EnvoyMeterData(
|
|
eid="100000020",
|
|
timestamp=1708006120,
|
|
energy_delivered=21234,
|
|
energy_received=22345,
|
|
active_power=101,
|
|
power_factor=0.21,
|
|
voltage=112,
|
|
current=0.3,
|
|
frequency=50.2,
|
|
state=CtState.ENABLED,
|
|
measurement_type=CtType.NET_CONSUMPTION,
|
|
metering_status=CtMeterStatus.NORMAL,
|
|
status_flags=[],
|
|
),
|
|
ctmeter_storage=EnvoyMeterData(
|
|
eid="100000030",
|
|
timestamp=1708006120,
|
|
energy_delivered=31234,
|
|
energy_received=32345,
|
|
active_power=103,
|
|
power_factor=0.23,
|
|
voltage=113,
|
|
current=0.4,
|
|
frequency=50.3,
|
|
state=CtState.ENABLED,
|
|
measurement_type=CtType.STORAGE,
|
|
metering_status=CtMeterStatus.NORMAL,
|
|
status_flags=[],
|
|
),
|
|
ctmeter_production_phases={
|
|
PhaseNames.PHASE_1: EnvoyMeterData(
|
|
eid="100000011",
|
|
timestamp=1708006111,
|
|
energy_delivered=112341,
|
|
energy_received=123451,
|
|
active_power=20,
|
|
power_factor=0.12,
|
|
voltage=111,
|
|
current=0.2,
|
|
frequency=50.1,
|
|
state=CtState.ENABLED,
|
|
measurement_type=CtType.PRODUCTION,
|
|
metering_status=CtMeterStatus.NORMAL,
|
|
status_flags=[CtStatusFlags.PODUCTION_IMBALANCE],
|
|
),
|
|
PhaseNames.PHASE_2: EnvoyMeterData(
|
|
eid="100000012",
|
|
timestamp=1708006112,
|
|
energy_delivered=112342,
|
|
energy_received=123452,
|
|
active_power=30,
|
|
power_factor=0.13,
|
|
voltage=111,
|
|
current=0.2,
|
|
frequency=50.1,
|
|
state=CtState.ENABLED,
|
|
measurement_type=CtType.PRODUCTION,
|
|
metering_status=CtMeterStatus.NORMAL,
|
|
status_flags=[CtStatusFlags.POWER_ON_UNUSED_PHASE],
|
|
),
|
|
PhaseNames.PHASE_3: EnvoyMeterData(
|
|
eid="100000013",
|
|
timestamp=1708006113,
|
|
energy_delivered=112343,
|
|
energy_received=123453,
|
|
active_power=50,
|
|
power_factor=0.14,
|
|
voltage=111,
|
|
current=0.2,
|
|
frequency=50.1,
|
|
state=CtState.ENABLED,
|
|
measurement_type=CtType.PRODUCTION,
|
|
metering_status=CtMeterStatus.NORMAL,
|
|
status_flags=[],
|
|
),
|
|
},
|
|
ctmeter_consumption_phases={
|
|
PhaseNames.PHASE_1: EnvoyMeterData(
|
|
eid="100000021",
|
|
timestamp=1708006121,
|
|
energy_delivered=212341,
|
|
energy_received=223451,
|
|
active_power=21,
|
|
power_factor=0.22,
|
|
voltage=112,
|
|
current=0.3,
|
|
frequency=50.2,
|
|
state=CtState.ENABLED,
|
|
measurement_type=CtType.NET_CONSUMPTION,
|
|
metering_status=CtMeterStatus.NORMAL,
|
|
status_flags=[],
|
|
),
|
|
PhaseNames.PHASE_2: EnvoyMeterData(
|
|
eid="100000022",
|
|
timestamp=1708006122,
|
|
energy_delivered=212342,
|
|
energy_received=223452,
|
|
active_power=31,
|
|
power_factor=0.23,
|
|
voltage=112,
|
|
current=0.3,
|
|
frequency=50.2,
|
|
state=CtState.ENABLED,
|
|
measurement_type=CtType.NET_CONSUMPTION,
|
|
metering_status=CtMeterStatus.NORMAL,
|
|
status_flags=[],
|
|
),
|
|
PhaseNames.PHASE_3: EnvoyMeterData(
|
|
eid="100000023",
|
|
timestamp=1708006123,
|
|
energy_delivered=212343,
|
|
energy_received=223453,
|
|
active_power=51,
|
|
power_factor=0.24,
|
|
voltage=112,
|
|
current=0.3,
|
|
frequency=50.2,
|
|
state=CtState.ENABLED,
|
|
measurement_type=CtType.NET_CONSUMPTION,
|
|
metering_status=CtMeterStatus.NORMAL,
|
|
status_flags=[],
|
|
),
|
|
},
|
|
ctmeter_storage_phases={
|
|
PhaseNames.PHASE_1: EnvoyMeterData(
|
|
eid="100000031",
|
|
timestamp=1708006121,
|
|
energy_delivered=312341,
|
|
energy_received=323451,
|
|
active_power=22,
|
|
power_factor=0.32,
|
|
voltage=113,
|
|
current=0.4,
|
|
frequency=50.3,
|
|
state=CtState.ENABLED,
|
|
measurement_type=CtType.STORAGE,
|
|
metering_status=CtMeterStatus.NORMAL,
|
|
status_flags=[],
|
|
),
|
|
PhaseNames.PHASE_2: EnvoyMeterData(
|
|
eid="100000032",
|
|
timestamp=1708006122,
|
|
energy_delivered=312342,
|
|
energy_received=323452,
|
|
active_power=33,
|
|
power_factor=0.23,
|
|
voltage=112,
|
|
current=0.3,
|
|
frequency=50.2,
|
|
state=CtState.ENABLED,
|
|
measurement_type=CtType.STORAGE,
|
|
metering_status=CtMeterStatus.NORMAL,
|
|
status_flags=[],
|
|
),
|
|
PhaseNames.PHASE_3: EnvoyMeterData(
|
|
eid="100000033",
|
|
timestamp=1708006123,
|
|
energy_delivered=312343,
|
|
energy_received=323453,
|
|
active_power=53,
|
|
power_factor=0.24,
|
|
voltage=112,
|
|
current=0.3,
|
|
frequency=50.2,
|
|
state=CtState.ENABLED,
|
|
measurement_type=CtType.STORAGE,
|
|
metering_status=CtMeterStatus.NORMAL,
|
|
status_flags=[],
|
|
),
|
|
},
|
|
inverters={
|
|
"1": EnvoyInverter(
|
|
serial_number="1",
|
|
last_report_date=1,
|
|
last_report_watts=1,
|
|
max_report_watts=1,
|
|
)
|
|
},
|
|
raw={"varies_by": "firmware_version"},
|
|
)
|
|
mock_envoy.update = AsyncMock(return_value=mock_envoy.data)
|
|
return mock_envoy
|
|
|
|
|
|
@pytest.fixture(name="setup_enphase_envoy")
|
|
async def setup_enphase_envoy_fixture(hass: HomeAssistant, config, mock_envoy):
|
|
"""Define a fixture to set up Enphase Envoy."""
|
|
with (
|
|
patch(
|
|
"homeassistant.components.enphase_envoy.config_flow.Envoy",
|
|
return_value=mock_envoy,
|
|
),
|
|
patch(
|
|
"homeassistant.components.enphase_envoy.Envoy",
|
|
return_value=mock_envoy,
|
|
),
|
|
):
|
|
assert await async_setup_component(hass, DOMAIN, config)
|
|
await hass.async_block_till_done()
|
|
yield
|
|
|
|
|
|
@pytest.fixture(name="mock_authenticate")
|
|
def mock_authenticate():
|
|
"""Define a mocked Envoy.authenticate fixture."""
|
|
return AsyncMock()
|
|
|
|
|
|
@pytest.fixture(name="mock_auth")
|
|
def mock_auth(serial_number):
|
|
"""Define a mocked EnvoyAuth fixture."""
|
|
token = jwt.encode(
|
|
payload={"name": "envoy", "exp": 1907837780}, key="secret", algorithm="HS256"
|
|
)
|
|
return EnvoyTokenAuth("127.0.0.1", token=token, envoy_serial=serial_number)
|
|
|
|
|
|
@pytest.fixture(name="mock_setup")
|
|
def mock_setup():
|
|
"""Define a mocked Envoy.setup fixture."""
|
|
return AsyncMock()
|
|
|
|
|
|
@pytest.fixture(name="serial_number")
|
|
def serial_number_fixture():
|
|
"""Define a serial number fixture."""
|
|
return "1234"
|