Flow Details
This app is a fully working Pomodoro Timer.
In order to use it you need to create 2 helpers: timer with default pomodoro duration (usually 25 minutes) and counter with range from 0 to 16 with step of 1. Then select created helpers inside blueprint and adjust other settings.
Then just start helper timer manually for the first time to install the app.
Features:
- Customizable pomodoro timer
- Customizable short/long break timer (long timer will start afer every 4-th completed pomodoro)
- Displaying completed pomodoros around timer
- Pomodoro/break timer progress bar
- Pausing/resuming pomodoro timer using middle button (only if the app is active)
- Reminding of paused or not started pomodoro timer
- Resetting pomodoros covering light sensor (only if the app is active, also please notice that illuminance sensor updates AFAIK once a 30 seconds by default so you may need to wait before actuall event happen)
- Some additional styles: icons, text blinking etc
P.S. in case somebody wonders I used 3591 and 23527 icons from LaMetric for pomodoro and break icons.
blueprint:
name: AWTRIX Pomodoro Timer
description: Creates custom app for AWTRIX device with Pomodoro timer
domain: automation
author: Lufton
source_url: https://github.com/lufton/ha-blueprints/blob/main/awtrix_pomodoro_timer.yaml
input:
awtrix_device:
name: AWTRIX Device
description: Select the AWTRIX device
selector:
device:
integration: mqtt
manufacturer: Blueforcer
app_name:
name: App name
description: Enter app name or leave as is for default value
default: Pomodoro
timer:
name: Timer
description: Select timer to be used as pomodoro timer (create helper timer and set default cycle duration, e.g. 25 minutes)
selector:
entity:
filter:
domain: timer
counter:
name: Counter
description: Select counter to be used as completed pomodoros (create helper counter and set minimum to 0, maximum to 16, initial to 0 and step to 1)
selector:
entity:
filter:
domain: counter
short_break:
name: Short break
description: Set short break duration (short break is a regular break between pomodoros), e.g. 5 minutes
default:
minutes: 5
selector:
duration:
long_break:
name: Long break
description: Set short break duration (long break is a break after each pomodoro that is multiple of 4), e.g. 15 minutes
default:
minutes: 15
selector:
duration:
reminder:
name: Reminder
description: Set reminder duration (reminder will be played if timer is not started or paused), e.g. 5 minutes
default:
minutes: 5
selector:
duration:
show_pomodoros:
name: Show pomodoros
description: >-
Check to show red dots around timer that indicates completed pomodoros:
Blinking dot – current pomodoro
Short space – short break
Long space – long break
default: true
selector:
boolean:
illuminance_threshold:
name: Illuminance threshold
description: Set illuminance threshold that is gonna be checked to determine if pomodoro should be reset
default: 1
selector:
number:
min: 0
max: 10
unit_of_measurement: lx
reset_time:
name: Reset time
description: Set time when pomodoros should reset (usually at night time when timer is not in use)
default: 03:00:00
selector:
time:
start_text:
name: Start text
description: Enter text as a hint for user to press a button to start pomodoro
default: Press
selector:
text:
done_text:
name: Done text
description: Enter text as a hint for user when all pomodoros are completed
default: Done!
selector:
text:
blink_text:
name: Blink text
description: Enter interval of text blinking (set 0 to avoid blinking)
default: 500
selector:
number:
min: 0
max: 5000
step: 100
unit_of_measurement: ms
pomodoro_icon:
name: Pomodoro icon
description: Enter icon number/filename for pomodoro timer
default:
break_icon:
name: Break icon
description: Enter icon number/filename for break timer
default:
start_rtttl:
name: Start rtttl sound
description: Enter rtttl sound that will be played when timer is ready to start (enter space to prevent playing any sound)
default: PomodoroStart:d=4,o=5,b=100:8e,8g,8c6,8e,8c6,8g,8e,8c6
finish_rtttl:
name: Finish rtttl sound
description: Enter rtttl sound that will be played when timer is finished (enter space to prevent playing any sound)
default: PomodoroFinish:d=4,o=5,b=100:8c,8g,8c6,8g,8c6,8g,8c6,8g,8c6
reminder_rtttl:
name: Reminder rtttl sound
description: Enter rtttl sound that will be played when timer is not active (not started or paused, enter space to prevent playing any sound)
default: PomodoroReminder:d=4,o=5,b=120:8c,8e,8g,8c6
trigger_variables:
awtrix_device: !input awtrix_device
illuminance_threshold: !input illuminance_threshold
timer: !input timer
button: "{{ (device_entities(awtrix_device) | select('search', 'button_select') | list)[0] }}"
illuminance: "{{ (device_entities(awtrix_device) | select('search', 'illuminance') | list)[0] }}"
current_app: "{{ (device_entities(awtrix_device) | select('search', 'current_app') | list)[0] }}"
variables:
app_name: !input app_name
device_topic: "{{ states((device_entities(awtrix_device) | select('search', 'device_topic') | list)[0]) }}"
app_topic: "{{ device_topic }}/custom/{{ app_name }}"
notify_topic: "{{ device_topic }}/notify"
switch_topic: "{{ device_topic }}/switch"
rtttl_topic: "{{ device_topic }}/rtttl"
switch_payload:
name: "{{ app_name }}"
counter: !input counter
short_break: !input short_break
long_break: !input long_break
reminder: !input reminder
show_pomodoros: !input show_pomodoros
reset_time: !input reset_time
start_text: !input start_text
done_text: !input done_text
blink_text: !input blink_text
pomodoro_icon: !input pomodoro_icon
break_icon: !input break_icon
start_rtttl: !input start_rtttl
finish_rtttl: !input finish_rtttl
reminder_rtttl: !input reminder_rtttl
trigger:
- platform: state
entity_id: !input timer
to: active
alias: Timer started
id: timer_started
- platform: state
entity_id: !input timer
to: paused
id: timer_paused
alias: Timer paused
- platform: state
entity_id: !input timer
to: idle
id: timer_stopped
alias: Timer stopped
- alias: Button pressed
platform: template
value_template: "{{ is_state(button, 'on') }}"
id: button_pressed
- alias: Day ended
platform: time
at: !input reset_time
id: day_ended
enabled: true
- alias: Illuminance sensor closed
platform: template
value_template: "{{ states(illuminance) | int <= illuminance_threshold }}"
id: illuminance_sensor_closed
action:
- choose:
- conditions:
- condition: trigger
id: timer_started
sequence:
- service: mqtt.publish
data:
topic: "{{ switch_topic }}"
payload: "{{ switch_payload }}"
- repeat:
sequence:
- service: mqtt.publish
data:
topic: "{{ app_topic }}"
payload: >-
{% set it_is_a_break = trigger.from_state.attributes.duration != trigger.to_state.attributes.duration %}
{% set duration = as_timedelta(state_attr(timer, 'duration')).total_seconds() %}
{% set remaining = (as_datetime(state_attr(timer, 'finishes_at')) - now().replace(microsecond=0)).total_seconds() %}
{% set progress = (duration - remaining) / duration %}
{% set draw = namespace(items=[]) %}
{% for i in range(states(counter) | int + 1) %}
{% if not loop.last or (remaining % 2 == 0 and not it_is_a_break) %}
{% set draw.items = draw.items + [dict(dp=[12 + (2 if (i % 8) > 3 else 0) + ((i * 2) % 16), 0 if i < 8 else 6, [255 * progress, 0, 0] if loop.last and not it_is_a_break else "#FF0000"])] %}
{% endif %}
{% endfor %}
{{ dict(icon=break_icon if it_is_a_break else pomodoro_icon, text=remaining | timestamp_custom('%M:%S' if remaining % 2 == 0 else '%M %S', False), progress=(progress * 100) | round(0), draw=draw.items if show_pomodoros else []) }}
- wait_template: "{{ not is_state(timer, 'active') }}"
continue_on_timeout: true
timeout: 1
while:
- condition: template
value_template: "{{ is_state(timer, 'active') }}"
- conditions:
- condition: trigger
id: timer_paused
sequence:
- service: mqtt.publish
data:
topic: "{{ switch_topic }}"
payload: "{{ switch_payload }}"
- repeat:
sequence:
- wait_template: "{{ not is_state(timer, 'paused') }}"
continue_on_timeout: true
timeout: "{{ reminder.get('hours', 0) * 3600 + reminder.get('minutes', 0) * 60 + reminder.get('seconds', 0) }}"
- if:
- condition: template
value_template: "{{ not wait.completed }}"
then:
- service: mqtt.publish
data:
topic: "{{ rtttl_topic }}"
payload: "{{ reminder_rtttl }}"
until:
- condition: template
value_template: "{{ not is_state(timer, 'paused') }}"
- conditions:
- condition: trigger
id: timer_stopped
- condition: template
value_template: "{{ (states(illuminance) | int > illuminance_threshold or not is_state(current_app, app_name)) and now().replace(microsecond=0) != today_at(reset_time) }}"
sequence:
- service: mqtt.publish
data:
topic: "{{ switch_topic }}"
payload: "{{ switch_payload }}"
- if:
- condition: template
value_template: "{{ trigger.from_state.attributes.duration == trigger.to_state.attributes.duration }}"
then:
- service: mqtt.publish
data:
topic: "{{ rtttl_topic }}"
payload: "{{ finish_rtttl }}"
- service: counter.increment
target:
entity_id: "{{ counter }}"
- if:
- condition: template
value_template: "{{ is_state(counter, state_attr(counter, 'maximum') | string) }}"
then:
- service: counter.reset
target:
entity_id: "{{ counter }}"
- service: mqtt.publish
data:
topic: "{{ app_topic }}"
payload: "{{ dict(icon=pomodoro_icon, text=done_text, blinkText=blink_text) }}"
- delay:
seconds: 5
- service: mqtt.publish
data:
topic: "{{ app_topic }}"
payload: "{{ dict(icon=pomodoro_icon, text=start_text, blinkText=blink_text) }}"
else:
- service: timer.start
data:
duration: >-
{% if states(counter) | int % 4 == 0 %}{{ long_break }}
{% else %}{{ short_break }}
{% endif %}
target:
entity_id: "{{ timer }}"
else:
- service: mqtt.publish
data:
topic: "{{ app_topic }}"
payload: "{{ dict(icon=pomodoro_icon, text=start_text, blinkText=blink_text) }}"
- repeat:
sequence:
- wait_template: "{{ is_state(timer, 'active') }}"
continue_on_timeout: true
timeout: "{{ reminder.get('hours', 0) * 3600 + reminder.get('minutes', 0) * 60 + reminder.get('seconds', 0) }}"
- if:
- condition: template
value_template: "{{ not wait.completed }}"
then:
- service: mqtt.publish
data:
topic: "{{ rtttl_topic }}"
payload: "{{ reminder_rtttl }}"
until:
- condition: template
value_template: "{{ is_state(timer, 'active') }}"
- conditions:
- condition: trigger
id: button_pressed
- condition: template
value_template: "{{ is_state(current_app, app_name) }}"
sequence:
- wait_template: "{{ is_state(button, 'off') }}"
- condition: template
value_template: >-
{% set duration = as_timedelta(state_attr(timer, 'duration')).total_seconds() %}
{% set short_break_duration = 3600 * short_break.get('hours', 0) + 60 * short_break.get('minutes', 0) + short_break.get('seconds', 0) %}
{% set long_break_duration = 3600 * long_break.get('hours', 0) + 60 * long_break.get('minutes', 0) + long_break.get('seconds', 0) %}
{{ (duration != short_break_duration) and (duration != long_break_duration) }}
- if:
- condition: template
value_template: "{{ is_state(timer, 'active') }}"
then:
- service: timer.pause
target:
entity_id: "{{ timer }}"
else:
- service: timer.start
target:
entity_id: "{{ timer }}"
- conditions:
- condition: template
value_template: "{{ trigger.id == 'day_ended' or (trigger.id == 'illuminance_sensor_closed' and is_state(current_app, app_name)) }}"
sequence:
- service: counter.reset
target:
entity_id: "{{ counter }}"
- service: timer.cancel
target:
entity_id: "{{ timer }}"
- service: mqtt.publish
data:
topic: "{{ app_topic }}"
payload: "{{ dict(icon=pomodoro_icon, text=start_text, blinkText=blink_text) }}"
mode: parallel
max: 10
-- Flow first published on April 2, 2024, last updated on April 2, 2024 at 23:37.