Create greeneye_monitor entities when monitor connects (#66710)
parent
93fab1f996
commit
a08165a8d7
|
@ -53,15 +53,25 @@ async def async_setup_platform(
|
|||
if not discovery_info:
|
||||
return
|
||||
|
||||
monitor_configs = discovery_info[CONF_MONITORS]
|
||||
|
||||
def on_new_monitor(monitor: greeneye.monitor.Monitor) -> None:
|
||||
monitor_config = next(
|
||||
filter(
|
||||
lambda monitor_config: monitor_config[CONF_SERIAL_NUMBER]
|
||||
== monitor.serial_number,
|
||||
monitor_configs,
|
||||
),
|
||||
None,
|
||||
)
|
||||
if monitor_config:
|
||||
entities: list[GEMSensor] = []
|
||||
for monitor_config in discovery_info[CONF_MONITORS]:
|
||||
monitor_serial_number = monitor_config[CONF_SERIAL_NUMBER]
|
||||
|
||||
channel_configs = monitor_config[CONF_CHANNELS]
|
||||
for sensor in channel_configs:
|
||||
entities.append(
|
||||
CurrentSensor(
|
||||
monitor_serial_number,
|
||||
monitor,
|
||||
sensor[CONF_NUMBER],
|
||||
sensor[CONF_NAME],
|
||||
sensor[CONF_NET_METERING],
|
||||
|
@ -72,7 +82,7 @@ async def async_setup_platform(
|
|||
for sensor in pulse_counter_configs:
|
||||
entities.append(
|
||||
PulseCounter(
|
||||
monitor_serial_number,
|
||||
monitor,
|
||||
sensor[CONF_NUMBER],
|
||||
sensor[CONF_NAME],
|
||||
sensor[CONF_COUNTED_QUANTITY],
|
||||
|
@ -85,7 +95,7 @@ async def async_setup_platform(
|
|||
for sensor in temperature_sensor_configs[CONF_SENSORS]:
|
||||
entities.append(
|
||||
TemperatureSensor(
|
||||
monitor_serial_number,
|
||||
monitor,
|
||||
sensor[CONF_NUMBER],
|
||||
sensor[CONF_NAME],
|
||||
temperature_sensor_configs[CONF_TEMPERATURE_UNIT],
|
||||
|
@ -95,14 +105,19 @@ async def async_setup_platform(
|
|||
voltage_sensor_configs = monitor_config[CONF_VOLTAGE_SENSORS]
|
||||
for sensor in voltage_sensor_configs:
|
||||
entities.append(
|
||||
VoltageSensor(
|
||||
monitor_serial_number,
|
||||
sensor[CONF_NUMBER],
|
||||
sensor[CONF_NAME],
|
||||
)
|
||||
VoltageSensor(monitor, sensor[CONF_NUMBER], sensor[CONF_NAME])
|
||||
)
|
||||
|
||||
async_add_entities(entities)
|
||||
monitor_configs.remove(monitor_config)
|
||||
|
||||
if len(monitor_configs) == 0:
|
||||
monitors.remove_listener(on_new_monitor)
|
||||
|
||||
monitors: greeneye.Monitors = hass.data[DATA_GREENEYE_MONITOR]
|
||||
monitors.add_listener(on_new_monitor)
|
||||
for monitor in monitors.monitors.values():
|
||||
on_new_monitor(monitor)
|
||||
|
||||
|
||||
UnderlyingSensorType = Union[
|
||||
|
@ -119,13 +134,19 @@ class GEMSensor(SensorEntity):
|
|||
_attr_should_poll = False
|
||||
|
||||
def __init__(
|
||||
self, monitor_serial_number: int, name: str, sensor_type: str, number: int
|
||||
self,
|
||||
monitor: greeneye.monitor.Monitor,
|
||||
name: str,
|
||||
sensor_type: str,
|
||||
sensor: UnderlyingSensorType,
|
||||
number: int,
|
||||
) -> None:
|
||||
"""Construct the entity."""
|
||||
self._monitor_serial_number = monitor_serial_number
|
||||
self._monitor = monitor
|
||||
self._monitor_serial_number = self._monitor.serial_number
|
||||
self._attr_name = name
|
||||
self._monitor: greeneye.monitor.Monitor | None = None
|
||||
self._sensor_type = sensor_type
|
||||
self._sensor: UnderlyingSensorType = sensor
|
||||
self._number = number
|
||||
self._attr_unique_id = (
|
||||
f"{self._monitor_serial_number}-{self._sensor_type}-{self._number}"
|
||||
|
@ -133,37 +154,12 @@ class GEMSensor(SensorEntity):
|
|||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Wait for and connect to the sensor."""
|
||||
monitors = self.hass.data[DATA_GREENEYE_MONITOR]
|
||||
|
||||
if not self._try_connect_to_monitor(monitors):
|
||||
monitors.add_listener(self._on_new_monitor)
|
||||
|
||||
def _on_new_monitor(self, monitor: greeneye.monitor.Monitor) -> None:
|
||||
monitors = self.hass.data[DATA_GREENEYE_MONITOR]
|
||||
if self._try_connect_to_monitor(monitors):
|
||||
monitors.remove_listener(self._on_new_monitor)
|
||||
self._sensor.add_listener(self.async_write_ha_state)
|
||||
|
||||
async def async_will_remove_from_hass(self) -> None:
|
||||
"""Remove listener from the sensor."""
|
||||
if self._sensor:
|
||||
self._sensor.remove_listener(self.async_write_ha_state)
|
||||
else:
|
||||
monitors = self.hass.data[DATA_GREENEYE_MONITOR]
|
||||
monitors.remove_listener(self._on_new_monitor)
|
||||
|
||||
def _try_connect_to_monitor(self, monitors: greeneye.Monitors) -> bool:
|
||||
self._monitor = monitors.monitors.get(self._monitor_serial_number)
|
||||
if not self._sensor:
|
||||
return False
|
||||
|
||||
self._sensor.add_listener(self.async_write_ha_state)
|
||||
self.async_write_ha_state()
|
||||
|
||||
return True
|
||||
|
||||
@property
|
||||
def _sensor(self) -> UnderlyingSensorType | None:
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class CurrentSensor(GEMSensor):
|
||||
|
@ -173,30 +169,25 @@ class CurrentSensor(GEMSensor):
|
|||
_attr_device_class = SensorDeviceClass.POWER
|
||||
|
||||
def __init__(
|
||||
self, monitor_serial_number: int, number: int, name: str, net_metering: bool
|
||||
self,
|
||||
monitor: greeneye.monitor.Monitor,
|
||||
number: int,
|
||||
name: str,
|
||||
net_metering: bool,
|
||||
) -> None:
|
||||
"""Construct the entity."""
|
||||
super().__init__(monitor_serial_number, name, "current", number)
|
||||
super().__init__(monitor, name, "current", monitor.channels[number - 1], number)
|
||||
self._sensor: greeneye.monitor.Channel = self._sensor
|
||||
self._net_metering = net_metering
|
||||
|
||||
@property
|
||||
def _sensor(self) -> greeneye.monitor.Channel | None:
|
||||
return self._monitor.channels[self._number - 1] if self._monitor else None
|
||||
|
||||
@property
|
||||
def native_value(self) -> float | None:
|
||||
"""Return the current number of watts being used by the channel."""
|
||||
if not self._sensor:
|
||||
return None
|
||||
|
||||
return self._sensor.watts
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self) -> dict[str, Any] | None:
|
||||
"""Return total wattseconds in the state dictionary."""
|
||||
if not self._sensor:
|
||||
return None
|
||||
|
||||
if self._net_metering:
|
||||
watt_seconds = self._sensor.polarized_watt_seconds
|
||||
else:
|
||||
|
@ -212,7 +203,7 @@ class PulseCounter(GEMSensor):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
monitor_serial_number: int,
|
||||
monitor: greeneye.monitor.Monitor,
|
||||
number: int,
|
||||
name: str,
|
||||
counted_quantity: str,
|
||||
|
@ -220,19 +211,18 @@ class PulseCounter(GEMSensor):
|
|||
counted_quantity_per_pulse: float,
|
||||
) -> None:
|
||||
"""Construct the entity."""
|
||||
super().__init__(monitor_serial_number, name, "pulse", number)
|
||||
super().__init__(
|
||||
monitor, name, "pulse", monitor.pulse_counters[number - 1], number
|
||||
)
|
||||
self._sensor: greeneye.monitor.PulseCounter = self._sensor
|
||||
self._counted_quantity_per_pulse = counted_quantity_per_pulse
|
||||
self._time_unit = time_unit
|
||||
self._attr_native_unit_of_measurement = f"{counted_quantity}/{self._time_unit}"
|
||||
|
||||
@property
|
||||
def _sensor(self) -> greeneye.monitor.PulseCounter | None:
|
||||
return self._monitor.pulse_counters[self._number - 1] if self._monitor else None
|
||||
|
||||
@property
|
||||
def native_value(self) -> float | None:
|
||||
"""Return the current rate of change for the given pulse counter."""
|
||||
if not self._sensor or self._sensor.pulses_per_second is None:
|
||||
if self._sensor.pulses_per_second is None:
|
||||
return None
|
||||
|
||||
result = (
|
||||
|
@ -258,11 +248,8 @@ class PulseCounter(GEMSensor):
|
|||
)
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self) -> dict[str, Any] | None:
|
||||
def extra_state_attributes(self) -> dict[str, Any]:
|
||||
"""Return total pulses in the data dictionary."""
|
||||
if not self._sensor:
|
||||
return None
|
||||
|
||||
return {DATA_PULSES: self._sensor.pulses}
|
||||
|
||||
|
||||
|
@ -272,26 +259,18 @@ class TemperatureSensor(GEMSensor):
|
|||
_attr_device_class = SensorDeviceClass.TEMPERATURE
|
||||
|
||||
def __init__(
|
||||
self, monitor_serial_number: int, number: int, name: str, unit: str
|
||||
self, monitor: greeneye.monitor.Monitor, number: int, name: str, unit: str
|
||||
) -> None:
|
||||
"""Construct the entity."""
|
||||
super().__init__(monitor_serial_number, name, "temp", number)
|
||||
self._attr_native_unit_of_measurement = unit
|
||||
|
||||
@property
|
||||
def _sensor(self) -> greeneye.monitor.TemperatureSensor | None:
|
||||
return (
|
||||
self._monitor.temperature_sensors[self._number - 1]
|
||||
if self._monitor
|
||||
else None
|
||||
super().__init__(
|
||||
monitor, name, "temp", monitor.temperature_sensors[number - 1], number
|
||||
)
|
||||
self._sensor: greeneye.monitor.TemperatureSensor = self._sensor
|
||||
self._attr_native_unit_of_measurement = unit
|
||||
|
||||
@property
|
||||
def native_value(self) -> float | None:
|
||||
"""Return the current temperature being reported by this sensor."""
|
||||
if not self._sensor:
|
||||
return None
|
||||
|
||||
return self._sensor.temperature
|
||||
|
||||
|
||||
|
@ -301,19 +280,14 @@ class VoltageSensor(GEMSensor):
|
|||
_attr_native_unit_of_measurement = ELECTRIC_POTENTIAL_VOLT
|
||||
_attr_device_class = SensorDeviceClass.VOLTAGE
|
||||
|
||||
def __init__(self, monitor_serial_number: int, number: int, name: str) -> None:
|
||||
def __init__(
|
||||
self, monitor: greeneye.monitor.Monitor, number: int, name: str
|
||||
) -> None:
|
||||
"""Construct the entity."""
|
||||
super().__init__(monitor_serial_number, name, "volts", number)
|
||||
|
||||
@property
|
||||
def _sensor(self) -> greeneye.monitor.VoltageSensor | None:
|
||||
"""Wire the updates to the monitor itself, since there is no voltage element in the API."""
|
||||
return self._monitor.voltage_sensor if self._monitor else None
|
||||
super().__init__(monitor, name, "volts", monitor.voltage_sensor, number)
|
||||
self._sensor: greeneye.monitor.VoltageSensor = self._sensor
|
||||
|
||||
@property
|
||||
def native_value(self) -> float | None:
|
||||
"""Return the current voltage being reported by this sensor."""
|
||||
if not self._sensor:
|
||||
return None
|
||||
|
||||
return self._sensor.voltage
|
||||
|
|
|
@ -239,3 +239,13 @@ def mock_monitor(serial_number: int) -> MagicMock:
|
|||
monitor.temperature_sensors = [mock_temperature_sensor() for i in range(0, 8)]
|
||||
monitor.channels = [mock_channel() for i in range(0, 32)]
|
||||
return monitor
|
||||
|
||||
|
||||
async def connect_monitor(
|
||||
hass: HomeAssistant, 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)
|
||||
await hass.async_block_till_done()
|
||||
return monitor
|
||||
|
|
|
@ -18,6 +18,7 @@ from .common import (
|
|||
SINGLE_MONITOR_CONFIG_TEMPERATURE_SENSORS,
|
||||
SINGLE_MONITOR_CONFIG_VOLTAGE_SENSORS,
|
||||
SINGLE_MONITOR_SERIAL_NUMBER,
|
||||
connect_monitor,
|
||||
setup_greeneye_monitor_component_with_config,
|
||||
)
|
||||
from .conftest import (
|
||||
|
@ -53,7 +54,7 @@ async def test_setup_creates_temperature_entities(
|
|||
assert await setup_greeneye_monitor_component_with_config(
|
||||
hass, SINGLE_MONITOR_CONFIG_TEMPERATURE_SENSORS
|
||||
)
|
||||
|
||||
await connect_monitor(hass, monitors, SINGLE_MONITOR_SERIAL_NUMBER)
|
||||
assert_temperature_sensor_registered(
|
||||
hass, SINGLE_MONITOR_SERIAL_NUMBER, 1, "temp_a"
|
||||
)
|
||||
|
@ -87,7 +88,7 @@ async def test_setup_creates_pulse_counter_entities(
|
|||
assert await setup_greeneye_monitor_component_with_config(
|
||||
hass, SINGLE_MONITOR_CONFIG_PULSE_COUNTERS
|
||||
)
|
||||
|
||||
await connect_monitor(hass, monitors, SINGLE_MONITOR_SERIAL_NUMBER)
|
||||
assert_pulse_counter_registered(
|
||||
hass,
|
||||
SINGLE_MONITOR_SERIAL_NUMBER,
|
||||
|
@ -124,7 +125,7 @@ async def test_setup_creates_power_sensor_entities(
|
|||
assert await setup_greeneye_monitor_component_with_config(
|
||||
hass, SINGLE_MONITOR_CONFIG_POWER_SENSORS
|
||||
)
|
||||
|
||||
await connect_monitor(hass, monitors, SINGLE_MONITOR_SERIAL_NUMBER)
|
||||
assert_power_sensor_registered(hass, SINGLE_MONITOR_SERIAL_NUMBER, 1, "channel 1")
|
||||
assert_power_sensor_registered(hass, SINGLE_MONITOR_SERIAL_NUMBER, 2, "channel two")
|
||||
|
||||
|
@ -136,7 +137,7 @@ async def test_setup_creates_voltage_sensor_entities(
|
|||
assert await setup_greeneye_monitor_component_with_config(
|
||||
hass, SINGLE_MONITOR_CONFIG_VOLTAGE_SENSORS
|
||||
)
|
||||
|
||||
await connect_monitor(hass, monitors, SINGLE_MONITOR_SERIAL_NUMBER)
|
||||
assert_voltage_sensor_registered(hass, SINGLE_MONITOR_SERIAL_NUMBER, 1, "voltage 1")
|
||||
|
||||
|
||||
|
@ -147,6 +148,10 @@ async def test_multi_monitor_config(hass: HomeAssistant, monitors: AsyncMock) ->
|
|||
MULTI_MONITOR_CONFIG,
|
||||
)
|
||||
|
||||
await connect_monitor(hass, monitors, 1)
|
||||
await connect_monitor(hass, monitors, 2)
|
||||
await connect_monitor(hass, monitors, 3)
|
||||
|
||||
assert_temperature_sensor_registered(hass, 1, 1, "unit_1_temp_1")
|
||||
assert_temperature_sensor_registered(hass, 2, 1, "unit_2_temp_1")
|
||||
assert_temperature_sensor_registered(hass, 3, 1, "unit_3_temp_1")
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
"""Tests for greeneye_monitor sensors."""
|
||||
from unittest.mock import AsyncMock, MagicMock
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
from homeassistant.components.greeneye_monitor.sensor import (
|
||||
DATA_PULSES,
|
||||
|
@ -19,38 +19,50 @@ from .common import (
|
|||
SINGLE_MONITOR_CONFIG_TEMPERATURE_SENSORS,
|
||||
SINGLE_MONITOR_CONFIG_VOLTAGE_SENSORS,
|
||||
SINGLE_MONITOR_SERIAL_NUMBER,
|
||||
mock_monitor,
|
||||
connect_monitor,
|
||||
setup_greeneye_monitor_component_with_config,
|
||||
)
|
||||
from .conftest import assert_sensor_state
|
||||
|
||||
|
||||
async def test_disable_sensor_before_monitor_connected(
|
||||
async def test_sensor_does_not_exist_before_monitor_connected(
|
||||
hass: HomeAssistant, monitors: AsyncMock
|
||||
) -> None:
|
||||
"""Test that a sensor disabled before its monitor connected stops listening for new monitors."""
|
||||
"""Test that a sensor does not exist before its monitor is connected."""
|
||||
# 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
|
||||
entity_registry = get_entity_registry(hass)
|
||||
assert entity_registry.async_get("sensor.voltage_1") is None
|
||||
|
||||
|
||||
async def test_updates_state_when_monitor_connected(
|
||||
async def test_sensors_created_when_monitor_connected(
|
||||
hass: HomeAssistant, monitors: AsyncMock
|
||||
) -> None:
|
||||
"""Test that a sensor updates its state when its monitor first connects."""
|
||||
"""Test that sensors get created when the 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)
|
||||
await connect_monitor(hass, 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_sensors_created_during_setup_if_monitor_already_connected(
|
||||
hass: HomeAssistant, monitors: AsyncMock
|
||||
) -> None:
|
||||
"""Test that sensors get created during setup if the monitor happens to connect really quickly."""
|
||||
# The sensor base class handles updating the state on connection, so we test this with a single voltage sensor for ease
|
||||
await connect_monitor(hass, monitors, SINGLE_MONITOR_SERIAL_NUMBER)
|
||||
await setup_greeneye_monitor_component_with_config(
|
||||
hass, SINGLE_MONITOR_CONFIG_VOLTAGE_SENSORS
|
||||
)
|
||||
|
||||
assert len(monitors.listeners) == 0 # Make sure we cleaned up the listener
|
||||
assert_sensor_state(hass, "sensor.voltage_1", "120.0")
|
||||
|
||||
|
@ -63,7 +75,7 @@ async def test_disable_sensor_after_monitor_connected(
|
|||
await setup_greeneye_monitor_component_with_config(
|
||||
hass, SINGLE_MONITOR_CONFIG_VOLTAGE_SENSORS
|
||||
)
|
||||
monitor = connect_monitor(monitors, SINGLE_MONITOR_SERIAL_NUMBER)
|
||||
monitor = await connect_monitor(hass, monitors, SINGLE_MONITOR_SERIAL_NUMBER)
|
||||
|
||||
assert len(monitor.voltage_sensor.listeners) == 1
|
||||
await disable_entity(hass, "sensor.voltage_1")
|
||||
|
@ -78,7 +90,7 @@ async def test_updates_state_when_sensor_pushes(
|
|||
await setup_greeneye_monitor_component_with_config(
|
||||
hass, SINGLE_MONITOR_CONFIG_VOLTAGE_SENSORS
|
||||
)
|
||||
monitor = connect_monitor(monitors, SINGLE_MONITOR_SERIAL_NUMBER)
|
||||
monitor = await connect_monitor(hass, monitors, SINGLE_MONITOR_SERIAL_NUMBER)
|
||||
assert_sensor_state(hass, "sensor.voltage_1", "120.0")
|
||||
|
||||
monitor.voltage_sensor.voltage = 119.8
|
||||
|
@ -93,7 +105,7 @@ async def test_power_sensor_initially_unknown(
|
|||
await setup_greeneye_monitor_component_with_config(
|
||||
hass, SINGLE_MONITOR_CONFIG_POWER_SENSORS
|
||||
)
|
||||
connect_monitor(monitors, SINGLE_MONITOR_SERIAL_NUMBER)
|
||||
await connect_monitor(hass, monitors, SINGLE_MONITOR_SERIAL_NUMBER)
|
||||
assert_sensor_state(
|
||||
hass, "sensor.channel_1", STATE_UNKNOWN, {DATA_WATT_SECONDS: 1000}
|
||||
)
|
||||
|
@ -109,7 +121,7 @@ async def test_power_sensor(hass: HomeAssistant, monitors: AsyncMock) -> None:
|
|||
await setup_greeneye_monitor_component_with_config(
|
||||
hass, SINGLE_MONITOR_CONFIG_POWER_SENSORS
|
||||
)
|
||||
monitor = connect_monitor(monitors, SINGLE_MONITOR_SERIAL_NUMBER)
|
||||
monitor = await connect_monitor(hass, monitors, SINGLE_MONITOR_SERIAL_NUMBER)
|
||||
monitor.channels[0].watts = 120.0
|
||||
monitor.channels[1].watts = 120.0
|
||||
monitor.channels[0].notify_all_listeners()
|
||||
|
@ -120,12 +132,35 @@ async def test_power_sensor(hass: HomeAssistant, monitors: AsyncMock) -> None:
|
|||
assert_sensor_state(hass, "sensor.channel_two", "120.0", {DATA_WATT_SECONDS: -400})
|
||||
|
||||
|
||||
async def test_pulse_counter_initially_unknown(
|
||||
hass: HomeAssistant, monitors: AsyncMock
|
||||
) -> None:
|
||||
"""Test that the pulse counter sensor can handle its initial state being unknown (since the GEM API needs at least two packets to arrive before it can compute pulses per time)."""
|
||||
await setup_greeneye_monitor_component_with_config(
|
||||
hass, SINGLE_MONITOR_CONFIG_PULSE_COUNTERS
|
||||
)
|
||||
monitor = await connect_monitor(hass, monitors, SINGLE_MONITOR_SERIAL_NUMBER)
|
||||
monitor.pulse_counters[0].pulses_per_second = None
|
||||
monitor.pulse_counters[1].pulses_per_second = None
|
||||
monitor.pulse_counters[2].pulses_per_second = None
|
||||
monitor.pulse_counters[0].notify_all_listeners()
|
||||
monitor.pulse_counters[1].notify_all_listeners()
|
||||
monitor.pulse_counters[2].notify_all_listeners()
|
||||
assert_sensor_state(hass, "sensor.pulse_a", STATE_UNKNOWN, {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", STATE_UNKNOWN, {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", STATE_UNKNOWN, {DATA_PULSES: 1000})
|
||||
|
||||
|
||||
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)
|
||||
await connect_monitor(hass, 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
|
||||
|
@ -140,7 +175,7 @@ async def test_temperature_sensor(hass: HomeAssistant, monitors: AsyncMock) -> N
|
|||
await setup_greeneye_monitor_component_with_config(
|
||||
hass, SINGLE_MONITOR_CONFIG_TEMPERATURE_SENSORS
|
||||
)
|
||||
connect_monitor(monitors, SINGLE_MONITOR_SERIAL_NUMBER)
|
||||
await connect_monitor(hass, 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")
|
||||
|
@ -151,28 +186,21 @@ async def test_voltage_sensor(hass: HomeAssistant, monitors: AsyncMock) -> None:
|
|||
await setup_greeneye_monitor_component_with_config(
|
||||
hass, SINGLE_MONITOR_CONFIG_VOLTAGE_SENSORS
|
||||
)
|
||||
connect_monitor(monitors, SINGLE_MONITOR_SERIAL_NUMBER)
|
||||
await connect_monitor(hass, monitors, SINGLE_MONITOR_SERIAL_NUMBER)
|
||||
assert_sensor_state(hass, "sensor.voltage_1", "120.0")
|
||||
|
||||
|
||||
async def test_multi_monitor_sensors(hass: HomeAssistant, monitors: AsyncMock) -> None:
|
||||
"""Test that sensors still work when multiple monitors are registered."""
|
||||
await setup_greeneye_monitor_component_with_config(hass, MULTI_MONITOR_CONFIG)
|
||||
connect_monitor(monitors, 1)
|
||||
connect_monitor(monitors, 2)
|
||||
connect_monitor(monitors, 3)
|
||||
await connect_monitor(hass, monitors, 1)
|
||||
await connect_monitor(hass, monitors, 2)
|
||||
await connect_monitor(hass, monitors, 3)
|
||||
assert_sensor_state(hass, "sensor.unit_1_temp_1", "32.0")
|
||||
assert_sensor_state(hass, "sensor.unit_2_temp_1", "0.0")
|
||||
assert_sensor_state(hass, "sensor.unit_3_temp_1", "32.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)
|
||||
|
|
Loading…
Reference in New Issue