Add tests to bring greeneye_monitor to 99% coverage (#58661)

* Bring greeneye_monitor to 99% coverage.

* Pass monitor into listeners on Monitors

* Updates for changes in `dev`, create mock monitor

* Remove logging left in after debugging

* Remove xfails now that #58764 has merged
This commit is contained in:
Jonathan Keljo 2021-11-11 04:20:16 -08:00 committed by GitHub
parent a29264518c
commit a079b4fd58
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 694 additions and 6 deletions

View File

@ -399,8 +399,6 @@ omit =
homeassistant/components/google_travel_time/sensor.py
homeassistant/components/gpmdp/media_player.py
homeassistant/components/gpsd/sensor.py
homeassistant/components/greeneye_monitor/*
homeassistant/components/greeneye_monitor/sensor.py
homeassistant/components/greenwave/light.py
homeassistant/components/group/notify.py
homeassistant/components/growatt_server/sensor.py

View File

@ -3,7 +3,7 @@ from __future__ import annotations
import logging
from greeneye import Monitors
import greeneye
import voluptuous as vol
from homeassistant.const import (
@ -123,7 +123,7 @@ CONFIG_SCHEMA = vol.Schema({DOMAIN: COMPONENT_SCHEMA}, extra=vol.ALLOW_EXTRA)
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the GreenEye Monitor component."""
monitors = Monitors()
monitors = greeneye.Monitors()
hass.data[DATA_GREENEYE_MONITOR] = monitors
server_config = config[DOMAIN]

View File

@ -4,7 +4,6 @@ from __future__ import annotations
from typing import Any, Generic, Optional, TypeVar, cast
import greeneye
from greeneye import Monitors
from homeassistant.components.sensor import SensorEntity
from homeassistant.const import (
@ -145,7 +144,7 @@ class GEMSensor(Generic[T], SensorEntity):
monitors = self.hass.data[DATA_GREENEYE_MONITOR]
monitors.remove_listener(self._on_new_monitor)
def _try_connect_to_monitor(self, monitors: Monitors) -> bool:
def _try_connect_to_monitor(self, monitors: greeneye.Monitors) -> bool:
monitor = monitors.monitors.get(self._monitor_serial_number)
if not monitor:
return False

View File

@ -463,6 +463,9 @@ googlemaps==2.5.1
# homeassistant.components.gree
greeclimate==0.12.3
# homeassistant.components.greeneye_monitor
greeneye_monitor==2.1
# homeassistant.components.growatt_server
growattServer==1.1.0

View File

@ -0,0 +1 @@
"""Tests for the GreenEye Monitor integration."""

View File

@ -0,0 +1,205 @@
"""Common helpers for greeneye_monitor tests."""
from __future__ import annotations
from typing import Any
from unittest.mock import AsyncMock, MagicMock
from homeassistant.components.greeneye_monitor import (
CONF_CHANNELS,
CONF_COUNTED_QUANTITY,
CONF_COUNTED_QUANTITY_PER_PULSE,
CONF_MONITORS,
CONF_NET_METERING,
CONF_NUMBER,
CONF_PULSE_COUNTERS,
CONF_SERIAL_NUMBER,
CONF_TEMPERATURE_SENSORS,
CONF_TIME_UNIT,
CONF_VOLTAGE_SENSORS,
DOMAIN,
)
from homeassistant.const import (
CONF_NAME,
CONF_PORT,
CONF_SENSORS,
CONF_TEMPERATURE_UNIT,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.typing import ConfigType
from homeassistant.setup import async_setup_component
SINGLE_MONITOR_SERIAL_NUMBER = 110011
def make_single_monitor_config_with_sensors(sensors: dict[str, Any]) -> dict[str, Any]:
"""Wrap the given sensor config in the boilerplate for a single monitor with serial number SINGLE_MONITOR_SERIAL_NUMBER."""
return {
DOMAIN: {
CONF_PORT: 7513,
CONF_MONITORS: [
{
CONF_SERIAL_NUMBER: f"00{SINGLE_MONITOR_SERIAL_NUMBER}",
**sensors,
}
],
}
}
SINGLE_MONITOR_CONFIG_NO_SENSORS = make_single_monitor_config_with_sensors({})
SINGLE_MONITOR_CONFIG_PULSE_COUNTERS = make_single_monitor_config_with_sensors(
{
CONF_PULSE_COUNTERS: [
{
CONF_NUMBER: 1,
CONF_NAME: "pulse_a",
CONF_COUNTED_QUANTITY: "pulses",
CONF_COUNTED_QUANTITY_PER_PULSE: 1.0,
CONF_TIME_UNIT: "s",
},
{
CONF_NUMBER: 2,
CONF_NAME: "pulse_2",
CONF_COUNTED_QUANTITY: "gal",
CONF_COUNTED_QUANTITY_PER_PULSE: 0.5,
CONF_TIME_UNIT: "min",
},
{
CONF_NUMBER: 3,
CONF_NAME: "pulse_3",
CONF_COUNTED_QUANTITY: "gal",
CONF_COUNTED_QUANTITY_PER_PULSE: 0.5,
CONF_TIME_UNIT: "h",
},
{
CONF_NUMBER: 4,
CONF_NAME: "pulse_d",
CONF_COUNTED_QUANTITY: "pulses",
CONF_COUNTED_QUANTITY_PER_PULSE: 1.0,
CONF_TIME_UNIT: "s",
},
]
}
)
SINGLE_MONITOR_CONFIG_POWER_SENSORS = make_single_monitor_config_with_sensors(
{
CONF_CHANNELS: [
{
CONF_NUMBER: 1,
CONF_NAME: "channel 1",
},
{
CONF_NUMBER: 2,
CONF_NAME: "channel two",
CONF_NET_METERING: True,
},
]
}
)
SINGLE_MONITOR_CONFIG_TEMPERATURE_SENSORS = make_single_monitor_config_with_sensors(
{
CONF_TEMPERATURE_SENSORS: {
CONF_TEMPERATURE_UNIT: "F",
CONF_SENSORS: [
{CONF_NUMBER: 1, CONF_NAME: "temp_a"},
{CONF_NUMBER: 2, CONF_NAME: "temp_2"},
{CONF_NUMBER: 3, CONF_NAME: "temp_c"},
{CONF_NUMBER: 4, CONF_NAME: "temp_d"},
{CONF_NUMBER: 5, CONF_NAME: "temp_5"},
{CONF_NUMBER: 6, CONF_NAME: "temp_f"},
{CONF_NUMBER: 7, CONF_NAME: "temp_g"},
{CONF_NUMBER: 8, CONF_NAME: "temp_h"},
],
}
}
)
SINGLE_MONITOR_CONFIG_VOLTAGE_SENSORS = make_single_monitor_config_with_sensors(
{
CONF_VOLTAGE_SENSORS: [
{
CONF_NUMBER: 1,
CONF_NAME: "voltage 1",
},
]
}
)
async def setup_greeneye_monitor_component_with_config(
hass: HomeAssistant, config: ConfigType
) -> bool:
"""Set up the greeneye_monitor component with the given config. Return True if successful, False otherwise."""
result = await async_setup_component(
hass,
DOMAIN,
config,
)
await hass.async_block_till_done()
return result
def mock_with_listeners() -> MagicMock:
"""Create a MagicMock with methods that follow the same pattern for working with listeners in the greeneye_monitor API."""
mock = MagicMock()
add_listeners(mock)
return mock
def async_mock_with_listeners() -> AsyncMock:
"""Create an AsyncMock with methods that follow the same pattern for working with listeners in the greeneye_monitor API."""
mock = AsyncMock()
add_listeners(mock)
return mock
def add_listeners(mock: MagicMock | AsyncMock) -> None:
"""Add add_listener and remove_listener methods to the given mock that behave like their counterparts on objects from the greeneye_monitor API, plus a notify_all_listeners method that calls all registered listeners."""
mock.listeners = []
mock.add_listener = mock.listeners.append
mock.remove_listener = mock.listeners.remove
def notify_all_listeners(*args):
for listener in list(mock.listeners):
listener(*args)
mock.notify_all_listeners = notify_all_listeners
def mock_pulse_counter() -> MagicMock:
"""Create a mock GreenEye Monitor pulse counter."""
pulse_counter = mock_with_listeners()
pulse_counter.pulses = 1000
pulse_counter.pulses_per_second = 10
return pulse_counter
def mock_temperature_sensor() -> MagicMock:
"""Create a mock GreenEye Monitor temperature sensor."""
temperature_sensor = mock_with_listeners()
temperature_sensor.temperature = 32.0
return temperature_sensor
def mock_channel() -> MagicMock:
"""Create a mock GreenEye Monitor CT channel."""
channel = mock_with_listeners()
channel.absolute_watt_seconds = 1000
channel.polarized_watt_seconds = -400
channel.watts = None
return channel
def mock_monitor(serial_number: int) -> MagicMock:
"""Create a mock GreenEye Monitor."""
monitor = mock_with_listeners()
monitor.serial_number = serial_number
monitor.voltage = 120.0
monitor.pulse_counters = [mock_pulse_counter() for i in range(0, 4)]
monitor.temperature_sensors = [mock_temperature_sensor() for i in range(0, 8)]
monitor.channels = [mock_channel() for i in range(0, 32)]
return monitor

View File

@ -0,0 +1,118 @@
"""Common fixtures for testing greeneye_monitor."""
from typing import Any, Dict
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
from homeassistant.components.greeneye_monitor import DOMAIN
from homeassistant.const import (
DEVICE_CLASS_POWER,
DEVICE_CLASS_TEMPERATURE,
DEVICE_CLASS_VOLTAGE,
ELECTRIC_POTENTIAL_VOLT,
POWER_WATT,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_registry import (
RegistryEntry,
async_get as get_entity_registry,
)
from .common import add_listeners
def assert_sensor_state(
hass: HomeAssistant,
entity_id: str,
expected_state: str,
attributes: Dict[str, Any] = {},
) -> None:
"""Assert that the given entity has the expected state and at least the provided attributes."""
state = hass.states.get(entity_id)
assert state
actual_state = state.state
assert actual_state == expected_state
for (key, value) in attributes.items():
assert key in state.attributes
assert state.attributes[key] == value
def assert_temperature_sensor_registered(
hass: HomeAssistant,
serial_number: int,
number: int,
name: str,
):
"""Assert that a temperature sensor entity was registered properly."""
sensor = assert_sensor_registered(hass, serial_number, "temp", number, name)
assert sensor.device_class == DEVICE_CLASS_TEMPERATURE
def assert_pulse_counter_registered(
hass: HomeAssistant,
serial_number: int,
number: int,
name: str,
quantity: str,
per_time: str,
):
"""Assert that a pulse counter entity was registered properly."""
sensor = assert_sensor_registered(hass, serial_number, "pulse", number, name)
assert sensor.unit_of_measurement == f"{quantity}/{per_time}"
def assert_power_sensor_registered(
hass: HomeAssistant, serial_number: int, number: int, name: str
) -> None:
"""Assert that a power sensor entity was registered properly."""
sensor = assert_sensor_registered(hass, serial_number, "current", number, name)
assert sensor.unit_of_measurement == POWER_WATT
assert sensor.device_class == DEVICE_CLASS_POWER
def assert_voltage_sensor_registered(
hass: HomeAssistant, serial_number: int, number: int, name: str
) -> None:
"""Assert that a voltage sensor entity was registered properly."""
sensor = assert_sensor_registered(hass, serial_number, "volts", number, name)
assert sensor.unit_of_measurement == ELECTRIC_POTENTIAL_VOLT
assert sensor.device_class == DEVICE_CLASS_VOLTAGE
def assert_sensor_registered(
hass: HomeAssistant,
serial_number: int,
sensor_type: str,
number: int,
name: str,
) -> RegistryEntry:
"""Assert that a sensor entity of a given type was registered properly."""
registry = get_entity_registry(hass)
unique_id = f"{serial_number}-{sensor_type}-{number}"
entity_id = registry.async_get_entity_id("sensor", DOMAIN, unique_id)
assert entity_id is not None
sensor = registry.async_get(entity_id)
assert sensor
assert sensor.unique_id == unique_id
assert sensor.original_name == name
return sensor
@pytest.fixture
def monitors() -> AsyncMock:
"""Provide a mock greeneye.Monitors object that has listeners and can add new monitors."""
with patch("greeneye.Monitors", new=AsyncMock) as mock_monitors:
add_listeners(mock_monitors)
mock_monitors.monitors = {}
def add_monitor(monitor: MagicMock) -> None:
"""Add the given mock monitor as a monitor with the given serial number, notifying any listeners on the Monitors object."""
serial_number = monitor.serial_number
mock_monitors.monitors[serial_number] = monitor
mock_monitors.notify_all_listeners(monitor)
mock_monitors.add_monitor = add_monitor
yield mock_monitors

View File

@ -0,0 +1,199 @@
"""Tests for greeneye_monitor component initialization."""
from __future__ import annotations
from unittest.mock import AsyncMock
import pytest
from homeassistant.components.greeneye_monitor import (
CONF_MONITORS,
CONF_NUMBER,
CONF_SERIAL_NUMBER,
CONF_TEMPERATURE_SENSORS,
DOMAIN,
)
from homeassistant.const import (
CONF_NAME,
CONF_PORT,
CONF_SENSORS,
CONF_TEMPERATURE_UNIT,
)
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
from .common import (
SINGLE_MONITOR_CONFIG_NO_SENSORS,
SINGLE_MONITOR_CONFIG_POWER_SENSORS,
SINGLE_MONITOR_CONFIG_PULSE_COUNTERS,
SINGLE_MONITOR_CONFIG_TEMPERATURE_SENSORS,
SINGLE_MONITOR_CONFIG_VOLTAGE_SENSORS,
SINGLE_MONITOR_SERIAL_NUMBER,
setup_greeneye_monitor_component_with_config,
)
from .conftest import (
assert_power_sensor_registered,
assert_pulse_counter_registered,
assert_temperature_sensor_registered,
assert_voltage_sensor_registered,
)
async def test_setup_fails_if_no_sensors_defined(
hass: HomeAssistant, monitors: AsyncMock
) -> None:
"""Test that component setup fails if there are no sensors defined in the YAML."""
success = await setup_greeneye_monitor_component_with_config(
hass, SINGLE_MONITOR_CONFIG_NO_SENSORS
)
assert not success
@pytest.mark.xfail(reason="Currently failing. Will fix in subsequent PR.")
async def test_setup_succeeds_no_config(
hass: HomeAssistant, monitors: AsyncMock
) -> None:
"""Test that component setup succeeds if there is no config present in the YAML."""
assert await async_setup_component(hass, DOMAIN, {})
async def test_setup_creates_temperature_entities(
hass: HomeAssistant, monitors: AsyncMock
) -> None:
"""Test that component setup registers temperature sensors properly."""
assert await setup_greeneye_monitor_component_with_config(
hass, SINGLE_MONITOR_CONFIG_TEMPERATURE_SENSORS
)
assert_temperature_sensor_registered(
hass, SINGLE_MONITOR_SERIAL_NUMBER, 1, "temp_a"
)
assert_temperature_sensor_registered(
hass, SINGLE_MONITOR_SERIAL_NUMBER, 2, "temp_2"
)
assert_temperature_sensor_registered(
hass, SINGLE_MONITOR_SERIAL_NUMBER, 3, "temp_c"
)
assert_temperature_sensor_registered(
hass, SINGLE_MONITOR_SERIAL_NUMBER, 4, "temp_d"
)
assert_temperature_sensor_registered(
hass, SINGLE_MONITOR_SERIAL_NUMBER, 5, "temp_5"
)
assert_temperature_sensor_registered(
hass, SINGLE_MONITOR_SERIAL_NUMBER, 6, "temp_f"
)
assert_temperature_sensor_registered(
hass, SINGLE_MONITOR_SERIAL_NUMBER, 7, "temp_g"
)
assert_temperature_sensor_registered(
hass, SINGLE_MONITOR_SERIAL_NUMBER, 8, "temp_h"
)
async def test_setup_creates_pulse_counter_entities(
hass: HomeAssistant, monitors: AsyncMock
) -> None:
"""Test that component setup registers pulse counters properly."""
assert await setup_greeneye_monitor_component_with_config(
hass, SINGLE_MONITOR_CONFIG_PULSE_COUNTERS
)
assert_pulse_counter_registered(
hass,
SINGLE_MONITOR_SERIAL_NUMBER,
1,
"pulse_a",
"pulses",
"s",
)
assert_pulse_counter_registered(
hass, SINGLE_MONITOR_SERIAL_NUMBER, 2, "pulse_2", "gal", "min"
)
assert_pulse_counter_registered(
hass,
SINGLE_MONITOR_SERIAL_NUMBER,
3,
"pulse_3",
"gal",
"h",
)
assert_pulse_counter_registered(
hass,
SINGLE_MONITOR_SERIAL_NUMBER,
4,
"pulse_d",
"pulses",
"s",
)
async def test_setup_creates_power_sensor_entities(
hass: HomeAssistant, monitors: AsyncMock
) -> None:
"""Test that component setup registers power sensors correctly."""
assert await setup_greeneye_monitor_component_with_config(
hass, SINGLE_MONITOR_CONFIG_POWER_SENSORS
)
assert_power_sensor_registered(hass, SINGLE_MONITOR_SERIAL_NUMBER, 1, "channel 1")
assert_power_sensor_registered(hass, SINGLE_MONITOR_SERIAL_NUMBER, 2, "channel two")
async def test_setup_creates_voltage_sensor_entities(
hass: HomeAssistant, monitors: AsyncMock
) -> None:
"""Test that component setup registers voltage sensors properly."""
assert await setup_greeneye_monitor_component_with_config(
hass, SINGLE_MONITOR_CONFIG_VOLTAGE_SENSORS
)
assert_voltage_sensor_registered(hass, SINGLE_MONITOR_SERIAL_NUMBER, 1, "voltage 1")
async def test_multi_monitor_config(hass: HomeAssistant, monitors: AsyncMock) -> None:
"""Test that component setup registers entities from multiple monitors correctly."""
assert await setup_greeneye_monitor_component_with_config(
hass,
{
DOMAIN: {
CONF_PORT: 7513,
CONF_MONITORS: [
{
CONF_SERIAL_NUMBER: "00000001",
CONF_TEMPERATURE_SENSORS: {
CONF_TEMPERATURE_UNIT: "C",
CONF_SENSORS: [
{CONF_NUMBER: 1, CONF_NAME: "unit_1_temp_1"}
],
},
},
{
CONF_SERIAL_NUMBER: "00000002",
CONF_TEMPERATURE_SENSORS: {
CONF_TEMPERATURE_UNIT: "F",
CONF_SENSORS: [
{CONF_NUMBER: 1, CONF_NAME: "unit_2_temp_1"}
],
},
},
],
}
},
)
assert_temperature_sensor_registered(hass, 1, 1, "unit_1_temp_1")
assert_temperature_sensor_registered(hass, 2, 1, "unit_2_temp_1")
async def test_setup_and_shutdown(hass: HomeAssistant, monitors: AsyncMock) -> None:
"""Test that the component can set up and shut down cleanly, closing the underlying server on shutdown."""
server = AsyncMock()
monitors.start_server = AsyncMock(return_value=server)
assert await setup_greeneye_monitor_component_with_config(
hass, SINGLE_MONITOR_CONFIG_POWER_SENSORS
)
await hass.async_stop()
assert server.close.called

View File

@ -0,0 +1,165 @@
"""Tests for greeneye_monitor sensors."""
from unittest.mock import AsyncMock, MagicMock
from homeassistant.components.greeneye_monitor.sensor import (
DATA_PULSES,
DATA_WATT_SECONDS,
)
from homeassistant.const import STATE_UNKNOWN
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_registry import async_get as get_entity_registry
from .common import (
SINGLE_MONITOR_CONFIG_POWER_SENSORS,
SINGLE_MONITOR_CONFIG_PULSE_COUNTERS,
SINGLE_MONITOR_CONFIG_TEMPERATURE_SENSORS,
SINGLE_MONITOR_CONFIG_VOLTAGE_SENSORS,
SINGLE_MONITOR_SERIAL_NUMBER,
mock_monitor,
setup_greeneye_monitor_component_with_config,
)
from .conftest import assert_sensor_state
async def test_disable_sensor_before_monitor_connected(
hass: HomeAssistant, monitors: AsyncMock
) -> None:
"""Test that a sensor disabled before its monitor connected stops listening for new monitors."""
# The sensor base class handles connecting the monitor, so we test this with a single voltage sensor for ease
await setup_greeneye_monitor_component_with_config(
hass, SINGLE_MONITOR_CONFIG_VOLTAGE_SENSORS
)
assert len(monitors.listeners) == 1
await disable_entity(hass, "sensor.voltage_1")
assert len(monitors.listeners) == 0 # Make sure we cleaned up the listener
async def test_updates_state_when_monitor_connected(
hass: HomeAssistant, monitors: AsyncMock
) -> None:
"""Test that a sensor updates its state when its monitor first connects."""
# The sensor base class handles updating the state on connection, so we test this with a single voltage sensor for ease
await setup_greeneye_monitor_component_with_config(
hass, SINGLE_MONITOR_CONFIG_VOLTAGE_SENSORS
)
assert_sensor_state(hass, "sensor.voltage_1", STATE_UNKNOWN)
assert len(monitors.listeners) == 1
connect_monitor(monitors, SINGLE_MONITOR_SERIAL_NUMBER)
assert len(monitors.listeners) == 0 # Make sure we cleaned up the listener
assert_sensor_state(hass, "sensor.voltage_1", "120.0")
async def test_disable_sensor_after_monitor_connected(
hass: HomeAssistant, monitors: AsyncMock
) -> None:
"""Test that a sensor disabled after its monitor connected stops listening for sensor changes."""
# The sensor base class handles connecting the monitor, so we test this with a single voltage sensor for ease
await setup_greeneye_monitor_component_with_config(
hass, SINGLE_MONITOR_CONFIG_VOLTAGE_SENSORS
)
monitor = connect_monitor(monitors, SINGLE_MONITOR_SERIAL_NUMBER)
assert len(monitor.listeners) == 1
await disable_entity(hass, "sensor.voltage_1")
assert len(monitor.listeners) == 0
async def test_updates_state_when_sensor_pushes(
hass: HomeAssistant, monitors: AsyncMock
) -> None:
"""Test that a sensor entity updates its state when the underlying sensor pushes an update."""
# The sensor base class handles triggering state updates, so we test this with a single voltage sensor for ease
await setup_greeneye_monitor_component_with_config(
hass, SINGLE_MONITOR_CONFIG_VOLTAGE_SENSORS
)
monitor = connect_monitor(monitors, SINGLE_MONITOR_SERIAL_NUMBER)
assert_sensor_state(hass, "sensor.voltage_1", "120.0")
monitor.voltage = 119.8
monitor.notify_all_listeners()
assert_sensor_state(hass, "sensor.voltage_1", "119.8")
async def test_power_sensor_initially_unknown(
hass: HomeAssistant, monitors: AsyncMock
) -> None:
"""Test that the power sensor can handle its initial state being unknown (since the GEM API needs at least two packets to arrive before it can compute watts)."""
await setup_greeneye_monitor_component_with_config(
hass, SINGLE_MONITOR_CONFIG_POWER_SENSORS
)
connect_monitor(monitors, SINGLE_MONITOR_SERIAL_NUMBER)
assert_sensor_state(
hass, "sensor.channel_1", STATE_UNKNOWN, {DATA_WATT_SECONDS: 1000}
)
# This sensor was configured with net metering on, so we should be taking the
# polarized value
assert_sensor_state(
hass, "sensor.channel_two", STATE_UNKNOWN, {DATA_WATT_SECONDS: -400}
)
async def test_power_sensor(hass: HomeAssistant, monitors: AsyncMock) -> None:
"""Test that a power sensor reports its values correctly, including handling net metering."""
await setup_greeneye_monitor_component_with_config(
hass, SINGLE_MONITOR_CONFIG_POWER_SENSORS
)
monitor = connect_monitor(monitors, SINGLE_MONITOR_SERIAL_NUMBER)
monitor.channels[0].watts = 120.0
monitor.channels[1].watts = 120.0
monitor.channels[0].notify_all_listeners()
monitor.channels[1].notify_all_listeners()
assert_sensor_state(hass, "sensor.channel_1", "120.0", {DATA_WATT_SECONDS: 1000})
# This sensor was configured with net metering on, so we should be taking the
# polarized value
assert_sensor_state(hass, "sensor.channel_two", "120.0", {DATA_WATT_SECONDS: -400})
async def test_pulse_counter(hass: HomeAssistant, monitors: AsyncMock) -> None:
"""Test that a pulse counter sensor reports its values properly, including calculating different units."""
await setup_greeneye_monitor_component_with_config(
hass, SINGLE_MONITOR_CONFIG_PULSE_COUNTERS
)
connect_monitor(monitors, SINGLE_MONITOR_SERIAL_NUMBER)
assert_sensor_state(hass, "sensor.pulse_a", "10.0", {DATA_PULSES: 1000})
# This counter was configured with each pulse meaning 0.5 gallons and
# wanting to show gallons per minute, so 10 pulses per second -> 300 gal/min
assert_sensor_state(hass, "sensor.pulse_2", "300.0", {DATA_PULSES: 1000})
# This counter was configured with each pulse meaning 0.5 gallons and
# wanting to show gallons per hour, so 10 pulses per second -> 18000 gal/hr
assert_sensor_state(hass, "sensor.pulse_3", "18000.0", {DATA_PULSES: 1000})
async def test_temperature_sensor(hass: HomeAssistant, monitors: AsyncMock) -> None:
"""Test that a temperature sensor reports its values properly, including proper handling of when its native unit is different from that configured in hass."""
await setup_greeneye_monitor_component_with_config(
hass, SINGLE_MONITOR_CONFIG_TEMPERATURE_SENSORS
)
connect_monitor(monitors, SINGLE_MONITOR_SERIAL_NUMBER)
# The config says that the sensor is reporting in Fahrenheit; if we set that up
# properly, HA will have converted that to Celsius by default.
assert_sensor_state(hass, "sensor.temp_a", "0.0")
async def test_voltage_sensor(hass: HomeAssistant, monitors: AsyncMock) -> None:
"""Test that a voltage sensor reports its values properly."""
await setup_greeneye_monitor_component_with_config(
hass, SINGLE_MONITOR_CONFIG_VOLTAGE_SENSORS
)
connect_monitor(monitors, SINGLE_MONITOR_SERIAL_NUMBER)
assert_sensor_state(hass, "sensor.voltage_1", "120.0")
def connect_monitor(monitors: AsyncMock, serial_number: int) -> MagicMock:
"""Simulate a monitor connecting to Home Assistant. Returns the mock monitor API object."""
monitor = mock_monitor(serial_number)
monitors.add_monitor(monitor)
return monitor
async def disable_entity(hass: HomeAssistant, entity_id: str) -> None:
"""Disable the given entity."""
entity_registry = get_entity_registry(hass)
entity_registry.async_update_entity(entity_id, disabled_by="user")
await hass.async_block_till_done()