Skip to content

Commit

Permalink
Merge pull request #62 from bruxy70/development
Browse files Browse the repository at this point in the history
Adding move_country_holidays parameter
  • Loading branch information
bruxy70 committed Dec 29, 2019
2 parents 7baf4eb + bef00d1 commit 04d452f
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 29 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ Entity_id change is not possible using the YAML configuration. Changing other pa
| `last_month` | Yes | Month three letter abbreviation.<br/>**Default**: `"dec"`
| `exclude_dates` | Yes | List of dates with no collection (using international date format `'yyyy-mm-dd'`.
| `include_dates` | Yes | List of extra collection (using international date format `'yyyy-mm-dd'`.
| `move_country_holidays` | Yes | A country code (see [holidays](https://github.com/dr-prodigy/python-holidays) for the list of valid country codes).<br/>Automatically move garbage collection on public holidays to the following day.<br/>*Example:* `US`


#### PARAMETERS FOR COLLECTION EVERY-N-WEEKS
|Attribute |Optional|Description
Expand Down
6 changes: 4 additions & 2 deletions custom_components/garbage_collection/.translations/cs.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@
"week_order_number_4": "Čtvrtý týden v měsíci",
"week_order_number_5": "Pátý týden v měsíci",
"include_dates": "Přidané datumy (volitelné)",
"exclude_dates": "Zakázané datumy (volitelné)"
"exclude_dates": "Zakázané datumy (volitelné)",
"move_country_holidays": "Přesunout svátky na další den (volitelné)"
}
}
},
Expand Down Expand Up @@ -133,7 +134,8 @@
"week_order_number_4": "Čtvrtý týden v měsíci",
"week_order_number_5": "Pátý týden v měsíci",
"include_dates": "Přidané datumy (volitelné)",
"exclude_dates": "Zakázané datumy (volitelné)"
"exclude_dates": "Zakázané datumy (volitelné)",
"move_country_holidays": "Pčesunout svátky na další den (volitelné)"
}
}
},
Expand Down
6 changes: 4 additions & 2 deletions custom_components/garbage_collection/.translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@
"week_order_number_4": "4th week of month",
"week_order_number_5": "5th week of month",
"include_dates": "Include dates (optional)",
"exclude_dates": "Exclude dates (optional)"
"exclude_dates": "Exclude dates (optional)",
"move_country_holidays": "Move holidays to next day (optional)"
}
}
},
Expand Down Expand Up @@ -132,7 +133,8 @@
"week_order_number_4": "4th week of month",
"week_order_number_5": "5th week of month",
"include_dates": "Include dates (optional)",
"exclude_dates": "Exclude dates (optional)"
"exclude_dates": "Exclude dates (optional)",
"move_country_holidays": "Move holidays to next day (optional)"
}
}
},
Expand Down
7 changes: 4 additions & 3 deletions custom_components/garbage_collection/.translations/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@
"week_order_number_4": "4ème semaine du mois",
"week_order_number_5": "5ème semaine du mois",
"include_dates": "Inclusion de dates (optionel)",
"exclude_dates": "Exclusion de dates (optionel)"
"exclude_dates": "Exclusion de dates (optionel)",
"move_country_holidays": "Move holidays to next day (optional)"
}
}
},
Expand Down Expand Up @@ -132,8 +133,8 @@
"week_order_number_4": "4ème semaine du mois",
"week_order_number_5": "5ème semaine du mois",
"include_dates": "Inclusion de dates (optionel)",
"exclude_dates": "Exclusion de dates (optionel)"

