Remove Oncue integration (#143945)

This commit is contained in:
Joost Lekkerkerker 2025-04-30 12:50:28 +02:00 committed by GitHub
parent 6c633668f6
commit 6168fe006e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 94 additions and 2078 deletions

2
CODEOWNERS generated
View File

@ -1081,8 +1081,6 @@ build.json @home-assistant/supervisor
/homeassistant/components/ombi/ @larssont /homeassistant/components/ombi/ @larssont
/homeassistant/components/onboarding/ @home-assistant/core /homeassistant/components/onboarding/ @home-assistant/core
/tests/components/onboarding/ @home-assistant/core /tests/components/onboarding/ @home-assistant/core
/homeassistant/components/oncue/ @bdraco @peterager
/tests/components/oncue/ @bdraco @peterager
/homeassistant/components/ondilo_ico/ @JeromeHXP /homeassistant/components/ondilo_ico/ @JeromeHXP
/tests/components/ondilo_ico/ @JeromeHXP /tests/components/ondilo_ico/ @JeromeHXP
/homeassistant/components/onedrive/ @zweckj /homeassistant/components/onedrive/ @zweckj

View File

@ -2,60 +2,40 @@
from __future__ import annotations from __future__ import annotations
from datetime import timedelta from homeassistant.config_entries import ConfigEntry
import logging
from aiooncue import LoginFailedException, Oncue, OncueDevice
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME, Platform
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady from homeassistant.helpers import issue_registry as ir
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from .const import CONNECTION_EXCEPTIONS, DOMAIN # noqa: F401 DOMAIN = "oncue"
from .types import OncueConfigEntry
PLATFORMS: list[str] = [Platform.BINARY_SENSOR, Platform.SENSOR]
_LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass: HomeAssistant, entry: OncueConfigEntry) -> bool: async def async_setup_entry(hass: HomeAssistant, _: ConfigEntry) -> bool:
"""Set up Oncue from a config entry.""" """Set up Oncue from a config entry."""
data = entry.data ir.async_create_issue(
websession = async_get_clientsession(hass)
client = Oncue(data[CONF_USERNAME], data[CONF_PASSWORD], websession)
try:
await client.async_login()
except CONNECTION_EXCEPTIONS as ex:
raise ConfigEntryNotReady from ex
except LoginFailedException as ex:
raise ConfigEntryAuthFailed from ex
async def _async_update() -> dict[str, OncueDevice]:
"""Fetch data from Oncue."""
try:
return await client.async_fetch_all()
except LoginFailedException as ex:
raise ConfigEntryAuthFailed from ex
coordinator = DataUpdateCoordinator[dict[str, OncueDevice]](
hass, hass,
_LOGGER, DOMAIN,
config_entry=entry, DOMAIN,
name=f"Oncue {entry.data[CONF_USERNAME]}", is_fixable=False,
update_interval=timedelta(minutes=10), severity=ir.IssueSeverity.ERROR,
update_method=_async_update, translation_key="integration_removed",
always_update=False, translation_placeholders={
"entries": "/config/integrations/integration/oncue",
"rehlko": "/config/integrations/integration/rehlko",
},
) )
await coordinator.async_config_entry_first_refresh()
entry.runtime_data = coordinator
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
return True return True
async def async_unload_entry(hass: HomeAssistant, entry: OncueConfigEntry) -> bool: async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry.""" """Unload a config entry."""
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS) return True
async def async_remove_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
"""Remove a config entry."""
if not hass.config_entries.async_loaded_entries(DOMAIN):
ir.async_delete_issue(hass, DOMAIN, DOMAIN)
# Remove any remaining disabled or ignored entries
for _entry in hass.config_entries.async_entries(DOMAIN):
hass.async_create_task(hass.config_entries.async_remove(_entry.entry_id))

View File

@ -1,50 +0,0 @@
"""Support for Oncue binary sensors."""
from __future__ import annotations
from homeassistant.components.binary_sensor import (
BinarySensorDeviceClass,
BinarySensorEntity,
BinarySensorEntityDescription,
)
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from .entity import OncueEntity
from .types import OncueConfigEntry
SENSOR_TYPES: tuple[BinarySensorEntityDescription, ...] = (
BinarySensorEntityDescription(
key="NetworkConnectionEstablished",
entity_category=EntityCategory.DIAGNOSTIC,
device_class=BinarySensorDeviceClass.CONNECTIVITY,
),
)
SENSOR_MAP = {description.key: description for description in SENSOR_TYPES}
async def async_setup_entry(
hass: HomeAssistant,
config_entry: OncueConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up binary sensors."""
coordinator = config_entry.runtime_data
devices = coordinator.data
async_add_entities(
OncueBinarySensorEntity(coordinator, device_id, device, sensor, SENSOR_MAP[key])
for device_id, device in devices.items()
for key, sensor in device.sensors.items()
if key in SENSOR_MAP
)
class OncueBinarySensorEntity(OncueEntity, BinarySensorEntity):
"""Representation of an Oncue binary sensor."""
@property
def is_on(self) -> bool:
"""Return the binary sensor state."""
return self._oncue_value == "true"

View File

