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
4 changes: 2 additions & 2 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ jobs:
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0

- name: Initialize CodeQL
uses: github/codeql-action/init@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v4.30.8
uses: github/codeql-action/init@16140ae1a102900babc80a33c44059580f687047 # v4.30.9
with:
languages: python

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v4.30.8
uses: github/codeql-action/analyze@16140ae1a102900babc80a33c44059580f687047 # v4.30.9
with:
category: "/language:python"
2 changes: 1 addition & 1 deletion homeassistant/components/cync/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
"integration_type": "hub",
"iot_class": "cloud_push",
"quality_scale": "bronze",
"requirements": ["pycync==0.4.1"]
"requirements": ["pycync==0.4.2"]
}
2 changes: 1 addition & 1 deletion homeassistant/components/nextdns/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@
"name": "Block WhatsApp"
},
"block_xboxlive": {
"name": "Block Xbox Live"
"name": "Block Xbox Network"
},
"block_youtube": {
"name": "Block YouTube"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@
from .const import CONF_SESSION_TOKEN, DOMAIN
from .coordinator import NintendoParentalControlsConfigEntry, NintendoUpdateCoordinator

_PLATFORMS: list[Platform] = [Platform.SENSOR, Platform.TIME, Platform.SWITCH]
_PLATFORMS: list[Platform] = [
Platform.SENSOR,
Platform.TIME,
Platform.SWITCH,
Platform.NUMBER,
]


async def async_setup_entry(
Expand Down
91 changes: 91 additions & 0 deletions homeassistant/components/nintendo_parental_controls/number.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
"""Number platform for Nintendo Parental controls."""

from __future__ import annotations

from collections.abc import Callable, Coroutine
from dataclasses import dataclass
from enum import StrEnum
from typing import Any

from homeassistant.components.number import (
NumberEntity,
NumberEntityDescription,
NumberMode,
)
from homeassistant.const import UnitOfTime
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback

from .coordinator import NintendoParentalControlsConfigEntry, NintendoUpdateCoordinator
from .entity import Device, NintendoDevice

PARALLEL_UPDATES = 0


class NintendoParentalNumber(StrEnum):
"""Store keys for Nintendo Parental numbers."""

TODAY_MAX_SCREENTIME = "today_max_screentime"


@dataclass(kw_only=True, frozen=True)
class NintendoParentalControlsNumberEntityDescription(NumberEntityDescription):
"""Description for Nintendo Parental number entities."""

value_fn: Callable[[Device], int | float | None]
set_native_value_fn: Callable[[Device, float], Coroutine[Any, Any, None]]


NUMBER_DESCRIPTIONS: tuple[NintendoParentalControlsNumberEntityDescription, ...] = (
NintendoParentalControlsNumberEntityDescription(
key=NintendoParentalNumber.TODAY_MAX_SCREENTIME,
translation_key=NintendoParentalNumber.TODAY_MAX_SCREENTIME,
native_min_value=-1,
native_step=1,
native_max_value=360,
native_unit_of_measurement=UnitOfTime.MINUTES,
mode=NumberMode.BOX,
set_native_value_fn=lambda device, value: device.update_max_daily_playtime(
minutes=value
),
value_fn=lambda device: device.limit_time,
),
)


async def async_setup_entry(
hass: HomeAssistant,
entry: NintendoParentalControlsConfigEntry,
async_add_devices: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up number platform."""
async_add_devices(
NintendoParentalControlsNumberEntity(entry.runtime_data, device, entity)
for device in entry.runtime_data.api.devices.values()
for entity in NUMBER_DESCRIPTIONS
)


class NintendoParentalControlsNumberEntity(NintendoDevice, NumberEntity):
"""Represent a Nintendo Parental number entity."""

entity_description: NintendoParentalControlsNumberEntityDescription

def __init__(
self,
coordinator: NintendoUpdateCoordinator,
device: Device,
description: NintendoParentalControlsNumberEntityDescription,
) -> None:
"""Initialize the time entity."""
super().__init__(coordinator=coordinator, device=device, key=description.key)
self.entity_description = description

@property
def native_value(self) -> float | None:
"""Return the state of the entity."""
return self.entity_description.value_fn(self._device)

async def async_set_native_value(self, value: float) -> None:
"""Update entity state."""
await self.entity_description.set_native_value_fn(self._device, value)
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@
"suspend_software": {
"name": "Suspend software"
}
},
"number": {
"today_max_screentime": {
"name": "Max screentime today"
}
}
},
"exceptions": {
Expand Down
2 changes: 1 addition & 1 deletion requirements_all.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion requirements_test_all.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions tests/components/nextdns/snapshots/test_switch.ambr
Original file line number Diff line number Diff line change
Expand Up @@ -2735,7 +2735,7 @@
'state': 'on',
})
# ---
# name: test_switch[switch.fake_profile_block_xbox_live-entry]
# name: test_switch[switch.fake_profile_block_xbox_network-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
Expand All @@ -2748,7 +2748,7 @@
'disabled_by': None,
'domain': 'switch',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'switch.fake_profile_block_xbox_live',
'entity_id': 'switch.fake_profile_block_xbox_network',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
Expand All @@ -2760,7 +2760,7 @@
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Block Xbox Live',
'original_name': 'Block Xbox Network',
'platform': 'nextdns',
'previous_unique_id': None,
'suggested_object_id': None,
Expand All @@ -2770,13 +2770,13 @@
'unit_of_measurement': None,
})
# ---
# name: test_switch[switch.fake_profile_block_xbox_live-state]
# name: test_switch[switch.fake_profile_block_xbox_network-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Fake Profile Block Xbox Live',
'friendly_name': 'Fake Profile Block Xbox Network',
}),
'context': <ANY>,
'entity_id': 'switch.fake_profile_block_xbox_live',
'entity_id': 'switch.fake_profile_block_xbox_network',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
Expand Down
1 change: 1 addition & 0 deletions tests/components/nintendo_parental_controls/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ def mock_nintendo_device() -> Device:
mock.today_playing_time = 110
mock.bedtime_alarm = time(hour=19)
mock.set_bedtime_alarm.return_value = None
mock.update_max_daily_playtime.return_value = None
mock.forced_termination_mode = True
return mock

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# serializer version: 1
# name: test_number[number.home_assistant_test_max_screentime_today-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'max': 360,
'min': -1,
'mode': <NumberMode.BOX: 'box'>,
'step': 1,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'number',
'entity_category': None,
'entity_id': 'number.home_assistant_test_max_screentime_today',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Max screentime today',
'platform': 'nintendo_parental_controls',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': <NintendoParentalNumber.TODAY_MAX_SCREENTIME: 'today_max_screentime'>,
'unique_id': 'testdevid_today_max_screentime',
'unit_of_measurement': <UnitOfTime.MINUTES: 'min'>,
})
# ---
# name: test_number[number.home_assistant_test_max_screentime_today-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Home Assistant Test Max screentime today',
'max': 360,
'min': -1,
'mode': <NumberMode.BOX: 'box'>,
'step': 1,
'unit_of_measurement': <UnitOfTime.MINUTES: 'min'>,
}),
'context': <ANY>,
'entity_id': 'number.home_assistant_test_max_screentime_today',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '120',
})
# ---
58 changes: 58 additions & 0 deletions tests/components/nintendo_parental_controls/test_number.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
"""Test number platform for Nintendo Parental Controls."""

from unittest.mock import AsyncMock, patch

from syrupy.assertion import SnapshotAssertion

from homeassistant.components.number import (
ATTR_VALUE,
DOMAIN as NUMBER_DOMAIN,
SERVICE_SET_VALUE,
)
from homeassistant.const import ATTR_ENTITY_ID, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er

from . import setup_integration

from tests.common import MockConfigEntry, snapshot_platform


async def test_number(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_nintendo_client: AsyncMock,
entity_registry: er.EntityRegistry,
snapshot: SnapshotAssertion,
) -> None:
"""Test number platform."""
with patch(
"homeassistant.components.nintendo_parental_controls._PLATFORMS",
[Platform.NUMBER],
):
await setup_integration(hass, mock_config_entry)

await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)


async def test_set_number(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_nintendo_client: AsyncMock,
mock_nintendo_device: AsyncMock,
) -> None:
"""Test number platform service."""
with patch(
"homeassistant.components.nintendo_parental_controls._PLATFORMS",
[Platform.NUMBER],
):
await setup_integration(hass, mock_config_entry)

await hass.services.async_call(
NUMBER_DOMAIN,
SERVICE_SET_VALUE,
service_data={ATTR_VALUE: "120"},
target={ATTR_ENTITY_ID: "number.home_assistant_test_max_screentime_today"},
blocking=True,
)
assert len(mock_nintendo_device.update_max_daily_playtime.mock_calls) == 1
Loading