Skip to content

Commit d0461af

Browse files
Forecast dates and overdue icon config options
1 parent 6b477ef commit d0461af

File tree

4 files changed

+67
-49
lines changed

4 files changed

+67
-49
lines changed

custom_components/chore_helper/config_flow.py

Lines changed: 43 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -58,57 +58,59 @@ def optional(
5858
return vol.Optional(key, description={"suggested_value": suggested_value})
5959

6060

61+
def general_schema_definition(
62+
handler: SchemaConfigFlowHandler | SchemaOptionsFlowHandler,
63+
) -> Mapping[str, Any]:
64+
"""Create general schema."""
65+
schema = {
66+
required(
67+
const.CONF_FREQUENCY, handler.options, const.DEFAULT_FREQUENCY
68+
): selector.SelectSelector(
69+
selector.SelectSelectorConfig(options=const.FREQUENCY_OPTIONS)
70+
),
71+
optional(
72+
const.CONF_ICON_NORMAL, handler.options, const.DEFAULT_ICON_NORMAL
73+
): selector.IconSelector(),
74+
optional(
75+
const.CONF_ICON_TOMORROW, handler.options, const.DEFAULT_ICON_TOMORROW
76+
): selector.IconSelector(),
77+
optional(
78+
const.CONF_ICON_TODAY, handler.options, const.DEFAULT_ICON_TODAY
79+
): selector.IconSelector(),
80+
optional(
81+
const.CONF_ICON_OVERDUE, handler.options, const.DEFAULT_ICON_OVERDUE
82+
): selector.IconSelector(),
83+
optional(
84+
const.CONF_FORECAST_DATES, handler.options, const.DEFAULT_FORECAST_DATES
85+
): selector.NumberSelector(
86+
selector.NumberSelectorConfig(
87+
min=0,
88+
max=100,
89+
mode=selector.NumberSelectorMode.BOX,
90+
step=1,
91+
)
92+
),
93+
optional(ATTR_HIDDEN, handler.options, False): bool,
94+
optional(const.CONF_MANUAL, handler.options, False): bool,
95+
}
96+
97+
return schema
98+
99+
61100
async def general_config_schema(
62101
handler: SchemaConfigFlowHandler | SchemaOptionsFlowHandler,
63102
) -> vol.Schema:
64103
"""Generate config schema."""
65-
return vol.Schema(
66-
{
67-
optional(CONF_NAME, handler.options): selector.TextSelector(),
68-
required(
69-
const.CONF_FREQUENCY, handler.options, const.DEFAULT_FREQUENCY
70-
): selector.SelectSelector(
71-
selector.SelectSelectorConfig(options=const.FREQUENCY_OPTIONS)
72-
),
73-
optional(
74-
const.CONF_ICON_NORMAL, handler.options, const.DEFAULT_ICON_NORMAL
75-
): selector.IconSelector(),
76-
optional(
77-
const.CONF_ICON_TODAY, handler.options, const.DEFAULT_ICON_TODAY
78-
): selector.IconSelector(),
79-
optional(
80-
const.CONF_ICON_TOMORROW, handler.options, const.DEFAULT_ICON_TOMORROW
81-
): selector.IconSelector(),
82-
optional(ATTR_HIDDEN, handler.options, False): bool,
83-
optional(const.CONF_MANUAL, handler.options, False): bool,
84-
}
85-
)
104+
schema_obj = {required(CONF_NAME, handler.options): selector.TextSelector()}
105+
schema_obj.update(general_schema_definition(handler))
106+
return vol.Schema(schema_obj)
86107

87108

88109
async def general_options_schema(
89110
handler: SchemaConfigFlowHandler | SchemaOptionsFlowHandler,
90111
) -> vol.Schema:
91112
"""Generate options schema."""
92-
return vol.Schema(
93-
{
94-
required(
95-
const.CONF_FREQUENCY, handler.options, const.DEFAULT_FREQUENCY
96-
): selector.SelectSelector(
97-
selector.SelectSelectorConfig(options=const.FREQUENCY_OPTIONS)
98-
),
99-
optional(
100-
const.CONF_ICON_NORMAL, handler.options, const.DEFAULT_ICON_NORMAL
101-
): selector.IconSelector(),
102-
optional(
103-
const.CONF_ICON_TODAY, handler.options, const.DEFAULT_ICON_TODAY
104-
): selector.IconSelector(),
105-
optional(
106-
const.CONF_ICON_TOMORROW, handler.options, const.DEFAULT_ICON_TOMORROW
107-
): selector.IconSelector(),
108-
optional(ATTR_HIDDEN, handler.options, False): bool,
109-
optional(const.CONF_MANUAL, handler.options, False): bool,
110-
}
111-
)
113+
return vol.Schema(general_schema_definition(handler))
112114

113115

114116
async def detail_config_schema(

custom_components/chore_helper/const.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,13 @@
2727

2828
CONF_SENSOR = "sensor"
2929
CONF_ENABLED = "enabled"
30+
CONF_FORECAST_DATES = "forecast_dates"
3031
CONF_FREQUENCY = "frequency"
3132
CONF_MANUAL = "manual_update"
3233
CONF_ICON_NORMAL = "icon_normal"
3334
CONF_ICON_TODAY = "icon_today"
3435
CONF_ICON_TOMORROW = "icon_tomorrow"
36+
CONF_ICON_OVERDUE = "icon_overdue"
3537
CONF_OFFSET = "offset"
3638
CONF_DAY_OF_MONTH = "day_of_month"
3739
CONF_FIRST_MONTH = "first_month"
@@ -54,10 +56,12 @@
5456
DEFAULT_PERIOD = 1
5557
DEFAULT_FIRST_WEEK = 1
5658
DEFAULT_DATE_FORMAT = "%b-%d-%Y"
59+
DEFAULT_FORECAST_DATES = 10
5760

5861
DEFAULT_ICON_NORMAL = "mdi:broom"
5962
DEFAULT_ICON_TODAY = "mdi:bell"
6063
DEFAULT_ICON_TOMORROW = "mdi:bell-outline"
64+
DEFAULT_ICON_OVERDUE = "mdi:bell-alert"
6165
ICON = DEFAULT_ICON_NORMAL
6266

6367
STATE_TODAY = "today"

custom_components/chore_helper/sensor.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from datetime import date, datetime, time, timedelta
66
from typing import Any
77
from collections.abc import Generator
8+
import itertools
89

910
from dateutil.relativedelta import relativedelta
1011
from homeassistant.config_entries import ConfigEntry
@@ -71,10 +72,12 @@ class Chore(RestoreEntity):
7172
"_icon_normal",
7273
"_icon_today",
7374
"_icon_tomorrow",
75+
"_icon_overdue",
7476
"_last_month",
7577
"_last_updated",
7678
"_manual",
7779
"_next_due_date",
80+
"_forecast_dates",
7881
"_overdue",
7982
"_overdue_days",
8083
"_frequency",
@@ -109,9 +112,11 @@ def __init__(self, config_entry: ConfigEntry) -> None:
109112
self._icon_normal = config.get(const.CONF_ICON_NORMAL)
110113
self._icon_today = config.get(const.CONF_ICON_TODAY)
111114
self._icon_tomorrow = config.get(const.CONF_ICON_TOMORROW)
115+
self._icon_overdue = config.get(const.CONF_ICON_OVERDUE)
112116
self._date_format = config.get(
113117
const.CONF_DATE_FORMAT, const.DEFAULT_DATE_FORMAT
114118
)
119+
self._forecast_dates: int = config.get(const.CONF_FORECAST_DATES) or 0
115120
self._due_dates: list[date] = []
116121
self._next_due_date: date | None = None
117122
self._last_updated: datetime | None = None
@@ -395,7 +400,9 @@ def chore_schedule(self) -> Generator[date, None, None]:
395400
today = helpers.now().date()
396401
start_date: date = self._calculate_start_date()
397402
last_date: date = date(today.year + 1, 12, 31)
398-
while True:
403+
for i in itertools.count():
404+
if i > self._forecast_dates:
405+
break
399406
try:
400407
next_due_date = self._find_candidate_date(start_date)
401408
except (TypeError, ValueError):
@@ -556,11 +563,12 @@ def update_state(self) -> None:
556563
self._attr_state = self._days
557564
if self._days > 1:
558565
self._attr_icon = self._icon_normal
559-
else:
560-
if self._days == 0:
561-
self._attr_icon = self._icon_today
562-
elif self._days == 1:
563-
self._attr_icon = self._icon_tomorrow
566+
elif self._days < 0:
567+
self._attr_icon = self._icon_overdue
568+
elif self._days == 0:
569+
self._attr_icon = self._icon_today
570+
elif self._days == 1:
571+
self._attr_icon = self._icon_tomorrow
564572
self._overdue = self._days < 0
565573
self._overdue_days = 0 if self._days > -1 else abs(self._days)
566574
else:

custom_components/chore_helper/translations/en.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
"manual_update": "Manual update - sensor state updated manually by a service (Blueprint)",
1212
"icon_normal": "Icon (mdi:broom) - optional",
1313
"icon_tomorrow": "Icon due tomorrow (mdi:bell-outline) - optional",
14-
"icon_today": "Icon due today (mdi:bell) - optional"
14+
"icon_today": "Icon due today (mdi:bell) - optional",
15+
"icon_overdue": "Icon overdue (mdi:bell-alert) - optional",
16+
"forecast_dates": "Number of future due dates to forecast"
1517
}
1618
},
1719
"detail": {
@@ -61,7 +63,9 @@
6163
"manual_update": "Manual update - sensor state updated manually by a service (Blueprint)",
6264
"icon_normal": "Icon (mdi:broom) - optional",
6365
"icon_tomorrow": "Icon due tomorrow (mdi:bell-outline) - optional",
64-
"icon_today": "Icon due today (mdi:bell) - optional"
66+
"icon_today": "Icon due today (mdi:bell) - optional",
67+
"icon_overdue": "Icon overdue (mdi:bell-alert) - optional",
68+
"forecast_dates": "Number of future due dates to forecast"
6569
}
6670
},
6771
"detail": {

0 commit comments

Comments
 (0)