@ -1,101 +1,11 @@
"""Config flow for Oncue integration.""" """The Oncue integration."""
from __future__ import annotations from homeassistant.config_entries import ConfigFlow
from collections.abc import Mapping from . import DOMAIN
import logging
from typing import Any
from aiooncue import LoginFailedException, Oncue
import voluptuous as vol
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from .const import CONNECTION_EXCEPTIONS, DOMAIN
_LOGGER = logging.getLogger(__name__)
class OncueConfigFlow(ConfigFlow, domain=DOMAIN): class OncueConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for Oncue.""" """Handle a config flow for Oncue."""
VERSION = 1 VERSION = 1
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle the initial step."""
errors: dict[str, str] = {}
if user_input is not None:
if not (errors := await self._async_validate_or_error(user_input)):
normalized_username = user_input[CONF_USERNAME].lower()
await self.async_set_unique_id(normalized_username)
self._abort_if_unique_id_configured(
updates={
CONF_USERNAME: user_input[CONF_USERNAME],
CONF_PASSWORD: user_input[CONF_PASSWORD],
}
)
return self.async_create_entry(
title=normalized_username, data=user_input
)
return self.async_show_form(
step_id="user",
data_schema=vol.Schema(
{
vol.Required(CONF_USERNAME): str,
vol.Required(CONF_PASSWORD): str,
}
),
errors=errors,
)
async def _async_validate_or_error(self, config: dict[str, Any]) -> dict[str, str]:
"""Validate the user input."""
errors: dict[str, str] = {}
try:
await Oncue(
config[CONF_USERNAME],
config[CONF_PASSWORD],
async_get_clientsession(self.hass),
).async_login()
except CONNECTION_EXCEPTIONS:
errors["base"] = "cannot_connect"
except LoginFailedException:
errors[CONF_PASSWORD] = "invalid_auth"
except Exception:
_LOGGER.exception("Unexpected exception")
errors["base"] = "unknown"
return errors
async def async_step_reauth(
self, entry_data: Mapping[str, Any]
) -> ConfigFlowResult:
"""Handle reauth."""
return await self.async_step_reauth_confirm()
async def async_step_reauth_confirm(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle reauth input."""
errors: dict[str, str] = {}
reauth_entry = self._get_reauth_entry()
existing_data = reauth_entry.data
description_placeholders: dict[str, str] = {
CONF_USERNAME: existing_data[CONF_USERNAME]
}
if user_input is not None:
new_config = {**existing_data, CONF_PASSWORD: user_input[CONF_PASSWORD]}
if not (errors := await self._async_validate_or_error(new_config)):
return self.async_update_reload_and_abort(reauth_entry, data=new_config)
return self.async_show_form(
description_placeholders=description_placeholders,
step_id="reauth_confirm",
data_schema=vol.Schema({vol.Required(CONF_PASSWORD): str}),
errors=errors,
)

View File

@ -1,16 +0,0 @@
"""Constants for the Oncue integration."""
import aiohttp
from aiooncue import ServiceFailedException
DOMAIN = "oncue"
CONNECTION_EXCEPTIONS = (
TimeoutError,
aiohttp.ClientError,
ServiceFailedException,
)
CONNECTION_ESTABLISHED_KEY: str = "NetworkConnectionEstablished"
VALUE_UNAVAILABLE: str = "--"

View File

@ -1,82 +0,0 @@
"""Support for Oncue sensors."""
from __future__ import annotations
from aiooncue import OncueDevice, OncueSensor
from homeassistant.const import ATTR_CONNECTIONS
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity import Entity, EntityDescription
from homeassistant.helpers.update_coordinator import (
CoordinatorEntity,
DataUpdateCoordinator,
)
from .const import CONNECTION_ESTABLISHED_KEY, DOMAIN, VALUE_UNAVAILABLE
class OncueEntity(
CoordinatorEntity[DataUpdateCoordinator[dict[str, OncueDevice]]], Entity
):
"""Representation of an Oncue entity."""
_attr_has_entity_name = True
def __init__(
self,
coordinator: DataUpdateCoordinator[dict[str, OncueDevice]],
device_id: str,
device: OncueDevice,
sensor: OncueSensor,
description: EntityDescription,
) -> None:
"""Initialize the sensor."""
super().__init__(coordinator)
self.entity_description = description
self._device_id = device_id
self._attr_unique_id = f"{device_id}_{description.key}"
self._attr_name = sensor.display_name
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, device_id)},
name=device.name,
hw_version=device.hardware_version,
sw_version=device.sensors["FirmwareVersion"].display_value,
model=device.sensors["GensetModelNumberSelect"].display_value,
manufacturer="Kohler",
)
try:
mac_address_hex = hex(int(device.sensors["MacAddress"].value))[2:]
except ValueError: # MacAddress may be invalid if the gateway is offline
return
self._attr_device_info[ATTR_CONNECTIONS] = {
(dr.CONNECTION_NETWORK_MAC, mac_address_hex)
}
@property
def _oncue_value(self) -> str:
"""Return the sensor value."""
device: OncueDevice = self.coordinator.data[self._device_id]
sensor: OncueSensor = device.sensors[self.entity_description.key]
return sensor.value
@property
def available(self) -> bool:
"""Return if entity is available."""
# The binary sensor that tracks the connection should not go unavailable.
if self.entity_description.key != CONNECTION_ESTABLISHED_KEY:
# If Kohler returns -- the entity is unavailable.
if self._oncue_value == VALUE_UNAVAILABLE:
return False
# If the cloud is reporting that the generator is not connected
# this also indicates the data is not available.
# The battery voltage sensor reports 0.0 rather than
# -- hence the purpose of this check.
device: OncueDevice = self.coordinator.data[self._device_id]
conn_established: OncueSensor = device.sensors[CONNECTION_ESTABLISHED_KEY]
if (
conn_established is not None
and conn_established.value == VALUE_UNAVAILABLE
):
return False
return super().available

View File

@ -1,16 +1,10 @@
{ {
"domain": "oncue", "domain": "oncue",
"name": "Oncue by Kohler", "name": "Oncue by Kohler",
"codeowners": ["@bdraco", "@peterager"], "codeowners": [],
"config_flow": true,
"dhcp": [
{
"hostname": "kohlergen*",
"macaddress": "00146F*"
}
],
"documentation": "https://www.home-assistant.io/integrations/oncue", "documentation": "https://www.home-assistant.io/integrations/oncue",
"integration_type": "system",
"iot_class": "cloud_polling", "iot_class": "cloud_polling",
"loggers": ["aiooncue"], "quality_scale": "legacy",
"requirements": ["aiooncue==0.3.9"] "requirements": []
} }

View File

@ -1,217 +0,0 @@
"""Support for Oncue sensors."""
from __future__ import annotations
from aiooncue import OncueDevice, OncueSensor
from homeassistant.components.sensor import (
SensorDeviceClass,
SensorEntity,
SensorEntityDescription,
SensorStateClass,
)
from homeassistant.const import (
PERCENTAGE,
EntityCategory,
UnitOfElectricCurrent,
UnitOfElectricPotential,
UnitOfEnergy,
UnitOfFrequency,
UnitOfPower,
UnitOfPressure,
UnitOfTemperature,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from .entity import OncueEntity
from .types import OncueConfigEntry
SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
SensorEntityDescription(
key="LatestFirmware",
icon="mdi:update",
entity_category=EntityCategory.DIAGNOSTIC,
),
SensorEntityDescription(
key="EngineSpeed",
icon="mdi:speedometer",
entity_category=EntityCategory.DIAGNOSTIC,
),
SensorEntityDescription(
key="EngineTargetSpeed",
icon="mdi:speedometer",
entity_category=EntityCategory.DIAGNOSTIC,
),
SensorEntityDescription(
key="EngineOilPressure",
native_unit_of_measurement=UnitOfPressure.PSI,
device_class=SensorDeviceClass.PRESSURE,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
),
SensorEntityDescription(
key="EngineCoolantTemperature",
device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
),
SensorEntityDescription(
key="BatteryVoltage",
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
),
SensorEntityDescription(
key="LubeOilTemperature",
device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
),
SensorEntityDescription(
key="GensetControllerTemperature",
device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
),
SensorEntityDescription(
key="EngineCompartmentTemperature",
device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
),
SensorEntityDescription(
key="GeneratorTrueTotalPower",
native_unit_of_measurement=UnitOfPower.WATT,
device_class=SensorDeviceClass.POWER,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
),
SensorEntityDescription(
key="GeneratorTruePercentOfRatedPower",
native_unit_of_measurement=PERCENTAGE,
entity_category=EntityCategory.DIAGNOSTIC,
),
SensorEntityDescription(
key="GeneratorVoltageAverageLineToLine",
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
),
SensorEntityDescription(
key="GeneratorFrequency",
native_unit_of_measurement=UnitOfFrequency.HERTZ,
device_class=SensorDeviceClass.FREQUENCY,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
),
SensorEntityDescription(key="GensetState", icon="mdi:home-lightning-bolt"),
SensorEntityDescription(
key="GensetControllerTotalOperationTime",
icon="mdi:hours-24",
entity_category=EntityCategory.DIAGNOSTIC,
),
SensorEntityDescription(
key="EngineTotalRunTime",
icon="mdi:hours-24",
entity_category=EntityCategory.DIAGNOSTIC,
),
SensorEntityDescription(
key="EngineTotalRunTimeLoaded",
icon="mdi:hours-24",
entity_category=EntityCategory.DIAGNOSTIC,
),
SensorEntityDescription(key="AtsContactorPosition", icon="mdi:electric-switch"),
SensorEntityDescription(
key="IPAddress",
icon="mdi:ip-network",
entity_category=EntityCategory.DIAGNOSTIC,
),
SensorEntityDescription(
key="ConnectedServerIPAddress",
icon="mdi:server-network",
entity_category=EntityCategory.DIAGNOSTIC,
),
SensorEntityDescription(
key="Source1VoltageAverageLineToLine",
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
),
SensorEntityDescription(
key="Source2VoltageAverageLineToLine",
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
),
SensorEntityDescription(
key="GensetTotalEnergy",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
),
SensorEntityDescription(
key="EngineTotalNumberOfStarts",
icon="mdi:engine",
entity_category=EntityCategory.DIAGNOSTIC,
),
SensorEntityDescription(
key="GeneratorCurrentAverage",
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
device_class=SensorDeviceClass.CURRENT,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
),
)
SENSOR_MAP = {description.key: description for description in SENSOR_TYPES}
UNIT_MAPPINGS = {
"C": UnitOfTemperature.CELSIUS,
"F": UnitOfTemperature.FAHRENHEIT,
}
async def async_setup_entry(
hass: HomeAssistant,
config_entry: OncueConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up sensors."""
coordinator = config_entry.runtime_data
devices = coordinator.data
async_add_entities(
OncueSensorEntity(coordinator, device_id, device, sensor, SENSOR_MAP[key])
for device_id, device in devices.items()
for key, sensor in device.sensors.items()
if key in SENSOR_MAP
)
class OncueSensorEntity(OncueEntity, SensorEntity):
"""Representation of an Oncue sensor."""
def __init__(
self,
coordinator: DataUpdateCoordinator[dict[str, OncueDevice]],
device_id: str,
device: OncueDevice,
sensor: OncueSensor,
description: SensorEntityDescription,
) -> None:
"""Initialize the sensor."""
super().__init__(coordinator, device_id, device, sensor, description)
if not description.native_unit_of_measurement and sensor.unit is not None:
self._attr_native_unit_of_measurement = UNIT_MAPPINGS.get(
sensor.unit, sensor.unit
)
@property
def native_value(self) -> str:
"""Return the sensors state."""
return self._oncue_value

View File

@ -1,27 +1,8 @@
{ {
"config": { "issues": {
"step": { "integration_removed": {
"user": { "title": "The Oncue integration has been removed",
"data": { "description": "The Oncue integration has been removed from Home Assistant.\n\nThe Oncue service has been discontinued and [Rehlko]({rehlko}) is the integration to keep using it.\n\nTo resolve this issue, please remove the (now defunct) integration entries from your Home Assistant setup. [Click here to see your existing Oncue integration entries]({entries})."
"username": "[%key:common::config_flow::data::username%]",
"password": "[%key:common::config_flow::data::password%]"
}
},
"reauth_confirm": {
"description": "Re-authenticate Oncue account {username}",
"data": {
"password": "[%key:common::config_flow::data::password%]"
}
}
},
"error": {
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
"unknown": "[%key:common::config_flow::error::unknown%]"
},
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_account%]",
"reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]"
} }
} }
} }

