1- """Support for file ++ notification."""
1+ """Support for File ++ notification."""
22
33from __future__ import annotations
44
5- from functools import partial
6- import logging
75import os
86from typing import Any , TextIO
97
10- import voluptuous as vol
11-
128from homeassistant .components .notify import (
13- ATTR_TITLE ,
149 ATTR_TITLE_DEFAULT ,
15- PLATFORM_SCHEMA as NOTIFY_PLATFORM_SCHEMA ,
16- BaseNotificationService ,
1710 NotifyEntity ,
1811 NotifyEntityFeature ,
19- migrate_notify_issue ,
2012)
2113from homeassistant .config_entries import ConfigEntry
22- from homeassistant .const import CONF_FILE_PATH , CONF_FILENAME , CONF_NAME
14+ from homeassistant .const import CONF_FILE_PATH , CONF_NAME
2315from homeassistant .core import HomeAssistant
2416from homeassistant .exceptions import ServiceValidationError
25- import homeassistant .helpers .config_validation as cv
2617from homeassistant .helpers .entity_platform import AddEntitiesCallback
27- from homeassistant .helpers .typing import ConfigType , DiscoveryInfoType
2818import homeassistant .util .dt as dt_util
2919
3020from .const import CONF_TIMESTAMP , DEFAULT_NAME , DOMAIN , FILE_ICON
3121
32- _LOGGER = logging .getLogger (__name__ )
33-
34- # The legacy platform schema uses a filename, after import
35- # The full file path is stored in the config entry
36- PLATFORM_SCHEMA = NOTIFY_PLATFORM_SCHEMA .extend (
37- {
38- vol .Required (CONF_FILENAME ): cv .string ,
39- vol .Optional (CONF_TIMESTAMP , default = False ): cv .boolean ,
40- }
41- )
42-
43-
44- async def async_get_service (
45- hass : HomeAssistant ,
46- config : ConfigType ,
47- discovery_info : DiscoveryInfoType | None = None ,
48- ) -> FileNotificationService | None :
49- """Get the file notification service."""
50- if discovery_info is None :
51- # We only set up through discovery
52- return None
53- file_path : str = discovery_info [CONF_FILE_PATH ]
54- timestamp : bool = discovery_info [CONF_TIMESTAMP ]
55-
56- return FileNotificationService (file_path , timestamp )
57-
58-
59- class FileNotificationService (BaseNotificationService ):
60- """Implement the notification service for the File++ service."""
61-
62- def __init__ (self , file_path : str , add_timestamp : bool ) -> None :
63- """Initialize the service."""
64- self ._file_path = file_path
65- self .add_timestamp = add_timestamp
66-
67- async def async_send_message (self , message : str = "" , ** kwargs : Any ) -> None :
68- """Send a message to a file."""
69- # The use of the legacy notify service was deprecated with HA Core 2024.6.0
70- # and will be removed with HA Core 2024.12
71- migrate_notify_issue (
72- self .hass , DOMAIN , "File" , "2024.12.0" , service_name = self ._service_name
73- )
74- await self .hass .async_add_executor_job (
75- partial (self .send_message , message , ** kwargs )
76- )
77-
78- def send_message (self , message : str = "" , ** kwargs : Any ) -> None :
79- """Send a message to a file."""
80- file : TextIO
81- filepath = self ._file_path
82- try :
83- with open (filepath , "a" , encoding = "utf8" ) as file :
84- if self .add_timestamp :
85- text = f"{ dt_util .utcnow ().isoformat ()} { message } \n "
86- else :
87- text = f"{ message } \n "
88- file .write (text )
89- except OSError as exc :
90- raise ServiceValidationError (
91- translation_domain = DOMAIN ,
92- translation_key = "write_access_failed" ,
93- translation_placeholders = {"filename" : filepath , "exc" : f"{ exc !r} " },
94- ) from exc
95-
9622
9723async def async_setup_entry (
9824 hass : HomeAssistant ,
@@ -105,7 +31,7 @@ async def async_setup_entry(
10531
10632
10733class FileNotifyEntity (NotifyEntity ):
108- """Implement the notification entity platform for the File service."""
34+ """Implement the notification entity platform for the File++ service."""
10935
11036 _attr_icon = FILE_ICON
11137 _attr_supported_features = NotifyEntityFeature .TITLE
@@ -115,16 +41,16 @@ def __init__(self, unique_id: str, config: dict[str, Any]) -> None:
11541 self ._file_path : str = config [CONF_FILE_PATH ]
11642 self ._add_timestamp : bool = config .get (CONF_TIMESTAMP , False )
11743 # Only import a name from an imported entity
118- self ._attr_name = config .get (CONF_NAME , DEFAULT_NAME ) + "_" + self . _file_path . split ( "/" )[ - 1 ]. replace ( "." , "_" )
44+ self ._attr_name = config .get (CONF_NAME , DEFAULT_NAME )
11945 self ._attr_unique_id = unique_id
12046
12147 def send_message (self , message : str , title : str | None = None ) -> None :
12248 """Send a message to a file."""
12349 file : TextIO
12450 filepath = self ._file_path
125- message = message .strip ()
12651 try :
127- with open (filepath , "w" , encoding = "utf8" ) as file :
52+ with open (filepath , "a" , encoding = "utf8" ) as file :
53+ # File++ - Delete header
12854 if self ._add_timestamp :
12955 text = f"{ dt_util .utcnow ().isoformat ()} { message } \n "
13056 else :
@@ -135,4 +61,4 @@ def send_message(self, message: str, title: str | None = None) -> None:
13561 translation_domain = DOMAIN ,
13662 translation_key = "write_access_failed" ,
13763 translation_placeholders = {"filename" : filepath , "exc" : f"{ exc !r} " },
138- ) from exc
64+ ) from exc
0 commit comments