-
-
Notifications
You must be signed in to change notification settings - Fork 32.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
18 changed files
with
732 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
"""The ntfy integration.""" | ||
|
||
from __future__ import annotations | ||
|
||
from aiontfy import Ntfy | ||
|
||
from homeassistant.config_entries import ConfigEntry | ||
from homeassistant.const import CONF_URL, Platform | ||
from homeassistant.core import HomeAssistant | ||
from homeassistant.helpers.aiohttp_client import async_get_clientsession | ||
|
||
PLATFORMS: list[Platform] = [Platform.NOTIFY] | ||
|
||
|
||
type NtfyConfigEntry = ConfigEntry[Ntfy] | ||
|
||
|
||
async def async_setup_entry(hass: HomeAssistant, entry: NtfyConfigEntry) -> bool: | ||
"""Set up ntfy from a config entry.""" | ||
|
||
session = async_get_clientsession(hass) | ||
entry.runtime_data = Ntfy(entry.data[CONF_URL], session) | ||
|
||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) | ||
|
||
return True | ||
|
||
|
||
async def async_unload_entry(hass: HomeAssistant, entry: NtfyConfigEntry) -> bool: | ||
"""Unload a config entry.""" | ||
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
"""Config flow for the ntfy integration.""" | ||
|
||
from __future__ import annotations | ||
|
||
import logging | ||
import random | ||
import string | ||
from typing import Any | ||
|
||
from aiontfy import Message, Ntfy | ||
from aiontfy.exceptions import NtfyException, NtfyForbiddenAccessError, NtfyHTTPError | ||
import voluptuous as vol | ||
|
||
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult | ||
from homeassistant.const import CONF_URL | ||
from homeassistant.helpers.aiohttp_client import async_get_clientsession | ||
|
||
from .const import CONF_TOPIC, DEFAULT_URL, DOMAIN | ||
|
||
_LOGGER = logging.getLogger(__name__) | ||
|
||
STEP_USER_DATA_SCHEMA = vol.Schema( | ||
{ | ||
vol.Required(CONF_URL, default=DEFAULT_URL): str, | ||
vol.Optional(CONF_TOPIC): str, | ||
} | ||
) | ||
|
||
|
||
class NtfyConfigFlow(ConfigFlow, domain=DOMAIN): | ||
"""Handle a config flow for ntfy.""" | ||
|
||
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 user_input.get(CONF_TOPIC): | ||
user_input[CONF_TOPIC] = "".join( | ||
random.choices( | ||
string.ascii_lowercase + string.ascii_uppercase + string.digits, | ||
k=16, | ||
) | ||
) | ||
self._async_abort_entries_match(user_input) | ||
try: | ||
session = async_get_clientsession(self.hass) | ||
ntfy = Ntfy(user_input[CONF_URL], session) | ||
await ntfy.publish( | ||
Message( | ||
topic=user_input[CONF_TOPIC], | ||
title="Home Assistant", | ||
message="The Home Assistant ntfy integration has been successfully set up for this topic.", | ||
) | ||
) | ||
except NtfyForbiddenAccessError: | ||
errors["base"] = "forbidden_topic" | ||
except NtfyHTTPError as e: | ||
_LOGGER.debug("Error %s: %s [%s]", e.code, e.error, e.link) | ||
errors["base"] = "cannot_connect" | ||
except NtfyException: | ||
errors["base"] = "cannot_connect" | ||
except ValueError: | ||
errors["base"] = "invalid_url" | ||
except Exception: | ||
_LOGGER.exception("Unexpected exception") | ||
errors["base"] = "unknown" | ||
else: | ||
return self.async_create_entry( | ||
title=user_input[CONF_TOPIC], data=user_input | ||
) | ||
|
||
return self.async_show_form( | ||
step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
"""Constants for the ntfy integration.""" | ||
|
||
from typing import Final | ||
|
||
DOMAIN = "ntfy" | ||
DEFAULT_URL: Final = "https://ntfy.sh" | ||
|
||
CONF_TOPIC = "topic" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"entity": { | ||
"notify": { | ||
"publish": { | ||
"default": "mdi:console-line" | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"domain": "ntfy", | ||
"name": "ntfy", | ||
"codeowners": ["@tr4nt0r"], | ||
"config_flow": true, | ||
"documentation": "https://www.home-assistant.io/integrations/ntfy", | ||
"iot_class": "cloud_push", | ||
"loggers": ["aionfty"], | ||
"quality_scale": "silver", | ||
"requirements": ["aiontfy==0.2.1"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
"""ntfy notification entity.""" | ||
|
||
from __future__ import annotations | ||
|
||
from aiontfy import Message | ||
from aiontfy.exceptions import NtfyException, NtfyHTTPError | ||
|
||
from homeassistant.components.notify import ( | ||
NotifyEntity, | ||
NotifyEntityDescription, | ||
NotifyEntityFeature, | ||
) | ||
from homeassistant.const import CONF_URL | ||
from homeassistant.core import HomeAssistant | ||
from homeassistant.exceptions import HomeAssistantError | ||
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo | ||
from homeassistant.helpers.entity_platform import AddEntitiesCallback | ||
|
||
from . import NtfyConfigEntry | ||
from .const import CONF_TOPIC, DEFAULT_URL, DOMAIN | ||
|
||
PARALLEL_UPDATES = 0 | ||
|
||
|
||
async def async_setup_entry( | ||
hass: HomeAssistant, | ||
config_entry: NtfyConfigEntry, | ||
async_add_entities: AddEntitiesCallback, | ||
) -> None: | ||
"""Set up the ntfy notification entity platform.""" | ||
|
||
async_add_entities([NtfyNotifyEntity(config_entry, config_entry.data[CONF_TOPIC])]) | ||
|
||
|
||
class NtfyNotifyEntity(NotifyEntity): | ||
"""Representation of a ntfy notification entity.""" | ||
|
||
entity_description = NotifyEntityDescription( | ||
key="publish", | ||
translation_key="publish", | ||
name=None, | ||
has_entity_name=True, | ||
) | ||
|
||
def __init__(self, config_entry: NtfyConfigEntry, topic: str) -> None: | ||
"""Initialize a notification entity.""" | ||
|
||
self._attr_unique_id = f"{config_entry.entry_id}_{self.entity_description.key}" | ||
self._attr_supported_features = NotifyEntityFeature.TITLE | ||
self.device_info = DeviceInfo( | ||
entry_type=DeviceEntryType.SERVICE, | ||
manufacturer="ntfy LLC", | ||
model="ntfy", | ||
model_id=config_entry.data[CONF_URL], | ||
name=topic, | ||
configuration_url=f"{DEFAULT_URL}/{topic}", | ||
identifiers={(DOMAIN, config_entry.entry_id)}, | ||
) | ||
self.ntfy = config_entry.runtime_data | ||
self.topic = topic | ||
|
||
async def async_send_message(self, message: str, title: str | None = None) -> None: | ||
"""Publish a message to a topic.""" | ||
try: | ||
msg = Message(topic=self.topic, message=message, title=title) | ||
await self.ntfy.publish(msg) | ||
except NtfyHTTPError as e: | ||
raise HomeAssistantError( | ||
translation_key="publish_failed_request_error", | ||
translation_domain=DOMAIN, | ||
translation_placeholders={"error_msg": e.error}, | ||
) from e | ||
except NtfyException as e: | ||
raise HomeAssistantError( | ||
translation_key="publish_failed_exception", | ||
translation_domain=DOMAIN, | ||
) from e |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
rules: | ||
# Bronze | ||
action-setup: | ||
status: exempt | ||
comment: only entity actions | ||
appropriate-polling: | ||
status: exempt | ||
comment: the integration does not poll | ||
brands: done | ||
common-modules: | ||
status: exempt | ||
comment: the integration currently implements only one platform and has no coordinator | ||
config-flow-test-coverage: done | ||
config-flow: done | ||
dependency-transparency: done | ||
docs-actions: done | ||
docs-high-level-description: done | ||
docs-installation-instructions: done | ||
docs-removal-instructions: done | ||
entity-event-setup: | ||
status: exempt | ||
comment: the integration does not subscribe to events | ||
entity-unique-id: done | ||
has-entity-name: done | ||
runtime-data: done | ||
test-before-configure: | ||
status: done | ||
comment: tested by publishing a success message to the topic | ||
test-before-setup: | ||
status: exempt | ||
comment: testing would require to trigger a notification | ||
unique-config-entry: done | ||
|
||
# Silver | ||
action-exceptions: done | ||
config-entry-unloading: done | ||
docs-configuration-parameters: | ||
status: exempt | ||
comment: the integration has no options | ||
docs-installation-parameters: done | ||
entity-unavailable: | ||
status: exempt | ||
comment: the integration only implements a stateless notify entity. | ||
integration-owner: done | ||
log-when-unavailable: | ||
status: exempt | ||
comment: the integration only integrates state-less entities | ||
parallel-updates: done | ||
reauthentication-flow: | ||
status: exempt | ||
comment: the integration currently does not implement authenticated requests | ||
test-coverage: done | ||
|
||
# Gold | ||
devices: todo | ||
diagnostics: todo | ||
discovery-update-info: todo | ||
discovery: todo | ||
docs-data-update: todo | ||
docs-examples: todo | ||
docs-known-limitations: todo | ||
docs-supported-devices: todo | ||
docs-supported-functions: todo | ||
docs-troubleshooting: todo | ||
docs-use-cases: todo | ||
dynamic-devices: todo | ||
entity-category: done | ||
entity-device-class: | ||
status: exempt | ||
comment: no suitable device class for the notify entity | ||
entity-disabled-by-default: | ||
status: exempt | ||
comment: only one entity | ||
entity-translations: | ||
status: exempt | ||
comment: the notify entity uses the topic as name, no translation required | ||
exception-translations: done | ||
icon-translations: done | ||
reconfiguration-flow: todo | ||
repair-issues: | ||
status: exempt | ||
comment: the integration has no repeairs | ||
stale-devices: | ||
status: exempt | ||
comment: only one device per entry, is deleted with the entry. | ||
|
||
# Platinum | ||
async-dependency: done | ||
inject-websession: done | ||
strict-typing: todo |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
{ | ||
"config": { | ||
"step": { | ||
"user": { | ||
"description": "Setup a topic for publishing notifications", | ||
"data": { | ||
"url": "Service URL", | ||
"topic": "Topic" | ||
}, | ||
|
||
"data_description": { | ||
"url": "Address of the ntfy service. Modify this if you want to use a different server", | ||
"topic": "Enter the name of the topic you want to publish to. Topics may not be password-protected, so choose a name that's not easy to guess. If left empty, a random topic name will be generated." | ||
} | ||
} | ||
}, | ||
"error": { | ||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", | ||
"forbidden_topic": "Protected topics are not supported", | ||
"unknown": "[%key:common::config_flow::error::unknown%]", | ||
"invalid_url": "Invalid service URL" | ||
}, | ||
"abort": { | ||
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]" | ||
} | ||
}, | ||
"exceptions": { | ||
"publish_failed_request_error": { | ||
"message": "Failed to publish notification: {error_msg}" | ||
}, | ||
"publish_failed_exception": { | ||
"message": "Failed to publish notification due to a connection error" | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -418,6 +418,7 @@ | |
"nobo_hub", | ||
"nordpool", | ||
"notion", | ||
"ntfy", | ||
"nuheat", | ||
"nuki", | ||
"nut", | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
"""Tests for ntfy integration.""" |
Oops, something went wrong.