View File

@ -1,10 +0,0 @@
"""Support for Oncue types."""
from __future__ import annotations
from aiooncue import OncueDevice
from homeassistant.config_entries import ConfigEntry
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
type OncueConfigEntry = ConfigEntry[DataUpdateCoordinator[dict[str, OncueDevice]]]

View File

@ -440,7 +440,6 @@ FLOWS = {
"ohme", "ohme",
"ollama", "ollama",
"omnilogic", "omnilogic",
"oncue",
"ondilo_ico", "ondilo_ico",
"onedrive", "onedrive",
"onewire", "onewire",

View File

@ -404,11 +404,6 @@ DHCP: Final[list[dict[str, str | bool]]] = [
"domain": "obihai", "domain": "obihai",
"macaddress": "9CADEF*", "macaddress": "9CADEF*",
}, },
{
"domain": "oncue",
"hostname": "kohlergen*",
"macaddress": "00146F*",
},
{ {
"domain": "onvif", "domain": "onvif",
"registered_devices": True, "registered_devices": True,

View File

@ -4563,12 +4563,6 @@
"iot_class": "cloud_polling", "iot_class": "cloud_polling",
"single_config_entry": true "single_config_entry": true
}, },
"oncue": {
"name": "Oncue by Kohler",
"integration_type": "hub",
"config_flow": true,
"iot_class": "cloud_polling"
},
"ondilo_ico": { "ondilo_ico": {
"name": "Ondilo ICO", "name": "Ondilo ICO",
"integration_type": "hub", "integration_type": "hub",

3
requirements_all.txt generated
View File

@ -324,9 +324,6 @@ aiontfy==0.5.1
# homeassistant.components.nut # homeassistant.components.nut
aionut==4.3.4 aionut==4.3.4
# homeassistant.components.oncue
aiooncue==0.3.9
# homeassistant.components.openexchangerates # homeassistant.components.openexchangerates
aioopenexchangerates==0.6.8 aioopenexchangerates==0.6.8

View File

@ -306,9 +306,6 @@ aiontfy==0.5.1
# homeassistant.components.nut # homeassistant.components.nut
aionut==4.3.4 aionut==4.3.4
# homeassistant.components.oncue
aiooncue==0.3.9
# homeassistant.components.openexchangerates # homeassistant.components.openexchangerates
aioopenexchangerates==0.6.8 aioopenexchangerates==0.6.8

View File

@ -1,881 +1 @@
"""Tests for the Oncue integration.""" """Tests for the Oncue integration."""
from contextlib import contextmanager
from unittest.mock import patch
from aiooncue import LoginFailedException, OncueDevice, OncueSensor
MOCK_ASYNC_FETCH_ALL = {
"123456": OncueDevice(
name="My Generator",
state="Off",
product_name="RDC 2.4",
hardware_version="319",
serial_number="SERIAL",
sensors={
"Product": OncueSensor(
name="Product",
display_name="Controller Type",
value="RDC 2.4",
display_value="RDC 2.4",
unit=None,
),
"FirmwareVersion": OncueSensor(
name="FirmwareVersion",
display_name="Current Firmware",
value="2.0.6",
display_value="2.0.6",
unit=None,
),
"LatestFirmware": OncueSensor(
name="LatestFirmware",
display_name="Latest Firmware",
value="2.0.6",
display_value="2.0.6",
unit=None,
),
"EngineSpeed": OncueSensor(
name="EngineSpeed",
display_name="Engine Speed",
value="0",
display_value="0 R/min",
unit="R/min",
),
"EngineTargetSpeed": OncueSensor(
name="EngineTargetSpeed",
display_name="Engine Target Speed",
value="0",
display_value="0 R/min",
unit="R/min",
),
"EngineOilPressure": OncueSensor(
name="EngineOilPressure",
display_name="Engine Oil Pressure",
value=0,
display_value="0 Psi",
unit="Psi",
),
"EngineCoolantTemperature": OncueSensor(
name="EngineCoolantTemperature",
display_name="Engine Coolant Temperature",
value=32,
display_value="32 F",
unit="F",
),
"BatteryVoltage": OncueSensor(
name="BatteryVoltage",
display_name="Battery Voltage",
value="13.4",
display_value="13.4 V",
unit="V",
),
"LubeOilTemperature": OncueSensor(
name="LubeOilTemperature",
display_name="Lube Oil Temperature",
value=32,
display_value="32 F",
unit="F",
),
"GensetControllerTemperature": OncueSensor(
name="GensetControllerTemperature",
display_name="Generator Controller Temperature",
value=84.2,
display_value="84.2 F",
unit="F",
),
"EngineCompartmentTemperature": OncueSensor(
name="EngineCompartmentTemperature",
display_name="Engine Compartment Temperature",
value=62.6,
display_value="62.6 F",
unit="F",
),
"GeneratorTrueTotalPower": OncueSensor(
name="GeneratorTrueTotalPower",
display_name="Generator True Total Power",
value="0.0",
display_value="0.0 W",
unit="W",
),
"GeneratorTruePercentOfRatedPower": OncueSensor(
name="GeneratorTruePercentOfRatedPower",
display_name="Generator True Percent Of Rated Power",
value="0",
display_value="0 %",
unit="%",
),
"GeneratorVoltageAB": OncueSensor(
name="GeneratorVoltageAB",
display_name="Generator Voltage AB",
value="0.0",
display_value="0.0 V",
unit="V",
),
"GeneratorVoltageAverageLineToLine": OncueSensor(
name="GeneratorVoltageAverageLineToLine",
display_name="Generator Voltage Average Line To Line",
value="0.0",
display_value="0.0 V",
unit="V",
),
"GeneratorCurrentAverage": OncueSensor(
name="GeneratorCurrentAverage",
display_name="Generator Current Average",
value="0.0",
display_value="0.0 A",
unit="A",
),
"GeneratorFrequency": OncueSensor(
name="GeneratorFrequency",
display_name="Generator Frequency",
value="0.0",
display_value="0.0 Hz",
unit="Hz",
),
"GensetSerialNumber": OncueSensor(
name="GensetSerialNumber",
display_name="Generator Serial Number",
value="33FDGMFR0026",
display_value="33FDGMFR0026",
unit=None,
),
"GensetState": OncueSensor(
name="GensetState",
display_name="Generator State",
value="Off",
display_value="Off",
unit=None,
),
"GensetControllerSerialNumber": OncueSensor(
name="GensetControllerSerialNumber",
display_name="Generator Controller Serial Number",
value="-1",
display_value="-1",
unit=None,
),
"GensetModelNumberSelect": OncueSensor(
name="GensetModelNumberSelect",
display_name="Genset Model Number Select",
value="38 RCLB",
display_value="38 RCLB",
unit=None,
),
"GensetControllerClockTime": OncueSensor(
name="GensetControllerClockTime",
display_name="Generator Controller Clock Time",
value="2022-01-13 18:08:13",
display_value="2022-01-13 18:08:13",
unit=None,
),
"GensetControllerTotalOperationTime": OncueSensor(
name="GensetControllerTotalOperationTime",
display_name="Generator Controller Total Operation Time",
value="16770.8",
display_value="16770.8 h",
unit="h",
),
"EngineTotalRunTime": OncueSensor(
name="EngineTotalRunTime",
display_name="Engine Total Run Time",
value="28.1",
display_value="28.1 h",
unit="h",
),
"EngineTotalRunTimeLoaded": OncueSensor(
name="EngineTotalRunTimeLoaded",
display_name="Engine Total Run Time Loaded",
value="5.5",
display_value="5.5 h",
unit="h",
),
"EngineTotalNumberOfStarts": OncueSensor(
name="EngineTotalNumberOfStarts",
display_name="Engine Total Number Of Starts",
value="101",
display_value="101",
unit=None,
),
"GensetTotalEnergy": OncueSensor(
name="GensetTotalEnergy",
display_name="Genset Total Energy",
value="1.2022309E7",
display_value="1.2022309E7 kWh",
unit="kWh",
),
"AtsContactorPosition": OncueSensor(
name="AtsContactorPosition",
display_name="Ats Contactor Position",
value="Source1",
display_value="Source1",
unit=None,
),
"AtsSourcesAvailable": OncueSensor(
name="AtsSourcesAvailable",
display_name="Ats Sources Available",
value="Source1",
display_value="Source1",
unit=None,
),
"Source1VoltageAverageLineToLine": OncueSensor(
name="Source1VoltageAverageLineToLine",
display_name="Source1 Voltage Average Line To Line",
value="253.5",
display_value="253.5 V",
unit="V",
),
"Source2VoltageAverageLineToLine": OncueSensor(
name="Source2VoltageAverageLineToLine",
display_name="Source2 Voltage Average Line To Line",
value="0.0",
display_value="0.0 V",
unit="V",
),
"IPAddress": OncueSensor(
name="IPAddress",
display_name="IP Address",
value="1.2.3.4:1026",
display_value="1.2.3.4:1026",
unit=None,
),
"MacAddress": OncueSensor(
name="MacAddress",
display_name="Mac Address",
value="221157033710592",
display_value="221157033710592",
unit=None,
),
"ConnectedServerIPAddress": OncueSensor(
name="ConnectedServerIPAddress",
display_name="Connected Server IP Address",
value="40.117.195.28",
display_value="40.117.195.28",
unit=None,
),
"NetworkConnectionEstablished": OncueSensor(
name="NetworkConnectionEstablished",
display_name="Network Connection Established",
value="true",
display_value="True",
unit=None,
),
"SerialNumber": OncueSensor(
name="SerialNumber",
display_name="Serial Number",
value="1073879692",
display_value="1073879692",
unit=None,
),
},
)
}
MOCK_ASYNC_FETCH_ALL_OFFLINE_DEVICE = {
"456789": OncueDevice(
name="My Generator",
state="Off",
product_name="RDC 2.4",
hardware_version="319",
serial_number="SERIAL",
sensors={
"Product": OncueSensor(
name="Product",
display_name="Controller Type",
value="RDC 2.4",
display_value="RDC 2.4",
unit=None,
),
"FirmwareVersion": OncueSensor(
name="FirmwareVersion",
display_name="Current Firmware",
value="2.0.6",
display_value="2.0.6",
unit=None,
),
"LatestFirmware": OncueSensor(
name="LatestFirmware",
display_name="Latest Firmware",
value="2.0.6",
display_value="2.0.6",
unit=None,
),
"EngineSpeed": OncueSensor(
name="EngineSpeed",
display_name="Engine Speed",
value="0",
display_value="0 R/min",
unit="R/min",
),
"EngineTargetSpeed": OncueSensor(
name="EngineTargetSpeed",
display_name="Engine Target Speed",
value="0",
display_value="0 R/min",
unit="R/min",
),
"EngineOilPressure": OncueSensor(
name="EngineOilPressure",
display_name="Engine Oil Pressure",
value=0,
display_value="0 Psi",
unit="Psi",
),
"EngineCoolantTemperature": OncueSensor(
name="EngineCoolantTemperature",
display_name="Engine Coolant Temperature",
value=32,
display_value="32 F",
unit="F",
),
"BatteryVoltage": OncueSensor(
name="BatteryVoltage",
display_name="Battery Voltage",
value="13.4",
display_value="13.4 V",
unit="V",
),
"LubeOilTemperature": OncueSensor(
name="LubeOilTemperature",
display_name="Lube Oil Temperature",
value=32,
display_value="32 F",
unit="F",
),
"GensetControllerTemperature": OncueSensor(
name="GensetControllerTemperature",
display_name="Generator Controller Temperature",
value=84.2,
display_value="84.2 F",
unit="F",
),
"EngineCompartmentTemperature": OncueSensor(
name="EngineCompartmentTemperature",
display_name="Engine Compartment Temperature",
value=62.6,
display_value="62.6 F",
unit="F",
),
"GeneratorTrueTotalPower": OncueSensor(
name="GeneratorTrueTotalPower",
display_name="Generator True Total Power",
value="0.0",
display_value="0.0 W",
unit="W",
),
"GeneratorTruePercentOfRatedPower": OncueSensor(
name="GeneratorTruePercentOfRatedPower",
display_name="Generator True Percent Of Rated Power",
value="0",
display_value="0 %",
unit="%",
),
"GeneratorVoltageAB": OncueSensor(
name="GeneratorVoltageAB",
display_name="Generator Voltage AB",
value="0.0",
display_value="0.0 V",
unit="V",
),
"GeneratorVoltageAverageLineToLine": OncueSensor(
name="GeneratorVoltageAverageLineToLine",
display_name="Generator Voltage Average Line To Line",
value="0.0",
display_value="0.0 V",
unit="V",
),
"GeneratorCurrentAverage": OncueSensor(
name="GeneratorCurrentAverage",
display_name="Generator Current Average",
value="0.0",
display_value="0.0 A",
unit="A",
),
"GeneratorFrequency": OncueSensor(
name="GeneratorFrequency",
display_name="Generator Frequency",
value="0.0",
display_value="0.0 Hz",
unit="Hz",
),
"GensetSerialNumber": OncueSensor(
name="GensetSerialNumber",
display_name="Generator Serial Number",
value="33FDGMFR0026",
display_value="33FDGMFR0026",
unit=None,
),
"GensetState": OncueSensor(
name="GensetState",
display_name="Generator State",
value="Off",
display_value="Off",
unit=None,
),
"GensetControllerSerialNumber": OncueSensor(
name="GensetControllerSerialNumber",
display_name="Generator Controller Serial Number",
value="-1",
display_value="-1",
unit=None,
),
"GensetModelNumberSelect": OncueSensor(
name="GensetModelNumberSelect",
display_name="Genset Model Number Select",
value="38 RCLB",
display_value="38 RCLB",
unit=None,
),
"GensetControllerClockTime": OncueSensor(
name="GensetControllerClockTime",
display_name="Generator Controller Clock Time",
value="2022-01-13 18:08:13",
display_value="2022-01-13 18:08:13",
unit=None,
),
"GensetControllerTotalOperationTime": OncueSensor(
name="GensetControllerTotalOperationTime",
display_name="Generator Controller Total Operation Time",
value="16770.8",
display_value="16770.8 h",
unit="h",
),
"EngineTotalRunTime": OncueSensor(
name="EngineTotalRunTime",
display_name="Engine Total Run Time",
value="28.1",
display_value="28.1 h",
unit="h",
),
"EngineTotalRunTimeLoaded": OncueSensor(
name="EngineTotalRunTimeLoaded",
display_name="Engine Total Run Time Loaded",
value="5.5",
display_value="5.5 h",
unit="h",
),
"EngineTotalNumberOfStarts": OncueSensor(
name="EngineTotalNumberOfStarts",
display_name="Engine Total Number Of Starts",
value="101",
display_value="101",
unit=None,
),
"GensetTotalEnergy": OncueSensor(
name="GensetTotalEnergy",
display_name="Genset Total Energy",
value="1.2022309E7",
display_value="1.2022309E7 kWh",
unit="kWh",
),
"AtsContactorPosition": OncueSensor(
name="AtsContactorPosition",
display_name="Ats Contactor Position",
value="Source1",
display_value="Source1",
unit=None,
),
"AtsSourcesAvailable": OncueSensor(
name="AtsSourcesAvailable",
display_name="Ats Sources Available",
value="Source1",
display_value="Source1",
unit=None,
),
"Source1VoltageAverageLineToLine": OncueSensor(
name="Source1VoltageAverageLineToLine",
display_name="Source1 Voltage Average Line To Line",
value="253.5",
display_value="253.5 V",
unit="V",
),
"Source2VoltageAverageLineToLine": OncueSensor(
name="Source2VoltageAverageLineToLine",
display_name="Source2 Voltage Average Line To Line",
value="0.0",
display_value="0.0 V",
unit="V",
),
"IPAddress": OncueSensor(
name="IPAddress",
display_name="IP Address",
value="1.2.3.4:1026",
display_value="1.2.3.4:1026",
unit=None,
),
"MacAddress": OncueSensor(
name="MacAddress",
display_name="Mac Address",
value="--",
display_value="--",
unit=None,
),
"ConnectedServerIPAddress": OncueSensor(
name="ConnectedServerIPAddress",
display_name="Connected Server IP Address",
value="40.117.195.28",
display_value="40.117.195.28",
unit=None,
),
"NetworkConnectionEstablished": OncueSensor(
name="NetworkConnectionEstablished",
display_name="Network Connection Established",
value="true",
display_value="True",
unit=None,
),
"SerialNumber": OncueSensor(
name="SerialNumber",
display_name="Serial Number",
value="1073879692",
display_value="1073879692",
unit=None,
),
},
)
}
MOCK_ASYNC_FETCH_ALL_UNAVAILABLE_DEVICE = {
"456789": OncueDevice(
name="My Generator",
state="Off",
product_name="RDC 2.4",
hardware_version="319",
serial_number="SERIAL",
sensors={
"Product": OncueSensor(
name="Product",
display_name="Controller Type",
value="--",
display_value="RDC 2.4",
unit=None,
),
"FirmwareVersion": OncueSensor(
name="FirmwareVersion",
display_name="Current Firmware",
value="--",
display_value="2.0.6",
unit=None,
),
"LatestFirmware": OncueSensor(
name="LatestFirmware",
display_name="Latest Firmware",
value="--",
display_value="2.0.6",
unit=None,
),
"EngineSpeed": OncueSensor(
name="EngineSpeed",
display_name="Engine Speed",
value="--",
display_value="0 R/min",
unit="R/min",
),
"EngineTargetSpeed": OncueSensor(
name="EngineTargetSpeed",
display_name="Engine Target Speed",
value="--",
display_value="0 R/min",
unit="R/min",
),
"EngineOilPressure": OncueSensor(
name="EngineOilPressure",
display_name="Engine Oil Pressure",
value="--",
display_value="0 Psi",
unit="Psi",
),
"EngineCoolantTemperature": OncueSensor(
name="EngineCoolantTemperature",
display_name="Engine Coolant Temperature",
value="--",
display_value="32 F",
unit="F",
),
"BatteryVoltage": OncueSensor(
name="BatteryVoltage",
display_name="Battery Voltage",
value="0.0",
display_value="13.4 V",
unit="V",
),
"LubeOilTemperature": OncueSensor(
name="LubeOilTemperature",
display_name="Lube Oil Temperature",
value="--",
display_value="32 F",
unit="F",
),
"GensetControllerTemperature": OncueSensor(
name="GensetControllerTemperature",
display_name="Generator Controller Temperature",
value="--",
display_value="84.2 F",
unit="F",
),
"EngineCompartmentTemperature": OncueSensor(
name="EngineCompartmentTemperature",
display_name="Engine Compartment Temperature",
value="--",
display_value="62.6 F",
unit="F",
),
"GeneratorTrueTotalPower": OncueSensor(
name="GeneratorTrueTotalPower",
display_name="Generator True Total Power",
value="--",
display_value="0.0 W",
unit="W",
),
"GeneratorTruePercentOfRatedPower": OncueSensor(
name="GeneratorTruePercentOfRatedPower",
display_name="Generator True Percent Of Rated Power",
value="--",
display_value="0 %",
unit="%",
),
"GeneratorVoltageAB": OncueSensor(
name="GeneratorVoltageAB",
display_name="Generator Voltage AB",
value="--",
display_value="0.0 V",
unit="V",
),
"GeneratorVoltageAverageLineToLine": OncueSensor(
name="GeneratorVoltageAverageLineToLine",
display_name="Generator Voltage Average Line To Line",
value="--",
display_value="0.0 V",
unit="V",
),
"GeneratorCurrentAverage": OncueSensor(
name="GeneratorCurrentAverage",
display_name="Generator Current Average",
value="--",
display_value="0.0 A",
unit="A",
),
"GeneratorFrequency": OncueSensor(
name="GeneratorFrequency",
display_name="Generator Frequency",
value="--",
display_value="0.0 Hz",
unit="Hz",
),
"GensetSerialNumber": OncueSensor(
name="GensetSerialNumber",
display_name="Generator Serial Number",
value="--",
display_value="33FDGMFR0026",
unit=None,
),
"GensetState": OncueSensor(
name="GensetState",
display_name="Generator State",
value="--",
display_value="Off",
unit=None,
),
"GensetControllerSerialNumber": OncueSensor(
name="GensetControllerSerialNumber",
display_name="Generator Controller Serial Number",
value="--",
display_value="-1",
unit=None,
),
"GensetModelNumberSelect": OncueSensor(
name="GensetModelNumberSelect",
display_name="Genset Model Number Select",
value="--",
display_value="38 RCLB",
unit=None,
),
"GensetControllerClockTime": OncueSensor(
name="GensetControllerClockTime",
display_name="Generator Controller Clock Time",
value="--",
display_value="2022-01-13 18:08:13",
unit=None,
),
"GensetControllerTotalOperationTime": OncueSensor(
name="GensetControllerTotalOperationTime",
display_name="Generator Controller Total Operation Time",
value="--",
display_value="16770.8 h",
unit="h",
),
"EngineTotalRunTime": OncueSensor(
name="EngineTotalRunTime",
display_name="Engine Total Run Time",
value="--",
display_value="28.1 h",
unit="h",
),
"EngineTotalRunTimeLoaded": OncueSensor(
name="EngineTotalRunTimeLoaded",
display_name="Engine Total Run Time Loaded",
value="--",
display_value="5.5 h",
unit="h",
),
"EngineTotalNumberOfStarts": OncueSensor(
name="EngineTotalNumberOfStarts",
display_name="Engine Total Number Of Starts",
value="--",
display_value="101",
unit=None,
),
"GensetTotalEnergy": OncueSensor(
name="GensetTotalEnergy",
display_name="Genset Total Energy",
value="--",
display_value="1.2022309E7 kWh",
unit="kWh",
),
"AtsContactorPosition": OncueSensor(
name="AtsContactorPosition",
display_name="Ats Contactor Position",
value="--",
display_value="Source1",
unit=None,
),
"AtsSourcesAvailable": OncueSensor(
name="AtsSourcesAvailable",
display_name="Ats Sources Available",
value="--",
display_value="Source1",
unit=None,
),
"Source1VoltageAverageLineToLine": OncueSensor(
name="Source1VoltageAverageLineToLine",
display_name="Source1 Voltage Average Line To Line",
value="--",
display_value="253.5 V",
unit="V",
),
"Source2VoltageAverageLineToLine": OncueSensor(
name="Source2VoltageAverageLineToLine",
display_name="Source2 Voltage Average Line To Line",
value="--",
display_value="0.0 V",
unit="V",
),
"IPAddress": OncueSensor(
name="IPAddress",
display_name="IP Address",
value="--",
display_value="1.2.3.4:1026",
unit=None,
),
"MacAddress": OncueSensor(
name="MacAddress",
display_name="Mac Address",
value="--",
display_value="--",
unit=None,
),
"ConnectedServerIPAddress": OncueSensor(
name="ConnectedServerIPAddress",
display_name="Connected Server IP Address",
value="--",
display_value="40.117.195.28",
unit=None,
),
"NetworkConnectionEstablished": OncueSensor(
name="NetworkConnectionEstablished",
display_name="Network Connection Established",
value="--",
display_value="True",
unit=None,
),
"SerialNumber": OncueSensor(
name="SerialNumber",
display_name="Serial Number",
value="--",
display_value="1073879692",
unit=None,
),
},
)
}
def _patch_login_and_data():
@contextmanager
def _patcher():
with (
patch(
"homeassistant.components.oncue.Oncue.async_login",
),
patch(
"homeassistant.components.oncue.Oncue.async_fetch_all",
return_value=MOCK_ASYNC_FETCH_ALL,
),
):
yield
return _patcher()
def _patch_login_and_data_offline_device():
@contextmanager
def _patcher():
with (
patch(
"homeassistant.components.oncue.Oncue.async_login",
),
patch(
"homeassistant.components.oncue.Oncue.async_fetch_all",
return_value=MOCK_ASYNC_FETCH_ALL_OFFLINE_DEVICE,
),
):
yield
return _patcher()
def _patch_login_and_data_unavailable():
@contextmanager
def _patcher():
with (
patch("homeassistant.components.oncue.Oncue.async_login"),
patch(
"homeassistant.components.oncue.Oncue.async_fetch_all",
return_value=MOCK_ASYNC_FETCH_ALL_UNAVAILABLE_DEVICE,
),
):
yield
return _patcher()
def _patch_login_and_data_unavailable_device():
@contextmanager
def _patcher():
with (
patch("homeassistant.components.oncue.Oncue.async_login"),
patch(
"homeassistant.components.oncue.Oncue.async_fetch_all",
return_value=MOCK_ASYNC_FETCH_ALL_UNAVAILABLE_DEVICE,
),
):
yield
return _patcher()
def _patch_login_and_data_auth_failure():
@contextmanager
def _patcher():
with (
patch(
"homeassistant.components.oncue.Oncue.async_login",
side_effect=LoginFailedException,
),
patch(
"homeassistant.components.oncue.Oncue.async_fetch_all",
side_effect=LoginFailedException,
),
):
yield
return _patcher()

View File

@ -1,58 +0,0 @@
"""Tests for the oncue binary_sensor."""
from __future__ import annotations
from homeassistant.components import oncue
from homeassistant.components.oncue.const import DOMAIN
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME, STATE_OFF, STATE_ON
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
from . import _patch_login_and_data, _patch_login_and_data_unavailable
from tests.common import MockConfigEntry
async def test_binary_sensors(hass: HomeAssistant) -> None:
"""Test that the binary sensors are setup with the expected values."""
config_entry = MockConfigEntry(
domain=DOMAIN,
data={CONF_USERNAME: "any", CONF_PASSWORD: "any"},
unique_id="any",
)
config_entry.add_to_hass(hass)
with _patch_login_and_data():
await async_setup_component(hass, oncue.DOMAIN, {oncue.DOMAIN: {}})
await hass.async_block_till_done()
assert config_entry.state is ConfigEntryState.LOADED
assert len(hass.states.async_all("binary_sensor")) == 1
assert (
hass.states.get(
"binary_sensor.my_generator_network_connection_established"
).state
== STATE_ON
)
async def test_binary_sensors_not_unavailable(hass: HomeAssistant) -> None:
"""Test the network connection established binary sensor is available when connection status is false."""
config_entry = MockConfigEntry(
domain=DOMAIN,
data={CONF_USERNAME: "any", CONF_PASSWORD: "any"},
unique_id="any",
)
config_entry.add_to_hass(hass)
with _patch_login_and_data_unavailable():
await async_setup_component(hass, oncue.DOMAIN, {oncue.DOMAIN: {}})
await hass.async_block_till_done()
assert config_entry.state is ConfigEntryState.LOADED
assert len(hass.states.async_all("binary_sensor")) == 1
assert (
hass.states.get(
"binary_sensor.my_generator_network_connection_established"
).state
== STATE_OFF
)

View File

@ -1,192 +0,0 @@
"""Test the Oncue config flow."""
from unittest.mock import patch
from aiooncue import LoginFailedException
from homeassistant import config_entries
from homeassistant.components.oncue.const import DOMAIN
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType
from tests.common import MockConfigEntry
async def test_form(hass: HomeAssistant) -> None:
"""Test we get the form."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] is FlowResultType.FORM
assert result["errors"] == {}
with (
patch("homeassistant.components.oncue.config_flow.Oncue.async_login"),
patch(
"homeassistant.components.oncue.async_setup_entry",
return_value=True,
) as mock_setup_entry,
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
"username": "TEST-username",
"password": "test-password",
},
)
await hass.async_block_till_done()
assert result2["type"] is FlowResultType.CREATE_ENTRY
assert result2["title"] == "test-username"
assert result2["data"] == {
"username": "TEST-username",
"password": "test-password",
}
assert mock_setup_entry.call_count == 1
async def test_form_invalid_auth(hass: HomeAssistant) -> None:
"""Test we handle invalid auth."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
with patch(
"homeassistant.components.oncue.config_flow.Oncue.async_login",
side_effect=LoginFailedException,
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
"username": "test-username",
"password": "test-password",
},
)
assert result2["type"] is FlowResultType.FORM
assert result2["errors"] == {CONF_PASSWORD: "invalid_auth"}
async def test_form_cannot_connect(hass: HomeAssistant) -> None:
"""Test we handle cannot connect error."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
with patch(
"homeassistant.components.oncue.config_flow.Oncue.async_login",
side_effect=TimeoutError,
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
"username": "test-username",
"password": "test-password",
},
)
assert result2["type"] is FlowResultType.FORM
assert result2["errors"] == {"base": "cannot_connect"}
async def test_form_unknown_exception(hass: HomeAssistant) -> None:
"""Test we handle unknown exceptions."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
with patch(
"homeassistant.components.oncue.config_flow.Oncue.async_login",
side_effect=Exception,
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
"username": "test-username",
"password": "test-password",
},
)
assert result2["type"] is FlowResultType.FORM
assert result2["errors"] == {"base": "unknown"}
async def test_already_configured(hass: HomeAssistant) -> None:
"""Test already configured."""
entry = MockConfigEntry(
domain=DOMAIN,
data={
"username": "TEST-username",
"password": "test-password",
},
unique_id="test-username",
)
entry.add_to_hass(hass)
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
with patch("homeassistant.components.oncue.config_flow.Oncue.async_login"):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
"username": "test-username",
"password": "test-password",
},
)
assert result2["type"] is FlowResultType.ABORT
assert result2["reason"] == "already_configured"
async def test_reauth(hass: HomeAssistant) -> None:
"""Test reauth flow."""
config_entry = MockConfigEntry(
domain=DOMAIN,
data={
CONF_USERNAME: "any",
CONF_PASSWORD: "old",
},
)
config_entry.add_to_hass(hass)
config_entry.async_start_reauth(hass)
await hass.async_block_till_done()
flows = hass.config_entries.flow.async_progress_by_handler(DOMAIN)
assert len(flows) == 1
flow = flows[0]
with patch(
"homeassistant.components.oncue.config_flow.Oncue.async_login",
side_effect=LoginFailedException,
):
result2 = await hass.config_entries.flow.async_configure(
flow["flow_id"],
{
CONF_PASSWORD: "test-password",
},
)
assert result2["type"] is FlowResultType.FORM
assert result2["errors"] == {"password": "invalid_auth"}
with (
patch("homeassistant.components.oncue.config_flow.Oncue.async_login"),
patch(
"homeassistant.components.oncue.async_setup_entry",
return_value=True,
) as mock_setup_entry,
):
result2 = await hass.config_entries.flow.async_configure(
flow["flow_id"],
{
CONF_PASSWORD: "test-password",
},
)
await hass.async_block_till_done()
assert result2["type"] is FlowResultType.ABORT
assert result2["reason"] == "reauth_successful"
assert config_entry.data[CONF_PASSWORD] == "test-password"
assert mock_setup_entry.call_count == 1

