Skip to content

Commit

Permalink
2024.3.0 (#88)
Browse files Browse the repository at this point in the history
Fix exception for user screen time sensor #87 
Fix authentication issues - #86 
Replace time entities with number entities - #84  
Remove bonus time - #81
Update readme - #89 
---------

Co-authored-by: Rob <robert.mclellan+github@gmail.com>
  • Loading branch information
pantherale0 and latetedemelon committed Mar 7, 2024
1 parent ac69780 commit 26976db
Show file tree
Hide file tree
Showing 12 changed files with 116 additions and 85 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ _Integration to integrate with [ha-nintendoparentalcontrols][ha-nintendoparental
1. In the HA UI go to "Configuration" -> "Integrations" click "+" and search for "Nintendo Switch Parental Controls
1. You will be prompted for an access token, click the link provided in the description of the dialog (this is unique) and login to your Nintendo account.
1. After login, you will see a `Linking an External Account` screen. For the account you wish to link, right click on the red button `Select this person` and click `Copy Link`
1. #Optional# - If you inspect the link you should find the following format npf54789befxxxxxxxx://auth#session_token_code={redacted}&state={redacted}&session_state={redacted}
1. Close the `Nintendo Account` tab
1. Paste the previously copied value into the `Access token` field
1. Paste the previously copied value into the `Access token` field (the entire string you copied)
1. Click `Submit`
1. The configuration flow should then show some additional options, don't adjust the first box as this is the refresh token that will be used to refresh the access tokens in the background and is retrieved from Nintndo using the token you previously provided.
1. Click `Submit`
Expand Down
2 changes: 1 addition & 1 deletion custom_components/nintendo_parental/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from .const import DOMAIN, CONF_SESSION_TOKEN
from .coordinator import NintendoUpdateCoordinator, Authenticator

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


async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
Expand Down
10 changes: 5 additions & 5 deletions custom_components/nintendo_parental/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
CONF_UPDATE_INTERVAL,
CONF_APPLICATIONS,
CONF_DEFAULT_MAX_PLAYTIME,
CONF_SESSION_TOKEN,
CONF_SESSION_TOKEN
)

from .coordinator import NintendoUpdateCoordinator
Expand Down Expand Up @@ -72,12 +72,12 @@ async def async_step_configure(self, user_input=None):
title=self.auth.account_id,
data={
CONF_SESSION_TOKEN: user_input[CONF_SESSION_TOKEN],
CONF_UPDATE_INTERVAL: user_input[CONF_UPDATE_INTERVAL],
CONF_UPDATE_INTERVAL: user_input[CONF_UPDATE_INTERVAL]
},
)
schema = {
vol.Required(CONF_SESSION_TOKEN, default=self.auth.get_session_token): str,
vol.Required(CONF_UPDATE_INTERVAL, default=DEFAULT_UPDATE_INTERVAL): int,
vol.Required(CONF_UPDATE_INTERVAL, default=DEFAULT_UPDATE_INTERVAL): int
}
return self.async_show_form(step_id="configure", data_schema=vol.Schema(schema))

Expand Down Expand Up @@ -183,7 +183,7 @@ async def async_step_config(self, user_input: dict[str, Any] | None = None):
vol.Required(CONF_UPDATE_INTERVAL, default=update_interval): int,
vol.Required(
CONF_DEFAULT_MAX_PLAYTIME, default=default_max_playtime
): int,
): int
}
),
)
Expand Down Expand Up @@ -220,7 +220,7 @@ async def async_step_done(self, _: dict[str, Any] | None = None):
CONF_SESSION_TOKEN: self.config_entry.data[CONF_SESSION_TOKEN],
CONF_UPDATE_INTERVAL: self._update_interval,
CONF_DEFAULT_MAX_PLAYTIME: self._default_max_playtime,
CONF_APPLICATIONS: self._applications,
CONF_APPLICATIONS: self._applications
},
)

Expand Down
11 changes: 1 addition & 10 deletions custom_components/nintendo_parental/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
CONF_SESSION_TOKEN = "session_token"
CONF_UPDATE_INTERVAL = "update_interval"
CONF_DEFAULT_MAX_PLAYTIME = "default_max_playtime"
CONF_EXPERIMENTAL = "experimental"


SW_CONFIGURATION_ENTITIES = {
Expand Down Expand Up @@ -47,16 +48,6 @@
}

