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 .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -1064,6 +1064,7 @@ omit =
homeassistant/components/shelly/sensor.py
homeassistant/components/shelly/utils.py
homeassistant/components/sigfox/sensor.py
homeassistant/components/simplepush/__init__.py
homeassistant/components/simplepush/notify.py
homeassistant/components/simplisafe/__init__.py
homeassistant/components/simplisafe/alarm_control_panel.py
Expand Down
2 changes: 2 additions & 0 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -927,6 +927,8 @@ build.json @home-assistant/supervisor
/tests/components/sighthound/ @robmarkcole
/homeassistant/components/signal_messenger/ @bbernhard
/tests/components/signal_messenger/ @bbernhard
/homeassistant/components/simplepush/ @engrbm87
/tests/components/simplepush/ @engrbm87
/homeassistant/components/simplisafe/ @bachya
/tests/components/simplisafe/ @bachya
/homeassistant/components/sinch/ @bendikrb
Expand Down
38 changes: 38 additions & 0 deletions homeassistant/components/simplepush/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,39 @@
"""The simplepush component."""

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import discovery
from homeassistant.helpers.typing import ConfigType

from .const import DATA_HASS_CONFIG, DOMAIN

PLATFORMS = [Platform.NOTIFY]


async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the simplepush component."""

hass.data[DATA_HASS_CONFIG] = config
return True


async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up simplepush from a config entry."""

hass.async_create_task(
discovery.async_load_platform(
hass,
Platform.NOTIFY,
DOMAIN,
dict(entry.data),
hass.data[DATA_HASS_CONFIG],
Comment thread
MartinHjelmare marked this conversation as resolved.
)
)

return True


async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry."""
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
88 changes: 88 additions & 0 deletions homeassistant/components/simplepush/config_flow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
"""Config flow for simplepush integration."""
from __future__ import annotations

import logging
from typing import Any

from simplepush import UnknownError, send, send_encrypted
import voluptuous as vol

from homeassistant import config_entries
from homeassistant.const import CONF_NAME, CONF_PASSWORD
from homeassistant.data_entry_flow import FlowResult

from .const import ATTR_ENCRYPTED, CONF_DEVICE_KEY, CONF_SALT, DEFAULT_NAME, DOMAIN

_LOGGER = logging.getLogger(__name__)


def validate_input(entry: dict[str, str]) -> dict[str, str] | None:
"""Validate user input."""
try:
if CONF_PASSWORD in entry:
send_encrypted(
entry[CONF_DEVICE_KEY],
entry[CONF_PASSWORD],
entry[CONF_PASSWORD],
"HA test",
"Message delivered successfully",
)
else:
send(entry[CONF_DEVICE_KEY], "HA test", "Message delivered successfully")
except UnknownError:
return {"base": "cannot_connect"}

return None


class SimplePushFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle a config flow for simplepush."""

async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> FlowResult:
"""Handle a flow initiated by the user."""
errors: dict[str, str] | None = None
if user_input is not None:

await self.async_set_unique_id(user_input[CONF_DEVICE_KEY])
self._abort_if_unique_id_configured()

self._async_abort_entries_match(
{
CONF_NAME: user_input[CONF_NAME],
}
)

if not (
errors := await self.hass.async_add_executor_job(
validate_input, user_input
)
):
return self.async_create_entry(
title=user_input[CONF_NAME],
data=user_input,
)

return self.async_show_form(
step_id="user",
data_schema=vol.Schema(
{
vol.Required(CONF_DEVICE_KEY): str,
vol.Required(CONF_NAME, default=DEFAULT_NAME): str,
vol.Inclusive(CONF_PASSWORD, ATTR_ENCRYPTED): str,
vol.Inclusive(CONF_SALT, ATTR_ENCRYPTED): str,
}
),
errors=errors,
)

async def async_step_import(self, import_config: dict[str, str]) -> FlowResult:
"""Import a config entry from configuration.yaml."""
_LOGGER.warning(
"Configuration of the simplepush integration in YAML is deprecated and "
"will be removed in a future release; Your existing configuration "
"has been imported into the UI automatically and can be safely removed "
"from your configuration.yaml file"
)
return await self.async_step_user(import_config)
13 changes: 13 additions & 0 deletions homeassistant/components/simplepush/const.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"""Constants for the simplepush integration."""

from typing import Final

DOMAIN: Final = "simplepush"
DEFAULT_NAME: Final = "simplepush"
DATA_HASS_CONFIG: Final = "simplepush_hass_config"

ATTR_ENCRYPTED: Final = "encrypted"
ATTR_EVENT: Final = "event"