View File

@ -1,94 +1,79 @@
"""Tests for the oncue component.""" """Tests for the Oncue integration."""
from __future__ import annotations from homeassistant.components.oncue import DOMAIN
from homeassistant.config_entries import (
from datetime import timedelta SOURCE_IGNORE,
from unittest.mock import patch ConfigEntryDisabler,
ConfigEntryState,
from aiooncue import LoginFailedException )
from homeassistant.components import oncue
from homeassistant.components.oncue.const import DOMAIN
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component from homeassistant.helpers import issue_registry as ir
from homeassistant.util import dt as dt_util
from . import _patch_login_and_data, _patch_login_and_data_auth_failure from tests.common import MockConfigEntry
from tests.common import MockConfigEntry, async_fire_time_changed
async def test_config_entry_reload(hass: HomeAssistant) -> None: async def test_oncue_repair_issue(
"""Test that a config entry can be reloaded.""" hass: HomeAssistant, issue_registry: ir.IssueRegistry
config_entry = MockConfigEntry( ) -> None:
"""Test the Oncue configuration entry loading/unloading handles the repair."""
config_entry_1 = MockConfigEntry(
title="Example 1",
domain=DOMAIN, domain=DOMAIN,
data={CONF_USERNAME: "any", CONF_PASSWORD: "any"},
unique_id="any",
) )
config_entry.add_to_hass(hass) config_entry_1.add_to_hass(hass)
with _patch_login_and_data(): await hass.config_entries.async_setup(config_entry_1.entry_id)
await async_setup_component(hass, oncue.DOMAIN, {oncue.DOMAIN: {}})
await hass.async_block_till_done()
assert config_entry.state is ConfigEntryState.LOADED
await hass.config_entries.async_unload(config_entry.entry_id)
await hass.async_block_till_done() await hass.async_block_till_done()
assert config_entry.state is ConfigEntryState.NOT_LOADED assert config_entry_1.state is ConfigEntryState.LOADED
# Add a second one
async def test_config_entry_login_error(hass: HomeAssistant) -> None: config_entry_2 = MockConfigEntry(
"""Test that a config entry is failed on login error.""" title="Example 2",
config_entry = MockConfigEntry(
domain=DOMAIN, domain=DOMAIN,
data={CONF_USERNAME: "any", CONF_PASSWORD: "any"},
unique_id="any",
) )
config_entry.add_to_hass(hass) config_entry_2.add_to_hass(hass)
with patch( await hass.config_entries.async_setup(config_entry_2.entry_id)
"homeassistant.components.oncue.Oncue.async_login", await hass.async_block_till_done()
side_effect=LoginFailedException,
):
await async_setup_component(hass, oncue.DOMAIN, {oncue.DOMAIN: {}})
await hass.async_block_till_done()
assert config_entry.state is ConfigEntryState.SETUP_ERROR
assert config_entry_2.state is ConfigEntryState.LOADED
assert issue_registry.async_get_issue(DOMAIN, DOMAIN)
async def test_config_entry_retry_later(hass: HomeAssistant) -> None: # Add an ignored entry
"""Test that a config entry retry on connection error.""" config_entry_3 = MockConfigEntry(
config_entry = MockConfigEntry( source=SOURCE_IGNORE,
domain=DOMAIN, domain=DOMAIN,
data={CONF_USERNAME: "any", CONF_PASSWORD: "any"},
unique_id="any",
) )
config_entry.add_to_hass(hass) config_entry_3.add_to_hass(hass)
with patch( await hass.config_entries.async_setup(config_entry_3.entry_id)
"homeassistant.components.oncue.Oncue.async_login", await hass.async_block_till_done()
side_effect=TimeoutError,
):
await async_setup_component(hass, oncue.DOMAIN, {oncue.DOMAIN: {}})
await hass.async_block_till_done()
assert config_entry.state is ConfigEntryState.SETUP_RETRY
assert config_entry_3.state is ConfigEntryState.NOT_LOADED
async def test_late_auth_failure(hass: HomeAssistant) -> None: # Add a disabled entry
"""Test auth fails after already setup.""" config_entry_4 = MockConfigEntry(
config_entry = MockConfigEntry( disabled_by=ConfigEntryDisabler.USER,
domain=DOMAIN, domain=DOMAIN,
data={CONF_USERNAME: "any", CONF_PASSWORD: "any"},
unique_id="any",
) )
config_entry.add_to_hass(hass) config_entry_4.add_to_hass(hass)
with _patch_login_and_data(): await hass.config_entries.async_setup(config_entry_4.entry_id)
await async_setup_component(hass, oncue.DOMAIN, {oncue.DOMAIN: {}}) await hass.async_block_till_done()
await hass.async_block_till_done()
assert config_entry.state is ConfigEntryState.LOADED
with _patch_login_and_data_auth_failure(): assert config_entry_4.state is ConfigEntryState.NOT_LOADED
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=10))
await hass.async_block_till_done()
flows = hass.config_entries.flow.async_progress_by_handler(DOMAIN) # Remove the first one
assert len(flows) == 1 await hass.config_entries.async_remove(config_entry_1.entry_id)
flow = flows[0] await hass.async_block_till_done()
assert flow["context"]["source"] == "reauth"
assert config_entry_1.state is ConfigEntryState.NOT_LOADED
assert config_entry_2.state is ConfigEntryState.LOADED
assert issue_registry.async_get_issue(DOMAIN, DOMAIN)
# Remove the second one
await hass.config_entries.async_remove(config_entry_2.entry_id)
await hass.async_block_till_done()
assert config_entry_1.state is ConfigEntryState.NOT_LOADED
assert config_entry_2.state is ConfigEntryState.NOT_LOADED
assert issue_registry.async_get_issue(DOMAIN, DOMAIN) is None
# Check the ignored and disabled entries are removed
assert not hass.config_entries.async_entries(DOMAIN)

