Skip to content

Commit 86bc6db

Browse files
committed
Fix oopsie
1 parent d1fbd74 commit 86bc6db

File tree

6 files changed

+227
-42
lines changed

6 files changed

+227
-42
lines changed

custom_components/file_plusplus/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""The file component."""
1+
"""The file++ component."""
22

33
from copy import deepcopy
44
from typing import Any
@@ -44,7 +44,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
4444
return True
4545
# The use of the legacy notify service was deprecated with HA Core 2024.6.0
4646
# and will be removed with HA Core 2024.12
47-
migrate_notify_issue(hass, DOMAIN, "File", "2024.12.0")
47+
migrate_notify_issue(hass, DOMAIN, "File++", "2024.12.0")
4848
# The YAML config was imported with HA Core 2024.6.0 and will be removed with
4949
# HA Core 2024.12
5050
ir.async_create_issue(
@@ -59,7 +59,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
5959
translation_key="deprecated_yaml",
6060
translation_placeholders={
6161
"domain": DOMAIN,
62-
"integration_title": "File",
62+
"integration_title": "File++",
6363
},
6464
)
6565

custom_components/file_plusplus/config_flow.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
"""Config flow for file integration."""
1+
"""Config flow for file++ integration."""
22

33
from copy import deepcopy
4+
import logging
45
import os
56
from typing import Any
67

@@ -20,8 +21,9 @@
2021
CONF_PLATFORM,
2122
CONF_UNIT_OF_MEASUREMENT,
2223
CONF_VALUE_TEMPLATE,
23-
Platform,
24+
Platform
2425
)
26+
2527
from homeassistant.core import callback
2628
from homeassistant.helpers.selector import (
2729
BooleanSelector,
@@ -35,6 +37,8 @@
3537

3638
from .const import CONF_TIMESTAMP, DEFAULT_NAME, DOMAIN
3739

40+
_LOGGER = logging.getLogger(__name__)
41+
3842
BOOLEAN_SELECTOR = BooleanSelector(BooleanSelectorConfig())
3943
TEMPLATE_SELECTOR = TemplateSelector(TemplateSelectorConfig())
4044
TEXT_SELECTOR = TextSelector(TextSelectorConfig(type=TextSelectorType.TEXT))
@@ -68,7 +72,7 @@
6872

6973

7074
class FileConfigFlowHandler(ConfigFlow, domain=DOMAIN):
71-
"""Handle a file config flow."""
75+
"""Handle a file++ config flow."""
7276

7377
VERSION = 2
7478

@@ -111,6 +115,9 @@ async def _async_handle_step(
111115
if key not in (CONF_FILE_PATH, CONF_PLATFORM, CONF_NAME):
112116
data.pop(key)
113117
options[key] = value
118+
_LOGGER.debug("DATA: " + str(data))
119+
_LOGGER.debug("TITLE: " + str(title))
120+
_LOGGER.debug("OPTIONS: " + str(options))
114121
return self.async_create_entry(data=data, title=title, options=options)
115122

116123
return self.async_show_form(
@@ -129,7 +136,9 @@ async def async_step_sensor(
129136
"""Handle file sensor config flow."""
130137
return await self._async_handle_step(Platform.SENSOR.value, user_input)
131138

132-
async def async_step_import(self, import_data: dict[str, Any]) -> ConfigFlowResult:
139+
async def async_step_import(
140+
self, import_data: dict[str, Any]
141+
) -> ConfigFlowResult:
133142
"""Import `file`` config from configuration.yaml."""
134143
self._async_abort_entries_match(import_data)
135144
platform = import_data[CONF_PLATFORM]
@@ -152,12 +161,12 @@ async def async_step_import(self, import_data: dict[str, Any]) -> ConfigFlowResu
152161

153162

154163
class FileOptionsFlowHandler(OptionsFlowWithConfigEntry):
155-
"""Handle File options."""
164+
"""Handle File++ options."""
156165

157166
async def async_step_init(
158167
self, user_input: dict[str, Any] | None = None
159168
) -> ConfigFlowResult:
160-
"""Manage File options."""
169+
"""Manage File++ options."""
161170
if user_input:
162171
return self.async_create_entry(data=user_input)
163172

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
"""Constants for the file integration."""
1+
"""Constants for the file++ integration."""
22

3-
DOMAIN = "file"
3+
DOMAIN = "file_plusplus"
44

55
CONF_TIMESTAMP = "timestamp"
66

7-
DEFAULT_NAME = "File"
7+
DEFAULT_NAME = "file_plusplus"
88
FILE_ICON = "mdi:file"
Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
{
2-
"domain": "file",
3-
"name": "File",
4-
"codeowners": ["@fabaff"],
5-
"config_flow": true,
6-
"documentation": "https://www.home-assistant.io/integrations/file",
7-
"iot_class": "local_polling",
8-
"requirements": ["file-read-backwards==2.0.0"]
2+
"domain": "file_plusplus",
3+
"name": "File++",
4+
"codeowners": ["@benjamin-dcs"],
5+
"config_flow": true,
6+
"documentation": "https://github.com/benjamin-dcs/File-plusplus/blob/main/README.md",
7+
"iot_class": "local_polling",
8+
"issue_tracker": "https://github.com/benjamin-dcs/File-plusplus/issues",
9+
"version": "0.1.0"
910
}

custom_components/file_plusplus/notify.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""Support for file notification."""
1+
"""Support for file++ notification."""
22

33
from __future__ import annotations
44

@@ -57,7 +57,7 @@ async def async_get_service(
5757

5858

5959
class FileNotificationService(BaseNotificationService):
60-
"""Implement the notification service for the File service."""
60+
"""Implement the notification service for the File++ service."""
6161

6262
def __init__(self, file_path: str, add_timestamp: bool) -> None:
6363
"""Initialize the service."""
@@ -81,12 +81,12 @@ def send_message(self, message: str = "", **kwargs: Any) -> None:
8181
filepath = self._file_path
8282
try:
8383
with open(filepath, "a", encoding="utf8") as file:
84-
if os.stat(filepath).st_size == 0:
85-
title = (
86-
f"{kwargs.get(ATTR_TITLE, ATTR_TITLE_DEFAULT)} notifications (Log"
87-
f" started: {dt_util.utcnow().isoformat()})\n{'-' * 80}\n"
88-
)
89-
file.write(title)
84+
# if os.stat(filepath).st_size == 0:
85+
# title = (
86+
# f"{kwargs.get(ATTR_TITLE, ATTR_TITLE_DEFAULT)} notifications (Log"
87+
# f" started: {dt_util.utcnow().isoformat()})\n{'-' * 80}\n"
88+
# )
89+
# file.write(title)
9090

9191
if self.add_timestamp:
9292
text = f"{dt_util.utcnow().isoformat()} {message}\n"
@@ -131,12 +131,12 @@ def send_message(self, message: str, title: str | None = None) -> None:
131131
filepath = self._file_path
132132
try:
133133
with open(filepath, "a", encoding="utf8") as file:
134-
if os.stat(filepath).st_size == 0:
135-
title = (
136-
f"{title or ATTR_TITLE_DEFAULT} notifications (Log"
137-
f" started: {dt_util.utcnow().isoformat()})\n{'-' * 80}\n"
138-
)
139-
file.write(title)
134+
# if os.stat(filepath).st_size == 0:
135+
# title = (
136+
# f"{title or ATTR_TITLE_DEFAULT} notifications (Log"
137+
# f" started: {dt_util.utcnow().isoformat()})\n{'-' * 80}\n"
138+
# )
139+
# file.write(title)
140140

141141
if self._add_timestamp:
142142
text = f"{dt_util.utcnow().isoformat()} {message}\n"

custom_components/file_plusplus/sensor.py

Lines changed: 184 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import logging
66
import os
77

8-
from file_read_backwards import FileReadBackwards
8+
# from file_read_backwards import FileReadBackwards
99
import voluptuous as vol
1010

1111
from homeassistant.components.sensor import (
@@ -98,21 +98,196 @@ def __init__(
9898
def update(self) -> None:
9999
"""Get the latest entry from a file and updates the state."""
100100
try:
101-
with FileReadBackwards(self._file_path, encoding="utf-8") as file_data:
102-
for line in file_data:
103-
data = line
104-
break
105-
data = data.strip()
106-
except (IndexError, FileNotFoundError, IsADirectoryError, UnboundLocalError):
101+
# with FileReadBackwards(self._file_path, encoding="utf-8") as file_data:
102+
# for line in file_data:
103+
# data = line
104+
# break
105+
# data = data.strip()
106+
with open(self._file_path, encoding="utf-8") as f:
107+
data = f.read()
108+
except (IndexError, FileNotFoundError, IsADirectoryError, UnboundLocalError) as e:
109+
_LOGGER.warning(
110+
"File or data not present at the moment: %s",
111+
os.path.basename(self._file_path),
112+
)
113+
return
114+
115+
self._attr_native_value = "Ok"
116+
117+
# if self._val_tpl is not None:
118+
# self._attr_native_value = (
119+
# self._val_tpl.async_render_with_possible_json_value(data, None)
120+
# )
121+
# else:
122+
# self._attr_native_value = data
123+
124+
@property
125+
def extra_state_attributes(self):
126+
"""Return device state attributes."""
127+
128+
try:
129+
with open(self._file_path, encoding="utf-8") as f:
130+
data = f.read()
131+
except (IndexError, FileNotFoundError, IsADirectoryError, UnboundLocalError) as e:
132+
_LOGGER.warning(
133+
"File or data not present at the moment: %s",
134+
os.path.basename(self._file_path),
135+
)
136+
return
137+
138+
if self._val_tpl is not None:
139+
content = (
140+
self._val_tpl.async_render_with_possible_json_value(data, None)
141+
)
142+
else:
143+
content = data
144+
145+
return {
146+
"content": content,
147+
}"""Support for sensor value(s) stored in local files."""
148+
149+
from __future__ import annotations
150+
151+
import logging
152+
import os
153+
154+
# from file_read_backwards import FileReadBackwards
155+
import voluptuous as vol
156+
157+
from homeassistant.components.sensor import (
158+
PLATFORM_SCHEMA as SENSOR_PLATFORM_SCHEMA,
159+
SensorEntity,
160+
)
161+
from homeassistant.config_entries import ConfigEntry
162+
from homeassistant.const import (
163+
CONF_FILE_PATH,
164+
CONF_NAME,
165+
CONF_UNIT_OF_MEASUREMENT,
166+
CONF_VALUE_TEMPLATE,
167+
)
168+
from homeassistant.core import HomeAssistant
169+
from homeassistant.helpers import config_validation as cv
170+
from homeassistant.helpers.entity_platform import AddEntitiesCallback
171+
from homeassistant.helpers.template import Template
172+
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
173+
174+
from .const import DEFAULT_NAME, FILE_ICON
175+
176+
_LOGGER = logging.getLogger(__name__)
177+
178+
PLATFORM_SCHEMA = SENSOR_PLATFORM_SCHEMA.extend(
179+
{
180+
vol.Required(CONF_FILE_PATH): cv.isfile,
181+
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
182+
vol.Optional(CONF_VALUE_TEMPLATE): cv.string,
183+
vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string,
184+
}
185+
)
186+
187+
188+
async def async_setup_platform(
189+
hass: HomeAssistant,
190+
config: ConfigType,
191+
async_add_entities: AddEntitiesCallback,
192+
discovery_info: DiscoveryInfoType | None = None,
193+
) -> None:
194+
"""Set up the file sensor from YAML.
195+
196+
The YAML platform config is automatically
197+
imported to a config entry, this method can be removed
198+
when YAML support is removed.
199+
"""
200+
201+
202+
async def async_setup_entry(
203+
hass: HomeAssistant,
204+
entry: ConfigEntry,
205+
async_add_entities: AddEntitiesCallback,
206+
) -> None:
207+
"""Set up the file sensor."""
208+
config = dict(entry.data)
209+
options = dict(entry.options)
210+
file_path: str = config[CONF_FILE_PATH]
211+
unique_id: str = entry.entry_id
212+
name: str = config.get(CONF_NAME, DEFAULT_NAME)
213+
unit: str | None = options.get(CONF_UNIT_OF_MEASUREMENT)
214+
value_template: Template | None = None
215+
216+
if CONF_VALUE_TEMPLATE in options:
217+
value_template = Template(options[CONF_VALUE_TEMPLATE], hass)
218+
219+
async_add_entities(
220+
[FileSensor(unique_id, name, file_path, unit, value_template)], True
221+
)
222+
223+
224+
class FileSensor(SensorEntity):
225+
"""Implementation of a file sensor."""
226+
227+
_attr_icon = FILE_ICON
228+
229+
def __init__(
230+
self,
231+
unique_id: str,
232+
name: str,
233+
file_path: str,
234+
unit_of_measurement: str | None,
235+
value_template: Template | None,
236+
) -> None:
237+
"""Initialize the file sensor."""
238+
self._attr_name = name
239+
self._file_path = file_path
240+
self._attr_native_unit_of_measurement = unit_of_measurement
241+
self._val_tpl = value_template
242+
self._attr_unique_id = unique_id
243+
244+
def update(self) -> None:
245+
"""Get the latest entry from a file and updates the state."""
246+
try:
247+
# with FileReadBackwards(self._file_path, encoding="utf-8") as file_data:
248+
# for line in file_data:
249+
# data = line
250+
# break
251+
# data = data.strip()
252+
with open(self._file_path, encoding="utf-8") as f:
253+
data = f.read()
254+
except (IndexError, FileNotFoundError, IsADirectoryError, UnboundLocalError) as e:
255+
_LOGGER.warning(
256+
"File or data not present at the moment: %s",
257+
os.path.basename(self._file_path),
258+
)
259+
return
260+
261+
self._attr_native_value = "Ok"
262+
263+
# if self._val_tpl is not None:
264+
# self._attr_native_value = (
265+
# self._val_tpl.async_render_with_possible_json_value(data, None)
266+
# )
267+
# else:
268+
# self._attr_native_value = data
269+
270+
@property
271+
def extra_state_attributes(self):
272+
"""Return device state attributes."""
273+
274+
try:
275+
with open(self._file_path, encoding="utf-8") as f:
276+
data = f.read()
277+
except (IndexError, FileNotFoundError, IsADirectoryError, UnboundLocalError) as e:
107278
_LOGGER.warning(
108279
"File or data not present at the moment: %s",
109280
os.path.basename(self._file_path),
110281
)
111282
return
112283

113284
if self._val_tpl is not None:
114-
self._attr_native_value = (
285+
content = (
115286
self._val_tpl.async_render_with_possible_json_value(data, None)
116287
)
117288
else:
118-
self._attr_native_value = data
289+
content = data
290+
291+
return {
292+
"content": content,
293+
}

0 commit comments

Comments
 (0)