"exclude_dates": "Exclusion de dates (optionel)",
"move_country_holidays": "Move holidays to next day (optional)"
}
}
},
Expand Down
6 changes: 4 additions & 2 deletions custom_components/garbage_collection/.translations/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@
"week_order_number_4": "4° settimana del mese",
"week_order_number_5": "5° settimana del mese",
"include_dates": "Includi date (opzionale)",
"exclude_dates": "Escludi date (opzionale)"
"exclude_dates": "Escludi date (opzionale)",
"move_country_holidays": "Move holidays to next day (optional)"
}
}
},
Expand Down Expand Up @@ -132,7 +133,8 @@
"week_order_number_4": "4° settimana del mese",
"week_order_number_5": "5° settimana del mese",
"include_dates": "Includi date (opzionale)",
"exclude_dates": "Escludi date (opzionale)"
"exclude_dates": "Escludi date (opzionale)",
"move_country_holidays": "Move holidays to next day (optional)"
}
}
},
Expand Down
20 changes: 20 additions & 0 deletions custom_components/garbage_collection/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
MONTHLY_FREQUENCY,
ANNUAL_FREQUENCY,
GROUP_FREQUENCY,
COUNTRY_CODES,
DEFAULT_FIRST_MONTH,
DEFAULT_LAST_MONTH,
DEFAULT_FREQUENCY,
Expand Down Expand Up @@ -44,6 +45,7 @@
CONF_DATE,
CONF_EXCLUDE_DATES,
CONF_INCLUDE_DATES,
CONF_MOVE_COUNTRY_HOLIDAYS,
CONF_PERIOD,
CONF_FIRST_WEEK,
CONF_SENSORS,
Expand Down Expand Up @@ -286,6 +288,9 @@ async def async_step_final(
final_info[CONF_EXCLUDE_DATES] = string_to_list(
user_input[CONF_EXCLUDE_DATES]
)
final_info[CONF_MOVE_COUNTRY_HOLIDAYS] = user_input[
CONF_MOVE_COUNTRY_HOLIDAYS
]
if not is_dates(final_info[CONF_INCLUDE_DATES]) or not is_dates(
final_info[CONF_EXCLUDE_DATES]
):
Expand All @@ -311,6 +316,7 @@ async def _show_final_form(self, user_input):
last_month = DEFAULT_LAST_MONTH
include_dates = ""
exclude_dates = ""
include_country_holidays = ""
period = 1
first_week = 1
if user_input is not None:
Expand All @@ -326,6 +332,8 @@ async def _show_final_form(self, user_input):
include_dates = user_input[CONF_INCLUDE_DATES]
if CONF_EXCLUDE_DATES in user_input:
exclude_dates = user_input[CONF_EXCLUDE_DATES]
if CONF_MOVE_COUNTRY_HOLIDAYS in user_input:
include_country_holidays = user_input[CONF_MOVE_COUNTRY_HOLIDAYS]
data_schema = OrderedDict()
data_schema[vol.Optional(CONF_FIRST_MONTH, default=first_month)] = vol.In(
MONTH_OPTIONS
Expand Down Expand Up @@ -366,6 +374,9 @@ async def _show_final_form(self, user_input):
] = bool
data_schema[vol.Optional(CONF_INCLUDE_DATES, default=include_dates)] = str
data_schema[vol.Optional(CONF_EXCLUDE_DATES, default=exclude_dates)] = str
data_schema[
vol.Optional(CONF_MOVE_COUNTRY_HOLIDAYS, default=include_country_holidays)
] = vol.In(COUNTRY_CODES)
return self.async_show_form(
step_id="final", data_schema=vol.Schema(data_schema), errors=self._errors
)
Expand Down Expand Up @@ -667,6 +678,9 @@ async def async_step_final(
final_info[CONF_EXCLUDE_DATES]
):
self._errors["base"] = "date"
final_info[CONF_MOVE_COUNTRY_HOLIDAYS] = user_input[
CONF_MOVE_COUNTRY_HOLIDAYS
]
if self._data[CONF_FREQUENCY] in WEEKLY_FREQUENCY_X:
final_info[CONF_PERIOD] = user_input[CONF_PERIOD]
final_info[CONF_FIRST_WEEK] = user_input[CONF_FIRST_WEEK]
Expand Down Expand Up @@ -737,6 +751,12 @@ async def _show_final_form(self, user_input):
default=",".join(self.config_entry.options.get(CONF_EXCLUDE_DATES)),
)
] = str
data_schema[
vol.Optional(
CONF_MOVE_COUNTRY_HOLIDAYS,
default=self.config_entry.options.get(CONF_MOVE_COUNTRY_HOLIDAYS),
)
] = vol.In(COUNTRY_CODES)
return self.async_show_form(
step_id="final", data_schema=vol.Schema(data_schema), errors=self._errors
)
Expand Down
58 changes: 54 additions & 4 deletions custom_components/garbage_collection/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
CONF_DATE = "date"
CONF_EXCLUDE_DATES = "exclude_dates"
CONF_INCLUDE_DATES = "include_dates"
CONF_MOVE_COUNTRY_HOLIDAYS = "move_country_holidays"
CONF_PERIOD = "period"
CONF_FIRST_WEEK = "first_week"
CONF_SENSORS = "sensors"
Expand Down Expand Up @@ -87,6 +88,57 @@
"dec",
]

COUNTRY_CODES = [
"AR",
"AT",
"AU",
"AW",
"BE",
"BG",
"BR",
"BY",
"CA",
"CH",
"CO",
"CZ",
"DE",
"DK",
"DO",
"ECB",
"EE",
"ES",
"FI",
"FRA",
"HR",
"HU",
"IE",
"IND",
"IS",
"IT",
"JP",
"KE",
"LT",
"LU",
"MX",
"NG",
"NI",
"NL",
"NO",
"NZ",
"PE",
"PL",
"PT",
"PTE",
"RU",
"SE",
"SI",
"SK",
"UA",
"UK",
"US",
"ZA",
]