View File

@ -1,309 +0,0 @@
"""Tests for the oncue sensor."""
from __future__ import annotations
import pytest
from homeassistant.components import oncue
from homeassistant.components.oncue.const import DOMAIN
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME, STATE_UNAVAILABLE
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.setup import async_setup_component
from . import (
_patch_login_and_data,
_patch_login_and_data_offline_device,
_patch_login_and_data_unavailable,
_patch_login_and_data_unavailable_device,
)
from tests.common import MockConfigEntry
@pytest.mark.parametrize(
("patcher", "connections"),
[
(_patch_login_and_data, {("mac", "c9:24:22:6f:14:00")}),
(_patch_login_and_data_offline_device, set()),
],
)
async def test_sensors(
hass: HomeAssistant,
device_registry: dr.DeviceRegistry,
entity_registry: er.EntityRegistry,
patcher,
connections,
) -> None:
"""Test that the sensors are setup with the expected values."""
config_entry = MockConfigEntry(
domain=DOMAIN,
data={CONF_USERNAME: "any", CONF_PASSWORD: "any"},
unique_id="any",
)
config_entry.add_to_hass(hass)
with patcher():
await async_setup_component(hass, oncue.DOMAIN, {oncue.DOMAIN: {}})
await hass.async_block_till_done()
assert config_entry.state is ConfigEntryState.LOADED
ent = entity_registry.async_get("sensor.my_generator_latest_firmware")
dev = device_registry.async_get(ent.device_id)
assert dev.connections == connections
assert len(hass.states.async_all("sensor")) == 25
assert hass.states.get("sensor.my_generator_latest_firmware").state == "2.0.6"
assert hass.states.get("sensor.my_generator_engine_speed").state == "0"
assert hass.states.get("sensor.my_generator_engine_oil_pressure").state == "0"
assert (
hass.states.get("sensor.my_generator_engine_coolant_temperature").state == "0"
)
assert hass.states.get("sensor.my_generator_battery_voltage").state == "13.4"
assert hass.states.get("sensor.my_generator_lube_oil_temperature").state == "0"
assert (
hass.states.get("sensor.my_generator_generator_controller_temperature").state
== "29.0"
)
assert (
hass.states.get("sensor.my_generator_engine_compartment_temperature").state
== "17.0"
)
assert (
hass.states.get("sensor.my_generator_generator_true_total_power").state == "0.0"
)
assert (
hass.states.get(
"sensor.my_generator_generator_true_percent_of_rated_power"
).state
== "0"
)
assert (
hass.states.get(
"sensor.my_generator_generator_voltage_average_line_to_line"
).state
== "0.0"
)
assert hass.states.get("sensor.my_generator_generator_frequency").state == "0.0"
assert hass.states.get("sensor.my_generator_generator_state").state == "Off"
assert (
hass.states.get(
"sensor.my_generator_generator_controller_total_operation_time"
).state
== "16770.8"
)
assert hass.states.get("sensor.my_generator_engine_total_run_time").state == "28.1"
assert (
hass.states.get("sensor.my_generator_ats_contactor_position").state == "Source1"
)
assert hass.states.get("sensor.my_generator_ip_address").state == "1.2.3.4:1026"
assert (
hass.states.get("sensor.my_generator_connected_server_ip_address").state
== "40.117.195.28"
)
assert hass.states.get("sensor.my_generator_engine_target_speed").state == "0"
assert (
hass.states.get("sensor.my_generator_engine_total_run_time_loaded").state
== "5.5"
)
assert (
hass.states.get(
"sensor.my_generator_source1_voltage_average_line_to_line"
).state
== "253.5"
)
assert (
hass.states.get(
"sensor.my_generator_source2_voltage_average_line_to_line"
).state
== "0.0"
)
assert (
hass.states.get("sensor.my_generator_genset_total_energy").state
== "1.2022309E7"
)
assert (
hass.states.get("sensor.my_generator_engine_total_number_of_starts").state
== "101"
)
assert (
hass.states.get("sensor.my_generator_generator_current_average").state == "0.0"
)
@pytest.mark.parametrize(
("patcher", "connections"),
[
(_patch_login_and_data_unavailable_device, set()),
(_patch_login_and_data_unavailable, {("mac", "c9:24:22:6f:14:00")}),
],
)
async def test_sensors_unavailable(hass: HomeAssistant, patcher, connections) -> None:
"""Test that the sensors are unavailable."""
config_entry = MockConfigEntry(
domain=DOMAIN,
data={CONF_USERNAME: "any", CONF_PASSWORD: "any"},
unique_id="any",
)
config_entry.add_to_hass(hass)
with patcher():
await async_setup_component(hass, oncue.DOMAIN, {oncue.DOMAIN: {}})
await hass.async_block_till_done()
assert config_entry.state is ConfigEntryState.LOADED
assert len(hass.states.async_all("sensor")) == 25
assert (
hass.states.get("sensor.my_generator_latest_firmware").state
== STATE_UNAVAILABLE
)
assert (
hass.states.get("sensor.my_generator_engine_speed").state == STATE_UNAVAILABLE
)
assert (
hass.states.get("sensor.my_generator_engine_oil_pressure").state
== STATE_UNAVAILABLE
)
assert (
hass.states.get("sensor.my_generator_engine_coolant_temperature").state
== STATE_UNAVAILABLE
)
assert (
hass.states.get("sensor.my_generator_battery_voltage").state
== STATE_UNAVAILABLE
)
assert (
hass.states.get("sensor.my_generator_lube_oil_temperature").state
== STATE_UNAVAILABLE
)
assert (
hass.states.get("sensor.my_generator_generator_controller_temperature").state
== STATE_UNAVAILABLE
)
assert (
hass.states.get("sensor.my_generator_engine_compartment_temperature").state
== STATE_UNAVAILABLE
)
assert (
hass.states.get("sensor.my_generator_generator_true_total_power").state
== STATE_UNAVAILABLE
)
assert (
hass.states.get(
"sensor.my_generator_generator_true_percent_of_rated_power"
).state
== STATE_UNAVAILABLE
)
assert (
hass.states.get(
"sensor.my_generator_generator_voltage_average_line_to_line"
).state
== STATE_UNAVAILABLE
)
assert (
hass.states.get("sensor.my_generator_generator_frequency").state
== STATE_UNAVAILABLE
)
assert (
hass.states.get("sensor.my_generator_generator_state").state
== STATE_UNAVAILABLE
)
assert (
hass.states.get(
"sensor.my_generator_generator_controller_total_operation_time"
).state
== STATE_UNAVAILABLE
)
assert (
hass.states.get("sensor.my_generator_engine_total_run_time").state
== STATE_UNAVAILABLE
)
assert (
hass.states.get("sensor.my_generator_ats_contactor_position").state
== STATE_UNAVAILABLE
)
assert hass.states.get("sensor.my_generator_ip_address").state == STATE_UNAVAILABLE
assert (
hass.states.get("sensor.my_generator_connected_server_ip_address").state
== STATE_UNAVAILABLE
)
assert (
hass.states.get("sensor.my_generator_engine_target_speed").state
== STATE_UNAVAILABLE
)
assert (
hass.states.get("sensor.my_generator_engine_total_run_time_loaded").state
== STATE_UNAVAILABLE
)
assert (
hass.states.get(
"sensor.my_generator_source1_voltage_average_line_to_line"
).state
== STATE_UNAVAILABLE
)
assert (
hass.states.get(
"sensor.my_generator_source2_voltage_average_line_to_line"
).state
== STATE_UNAVAILABLE
)
assert (
hass.states.get("sensor.my_generator_genset_total_energy").state
== STATE_UNAVAILABLE
)
assert (
hass.states.get("sensor.my_generator_engine_total_number_of_starts").state
== STATE_UNAVAILABLE
)
assert (
hass.states.get("sensor.my_generator_generator_current_average").state
== STATE_UNAVAILABLE
)
assert (
hass.states.get("sensor.my_generator_battery_voltage").state
== STATE_UNAVAILABLE
)