Compare commits

...

8 Commits

7 changed files with 941 additions and 228 deletions

View File

@ -1 +1 @@
2025.4.3
2025.5.0

View File

@ -2632,100 +2632,100 @@
- id: '1696356974829'
alias: Scheduled Reset
description: Reset all context entities for the next day at the appropriate times
trigger:
- platform: time
at: 00:00:00
triggers:
- at: 00:00:00
id: midnight
- platform: time
at: input_datetime.audible_notification_on
trigger: time
- at: input_datetime.audible_notification_on
id: audible-on
- platform: time
at: input_datetime.kallen_school_day_end
trigger: time
- at: input_datetime.kallen_school_day_end
id: school-end
- platform: state
entity_id: sensor.twitch_ironnerd24
trigger: time
- entity_id: sensor.twitch_ironnerd24
from: streaming
to: offline
id: stream-offline
- platform: time
at: 04:00:00
trigger: state
- at: 04:00:00
id: 4am
- platform: time
at: '16:00:00'
id: 4pm
- platform: time
at: 06:00:00
trigger: time
- at: '12:00:00'
id: noon
trigger: time
- at: 06:00:00
id: 6am
condition: []
action:
trigger: time
conditions: []
actions:
- choose:
- conditions:
- condition: trigger
id: midnight
sequence:
- service: script.scheduling_reset
data: {}
- service: script.kallen_school_reset_late
data: {}
- service: automation.turn_on
target:
- data: {}
action: script.scheduling_reset
- data: {}
action: script.kallen_school_reset_late
- target:
entity_id:
- automation.scheduled_alarm_rearm
- automation.scheduled_alarm_disarm
data: {}
- service: input_boolean.turn_off
target:
action: automation.turn_on
- target:
entity_id:
- input_boolean.skip_disarm
- input_boolean.skip_rearm
data: {}
- service: counter.reset
target:
action: input_boolean.turn_off
- target:
entity_id:
- counter.back_door_opened_today
- counter.front_door_opened_today
- counter.basement_studio_door_opened_today
- counter.basement_led_strip_resets
data: {}
action: counter.reset
- conditions:
- condition: trigger
id:
- audible-on
sequence:
- service: script.reset_annc_switches
data: {}
- data: {}
action: script.reset_annc_switches
- conditions:
- condition: trigger
id: school-end
sequence:
- service: script.kallen_school_reset
data: {}
- data: {}
action: script.kallen_school_reset
- conditions:
- condition: trigger
id: stream-offline
sequence:
- service: input_boolean.turn_off
target:
- target:
entity_id: input_boolean.tony_streaming_today
data: {}
action: input_boolean.turn_off
- conditions:
- condition: trigger
id: 4am
sequence:
- service: input_boolean.turn_off
target:
- target:
entity_id:
- input_boolean.kallen_morning_meds_taken
- input_boolean.kallen_night_meds_taken
- input_boolean.tina_morning_meds_taken
- input_boolean.emma_scheduling_evening_ran
data: {}
- service: counter.reset
target:
action: input_boolean.turn_off
- target:
entity_id:
- counter.tony_morning_meds_reminder_count
- counter.tony_afternoon_meds_reminder_count
data: {}
action: counter.reset
- conditions:
- condition: trigger
id: 6am
@ -2735,19 +2735,16 @@
entity_id: sensor.twitch_ironnerd24
state: offline
then:
- service: input_boolean.turn_off
target:
- target:
entity_id: input_boolean.tony_streaming_today
data: {}
action: input_boolean.turn_off
- conditions:
- condition: trigger
id: 4pm
id:
- noon
sequence:
- service: input_boolean.turn_off
target:
entity_id:
- input_boolean.tina_night_meds_taken
data: {}
- stop: No current actions scheduled at noon, remove this action if this changes
mode: restart
- id: '1696361494561'
alias: Turn On Audible Notifications
@ -6112,3 +6109,67 @@
entity_id: input_boolean.emma_awake
alias: Turn on Emma Awake
mode: restart
- id: '1746632520108'
alias: Tina Sleep Handling
description: Awareness of when Tina is asleep or wakes up
triggers:
- alias: Leave Home
entity_id: person.christina_stork
zone: zone.home
event: leave
id: wake-leave
trigger: zone
- alias: Sentence
command:
- Tina is awake
- Christina is awake
id: wake-sentence
trigger: conversation
- alias: Focus off
entity_id:
- binary_sensor.tinas_iphone_focus
from: 'on'
to: 'off'
for:
hours: 0
minutes: 0
seconds: 30
id: wake-focus
trigger: state
conditions: []
actions:
- alias: Routing
choose:
- conditions:
- condition: and
conditions:
- alias: Wakeup
condition: trigger
id:
- wake-sentence
- wake-focus
- wake-leave
- condition: state
entity_id: input_boolean.tina_awake
state: 'off'
alias: Wakeup Trigger
sequence:
- delay:
hours: 0
minutes: 0
seconds: 5
milliseconds: 0
- alias: Set context that Tina is awake
data: {}
action: input_boolean.turn_on
target:
entity_id: input_boolean.tina_awake
- action: input_boolean.turn_off
metadata: {}
data: {}
target:
entity_id:
- input_boolean.tina_morning_meds_taken
- input_boolean.tina_night_meds_taken
alias: Reset Tina meds taken switches
mode: restart

View File