def date_text(value):
if value is None or value == "":
Expand Down Expand Up @@ -137,6 +189,7 @@ def month_day_text(value):
vol.Optional(CONF_EXCLUDE_DATES, default=[]): vol.All(
cv.ensure_list, [date_text]
),
vol.Optional(CONF_MOVE_COUNTRY_HOLIDAYS): vol.In(COUNTRY_CODES),
vol.Optional(CONF_ICON_NORMAL, default=DEFAULT_ICON_NORMAL): cv.icon,
vol.Optional(CONF_ICON_TODAY, default=DEFAULT_ICON_TODAY): cv.icon,
vol.Optional(CONF_ICON_TOMORROW, default=DEFAULT_ICON_TOMORROW): cv.icon,
Expand All @@ -148,11 +201,8 @@ def month_day_text(value):

CONFIG_SCHEMA = vol.Schema(
{

DOMAIN: vol.Schema(
{
vol.Optional(CONF_SENSORS): vol.All(cv.ensure_list, [SENSOR_SCHEMA])
}
{vol.Optional(CONF_SENSORS): vol.All(cv.ensure_list, [SENSOR_SCHEMA])}
)
},
extra=vol.ALLOW_EXTRA,
Expand Down
1 change: 1 addition & 0 deletions custom_components/garbage_collection/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"requirements": [
"datetime",
"integrationhelper",
"holidays",
"typing",
"uuid",
"voluptuous"
Expand Down
49 changes: 33 additions & 16 deletions custom_components/garbage_collection/sensor.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Sensor platform for garbage_collection."""
from homeassistant.helpers.entity import Entity
import homeassistant.util.dt as dt_util
import holidays
import logging
import locale
from datetime import datetime, date, timedelta
Expand Down Expand Up @@ -39,6 +40,7 @@
CONF_DATE,
CONF_EXCLUDE_DATES,
CONF_INCLUDE_DATES,
CONF_MOVE_COUNTRY_HOLIDAYS,
CONF_PERIOD,
CONF_FIRST_WEEK,
CONF_SENSORS,
Expand Down Expand Up @@ -129,6 +131,18 @@ def __init__(self, hass, config):
)
self.__include_dates = to_dates(config.get(CONF_INCLUDE_DATES, []))
self.__exclude_dates = to_dates(config.get(CONF_EXCLUDE_DATES, []))
country_holidays = config.get(CONF_MOVE_COUNTRY_HOLIDAYS)
self.__holidays = []
if country_holidays is not None and country_holidays != "":
this_year = dt_util.now().date().year
years = [this_year, this_year + 1]
try:
for date, name in holidays.CountryHoliday(
country_holidays, years=years
).items():
self.__holidays.append(date)
except KeyError:
_LOGGER.error("Invalid country code (%s)", country_holidays)
self.__period = config.get(CONF_PERIOD)
self.__first_week = config.get(CONF_FIRST_WEEK)
self.__next_date = None
Expand Down Expand Up @@ -291,28 +305,31 @@ def find_candidate_date(self, day1: date) -> date:
_LOGGER.debug(f"({self.__name}) Unknown frequency {self.__frequency}")
return None

def __insert_include_date(self, day1: date, next_date: date) -> date:
include_dates = list(filter(lambda date: date >= day1, self.__include_dates))
if len(include_dates) > 0 and include_dates[0] < next_date:
return include_dates[0]
else:
return next_date

def __skip_holiday(self, day: date) -> date:
return day + timedelta(days=1)

def get_next_date(self, day1: date) -> date:
"""Find the next date starting from day1.
Looks at include and exclude days"""
"""Find the next date starting from day1."""
first_day = day1
i = 0
while True:
while i < 365:
next_date = self.find_candidate_date(first_day)
include_dates = list(
filter(lambda date: date >= day1, self.__include_dates)
)
if len(include_dates) > 0 and include_dates[0] < next_date:
next_date = include_dates[0]
while next_date in self.__holidays:
next_date = self.__skip_holiday(next_date)
next_date = self.__insert_include_date(first_day, next_date)
if next_date not in self.__exclude_dates:
break
else:
first_day = next_date + timedelta(days=1)
return next_date
first_day = next_date + timedelta(days=1)
i += 1
if i > 365:
_LOGGER.error("(%s) Cannot find any suitable date", self.__name)
next_date = None
break
return next_date
_LOGGER.error("(%s) Cannot find any suitable date", self.__name)
return None

async def async_update(self) -> None:
"""Get the latest data and updates the states."""
Expand Down

0 comments on commit 04d452f

Please sign in to comment.