TIME_CONFIGURATION_ENTITIES = {
"today_max_screentime": {
"name": "{DEV_NAME} Play Time Limit",
"value": "limit_time",
"update_method": "update_max_daily_playtime",
},
"bonus_time": {
"name": "{DEV_NAME} Bonus Time",
"value": "bonus_time",
"update_method": "give_bonus_time",
},
"bedtime_alarm": {
"name": "{DEV_NAME} Bedtime Alarm",
"value": "bedtime",
Expand Down
5 changes: 5 additions & 0 deletions custom_components/nintendo_parental/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
DEFAULT_MAX_PLAYTIME,
CONF_DEFAULT_MAX_PLAYTIME,
CONF_UPDATE_INTERVAL,
CONF_EXPERIMENTAL
)


Expand Down Expand Up @@ -61,10 +62,14 @@ def __init__(
self.default_max_playtime = config_entry.data.get(
CONF_DEFAULT_MAX_PLAYTIME, DEFAULT_MAX_PLAYTIME
)
self.experimental_mode = config_entry.data.get(CONF_EXPERIMENTAL, False)
if config_entry.options:
self.default_max_playtime = config_entry.options.get(
CONF_DEFAULT_MAX_PLAYTIME, DEFAULT_MAX_PLAYTIME
)
self.experimental_mode = config_entry.options.get(
CONF_EXPERIMENTAL, False
)

async def _async_update_data(self):
"""Request the API to update."""
Expand Down
4 changes: 2 additions & 2 deletions custom_components/nintendo_parental/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"iot_class": "cloud_polling",
"issue_tracker": "https://github.com/pantherale0/ha-nintendoparentalcontrols/issues",
"requirements": [
"pynintendoparental==0.4.7"
"pynintendoparental==0.4.9"
],
"version": "2024.2.0"
"version": "2024.3.0"
}
81 changes: 81 additions & 0 deletions custom_components/nintendo_parental/number.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
"""Number platform."""


import logging

from homeassistant.components.number import NumberEntity, NumberMode
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ServiceValidationError, HomeAssistantError
from homeassistant.helpers.entity_platform import AddEntitiesCallback

from pynintendoparental.exceptions import HttpException

from .coordinator import NintendoUpdateCoordinator

from .const import DOMAIN

from .entity import NintendoDevice

_LOGGER = logging.getLogger(__name__)

async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Set up Nintendo Switch Parental Control number platform."""
coordinator: NintendoUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
entities = []
if coordinator.api.devices is not None:
for device in list(coordinator.api.devices.values()):
entities.append(ScreenTimeEntity(
coordinator=coordinator,
device_id=device.device_id,
entity_id="today_max_screentime"))
async_add_entities(entities, True)


class ScreenTimeEntity(NintendoDevice, NumberEntity):
"""A screen time entity."""

_attr_should_poll = True
_attr_mode = NumberMode.SLIDER
_attr_native_max_value = 360
_attr_native_step = 1
_attr_native_unit_of_measurement = "min"

@property
def native_min_value(self) -> float | None:
"""Return the min value."""
return -1

@property
def native_value(self) -> float | None:
"""Return the state of the entity."""
if self._device.limit_time is None:
return -1
return float(self._device.limit_time)

@property
def name(self) -> str:
"""Return the name of the entity."""
return f"{self._device.name} Play Time Limit"

async def async_set_native_value(self, value: float) -> None:
"""Update the state of the entity."""
if value > 360:
raise ServiceValidationError(
"Play Time Limit cannot be more than 6 hours.",
translation_domain=DOMAIN,
translation_key="play_time_limit_out_of_range",
)
try:
if value == -1:
await self._device.update_max_daily_playtime(minutes=None)
else:
await self._device.update_max_daily_playtime(minutes=value)
await self.coordinator.async_request_refresh()
except HttpException as exc:
raise HomeAssistantError(
"Nintendo returned an unexpected response.",
translation_domain=DOMAIN,
translation_key="unexpected_response") from exc
7 changes: 6 additions & 1 deletion custom_components/nintendo_parental/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from __future__ import annotations
from collections.abc import Mapping
from typing import Any
from datetime import datetime

from homeassistant.components.sensor import SensorEntity
from homeassistant.components.sensor.const import SensorDeviceClass
Expand Down Expand Up @@ -34,13 +35,17 @@ def __init__(self, coordinator, device_id, sensor) -> None:
self._attr_should_poll = True # allow native value to be polled.

@property
def native_value(self) -> float:
def native_value(self) -> float | None:
"""Return the native value of the sensor."""
if self._config.get("native_value") == "playing_time":
return self._device.daily_summaries[0].get("playingTime", 0) / 60
if self._config.get("native_value") == "time_remaining":
if self._device.limit_time == 0:
return 0
if self._device.limit_time is None:
# we will assume until midnight in this case
# Calculate and return the total minutes passed since midnight
return 1440-(datetime.now().hour * 60 + datetime.now().minute)
return self._device.limit_time - (
self._device.daily_summaries[0].get("playingTime", 0) / 60
)
Expand Down
8 changes: 5 additions & 3 deletions custom_components/nintendo_parental/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"data": {
"session_token": "Session token",
"update_interval": "Update interval (seconds)",
"default_max_playtime": "Default maximum play time (minutes)"
"default_max_playtime": "Default maximum play time (minutes)",
"experimental": "Experimental features"
}
},
"nintendo_website_auth": {
Expand Down Expand Up @@ -46,7 +47,8 @@
"description": "Update Nintendo Switch Parental Controls configuration",
"data": {
"update_interval": "Update interval (seconds)",
"default_max_playtime": "Default maximum play time (minutes)"
"default_max_playtime": "Default maximum play time (minutes)",
"experimental": "Experimental features"
}
},
"applications": {
Expand All @@ -73,7 +75,7 @@
"message": "Invalid time provided, expected between 16:00 and 23:59. Got {time}"
},
"play_time_limit_out_of_range": {
"message": "Play Time Limit cannot be more than 6 hours (6:00). To disable, set to 0:00"
"message": "Play Time Limit cannot be more than 6 hours. To lock the switch, set to 0, to disable screen time limits, set to -1."
}
}
}
60 changes: 2 additions & 58 deletions custom_components/nintendo_parental/time.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Time platform for Home Assistant."""

from datetime import time, timedelta
from datetime import time
import logging

from homeassistant.components.time import TimeEntity
Expand Down Expand Up @@ -52,39 +52,7 @@ def name(self) -> str:

def _value(self) -> time:
"""Conversion class for time."""
if self._config["value"] == "limit_time":
if self._device.limit_time is None:
return None
return time(
int(
str(timedelta(minutes=self._device.limit_time)).split(
":", maxsplit=1
)[0]
),
int(
str(timedelta(minutes=self._device.limit_time)).split(
":", maxsplit=2
)[1]
),
0,
)
elif self._config["value"] == "bonus_time":
if self._device.bonus_time is None:
return None
return time(
int(
str(timedelta(minutes=self._device.bonus_time)).split(
":", maxsplit=1
)[0]
),
int(
str(timedelta(minutes=self._device.bonus_time)).split(
":", maxsplit=2
)[1]
),
0,
)
elif self._config["value"] == "bedtime":
if self._config["value"] == "bedtime":
return self._device.bedtime_alarm

@property
Expand All @@ -94,30 +62,6 @@ def native_value(self) -> time | None:

async def async_set_value(self, value: time) -> None:
"""Update the value."""
if self._config.get("update_method") == "update_max_daily_playtime":
_LOGGER.debug(
"Got request to update play time for device %s to %s",
self._device_id,
value,
)
minutes = value.hour * 60
minutes += value.minute
if minutes > 360:
raise ServiceValidationError(
"Play Time Limit cannot be more than 6 hours (6:00). To disable, set to 0:00",
translation_domain=DOMAIN,
translation_key="play_time_limit_out_of_range",
)
await self._device.update_max_daily_playtime(minutes)
if self._config.get("update_method") == "give_bonus_time":
_LOGGER.debug(
"Got request to add bonus time for device %s to %s",
self._device_id,
value,
)
minutes = value.hour * 60
minutes += value.minute
await self._device.give_bonus_time(minutes)
if self._config["update_method"] == "set_bedtime_alarm":
if value.hour >= 16 and value.hour <= 23:
await self._device.set_bedtime_alarm(end_time=value, enabled=True)
Expand Down
8 changes: 5 additions & 3 deletions custom_components/nintendo_parental/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"data": {
"session_token": "Session token",
"update_interval": "Update interval (seconds)",
"default_max_playtime": "Default maximum play time (minutes)"
"default_max_playtime": "Default maximum play time (minutes)",
"experimental": "Experimental features"
}
},
"nintendo_website_auth": {
Expand Down Expand Up @@ -46,7 +47,8 @@
"description": "Update Nintendo Switch Parental Controls configuration",
"data": {
"update_interval": "Update interval (seconds)",
"default_max_playtime": "Default maximum play time (minutes)"
"default_max_playtime": "Default maximum play time (minutes)",
"experimental": "Experimental features"
}
},
"applications": {
Expand All @@ -73,7 +75,7 @@
"message": "Invalid time provided, expected between 16:00 and 23:59. Got {time}"
},
"play_time_limit_out_of_range": {
"message": "Play Time Limit cannot be more than 6 hours (6:00). To disable, set to 0:00"
"message": "Play Time Limit cannot be more than 6 hours. To lock the switch, set to 0, to disable screen time limits, set to -1."
}
}
}
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ colorlog==6.8.0
homeassistant==2024.2.0
pip>=21.0,<23.4
ruff==0.1.9
pynintendoparental==0.4.6
pynintendoparental==0.4.9

0 comments on commit 26976db

Please sign in to comment.