CONF_DEVICE_KEY: Final = "device_key"
CONF_SALT: Final = "salt"
3 changes: 2 additions & 1 deletion homeassistant/components/simplepush/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"name": "Simplepush",
"documentation": "https://www.home-assistant.io/integrations/simplepush",
"requirements": ["simplepush==1.1.4"],
"codeowners": [],
"codeowners": ["@engrbm87"],
"config_flow": true,
"iot_class": "cloud_polling",
"loggers": ["simplepush"]
}
83 changes: 59 additions & 24 deletions homeassistant/components/simplepush/notify.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
"""Simplepush notification service."""
from simplepush import send, send_encrypted
from __future__ import annotations

import logging
from typing import Any

from simplepush import BadRequest, UnknownError, send, send_encrypted
import voluptuous as vol

from homeassistant.components.notify import (
Expand All @@ -8,14 +13,16 @@
PLATFORM_SCHEMA,
BaseNotificationService,
)
from homeassistant.components.notify.const import ATTR_DATA
from homeassistant.config_entries import SOURCE_IMPORT
from homeassistant.const import CONF_EVENT, CONF_PASSWORD
from homeassistant.core import HomeAssistant
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType

ATTR_ENCRYPTED = "encrypted"

CONF_DEVICE_KEY = "device_key"
CONF_SALT = "salt"
from .const import ATTR_ENCRYPTED, ATTR_EVENT, CONF_DEVICE_KEY, CONF_SALT, DOMAIN

# Configuring simplepush under the notify platform will be removed in 2022.9.0
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
{
vol.Required(CONF_DEVICE_KEY): cv.string,
Expand All @@ -25,34 +32,62 @@
}
)

_LOGGER = logging.getLogger(__name__)

def get_service(hass, config, discovery_info=None):

async def async_get_service(
hass: HomeAssistant,
config: ConfigType,
discovery_info: DiscoveryInfoType | None = None,
) -> SimplePushNotificationService | None:
"""Get the Simplepush notification service."""
return SimplePushNotificationService(config)
if discovery_info is None:
hass.async_create_task(
hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_IMPORT}, data=config
)
)
return None

return SimplePushNotificationService(discovery_info)


class SimplePushNotificationService(BaseNotificationService):
"""Implementation of the notification service for Simplepush."""

def __init__(self, config):
def __init__(self, config: dict[str, Any]) -> None:
"""Initialize the Simplepush notification service."""
self._device_key = config.get(CONF_DEVICE_KEY)
self._event = config.get(CONF_EVENT)
self._password = config.get(CONF_PASSWORD)
self._salt = config.get(CONF_SALT)
self._device_key: str = config[CONF_DEVICE_KEY]
self._event: str | None = config.get(CONF_EVENT)
self._password: str | None = config.get(CONF_PASSWORD)
self._salt: str | None = config.get(CONF_SALT)

def send_message(self, message="", **kwargs):
def send_message(self, message: str, **kwargs: Any) -> None:
"""Send a message to a Simplepush user."""
title = kwargs.get(ATTR_TITLE, ATTR_TITLE_DEFAULT)

if self._password:
send_encrypted(
self._device_key,
self._password,
self._salt,
title,
message,
event=self._event,
)
else:
send(self._device_key, title, message, event=self._event)
# event can now be passed in the service data
event = None
if data := kwargs.get(ATTR_DATA):
event = data.get(ATTR_EVENT)

# use event from config until YAML config is removed
event = event or self._event

try:
if self._password:
send_encrypted(
self._device_key,
self._password,
self._salt,
title,
message,
event=event,
)
else:
send(self._device_key, title, message, event=event)

except BadRequest:
_LOGGER.error("Bad request. Title or message are too long")
except UnknownError:
_LOGGER.error("Failed to send the notification")
21 changes: 21 additions & 0 deletions homeassistant/components/simplepush/strings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"config": {
"step": {
"user": {
"data": {
"name": "[%key:common::config_flow::data::name%]",
"device_key": "The device key of your device",
"event": "The event for the events.",
"password": "The password of the encryption used by your device",
"salt": "The salt used by your device."
}
}
},
"error": {
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]"
},
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
}
}
}
21 changes: 21 additions & 0 deletions homeassistant/components/simplepush/translations/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"config": {
"abort": {
"already_configured": "Device is already configured"
},
"error": {
"cannot_connect": "Failed to connect"
},
"step": {
"user": {
"data": {
"device_key": "The device key of your device",
"event": "The event for the events.",
"name": "Name",
"password": "The password of the encryption used by your device",
"salt": "The salt used by your device."
}
}
}
}
}
1 change: 1 addition & 0 deletions homeassistant/generated/config_flows.py
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@
"shelly",
"shopping_list",
"sia",
"simplepush",
"simplisafe",
"skybell",
"slack",
Expand Down
3 changes: 3 additions & 0 deletions requirements_test_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1430,6 +1430,9 @@ sharkiq==0.0.1
# homeassistant.components.sighthound
simplehound==0.3

# homeassistant.components.simplepush
simplepush==1.1.4

# homeassistant.components.simplisafe
simplisafe-python==2022.06.0

Expand Down
1 change: 1 addition & 0 deletions tests/components/simplepush/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Tests for the simeplush integration."""
Loading