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>
This commit is contained in:
34
Common/Telegram Question/README.md
Normal file
34
Common/Telegram Question/README.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# Telegram Keyboard Action Blueprint
|
||||
|
||||
This blueprint creates interactive Telegram messages with inline keyboard buttons. When a button is pressed, the corresponding callback action runs.
|
||||
|
||||
## How It Works
|
||||
|
||||
1. Manual trigger (service call) → Sends message with keyboard to chat(s)
|
||||
2. Button press → Triggers `telegram_callback` event
|
||||
3. Blueprint matches callback data to `keyboard_id`
|
||||
4. Executes the corresponding button's callback action
|
||||
5. Optionally sends answer and/or hides keyboard/message
|
||||
|
||||
## Chat ID Resolution
|
||||
|
||||
Chat IDs can be provided in two ways:
|
||||
|
||||
- Directly as text list (`chat_ids` input)
|
||||
- From notify entities with friendly names like `"Alex (123456789)"` - the number in parentheses is extracted as the chat ID
|
||||
|
||||
## Multiple Telegram Bots
|
||||
|
||||
If you have multiple Telegram bots configured in Home Assistant, you must specify the `config_entry_id` to identify which bot to use.
|
||||
|
||||
Find it in: Settings → Devices & Services → Telegram Bot → your bot → URL
|
||||
|
||||
## Callback Data Format
|
||||
|
||||
Each button sends callback data: `/<keyboard_id>_<button_index>`
|
||||
|
||||
Example: `/my_keyboard_0` for first button of keyboard `"my_keyboard"`
|
||||
|
||||
## Author
|
||||
|
||||
Alexei Dolgolyov (dolgolyov.alexei@gmail.com)
|
||||
404
Common/Telegram Question/blueprint.yaml
Normal file
404
Common/Telegram Question/blueprint.yaml
Normal file
@@ -0,0 +1,404 @@
|
||||
# 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 }}
|
||||
Reference in New Issue
Block a user