@ -79,7 +79,7 @@
45: 'quarter to {hour}',
59: 'a minute to {hour}',
'past_hour': '{minute} past {hour}',
'to_hour': '{minute} to {hour}',
'to_hour': '{minute} to {hour}',
},
'time_of_day':{
'midnight': 'midnight',
@ -157,7 +157,7 @@
'November',
'December',
]
},
},
'nl':{
'_language': 'Nederlands',
'and': 'en',
@ -203,6 +203,8 @@
'today': 'vandaag',
'tomorrow': 'morgen',
'yesterday': 'gisteren',
'next': 'volgende',
'last': 'afgelopen',
},
'days':[
"maandag",
@ -226,12 +228,30 @@
'oktober',
'november',
'december',
]
],
'time_of_hour':{
0: '{hour} uur',
1: '1 over {hour}',
15: 'kwart over {hour}',
30: 'half {hour}',
45: 'kwart voor {hour}',
59: '1 voor {hour}',
'past_hour': '{minute} over {hour}',
'to_hour': '{minute} voor {hour}',
'to_half_hour': '{minute} voor half {hour}',
'past_half_hour': '{minute} over half {hour}',
'half_hour': 'half {hour}',
'use_twelve': true,
},
'time_of_day':{
'midnight': 'middernacht',
'noon': 'middag',
},
},
'sv':{
'_language': 'Svenska',
'and': 'och',
'in': 'i',
'in': 'om',
'ago': 'sedan',
'now': 'nu',
'lose': 'förlora',
@ -273,6 +293,7 @@
'today': 'idag',
'tomorrow': 'imorgon',
'yesterday': 'igår',
'next': 'nästa',
},
'days':[
"måndag",
@ -302,7 +323,7 @@
'_language': 'Deutsch',
'and': 'und',
'in': 'in',
'ago': 'vor',
'ago': 'vor %s',
'now': 'jetzt',
'lose': 'Du verlierst',
'gain': 'Du gewinnst',
@ -363,7 +384,7 @@
'Juli',
'August',
'September',
'October',
'Oktober',
'November',
'Dezember',
]
@ -623,6 +644,8 @@
'today': "aujourd'hui",
'tomorrow': 'demain',
'yesterday': 'hier',
'next': 'prochain',
'last': 'dernier',
},
'days':[
"lundi",
@ -693,6 +716,8 @@
'today': 'hoy',
'tomorrow': 'mañana',
'yesterday': 'ayer',
'next': 'el próximo',
'last': 'el pasado',
},
'days':[
'lunes',
@ -711,12 +736,26 @@
'mayo',
'junio',
'julio',
'agosto'
'agosto',
'septiembre',
'octubre',
'noviembre',
'diciembre'
]
],
'time_of_hour':{
0: '{hour} en punto',
1: '{hour} y un minuto',
15: '{hour} y quarto',
30: '{hour} y media',
45: '{hour} menos quarto',
59: '{hour} menos uno',
'past_hour': '{hour} y {minute}',
'to_hour': '{hour} menos {minute}',
},
'time_of_day':{
'midnight': 'medianoche',
'noon': 'mediodía',
},
},
'it':{
'_language': 'Italiano',
@ -865,9 +904,9 @@
'and': 'i',
'in': 'u',
'ago': 'prije',
'now': 'sad',
'now': 'sada',
'lose': 'gubiš',
'gain': 'dobijaš',
'gain': 'dobivaš',
'time':{
'format': '24-hr',
'year': [
@ -905,8 +944,8 @@
'today': 'danas',
'tomorrow': 'sutra',
'yesterday': 'jučer',
'next': 'slijedeći',
'last': 'prošli',
'next': 'sljedeći',
'last': 'protekli',
},
'days':[
"Ponedjeljak",
@ -1003,11 +1042,421 @@
'Listopad',
'Grudzień',
]
},
'ru':{
'_language': 'Русский',
'and': 'и',
'in': 'в',
'ago': 'назад',
'now': 'сейчас',
'lose': 'уменьшение',
'gain': 'увеличение',
'time':{
'format': '24-hr',
'year': [
'г',
'год',
'лет',
],
'week': [
'нед',
'неделя',
'недель',
],
'day': [
'д',
'день',
'дней',
],
'hour': [
'ч',
'час',
'часов',
],
'minute': [
'мин',
'минута',
'минут',
],
'second': [
'сек',
'секунда',
'секунд',
],
},
'delta':{
'today': 'сегодня',
'tomorrow': 'завтра',
'yesterday': 'вчера',
'next': 'следующий',
'last': 'последний',
},
'days':[
"Понедельник",
"Вторник",
"Среда",
"Четверг",
"Пятница",
"Суббота",
"Воскресенье",
],
'months':[
'Январь',
'Февраль',
'Март',
'Апрель',
'Май',
'Июнь',
'Июль',
'Август',
'Сентябрь',
'Октябрь',
'Ноябрь',
'Декабрь',
],
'time_of_hour':{
0: '{hour} часов ровно',
1: '{hour} и 1 минута',
15: '{hour} с четвертью',
30: '{hour} с половиной',
45: 'без четверти {hour}',
59: 'без минуты {hour}',
'past_hour': '{hour} и {minute} минут',
'to_hour': 'без {minute} минут {hour}',
},
'time_of_day':{
'midnight': 'полночь',
'noon': 'полдень',
},
},
'uk':{
'_language': 'Українська',
'and': 'і',
'in': 'в',
'ago': 'тому',
'now': 'зараз',
'lose': 'зменшення',
'gain': 'збільшення',
'time':{
'format': '24-hr',
'year': [
'р',
'рік',
'роки',
],
'week': [
'тиж',
'тиждень',
'тижні',
],
'day': [
'д',
'день',
'дні',
],
'hour': [
'год',
'година',
'години',
],
'minute': [
'хв',
'хвилина',
'хвилини',
],
'second': [
'сек',
'секунда',
'секунди',
],
},
'delta':{
'today': 'сьогодні',
'tomorrow': 'завтра',
'yesterday': 'вчора',
'next': 'наступний',
'last': 'останній',
},
'days':[
"Понеділок",
"Вівторок",
"Середа",
"Четвер",
"П'ятниця",
"Субота",
"Неділя",
],
'months':[
'Січень',
'Лютий',
'Березень',
'Квітень',
'Травень',
'Червень',
'Липень',
'Серпень',
'Вересень',
'Жовтень',
'Листопад',
'Грудень',
],
'time_of_hour':{
0: '{hour} годин',
1: '{hour} годин(а) одна хвилина',
15: 'чверть на {hour}',
30: 'пів на {hour}',
45: 'за чверть {hour}',
59: 'за хвилину {hour}',
'past_hour': '{hour} та {minute} хвилин',
'to_hour': 'за {minute} хвилин {hour}',
},
'time_of_day':{
'midnight': 'опівночі',
'noon': 'опівдні',
},
},
'zh-Hans':{
'_language': '简体中文',
'and': '',
'in': '',
'ago': '之前',
'now': '现在',
'lose': '失去',
'gain': '获得',
'time':{
'format': '24-hr',
'year': [
'年',
'年',
'年',
],
'week': [
'周',
'星期',
'星期',
],
'day': [
'天',
'天',
'天',
],
'hour': [
'时',
'小时',
'小时',
],
'minute': [
'分',
'分钟',
'分钟',
],
'second': [
'秒',
'秒',
'秒',
],
},
'delta':{
'today': '今天',
'tomorrow': '明天',
'yesterday': '昨天',
'next': '下一个',
'last': '上一个',
},
'days':[
"星期一",
"星期二",
"星期三",
"星期四",
"星期五",
"星期六",
"星期日",
],
'months':[
'一月',
'二月',
'三月',
'四月',
'五月',
'六月',
'七月',
'八月',
'九月',
'十月',
'十一月',
'十二月',
],
'time_of_day':{
'midnight': '午夜',
'noon': '正午',
},
},
'ko':{
'_language':'Korean',
'and':'',
'in':'후',
'ago':'전',
'now':'지금',
'lose':'감소',
'gain':'증가',
'time':{
'format':'24-hr',
'year':[
'년',
'년',
'년',
],
'week':[
'주',
'주',
'주',
],
'day':[
'일',
'일',
'일',
],
'hour':[
'시',
'시간',
'시간',
],
'minute':[
'분',
'분',
'분',
],
'second':[
'초',
'초',
'초',
],
},
'delta':{
'today':'오늘',
'tomorrow':'내일',
'yesterday':'어제',
'next':'다음',
'last':'지난',
},
'days':[
'월요일',
'화요일',
'수요일',
'목요일',
'금요일',
'토요일',
'일요일',
],
'months':[
'1월',
'2월',
'3월',
'4월',
'5월',
'6월',
'7월',
'8월',
'9월',
'10월',
'11월',
'12월',
],
'time_of_day':{
'midnight':'자정',
'noon':'정오',
},
},
'cs': {
'_language': 'Čeština',
'and': 'a',
'in': 'za',
'ago': 'před %s',
'now': 'nyní',
'lose': 'ztratit',
'gain': 'získat',
'time': {
'format': '12-hodin',
'year': [
'rok',
'rok',
'roky'
],
'week': [
'týd',
'týden',
'týdny'
],
'day': [
'd',
'den',
'dny'
],
'hour': [
'hod',
'hodina',
'hodiny'
],
'minute': [
'min',
'minuta',
'minuty'
],
'second': [
'sek',
'sekunda',
'sekundy'
]
},
'delta': {
'today': 'dnes',
'tomorrow': 'zítra',
'yesterday': 'včera',
'next': 'příští',
'last': 'poslední'
},
'days': [
'Pondělí',
'Úterý',
'Středa',
'Čtvrtek',
'Pátek',
'Sobota',
'Neděle'
],
'months': [
'Leden',
'Únor',
'Březen',
'Duben',
'Květen',
'Červen',
'Červenec',
'Srpen',
'Září',
'Říjen',
'Listopad',
'Prosinec'
],
'time_of_hour': {
0: '{hour} hodin',
1: 'minuta po {hour}',
15: 'čtvrt na {hour}',
30: 'půl {hour}',
45: 'tři čtvrtě na {hour}',
59: 'minuta do {hour}',
'past_hour': '{minute} po {hour}',
'to_hour': '{minute} do {hour}'
},
'time_of_day': {
'midnight': 'půlnoc',
'noon': 'poledne'
}
}
} %}
{# DO NOT MODIFY BELOW THIS LINE #}
{% set valid_entity_id_pattern = '^(?!.+__)(?!_)[\\da-z_]+(?<!_)\\.(?!_)[\\da-z_]+(?<!_)$' %}
{% set _bad_value = '?' %}
{% set _durations = {
'year': 31536000,
@ -1091,10 +1540,10 @@
{%- endmacro -%}
{%- macro _check_for_duration_sensor(input) %}
{%- if input is string and input | regex_search('^(?!.+__)(?!_)[\da-z_]+(?<!_)\.(?!_)[\da-z_]+(?<!_)$') and input.startswith('sensor') and states[input] is not none and states[input].attributes.device_class is defined and states[input].attributes.unit_of_measurement is defined -%}
{%- if input is string and input | regex_search(valid_entity_id_pattern) and input.startswith('sensor') and states[input] is not none and states[input].attributes.device_class is defined and states[input].attributes.unit_of_measurement is defined -%}
{%- set obj = states[input] -%}
{%- set divisor = _duration_sensor.get(obj.attributes.unit_of_measurement) -%}
{{- (obj.state | float / divisor) | string | as_timedelta -}}
{%- set multiplier = _duration_sensor.get(obj.attributes.unit_of_measurement) -%}
{{- (obj.state | float * multiplier) | string | as_timedelta -}}
{%- else %}
{{- '' -}}
{%- endif -%}
@ -1116,7 +1565,7 @@
{#- assume time as string or entity_id -#}
{%- elif input is string and input not in ['', 'None'] -%}
{#- if entity_id -#}
{%- if input | regex_search('^(?!.+__)(?!_)[\da-z_]+(?<!_)\.(?!_)[\da-z_]+(?<!_)$') -%}
{%- if input | regex_search(valid_entity_id_pattern) -%}
{%- if attribute is not none and attribute is string -%}
{{- _to_datetime(state_attr(input, attribute), None) -}}
{%- elif input.startswith('input_datetime') and is_state_attr(input, 'has_date', False) -%}
@ -1201,7 +1650,7 @@
{%- set index = values.index(values | first | default) %}
{%- for item in values[index:] %}
{%- set duration = _durations.get(item, 1) %}
{%- set period = _periods.get(item, 1) %}
{%- set period = _periods.get(item, 0) %}
{%- set value = ((seconds // duration) % (period if period else duration)) | int %}
{%- if value > 0 or raw %}
{%- if ns.ret | length == 0 %}
@ -1252,8 +1701,8 @@
{%- endmacro %}
{%- macro _time_between(func, input1, attr1, utc1, input2, attr2, utc2) -%}
{%- set t1 = _to_datetime(input1, attr1, utc1) | as_datetime -%}
{%- set t2 = _to_datetime(input2, attr2, utc2) | as_datetime -%}
{%- set t1 = _to_datetime(input1, attr1, utc1) | as_datetime | as_local -%}
{%- set t2 = _to_datetime(input2, attr2, utc2) | as_datetime | as_local -%}
{%- if t1 is not none and t2 is not none -%}
{{- func(t1, t2) -}}
{%- else -%}
@ -1320,9 +1769,12 @@
{%- if uptime %}
{%- set value = _delta_seconds(now(), uptime) | int %}
{%- set seconds = value | abs %}
{%- set future = value / seconds > 0 %}
{%- set current = value == 0 %}
{%- set future = not current and value / seconds > 0 %}
{%- set items = _just_time(seconds, language, values, biggest, short=short, floor=floor) %}
{%- if future %}
{%- if current %}
{{- items }}
{%- elif future %}
{{- translate('in', language=language) }} {{ items }}
{%- else %}
{%- set t = translate('ago', language=language) %}
@ -1411,6 +1863,16 @@
{{- _next_weekday(weekday, -7) }}
{%- endmacro %}
{%- macro nearest_day(weekday) %}
{%- set today_timestamp = as_timestamp(today_at())|int %}
{%- set this_weekday_timestamp = as_timestamp(this_weekday(weekday))|int %}
{%- if today_timestamp < this_weekday_timestamp %}
{{- _next_weekday(weekday, 0) }}
{%- else %}
{{- _next_weekday(weekday, 7) }}
{%- endif %}
{%- endmacro %}
{%- macro days_in_month(month=None) %}
{%- set today = today_at() %}
{%- set input = month if month is not none else today.month %}
@ -1527,30 +1989,36 @@
{%- endif -%}
{%- endmacro -%}
{%- macro month(month=None, language=None) %}
{%- macro month(month=None, language=None, short=False) %}
{%- if month is datetime %}
{%- set idx = month.month - 1 %}
{%- elif month is integer and month > 0 %}
{%- set idx = (month - 1) % 12 %}
{%- elif month | regex_match(valid_entity_id_pattern) %}
{%- set idx = (states(month) | as_datetime | as_local).month - 1 %}
{%- else %}
{%- set idx = now().month - 1 %}
{%- endif %}
{{- translate('months', index=idx, language=language) }}
{%- set ret = translate('months', index=idx, language=language) %}
{{- ret[:3] if short else ret }}
{%- endmacro %}
{%- macro weekday(weekday=None, language=None) %}
{%- macro weekday(weekday=None, language=None, short=False) %}
{%- if weekday is datetime %}
{%- set idx = weekday.weekday() %}
{%- elif weekday is integer and weekday > 0 %}
{%- set idx = (weekday - 1) % 7 %}
{%- elif weekday | regex_match(valid_entity_id_pattern) %}
{%- set idx = (states(weekday) | as_datetime | as_local).weekday() %}
{%- else %}
{%- set idx = now().weekday() %}
{%- endif %}
{{- translate('days', index=idx, language=language) }}
{%- set ret = translate('days', index=idx, language=language) %}
{{- ret[:3] if short else ret }}
{%- endmacro %}
{%- macro count_the_days(input, attr, utc=False) %}
{%- set input = _to_datetime(input, attr, utc) | as_datetime %}
{%- set input = _to_datetime(input, attr, utc) | as_datetime | as_local %}
{%- set midnight = today_at() %}
{{- (input - midnight).days }}
{%- endmacro %}
@ -1561,7 +2029,7 @@
{%- set ns = namespace(days=[]) %}
{%- for i in range(-7, 14) %}
{%- set prefix = translate('delta', 'last', language=language) ~ ' ' if i < -1 else translate('delta', 'next', language=language) ~ ' ' if i > 6 else '' %}
{%- set ns.days = ns.days + [ (i | string, prefix ~ _days.get(i, weekday(midnight.weekday() + i + 1, language))) ] %}
{%- set ns.days = ns.days + [ (i | string, prefix ~ _days.get(i, weekday(midnight.weekday() + (i % 7) + 1, language))) ] %}
{%- endfor %}
{%- set collection = dict.from_keys(ns.days) %}
{%- set days = count_the_days(input, attr, utc) %}
@ -1586,16 +2054,20 @@
{%- macro hour(hour, language=None) %}
{%- if hour is datetime %}
{%- set hour = hour.hour %}
{%- elif hour | regex_match(valid_entity_id_pattern) %}
{%- set hour = (states(hour) | as_datetime | as_local).hour %}
{%- endif %}
{%- set _12 = not (hour % 12) %}
{%- set _24 = not (hour % 24) %}
{%- set _12hr = translate('time','format') == '12-hr' %}
{%- if _12 and _24 and _12hr %}
{%- set use_twelve = translate('time_of_day', 'use_twelve', language=language, fallback=false) %}
{%- set _12hr = translate('time','format', language=language) == '12-hr' %}
{%- if _12 and _24 and _12hr and not use_twelve %}
{{- translate('time_of_day', 'midnight', language=language) }}
{%- elif _12 and _12hr %}
{%- elif _12 and _12hr and not use_twelve %}
{{- translate('time_of_day', 'noon', language=language) }}
{%- else %}
{{- hour % 12 if _12hr else hour }}
{%- set ret = hour % 12 if _12hr else hour %}
{{- 12 if ret == 0 and use_twelve else ret }}
{%- endif %}
{%- endmacro %}
@ -1617,7 +2089,22 @@
{%- set hour_phrase = hour(this_hour, language=language) %}
{%- set minute_phrase = _phrase('minute', 60 * this_minute, language, True, True) if this_minute % 5 else this_minute | string %}
{%- endif %}
{%- if this_minute in [0, 1, 15, 30, 45, 59] %}
{%- set this_config = translate('time_of_hour', language=language) %}
{%- if (16 <= this_minute <= 29 and 'to_half_hour' in this_config) or (31 <= this_minute <= 44 and 'past_half_hour' in this_config) or (this_minute == 30 and 'half_hour' in this_config) %}
{%- set hour_phrase = hour(this_hour + 1, language=language) %}
{%- if 16 <= this_minute <= 29 %}
{%- set minute_calc = 30 - this_minute %}
{%- set fmat = translate('time_of_hour', 'to_half_hour', language=language) %}
{%- set minute_phrase = _phrase('minute', 60 * minute_calc, language, True, True) if this_minute % 5 else minute_calc | string %}
{%- elif 31 <= this_minute <= 44 %}
{%- set minute_calc = this_minute - 30 %}
{%- set fmat = translate('time_of_hour', 'past_half_hour', language=language) %}
{%- set minute_phrase = _phrase('minute', 60 * minute_calc, language, True, True) if this_minute % 5 else minute_calc | string %}
{%- else %}
{%- set minute_calc = None %}
{%- set fmat = translate('time_of_hour', 'half_hour', language=language) %}
{%- endif %}
{%- elif this_minute in [0, 1, 15, 30, 45, 59] %}
{%- if hour_phrase in ['noon', 'midnight'] and this_minute == 0 %}
{%- set fmat = '{hour}' %}
{%- else %}

View File

@ -1,234 +1,342 @@
{#
set phrases to be used in the relative_time_period macro
one list item per language, each time fraction contains a list with the singular, plural and abbriviated phrase
set phrases to be used in the relative_time_period macro
one list item per language, each time fraction contains a list with the short and several long forms of time units
combine contains the text to combine the last time fraction, and error the text to display on wrong date input
Plural forms for languages: https://www.gnu.org/software/gettext/manual/gettext.html#Plural-forms
asian: ja, vi, ko
english: en, de, nl, sv, da, no, nb, nn, fo, es, pt, it, bg, el, fi, et, he, eo, hu, tr, ca
french: pt_BR, fr
latvian: lv
irish: ga
romanian: ro
lithuanian: lv
russian: ru, uk, be, sr, hr
slovak: cs, sk
polish: pl
slovenian: sl
arabic: ar
#}
{%- set _time_period_phrases = [
{
'language': 'en',
'plural_form': 'english',
'phrases': {
'year': ['year', 'years', 'yr'],
'month': ['month', 'months', 'mth'],
'week': ['week', 'weeks', 'wk'],
'day': ['day', 'days', 'day'],
'hour': ['hour', 'hours', 'hr'],
'minute': ['minute', 'minutes', 'min'],
'second': ['second', 'seconds', 'sec'],
'millisecond': ['millisecond', 'milliseconds', 'ms'],
'year': ['yr', 'year', 'years'],
'month': ['mth', 'month', 'months'],
'week': ['wk', 'week', 'weeks'],
'day': ['day', 'day', 'days'],
'hour': ['hr', 'hour', 'hours'],
'minute': ['min', 'minute', 'minutes'],
'second': ['sec', 'second', 'seconds'],
'millisecond': ['ms', 'millisecond', 'milliseconds'],
'combine': 'and',
'error': 'Invalid date',
}
},
{
'language': 'pl',
'plural_form': 'polish',
'phrases': {
'year': ['rok', 'lat', 'r'],
'month': ['miesiąc', 'miesięcy', 'msc'],
'week': ['tydzień', 'tygodni', 'tyg'],
'day': ['dzień', 'dni', 'dzień'],
'hour': ['godzina', 'godzin', 'godz'],
'minute': ['minuta', 'minut', 'min'],
'second': ['sekunda', 'sekund', 'sek'],
'millisecond': ['milisekunda', 'milisekund', 'ms'],
'year': ['r', 'rok', 'lata', 'lat'],
'month': ['msc', 'miesiąc', 'miesiące', 'miesięcy'],
'week': ['tyg', 'tydzień', 'tygodnie', 'tygodni'],
'day': ['dzień', 'dzień', 'dni', 'dni'],
'hour': ['godz', 'godzina', 'godziny', 'godzin'],
'minute': ['min', 'minuta', 'minuty', 'minut'],
'second': ['sek', 'sekunda', 'sekundy', 'sekund'],
'millisecond': ['ms', 'milisekunda', 'milisekundy', 'milisekund'],
'combine': 'i',
'error': 'Niepoprawna data',
}
},
{
'language': 'fr',
'plural_form': 'french',
'phrases': {
'year': ['année', 'années', 'an'],
'year': ['an', 'année', 'années'],
'month': ['mois', 'mois', 'mois'],
'week': ['semaine', 'semaines', 'sem'],
'day': ['jour', 'jours', 'j'],
'hour': ['heure', 'heures', 'h'],
'minute': ['minute', 'minutes', 'min'],
'second': ['seconde', 'secondes', 'sec'],
'millisecond': ['milliseconde', 'millisecondes', 'ms'],
'week': ['sem', 'semaine', 'semaines'],
'day': ['j', 'jour', 'jours'],
'hour': ['h', 'heure', 'heures'],
'minute': ['min', 'minute', 'minutes'],
'second': ['sec', 'seconde', 'secondes'],
'millisecond': ['ms', 'milliseconde', 'millisecondes'],
'combine': 'et',
'error': 'Date non valide',
}
},
{
'language': 'it',
'plural_form': 'english',
'phrases': {
'year': ['anno', 'anni', 'aa'],
'month': ['mese', 'mesi', 'mm'],
'week': ['settimana', 'settimane', 'set'],
'day': ['giorno', 'giorni', 'gg'],
'hour': ['ora', 'ore', 'h'],
'minute': ['minuto', 'minuti', 'min'],
'second': ['secondo', 'secondi', 'sec'],
'millisecond': ['millisecondo', 'millisecondi', 'ms'],
'year': ['aa', 'anno', 'anni'],
'month': ['mm', 'mese', 'mesi'],
'week': ['set', 'settimana', 'settimane'],
'day': ['gg', 'giorno', 'giorni'],
'hour': ['h', 'ora', 'ore'],
'minute': ['min', 'minuto', 'minuti'],
'second': ['sec', 'secondo', 'secondi'],
'millisecond': ['ms', 'millisecondo', 'millisecondi'],
'combine': 'e',
'error': 'Data non valida',
}
},
{
'language': 'nb',
'plural_form': 'english',
'phrases': {
'year': ['år', 'år', 'år'],
'month': ['måned', 'måneder', 'mnd'],
'week': ['uke', 'uker', 'u'],
'day': ['dag', 'dager', 'd'],
'hour': ['time', 'timer', 't'],
'minute': ['minutt', 'minutter', 'min'],
'second': ['sekund', 'sekunder', 'sek'],
'millisecond': ['millisekund', 'millisekunder', 'ms'],
'month': ['mnd', 'måned', 'måneder'],
'week': ['u', 'uke', 'uker'],
'day': ['d', 'dag', 'dager'],
'hour': ['t', 'time', 'timer'],
'minute': ['min', 'minutt', 'minutter'],
'second': ['sek', 'sekund', 'sekunder'],
'millisecond': ['ms', 'millisekund', 'millisekunder'],
'combine': 'og',
'error': 'Ugyldig dato',
}
},
{
'language': 'nl',
'plural_form': 'english',
'phrases': {
'year': ['jaar', 'jaar', 'jr'],
'month': ['maand', 'maanden', 'mnd'],
'week': ['week', 'weken', 'wk'],
'day': ['dag', 'dagen', 'dg'],
'hour': ['uur', 'uur', 'u'],
'minute': ['minuut', 'minuten', 'min'],
'second': ['seconde', 'seconden', 'sec'],
'millisecond': ['milliseconde', 'milliseconden', 'ms'],
'year': ['jr', 'jaar', 'jaar'],
'month': ['mnd', 'maand', 'maanden'],
'week': ['wk', 'week', 'weken'],
'day': ['dg', 'dag', 'dagen'],
'hour': ['u', 'uur', 'uur'],
'minute': ['min', 'minuut', 'minuten'],
'second': ['sec', 'seconde', 'seconden'],
'millisecond': ['ms', 'milliseconde', 'milliseconden'],
'combine': 'en',
'error': 'Ongeldige datum',
}
},
{
'language': 'nn',
'plural_form': 'english',
'phrases': {
'year': ['år', 'år', 'år'],
'month': ['månad', 'månader', 'mnd'],
'week': ['veke', 'veker', 'v'],
'day': ['dag', 'dagar', 'd'],
'hour': ['time', 'timar', 't'],
'minute': ['minutt', 'minutt', 'min'],
'second': ['sekund', 'sekund', 'sek'],
'millisecond': ['millisekund', 'millisekund', 'ms'],
'month': ['mnd', 'månad', 'månader'],
'week': ['v', 'veke', 'veker'],
'day': ['d', 'dag', 'dagar'],
'hour': ['t', 'time', 'timar'],
'minute': ['min', 'minutt', 'minutt'],
'second': ['sek', 'sekund', 'sekund'],
'millisecond': ['ms', 'millisekund', 'millisekund'],
'combine': 'og',
'error': 'Ugyldig dato',
}
},
{
'language': 'de',
'plural_form': 'english',
'phrases': {
'year': ['Jahr', 'Jahre', 'J.'],
'month': ['Monat', 'Monate', 'M.'],
'week': ['Woche', 'Wochen', 'Wo.'],
'day': ['Tag', 'Tage', 'Tg.'],
'hour': ['Stunde', 'Stunden', 'Std.'],
'minute': ['Minute', 'Minuten', 'Min.'],
'second': ['Sekunde', 'Sekunden', 'Sek.'],
'millisecond': ['Millisekunde', 'Millisekunden', 'ms'],
'year': ['J.', 'Jahr', 'Jahre'],
'month': ['M.', 'Monat', 'Monate'],
'week': ['Wo.', 'Woche', 'Wochen'],
'day': ['Tg.', 'Tag', 'Tage'],
'hour': ['Std.', 'Stunde', 'Stunden'],
'minute': ['Min.', 'Minute', 'Minuten'],
'second': ['Sek.', 'Sekunde', 'Sekunden'],
'millisecond': ['ms', 'Millisekunde', 'Millisekunden'],
'combine': 'und',
'error': 'Falsches Datum',
}
},
{
'language': 'pt',
'plural_form': 'english',
'phrases': {
'year': ['ano', 'anos', 'aa'],
'month': ['mês', 'meses', 'mm'],
'week': ['semana', 'semanas', 'sem'],
'day': ['dia', 'dias', 'd'],
'hour': ['hora', 'horas', 'h'],
'minute': ['minuto', 'minutos', 'min'],
'second': ['segundo', 'segundos', 'seg'],
'millisecond': ['millissegundo', 'millissegundos', 'ms'],
'year': ['aa', 'ano', 'anos'],
'month': ['mm', 'mês', 'meses'],
'week': ['sem', 'semana', 'semanas'],
'day': ['d', 'dia', 'dias'],
'hour': ['h', 'hora', 'horas'],
'minute': ['min', 'minuto', 'minutos'],
'second': ['seg', 'segundo', 'segundos'],
'millisecond': ['ms', 'millissegundo', 'millissegundos'],
'combine': 'e',
'error': 'Data Inválida',
}
},
{
'language': 'dk',
'plural_form': 'english',
'phrases': {
'year': ['år', 'år', 'år'],
'month': ['måned', 'måneder', 'mnd'],
'week': ['uge', 'uger', 'uge'],
'day': ['dag', 'dage', 'dag'],
'hour': ['time', 'timer', 't.'],
'minute': ['minut', 'minuter', 'min.'],
'second': ['sekund', 'sekunder', 'sek.'],
'millisecond': ['millisekund', 'millisekunder', 'ms.'],
'month': ['mnd', 'måned', 'måneder'],
'week': ['uge', 'uge', 'uger'],
'day': ['dag', 'dag', 'dage'],
'hour': ['t.', 'time', 'timer'],
'minute': ['min.', 'minut', 'minuter'],
'second': ['sek.', 'sekund', 'sekunder'],
'millisecond': ['ms.', 'millisekund', 'millisekunder'],
'combine': 'og',
'error': 'Ugyldig dato',
}
},
{
'language': 'sv',
'plural_form': 'english',
'phrases': {
'year': ['år', 'år', 'år'],
'month': ['månad', 'månader', 'mån'],
'week': ['vecka', 'veckor', 'v'],
'day': ['dag', 'dagar', 'dag'],
'hour': ['timme', 'timmar', 'tim'],
'minute': ['minut', 'minuter', 'min'],
'second': ['sekund', 'sekunder', 'sek'],
'millisecond': ['millisekund', 'millisekunder', 'ms'],
'month': ['mån', 'månad', 'månader'],
'week': ['v', 'vecka', 'veckor'],
'day': ['dag', 'dag', 'dagar'],
'hour': ['tim', 'timme', 'timmar'],
'minute': ['min', 'minut', 'minuter'],
'second': ['sek', 'sekund', 'sekunder'],
'millisecond': ['ms', 'millisekund', 'millisekunder'],
'combine': 'och',
'error': 'Ogiltigt datum',
}
},
{
'language': 'cs',
'plural_form': 'slovak',
'phrases': {
'year': ['rok', 'roky', 'rok'],
'month': ['měsíc', 'měsíce', 'měs'],
'week': ['týden', 'týdny', 'týd'],
'day': ['den', 'dny', 'd'],
'hour': ['hodina', 'hodiny', 'hod'],
'minute': ['minuta', 'minuty', 'min'],
'second': ['sekunda', 'sekundy', 'sek'],
'millisecond': ['millisekunda', 'millisekundy', 'ms'],
'year': ['rok', 'rok', 'roky', 'let'],
'month': ['měs', 'měsíc', 'měsíce', 'měsíců'],
'week': ['týd', 'týden', 'týdny', 'týd'],
'day': ['d', 'den', 'dny', 'd'],
'hour': ['hod', 'hodina', 'hodiny', 'hodin'],
'minute': ['min', 'minuta', 'minuty', 'minut'],
'second': ['sek', 'sekunda', 'sekundy', 'sekund'],
'millisecond': ['ms', 'millisekunda', 'millisekundy', 'millisekund'],
'combine': 'a',
'error': 'špatný datum'
'error': 'špatné datum'
}
},
{
'language': 'fi',
'plural_form': 'english',
'phrases': {
'year': ['vuosi', 'vuotta', 'v'],
'month': ['kuukausi', 'kuukautta', 'kk'],
'week': ['viikko', 'viikkoa', 'vk'],
'day': ['päivä', 'päivää', 'pv'],
'hour': ['tunti', 'tuntia', 't'],
'minute': ['minuutti', 'minuuttia', 'min'],
'second': ['sekunti', 'sekuntia', 's'],
'millisecond': ['millisekunti', 'millisekuntia', 'ms'],
'year': ['v', 'vuosi', 'vuotta'],
'month': ['kk', 'kuukausi', 'kuukautta'],
'week': ['vk', 'viikko', 'viikkoa'],
'day': ['pv', 'päivä', 'päivää'],
'hour': ['t', 'tunti', 'tuntia'],
'minute': ['min', 'minuutti', 'minuuttia'],
'second': ['s', 'sekunti', 'sekuntia'],
'millisecond': ['ms', 'millisekunti', 'millisekuntia'],
'combine': 'ja',
'error': 'Väärä päivämäärä',
}
},
{
'language': 'ru',
'plural_form': 'russian',
'phrases': {
'year': ['год', 'года', 'г'],
'month': ['месяц', 'месяцы', 'м'],
'week': ['неделя', 'недели', 'н'],
'day': ['день', 'дни', 'д'],
'hour': ['час', 'часы', 'ч'],
'minute': ['минута', 'минут', 'м'],
'second': ['секунд', 'секунды', 'с'],
'millisecond': ['милисекунд', 'милисекунды', 'мс'],
'year': ['г', 'год', 'года', 'лет'],
'month': ['м', 'месяц', 'месяца', 'месяцев'],
'week': ['н', 'неделя', 'недели', 'недель'],
'day': ['д', 'день', 'дня', 'дней'],
'hour': ['ч', 'час', 'часа', 'часов'],
'minute': ['м', 'минута', 'минуты', 'минут'],
'second': ['с', 'секунда', 'секунды', 'секунд'],
'millisecond': ['мс', 'милисекунда', 'милисекунды', 'милисекунд'],
'combine': 'и',
'error': 'Неверная дата',
}
},
{
'language': 'uk',
'plural_form': 'russian',
'phrases': {
'year': ['рік', 'років', 'р'],
'month': ['місяць', 'місяців', 'м'],
'week': ['тиждень', 'тижнів', 'тижд'],
'day': ['день', 'днів', 'дн'],
'hour': ['годину', 'годин', 'год'],
'minute': ['хвилину', 'хвилин', 'хв'],
'second': ['секунду', 'секунд', 'сек'],
'millisecond': ['мілісекунду', 'мілісекунд', 'мсек'],
'year': ['р', 'рік', 'роки', 'років'],
'month': ['м', 'місяць', 'місяці', 'місяців'],
'week': ['тижд', 'тиждень', 'тижні', 'тижнів'],
'day': ['дн', 'день', 'дні', 'днів'],
'hour': ['год', 'година', 'години', 'годин'],
'minute': ['хв', 'хвилина', 'хвилини', 'хвилин'],
'second': ['сек', 'секунда', 'секунди', 'секунд'],
'millisecond': ['мсек', 'мілісекунда', 'мілісекунди', 'мілісекунд'],
'combine': 'та',
'error': 'Недійсна дата',
}
},
{
'language': 'bg',
'plural_form': 'english',
'phrases': {
'year': ['г', 'година', 'години'],
'month': ['м', 'месец', 'месеца'],
'week': ['седм', 'седмица', 'седмици'],
'day': ['д', 'ден', 'дни'],
'hour': ['ч', 'час', 'часа'],
'minute': ['м', 'минута', 'минути'],
'second': ['с', 'секунда', 'секунди'],
'millisecond': ['мс', 'милисекунда', 'милисекунди'],
'combine': 'и',
'error': 'Невалидна дата',
}
},
{
'language': 'vi',
'plural_form': 'asian',
'phrases': {
'year': ['y', 'năm'],
'month': ['m', 'tháng'],
'week': ['w', 'tuần'],
'day': ['d', 'ngày'],
'hour': ['h', 'giờ'],
'minute': ['m', 'phút', 'phút'],
'second': ['s', 'giây'],
'millisecond': ['ms', 'mili giây'],
'combine': 'và',
'error': 'Ngày không hợp lệ',
}
},
{
'language': 'es',
'plural_form': 'english',
'phrases': {
'year': ['a', 'año', 'años'],
'month': ['m', 'mes', 'meses'],
'week': ['sem', 'semana', 'semanas'],
'day': ['d', 'día', 'días'],
'hour': ['h', 'hora', 'horas'],
'minute': ['min', 'minuto', 'minutos'],
'second': ['s', 'segundo', 'segundos'],
'millisecond': ['ms', 'milisegundo', 'milisegundos'],
'combine': 'y',
'error': 'Fecha inválida',
}
},
{
'language': 'he',
'plural_form': 'english',
'phrases': {
'year': ['שנה', 'שנה', 'שנים'],
'month': ['חודש', 'חודש', 'חודשים'],
'week': ['שבוע', 'שבוע', 'שבועות'],
'day': ['יום', 'יום', 'ימים'],
'hour': ['שעה', 'שעה', 'שעות'],
'minute': ['דקה', 'דקה', 'דקות'],
'second': ['שניה', 'שניה', 'שניות'],
'millisecond': ['מילי', 'מילישניה', 'מילישניות'],
'combine': 'ו',
'error': 'תאריך לא חוקי',
}
},
{
'language': 'hu',
'plural_form': 'english',
'phrases': {
'year': ['é', 'év', 'év'],
'month': ['hó', 'hónap', 'hónap'],
'week': ['hét', 'hét', 'hét'],
'day': ['n', 'nap', 'nap'],
'hour': ['ó', 'óra', 'óra'],
'minute': ['p', 'perc', 'perc'],
'second': ['mp', 'másodperc', 'másodperc'],
'millisecond': ['ms', 'ezredmásodperc', 'ezredmásodperc'],
'combine': 'és',
'error': 'Érvénytelen dátum',
}
},
] -%}
{# macro to convert the abbreviated input for the not_use and always_show lists to the full time part names #}
@ -255,12 +363,14 @@
{%- set date = date if date is datetime else date | as_datetime('invalid') -%}
{%- set compare_date = compare_date if compare_date is datetime else compare_date | as_datetime('invalid') -%}
{%- set time = time | bool(true) -%}
{%- set parts = [parts | int(1), always_show | count] | max -%}
{%- set parts = [parts | int(1), always_show | count] | max -%}
{# create namespace to store debug data #}
{%- set debug = namespace(debug="") -%}
{# 1: check if date input is correct #}
{%- if date is datetime and compare_date is datetime -%}
{# convert date input to local or date only #}
{%- set date = date | as_local if time else (date | as_local).date() -%}
{%- set compare_date = compare_date | as_local if time else (compare_date | as_local).date() -%}
{%- set compare_date = compare_date | as_local if time else (compare_date | as_local).date() -%}
{# determine highest and lowest date #}
{%- set date_max = [compare_date, date] | max -%}
{%- set date_min = [compare_date, date] | min -%}
@ -282,7 +392,7 @@
{%- if not not_use in [['millisecond'], []] -%}
{%- set not_use = _abbr_to_full(not_use) | from_json -%}
{%- endif -%}
{%- set not_use = not_use + ['hour', 'minute', 'second', 'millisecond' ] if not time else not_use -%}
{%- set not_use = not_use + ['hour', 'minute', 'second', 'millisecond' ] if not time else not_use -%}
{%- if always_show in [['all'], 'all'] -%}
{%- set always_show = dur.keys() | list -%}
{%- elif always_show != [] -%}
@ -296,7 +406,7 @@
{%- if do_use and ms < dur[do_use|last] -%}
{{- {do_use | last: (ms / dur[do_use|last]) | round(0, round_mode)} | to_json -}}
{%- else -%}
{# check if it is needed to determine years #}
{# check if it is needed to determine years #}
{%- if ms >= dur.day * 365 -%}
{#- set numer of years, and set highest date using this number of years #}
{%- set yrs = date_max.year - date_min.year - (1 if date_max.replace(year=date_min.year) < date_min else 0) -%}
@ -305,7 +415,7 @@
{%- set ms_yrs = ms -%}
{%- endif -%}
{%- set yrs = yrs | default(0) -%}
{# check if it is needed to determine months #}
{# check if it is needed to determine months #}
{%- set check_mth =
ms >= dur.day * 28
and 'month' in do_use
@ -354,7 +464,7 @@
{%- set first = keys | select('in', always_show | default([], true) + [first]) | first -%}
{%- set to_use = keys[keys.index(first):] -%}
{%- set to_output = to_use[:parts] -%}
{%- set last = to_output | last |default('millisecond') -%}
{%- set last = dur.items() | selectattr('0', 'in', to_output) | map(attribute='0') | list | last | default('millisecond') -%}
{# 3: check if there is anything left to use #}
{%- if to_use -%}
{%- set to_output = to_use[:parts] -%}
@ -365,9 +475,10 @@
{%- set to_reject = to_use | reject('in', to_output) | reject('in', always_show) | list -%}
{%- set not_use = not_use + to_output[as_check*-1:] + to_reject -%}
{%- set to_output = to_output | reject('in', not_use) | list + always_show -%}
{%- set to_output = keys | select('in', to_output) | list -%}
{%- set to_output = keys | select('in', to_output) | list + ['extra']-%}
{%- set output = time_split(date, parts, compare_date, not_use, always_show, time, round_mode) | from_json -%}
{%- endif -%}
{# apply round if needed #}
{%- if round_mode in ['common', 'ceil'] and last != 'millisecond' -%}
{# determine first and last item with data #}
@ -376,22 +487,59 @@
{%- set remain_part = remain / dur[last] -%}
{%- set to_round = 1 if remain_part >= 0.5 and round_mode == 'common' else remain_part | round(0, round_mode) -%}
{%- set sec_to_add = ((dur[last] + (dur.day if last in ['year', 'month'] else 1) - remain) | round(0, 'ceil') * to_round) / 1000 -%}
{%- set round_mode = 'floor' -%}
{%- set date_max = [compare_date, date] | max + timedelta(seconds=sec_to_add) -%}
{%- set date_min = [compare_date, date] | min -%}
{%- set output = time_split(date_max, parts, date_min, not_use, always_show, time, round_mode) | from_json -%}
{%- set output = time_split(date_max, parts, date_min, not_use, always_show, time, 'floor') | from_json -%}
{%- set output = dict(output.items() | selectattr('0', 'in', do_use)) -%}
{%- set keys = output.keys() | list -%}
{%- set with_value = output.items() | rejectattr('1', 'eq', 0) | map(attribute='0') | list -%}
{%- set first = with_value | first | default('millisecond') -%}
{%- set first = keys | select('in', always_show | default([], true) + [first]) | first -%}
{%- set to_use = keys[keys.index(first):] -%}
{%- set to_output = to_use[:parts] -%}
{%- endif -%}
{# output result #}
{%- set zero_values = output.items() | selectattr('1', 'eq', 0) | map(attribute='0') | list -%}
{%- set reject_list = zero_values | reject('in', always_show) | list -%}
{{- dict(output.items() | selectattr('0', 'in', to_output) | rejectattr('0', 'in', reject_list)) | default({always_return: 0}, true) | to_json -}}
{%- else -%} {{- dict(error='No time parts left to output') | to_json -}}
{{- dict(output.items() | selectattr('0', 'in', to_output) | rejectattr('0', 'in', reject_list), **dict(debug=debug.debug) if debug.debug else dict()) | default({always_return: 0}, true) | to_json-}}
{%- else -%} {{- dict(error='No time parts left to output') -}}
{%- endif -%} {# 3 #}
{%- endif -%} {# 2 #}
{%- else -%} {{- dict(error='Invalid date input') | to_json -}}
{%- endif -%} {# 2 #}
{%- else -%} {{- dict(error='Invalid date input')-}}
{%- endif -%} {# 1 #}
{%- endmacro -%}
{# macro for determining the time unit variant depending on the language #}
{%- macro plural(number=0, rule='english') -%}
{%- set mod100 = number % 100 -%}
{%- set mod10 = number % 10 -%}
{%- set form = 1 -%}
{%- if rule == 'english' -%}
{%- set form = 1 if number == 1 else 2 -%}
{%- elif rule == 'french' -%}
{%- set form = 1 if number <= 1 else 2 -%}
{%- elif rule == 'latvian' -%}
{%- set form = 1 if (mod10 == 1 and mod100 != 11) else 2 if number != 0 else 3 -%}
{%- elif rule == 'irish' -%}
{%- set form = 1 if number == 1 else 2 if number == 2 else 3 -%}
{%- elif rule == 'romanian' -%}
{%- set form = 1 if number == 1 else 2 if (number == 0 or (mod100 > 0 and mod100 < 20 )) else 3 -%}
{%- elif rule == 'lithuanian' -%}
{%- set form = 1 if (mod10 == 1 and mod100 != 11) else 2 if (mod10 >= 2 and (mod100 < 10 or mod100 >= 20)) else 3 -%}
{%- elif rule == 'russian' -%}
{%- set form = 1 if (mod10 == 1 and mod100 != 11) else 2 if (mod10 >= 2 and mod10 <= 4 and (mod100 < 10 or mod100 >= 20)) else 3 -%}
{%- elif rule == 'slovak' -%}
{%- set form = 1 if number == 1 else 2 if (number >= 2 and number <= 4) else 3 -%}
{%- elif rule == 'polish' -%}
{%- set form = 1 if number == 1 else 2 if (mod10 >= 2 and mod10 <= 4 and (mod100 < 10 or mod100 >= 20)) else 3 -%}
{%- elif rule == 'slovenian' -%}
{%- set form = 1 if mod100 == 1 else 2 if mod100 == 2 else 3 if (mod100 == 3 or mod100 == 4) else 4 -%}
{%- elif rule == 'arabic' -%}
{%- set form = 1 if number == 0 else 2 if number == 1 else 3 if number == 2 else 4 if (mod100 >= 3 and mod100 <= 10) else 5 if mod100 >= 11 else 6 -%}
{%- endif -%}
{{- form -}}
{%- endmacro -%}
{# macro to output a timedelta in a readable format #}
{%- macro relative_time_plus(date, parts=1, abbr=false, language='en', compare_date=now(), not_use=['millisecond'], always_show=[], time=true, round_mode='floor') -%}
{#- select correct phrases bases on language input #}
@ -399,6 +547,7 @@
{%- set languages = phrases | map(attribute='language') | list -%}
{%- set language = iif(language in languages, language, 'en') -%}
{%- set phr = phrases | selectattr('language', 'eq', language) | map(attribute='phrases') | list | first -%}
{%- set plural_form = phrases | selectattr('language', 'eq', language) | map(attribute='plural_form') | list | first -%}
{%- set abbr = abbr | bool(false) -%}
{# split timedelta #}
{%- set time_parts = time_split(date, parts, compare_date, not_use, always_show, time, round_mode) | from_json -%}
@ -409,9 +558,9 @@
{# convert to phrases #}
{%- set ns = namespace(phrases=[]) -%}
{%- for i in time_parts.keys() -%}
{%- set phr_abbr = phr[i][2] -%}
{%- set phr_verb = phr[i][1] if time_parts[i] != 1 else phr[i][0] -%}
{%- set phrase = '{} {}'.format(time_parts[i], phr_abbr if abbr else phr_verb) -%}
{%- set plural_variant = plural(time_parts[i], plural_form) | int -%}
{%- set phr_form = phr[i][0] if abbr else phr[i][plural_variant] -%}
{%- set phrase = '{} {}'.format(time_parts[i], phr_form) -%}
{%- set ns.phrases = ns.phrases + [phrase] -%}
{%- endfor -%}
{#- join phrases in a string, using phr.combine for the last item #}

11
packages/dashboards.yaml Normal file
View File

@ -0,0 +1,11 @@
template:
- trigger:
- trigger: event
event_type: bubble_card_update_modules
sensor:
- name: "Bubble Card Modules"
state: "saved"
icon: "mdi:puzzle"
attributes:
modules: "{{ trigger.event.data.modules }}"
last_updated: "{{ trigger.event.data.last_updated }}"

View File

@ -600,20 +600,25 @@ script:
data:
time: >
{% set low = states('sensor.overnight_lowest_temperature') | int %}
{% set high = states('sensor.todays_high_temp') | int %}
{% set kallen_bedtime = state_attr('input_datetime.kallen_bedtime','timestamp') | int %}
{% set cutoff = 81000 %}
{% if is_state('input_boolean.hot_day','on') and is_state('binary_sensor.kallen_school_tomorrow','on') %}
{{ (kallen_bedtime - 3600) | timestamp_custom('%H:%M',false) }}
{% elif is_state('input_boolean.hot_day','on') and is_state('binary_sensor.kallen_school_tomorrow','off') %}
{{ kallen_bedtime | timestamp_custom('%H:%M',false) }}
{% elif 56 <= low <= 60 %}
22:30
{% elif low > 60 %}
{% set cutoff = 81000 %} {# Cutoff time is 22:30 #}
{% if is_state('binary_sensor.kallen_school_tomorrow','on') %}
{% if is_state('input_boolean.hot_day','on') %}
{{ (kallen_bedtime - 3600) | timestamp_custom('%H:%M',false) }}
{% elif low >= 56 or high >= 75 %}
{{ (kallen_bedtime - 1800) | timestamp_custom('%H:%M',false) }}
{% else %}
{{ kallen_bedtime | timestamp_custom('%H:%M',false) }}
{% endif %}
{% elif low > 60 or high > 74 %}
{% if kallen_bedtime < cutoff %}
{{ kallen_bedtime | timestamp_custom('%H:%M',false) }}
{% else %}
21:30
22:00
{% endif %}
{% elif 56 <= low <= 60 %}
22:30
{% else %}
00:00
{% endif %}
@ -624,11 +629,11 @@ script:
{% set low = states('sensor.overnight_lowest_temperature') | int %}
{% set high = states('sensor.todays_high_temp') | int %}
{% if low > 60 or is_state('input_boolean.hot_day','on') %}
00:00
{% elif 50 <= low <= 60 %}
01:00
{% elif low >= states('input_number.master_bedroom_fan_threshold') | int and high > 60 %}
{% elif 50 <= low <= 60 %}
02:00
{% elif low >= states('input_number.master_bedroom_fan_threshold') | int and high > 60 %}
03:00
{% else %}
06:00
{% endif %}
@ -718,7 +723,7 @@ script:
{% set run_threshold = states('input_number.emma_bedroom_aircon_run_threshold') | int %}
{% set mode_threshold = states('input_number.emma_bedroom_aircon_mode_threshold') | int %}
{% if is_state('input_boolean.emma_bedroom_aircon_installed','off') %}
N/A
White Noise
{% elif low >= run_threshold %}
{% if low >= mode_threshold %}
AC
@ -726,7 +731,7 @@ script:
Fan
{% endif %}
{% else %}
N/A
White Noise
{% endif %}
- service: input_datetime.set_datetime
target: