Files
haos-blueprints/Common/Telegram Question/blueprint.yaml
alexei.dolgolyov 7b00899903 Restructure repository: organize blueprints into folders
Each blueprint now has its own folder containing:
- blueprint.yaml: The automation code with a short header
- README.md: Detailed documentation extracted from headers

Updated CLAUDE.md with repository structure guidelines.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 02:38:52 +03:00

405 lines
16 KiB
YAML

# Telegram Keyboard Action Blueprint
# Creates interactive Telegram messages with inline keyboard buttons and
# handles button callbacks. See README.md for detailed documentation.
#
# Author: Alexei Dolgolyov (dolgolyov.alexei@gmail.com)
blueprint:
name: "Custom: Telegram Keyboard Action"
description: >
Sends a Telegram message with inline keyboard buttons to multiple chat IDs.
When a button is pressed, executes the corresponding callback action.
Supports up to 4 buttons with individual callbacks.
domain: automation
input:
# -------------------------------------------------------------------------
# Chat Configuration
# -------------------------------------------------------------------------
chat_group:
name: "Chats"
collapsed: false
input:
chat_ids:
name: Telegram Chat IDs
description: >
List of numeric chat IDs to send messages to.
You can find your chat ID by messaging @userinfobot on Telegram.
default: []
selector:
text:
multiple: true
chat_entities:
name: Telegram Notification Targets
description: >
Notify entities with chat ID in friendly name.
Format: "<Name> (<ChatID>)" - e.g., "Alex (2132562465)"
The number in parentheses will be extracted as chat ID.
default: []
selector:
entity:
domain: notify
multiple: true
config_entry_id:
name: Telegram Bot Config Entry ID
description: >
Required if you have multiple Telegram bots configured.
Find this in Home Assistant: Settings → Devices & Services → Telegram Bot
→ Click on your bot → look at the URL, the ID is after /config_entry/
Example: "01JKXXXXXXXXXXXXXXXXXXX"
Leave empty if you only have one Telegram bot.
default: ""
selector:
text:
# -------------------------------------------------------------------------
# Message Configuration
# -------------------------------------------------------------------------
message_group:
name: "Message"
collapsed: false
input:
keyboard_id:
name: Keyboard ID
description: >
Unique identifier for this keyboard. Used to distinguish
button presses from different blueprints/automations.
default: "keyboard"
selector:
text:
message_text:
name: Message Text
description: The message displayed above the keyboard buttons
default: "Hey, here's a new message"
selector:
text:
multiline: true
buttons:
name: Button Labels
description: >
Text displayed on each button (up to 4 buttons).
Buttons appear in a single row.
default:
- "✔"
- "✖"
selector:
text:
multiple: true
answers:
name: Answer Messages (optional)
description: >
Reply message for each button (same order as buttons).
Leave empty to not send any reply when button is pressed.
default: []
selector:
text:
multiple: true
hide_keyboard_on_press:
name: Hide Keyboard After Press
description: Remove the keyboard buttons after any button is pressed
default: true
selector:
boolean:
hide_message_on_press:
name: Delete Message After Press
description: Delete the entire message after any button is pressed
default: false
selector:
boolean:
# -------------------------------------------------------------------------
# Button Callbacks
# -------------------------------------------------------------------------
callbacks_group:
name: "Callbacks"
collapsed: false
input:
button_1_callback:
name: Button 1 Callback
description: Actions to run when first button is pressed
default: []
selector:
action: {}
button_2_callback:
name: Button 2 Callback
description: Actions to run when second button is pressed
default: []
selector:
action: {}
button_3_callback:
name: Button 3 Callback
description: Actions to run when third button is pressed
default: []
selector:
action: {}
button_4_callback:
name: Button 4 Callback
description: Actions to run when fourth button is pressed
default: []
selector:
action: {}
# -------------------------------------------------------------------------
# Debug
# -------------------------------------------------------------------------
debug_group:
name: "Debug"
collapsed: true
input:
enable_debug:
name: Enable Debug Notifications
description: >
Send persistent notifications for debugging automation behavior.
Shows resolved chat IDs, callback data, and configuration.
default: false
selector:
boolean:
# Parallel mode allows multiple button presses to be processed simultaneously
mode: parallel
# =============================================================================
# Trigger
# =============================================================================
trigger:
# Listen for Telegram callback events (button presses)
- platform: event
event_type: telegram_callback
id: "telegram_callback"
# =============================================================================
# Variables
# =============================================================================
variables:
# Input references
buttons: !input buttons
keyboard_id: !input keyboard_id
hide_keyboard_on_press: !input hide_keyboard_on_press
hide_message_on_press: !input hide_message_on_press
answers: !input answers
config_entry_id: !input config_entry_id
# Callback references (needed for condition checks)
button_1_callback: !input button_1_callback
button_2_callback: !input button_2_callback
button_3_callback: !input button_3_callback
button_4_callback: !input button_4_callback
# Determine trigger type
# When automation is called via service (action), trigger.platform is undefined
is_manual_trigger: "{{ trigger.platform is not defined or trigger.platform is none }}"
# Check if this callback event belongs to our keyboard
# Callback data format: /<keyboard_id>_<index>
is_our_callback: >
{% if is_manual_trigger %}
false
{% else %}
{% set callback_data = trigger.event.data.data | default('') %}
{{ callback_data.startswith('/' ~ keyboard_id ~ '_') }}
{% endif %}
# Debug flag
is_debug: !input enable_debug
# =============================================================================
# Actions
# =============================================================================
action:
# ---------------------------------------------------------------------------
# Debug Logging - Callback Events
# ---------------------------------------------------------------------------
- choose:
- conditions:
- condition: template
value_template: "{{ is_debug and not is_manual_trigger }}"
sequence:
- service: persistent_notification.create
data:
title: "Telegram Keyboard Debug - Callback"
message: >
**Trigger Info:**
- Platform: {{ trigger.platform | default('unknown') }}
- Is our callback: {{ is_our_callback }}
{% if is_our_callback %}
**Callback Data:**
- Raw data: {{ trigger.event.data.data | default('N/A') }}
- Chat ID: {{ trigger.event.data.chat_id | default('N/A') }}
- Message ID: {{ trigger.event.data.message.message_id | default('N/A') }}
- Keyboard ID: {{ keyboard_id }}
{% else %}
**Ignored** (callback not for this keyboard)
- Expected prefix: /{{ keyboard_id }}_
- Received: {{ trigger.event.data.data | default('N/A') }}
{% endif %}
**Config:**
- Config Entry ID: {{ config_entry_id if config_entry_id | length > 0 else '(not set)' }}
# ---------------------------------------------------------------------------
# Handle Button Press (Callback Event)
# ---------------------------------------------------------------------------
- choose:
- conditions:
- condition: template
value_template: "{{ is_our_callback }}"
sequence:
- variables:
# Extract data from the callback event
callback_data: "{{ trigger.event.data.data }}"
chat_id: "{{ trigger.event.data.chat_id }}"
message_id: "{{ trigger.event.data.message.message_id }}"
# Extract button index from callback data (format: /<keyboard_id>_<index>)
# This handles multi-digit indices correctly
button_index: >
{% set prefix = '/' ~ keyboard_id ~ '_' %}
{% set idx_str = callback_data[prefix | length:] %}
{{ idx_str | int(-1) }}
# Execute the appropriate button callback
- choose:
- conditions: "{{ button_index == 0 and button_1_callback | length > 0 }}"
sequence: !input button_1_callback
- conditions: "{{ button_index == 1 and button_2_callback | length > 0 }}"
sequence: !input button_2_callback
- conditions: "{{ button_index == 2 and button_3_callback | length > 0 }}"
sequence: !input button_3_callback
- conditions: "{{ button_index == 3 and button_4_callback | length > 0 }}"
sequence: !input button_4_callback
# Send answer message if configured for this button
- choose:
- conditions: >
{{ button_index >= 0 and button_index < (answers | length)
and (answers[button_index] | length) > 0 }}
sequence:
- service: telegram_bot.send_message
data:
target: "{{ chat_id }}"
message: "{{ answers[button_index] }}"
# Reply to original message unless we're deleting it
reply_to_message_id: >
{{ omit if hide_message_on_press else message_id }}
config_entry_id: >
{{ config_entry_id if config_entry_id | length > 0 else omit }}
# Handle message/keyboard cleanup
- choose:
# Delete entire message
- conditions: "{{ hide_message_on_press }}"
sequence:
- service: telegram_bot.delete_message
data:
chat_id: "{{ chat_id }}"
message_id: "{{ message_id }}"
config_entry_id: >
{{ config_entry_id if config_entry_id | length > 0 else omit }}
# Just remove keyboard (keep message)
- conditions: "{{ hide_keyboard_on_press }}"
sequence:
- service: telegram_bot.edit_replymarkup
data:
chat_id: "{{ chat_id }}"
message_id: "{{ message_id }}"
inline_keyboard: []
config_entry_id: >
{{ config_entry_id if config_entry_id | length > 0 else omit }}
# ---------------------------------------------------------------------------
# Send Initial Message (Manual Trigger / Service Call)
# ---------------------------------------------------------------------------
- choose:
- conditions:
- condition: template
value_template: "{{ is_manual_trigger }}"
sequence:
- variables:
# Get chat IDs from direct input
chat_ids: !input chat_ids
# Extract chat IDs from notify entity friendly names
# Format: "Name (123456789)" or "Name (-123456789)" -> extracts the number
# Supports both positive (user) and negative (group/channel) chat IDs
chat_entities: !input chat_entities
chat_ids_from_entities: >
{% set ns = namespace(ids=[]) %}
{% for entity in chat_entities %}
{% set friendly_name = state_attr(entity, 'friendly_name') | default('') %}
{% set match = friendly_name | regex_findall('\\((-?\\d+)\\)') %}
{% if match | length > 0 %}
{% set ns.ids = ns.ids + [match[0]] %}
{% endif %}
{% endfor %}
{{ ns.ids }}
# Combine all chat IDs
result_chat_ids: "{{ (chat_ids + chat_ids_from_entities) | unique | list }}"
# Build inline keyboard with callback data
# Format: ["Button Text:/<keyboard_id>_<index>", ...]
message_text: !input message_text
inline_keyboard: >
{% set ns = namespace(buttons=[]) %}
{% for i in range(buttons | length) %}
{% set callback_data = '/' ~ keyboard_id ~ '_' ~ i %}
{% set ns.buttons = ns.buttons + [(buttons[i] ~ ':' ~ callback_data)] %}
{% endfor %}
{{ ns.buttons }}
# Debug logging for manual trigger
- choose:
- conditions:
- condition: template
value_template: "{{ is_debug }}"
sequence:
- service: persistent_notification.create
data:
title: "Telegram Keyboard Debug - Send Message"
message: >
**Chat ID Resolution:**
- Direct chat IDs: {{ chat_ids | join(', ') if chat_ids | length > 0 else '(none)' }}
- From entities: {{ chat_ids_from_entities | join(', ') if chat_ids_from_entities | length > 0 else '(none)' }}
- **Resolved IDs: {{ result_chat_ids | join(', ') if result_chat_ids | length > 0 else '(none)' }}**
**Entity Parsing:**
{% for entity in chat_entities %}
- {{ entity }}: "{{ state_attr(entity, 'friendly_name') | default('N/A') }}"
{% else %}
- (no entities configured)
{% endfor %}
**Message:**
- Keyboard ID: {{ keyboard_id }}
- Buttons: {{ buttons | join(', ') }}
- Message: {{ message_text[:100] }}{{ '...' if message_text | length > 100 else '' }}
**Config:**
- Config Entry ID: {{ config_entry_id if config_entry_id | length > 0 else '(not set)' }}
# Validate we have at least one chat ID
- choose:
- conditions: "{{ result_chat_ids | length == 0 }}"
sequence:
- stop: "No chat IDs resolved. Check chat_ids or chat_entities configuration."
# Send the message with keyboard
- service: telegram_bot.send_message
data:
target: "{{ result_chat_ids }}"
message: "{{ message_text }}"
inline_keyboard: "{{ inline_keyboard }}"
config_entry_id: >
{{ config_entry_id if config_entry_id | length > 0 else omit }}