Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions homeassistant/components/fressnapf_tracker/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
Platform.DEVICE_TRACKER,
Platform.LIGHT,
Platform.SENSOR,
Platform.SWITCH,
]


Expand Down
8 changes: 8 additions & 0 deletions homeassistant/components/fressnapf_tracker/icons.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@
"pet": {
"default": "mdi:paw"
}
},
"switch": {
"energy_saving": {
"default": "mdi:sleep",
"state": {
"off": "mdi:sleep-off"
}
}
}
}
}
5 changes: 5 additions & 0 deletions homeassistant/components/fressnapf_tracker/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@
"led": {
"name": "Flashlight"
}
},
"switch": {
"energy_saving": {
"name": "Sleep mode"
}
}
},
"exceptions": {
Expand Down
58 changes: 58 additions & 0 deletions homeassistant/components/fressnapf_tracker/switch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
"""Switch platform for Fressnapf Tracker."""

from typing import TYPE_CHECKING, Any

from homeassistant.components.switch import (
SwitchDeviceClass,
SwitchEntity,
SwitchEntityDescription,
)
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback

from . import FressnapfTrackerConfigEntry
from .entity import FressnapfTrackerEntity

SWITCH_ENTITY_DESCRIPTION = SwitchEntityDescription(
translation_key="energy_saving",
entity_category=EntityCategory.CONFIG,
device_class=SwitchDeviceClass.SWITCH,
key="energy_saving",
)


async def async_setup_entry(
hass: HomeAssistant,
entry: FressnapfTrackerConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up the Fressnapf Tracker switches."""

async_add_entities(
FressnapfTrackerSwitch(coordinator, SWITCH_ENTITY_DESCRIPTION)
for coordinator in entry.runtime_data
if coordinator.data.tracker_settings.features.energy_saving_mode
)


class FressnapfTrackerSwitch(FressnapfTrackerEntity, SwitchEntity):
"""Fressnapf Tracker switch."""

async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn on the device."""
await self.coordinator.client.set_energy_saving(True)
await self.coordinator.async_request_refresh()

async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn off the device."""
await self.coordinator.client.set_energy_saving(False)
await self.coordinator.async_request_refresh()

@property
def is_on(self) -> bool:
"""Return true if device is on."""
if TYPE_CHECKING:
# The entity is not created if energy_saving is None
assert self.coordinator.data.energy_saving is not None
return self.coordinator.data.energy_saving.value == 1
9 changes: 7 additions & 2 deletions tests/components/fressnapf_tracker/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from fressnapftracker import (
Device,
EnergySaving,
LedActivatable,
LedBrightness,
PhoneVerificationResponse,
Expand Down Expand Up @@ -44,9 +45,12 @@
),
tracker_settings=TrackerSettings(
generation="GPS Tracker 2.0",
features=TrackerFeatures(flash_light=True, live_tracking=True),
features=TrackerFeatures(
flash_light=True, energy_saving_mode=True, live_tracking=True
),
),
led_brightness=LedBrightness(value=50),
led_brightness=LedBrightness(status="ok", value=50),
energy_saving=EnergySaving(status="ok", value=1),
deep_sleep=None,
led_activatable=LedActivatable(
has_led=True,
Expand Down Expand Up @@ -133,6 +137,7 @@ def mock_api_client() -> Generator[MagicMock]:
client = mock_api_client.return_value
client.get_tracker = AsyncMock(return_value=MOCK_TRACKER)
client.set_led_brightness = AsyncMock(return_value=None)
client.set_energy_saving = AsyncMock(return_value=None)
yield client


Expand Down
50 changes: 50 additions & 0 deletions tests/components/fressnapf_tracker/snapshots/test_switch.ambr
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# serializer version: 1
# name: test_state_entity_device_snapshots[switch.fluffy_sleep_mode-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'switch',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'switch.fluffy_sleep_mode',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SwitchDeviceClass.SWITCH: 'switch'>,
'original_icon': None,
'original_name': 'Sleep mode',
'platform': 'fressnapf_tracker',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'energy_saving',
'unique_id': 'ABC123456_energy_saving',
'unit_of_measurement': None,
})
# ---
# name: test_state_entity_device_snapshots[switch.fluffy_sleep_mode-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'switch',
'friendly_name': 'Fluffy Sleep mode',
}),
'context': <ANY>,
'entity_id': 'switch.fluffy_sleep_mode',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'on',
})
# ---
114 changes: 114 additions & 0 deletions tests/components/fressnapf_tracker/test_switch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
"""Test the Fressnapf Tracker switch platform."""

from collections.abc import AsyncGenerator
from unittest.mock import MagicMock, patch

from fressnapftracker import Tracker, TrackerFeatures, TrackerSettings
import pytest
from syrupy.assertion import SnapshotAssertion

from homeassistant.components.switch import (
DOMAIN as SWITCH_DOMAIN,
SERVICE_TURN_OFF,
SERVICE_TURN_ON,
)
from homeassistant.const import ATTR_ENTITY_ID, STATE_ON, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er

from tests.common import MockConfigEntry, snapshot_platform

TRACKER_NO_ENERGY_SAVING_MODE = Tracker(
name="Fluffy",
battery=0,
charging=False,
position=None,
tracker_settings=TrackerSettings(
generation="GPS Tracker 2.0",
features=TrackerFeatures(energy_saving_mode=False),
),
)


@pytest.fixture(autouse=True)
async def platforms() -> AsyncGenerator[None]:
"""Return the platforms to be loaded for this test."""
with patch(
"homeassistant.components.fressnapf_tracker.PLATFORMS", [Platform.SWITCH]
):
yield


@pytest.mark.usefixtures("init_integration")
async def test_state_entity_device_snapshots(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
mock_config_entry: MockConfigEntry,
snapshot: SnapshotAssertion,
) -> None:
"""Test switch entity is created correctly."""
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)


@pytest.mark.usefixtures("mock_auth_client")
async def test_not_added_when_no_energy_saving_mode(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
mock_config_entry: MockConfigEntry,
mock_api_client: MagicMock,
) -> None:
"""Test switch entity is created correctly."""
mock_api_client.get_tracker.return_value = TRACKER_NO_ENERGY_SAVING_MODE

mock_config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()

entity_entries = er.async_entries_for_config_entry(
entity_registry, mock_config_entry.entry_id
)
assert len(entity_entries) == 0


@pytest.mark.usefixtures("init_integration")
async def test_turn_on(
hass: HomeAssistant,
mock_api_client: MagicMock,
) -> None:
"""Test turning the switch on."""
entity_id = "switch.fluffy_sleep_mode"

state = hass.states.get(entity_id)
assert state is not None
assert state.state == STATE_ON

await hass.services.async_call(
SWITCH_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: entity_id},
blocking=True,
)

mock_api_client.set_energy_saving.assert_called_once_with(True)


@pytest.mark.usefixtures("init_integration")
async def test_turn_off(
hass: HomeAssistant,
mock_api_client: MagicMock,
) -> None:
"""Test turning the switch off."""
entity_id = "switch.fluffy_sleep_mode"

state = hass.states.get(entity_id)
assert state is not None
assert state.state == STATE_ON

await hass.services.async_call(
SWITCH_DOMAIN,
SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: entity_id},
blocking=True,
)

mock_api_client.set_energy_saving.assert_called_once_with(False)
Loading