Skip to content

Telegram Bot enhancements with callback queries and more notification options#7294

Closed
azogue wants to merge 3 commits into
home-assistant:devfrom
azogue:telegram-callbacks
Closed

Telegram Bot enhancements with callback queries and more notification options#7294
azogue wants to merge 3 commits into
home-assistant:devfrom
azogue:telegram-callbacks

Conversation

@azogue
Copy link
Copy Markdown
Member

@azogue azogue commented Apr 25, 2017

Description:

When making inline keyboards with the telegram notify platform, if pressed, they send data like this:

 {'chat_instance': 'XXXXXXXXXXXXXXXXXXX',
 'data': '[/data sended]',
 'from': {'username': '[USERNAME]',
          'last_name': '[LAST_NAME]', 'first_name': '[FIRST_NAME]',
          'id': 123456789},
 'id': '1234567890123456789',
 'message': { original_msg }

which isn't processed correctly with the current telegram_bot platform. With these changes, when received, HA sends a telegram_callback event with the callback data, the chat instance, the original message and a unique id of the callback.

Also, some changes in the telegram notifier for using more features of the Telegram API 2.0, like:

  • disable_notification, disable_web_page_preview and reply_to_message_id optional keyword args, or the inline keyboards with data: {'inline_keyboard': [(text_btn1, data_callback_btn1), ...]}.
  • Ablility to target multiple pre-authorized chat_ids (target=[12345, 67890]) when sending a message.
  • Custom reply_markup (keyboard or inline_keyboard) for every type of message (message, photo, location & document).
  • Customized for using any of both parsers (markdown and html) in any message with: data: {'parse_mode': 'html'}, with markdown as default, but can be globally customized with 'parse_mode' in the yaml config.
  • Callback replies for edit messages, reply_markup keyboards and captions, and for answering callback queries with: data: {'callback_query'|'edit_message'| 'edit_caption'|'edit_replymarkup': ...}
  • Line break between title and message fields: '{}\n{}'.format(title, message)

With these changes it is now very easy to make a custom bot witch presents messages and buttons with posible responses, and change dynamically these messages and inline keyboards guiding the user in some sort of a wizard menu.

Pull request in home-assistant.github.io with documentation (if applicable): home-assistant/home-assistant.io#2508

Example entry for configuration.yaml (if applicable):

# Telegram Notifier
notify:
  - platform: telegram
    name: telegram_bot
    api_key: !secret telegram_bot_api_key
    parse_mode: html
    user_id:
      User_name_1: !secret telegram_bot_chat_id_admin
      User_name_2: !secret telegram_bot_chat_id_2

# The current config also works:
  - platform: telegram
    name: telegram_bot
    api_key: !secret telegram_bot_api_key
    chat_id: !secret telegram_bot_chat_id_admin

# Telegram Bot
telegram_bot:
  platform: webhooks
  api_key: !secret telegram_bot_api_key
  allowed_chat_ids:
    - !secret telegram_bot_chat_id_admin
    - !secret telegram_bot_chat_id_2

Checklist:

If user exposed functionality or configuration variables are added/changed:

@mention-bot
Copy link
Copy Markdown

@azogue, thanks for your PR! By analyzing the history of the files in this pull request, we identified @pvizeli, @fabaff and @balloob to be potential reviewers.

@homeassistant
Copy link
Copy Markdown
Contributor

Hi @azogue,

It seems you haven't yet signed a CLA. Please do so here.

Once you do that we will be able to review and accept this pull request.

Thanks!

if ATTR_DISABLE_NOTIF in data:
params['disable_notification'] = data[ATTR_DISABLE_NOTIF]
if ATTR_DISABLE_WEB_PREV in data:
params['disable_web_page_preview'] = data[ATTR_DISABLE_WEB_PREV]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line too long (80 > 79 characters)

- Callback replies for edit messages, reply_markup keyboards and captions, and for answering callback queries with: `data: {'callback_query'|'edit_message'| 'edit_caption'|'edit_replymarkup': ...}`
- Line break between title and message fields: `'{}\n{}'.format(title, message)`
- Ablility to target multiple pre-authorized chat_ids (`target=[12345, 67890]`) when sending a message.
- BREAKING CHANGE: use array of `user_id` to allow one notifier to comunicate with multiple users (first user is the default, but you can pass a `ATTR_TARGET=chat_id_X` to send a message to other recipient). (Reading `chat_id` as User1 to work with old configuration)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line too long (267 > 79 characters)

- `disable_notification`, `disable_web_page_preview` and `reply_to_message_id` optional keyword args.
- Callback replies for edit messages, reply_markup keyboards and captions, and for answering callback queries with: `data: {'callback_query'|'edit_message'| 'edit_caption'|'edit_replymarkup': ...}`
- Line break between title and message fields: `'{}\n{}'.format(title, message)`
- Ablility to target multiple pre-authorized chat_ids (`target=[12345, 67890]`) when sending a message.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line too long (103 > 79 characters)

- Custom reply_markup (keyboard or inline_keyboard) for every type of message (message, photo, location & document).
- `disable_notification`, `disable_web_page_preview` and `reply_to_message_id` optional keyword args.
- Callback replies for edit messages, reply_markup keyboards and captions, and for answering callback queries with: `data: {'callback_query'|'edit_message'| 'edit_caption'|'edit_replymarkup': ...}`
- Line break between title and message fields: `'{}\n{}'.format(title, message)`
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line too long (80 > 79 characters)

- Inline keyboards with `data: {'inline_keyboard': [(text_btn1, data_callback_btn1), ...]}`
- Custom reply_markup (keyboard or inline_keyboard) for every type of message (message, photo, location & document).
- `disable_notification`, `disable_web_page_preview` and `reply_to_message_id` optional keyword args.
- Callback replies for edit messages, reply_markup keyboards and captions, and for answering callback queries with: `data: {'callback_query'|'edit_message'| 'edit_caption'|'edit_replymarkup': ...}`
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line too long (197 > 79 characters)

- Customized for using any of both parsers (`markdown` and `html`) in any message with: `data: {'parse_mode': 'html'}`, with markdown as default, but can be globally customized with 'parse_mode' in yaml config.
- Inline keyboards with `data: {'inline_keyboard': [(text_btn1, data_callback_btn1), ...]}`
- Custom reply_markup (keyboard or inline_keyboard) for every type of message (message, photo, location & document).
- `disable_notification`, `disable_web_page_preview` and `reply_to_message_id` optional keyword args.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line too long (101 > 79 characters)

Changes:
- Customized for using any of both parsers (`markdown` and `html`) in any message with: `data: {'parse_mode': 'html'}`, with markdown as default, but can be globally customized with 'parse_mode' in yaml config.
- Inline keyboards with `data: {'inline_keyboard': [(text_btn1, data_callback_btn1), ...]}`
- Custom reply_markup (keyboard or inline_keyboard) for every type of message (message, photo, location & document).
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line too long (116 > 79 characters)


Changes:
- Customized for using any of both parsers (`markdown` and `html`) in any message with: `data: {'parse_mode': 'html'}`, with markdown as default, but can be globally customized with 'parse_mode' in yaml config.
- Inline keyboards with `data: {'inline_keyboard': [(text_btn1, data_callback_btn1), ...]}`
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line too long (91 > 79 characters)

https://home-assistant.io/components/notify.telegram/

Changes:
- Customized for using any of both parsers (`markdown` and `html`) in any message with: `data: {'parse_mode': 'html'}`, with markdown as default, but can be globally customized with 'parse_mode' in yaml config.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line too long (210 > 79 characters)

@azogue
Copy link
Copy Markdown
Member Author

azogue commented Apr 26, 2017

##Added new doc with yaml examples for using telegram callback queries:

Sample automations with callback queries and inline keyboards

Quick example to show some of the callback capabilities of inline keyboards with a dumb automation consisting in a simple repeater of normal text that presents an inline keyboard with 3 buttons: 'EDIT', 'NO' and 'REMOVE BUTTON':

  • Pressing 'EDIT' changes the sended message.
  • Pressing 'NO' only shows a brief notification (answering the callback query).
  • Pressing 'REMOVE BUTTON' changes the inline keyboard removing that button.

Text repeater:

- alias: 'telegram bot that repeats text'
  hide_entity: true
  trigger:
    platform: event
    event_type: telegram_text
  action:
    - service: notify.telegram
      data_template:
        title: '*Dumb automation*'
        target: '{{ trigger.event.data.user_id }}'
        message: 'You said: ``` {{ trigger.event.data.text }} ```'
        data:
          disable_notification: true
          inline_keyboard:
            - '/edit,/NO'
            - '/remove button'

Message editor:

- alias: 'telegram bot last sended msg edit'
  hide_entity: true
  trigger:
    platform: event
    event_type: telegram_callback
    event_data:
      data: '/edit'
  action:
    - service: notify.telegram
      data_template:
        target: '{{ trigger.event.data.user_id }}'
        message: 'Editing the message!'
        data:
          callback_query:
            callback_query_id: '{{ trigger.event.data.id }}'
            show_alert: true
    - service: notify.telegram
      data_template:
        title: '*Message edit*'
        target: '{{ trigger.event.data.user_id }}'
        message: >
          Callback received from {{ trigger.event.data.from_first }}.
          Message id: {{ trigger.event.data.message.message_id }}.
          Data: ``` {{ trigger.event.data.data }} ```
        data:
          edit_message:
            message_id: '{{ trigger.event.data.message.message_id }}'
          disable_notification: true
          inline_keyboard:
            - '/edit,/NO'
            - '/remove button'

Keyboard editor:

- alias: 'telegram bot keyboard edit'
  hide_entity: true
  trigger:
    platform: event
    event_type: telegram_callback
    event_data:
      data: '/remove button'
  action:
    - service: notify.telegram
      data_template:
        target: '{{ trigger.event.data.user_id }}'
        message: 'Callback received for editing the inline keyboard!'
        data:
          callback_query:
            callback_query_id: '{{ trigger.event.data.id }}'
            show_alert: false
    - service: notify.telegram
      data_template:
        target: '{{ trigger.event.data.user_id }}'
        message: ''  # this is needed for the general hass notify service
        data:
          edit_replymarkup:
            message_id: 'last'
          disable_notification: true
          inline_keyboard:
            - '/edit,/NO'

Only acknowledges the 'NO' answer:

- alias: 'telegram bot simply acknowledges'
  hide_entity: true
  trigger:
    platform: event
    event_type: telegram_callback
    event_data:
      data: '/NO'
  action:
    - service: notify.telegram
      data_template:
        target: '{{ trigger.event.data.user_id }}'
        message: 'OK, you said no!'
        data:
          callback_query:
            callback_query_id: '{{ trigger.event.data.id }}'
            show_alert: false

Snapshots of these automations running:

Text repeater:
img_5651

Pressing 'NO':
img_5652

Pressing 'REMOVE BUTTON':
img_5653

Pressing 'EDIT':
img_5654


I don't know if it is desirable to add the images to the PR

@Landrash
Copy link
Copy Markdown
Contributor

I don't think images are necessary in this case since hopefully the end users of this function is familiar with Telegram and it's not support.

@MartinHjelmare
Copy link
Copy Markdown
Member

MartinHjelmare commented Apr 28, 2017

But a picture says more than thousand words. 😄
I like the pictures.

Copy link
Copy Markdown
Member

@balloob balloob left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

This comment is a pretty good indicator that we should move the communication with telegram into the component. The telegram notify service can then just be forwarding things to the telegram component.

When moving it to the telegram component, break it up in different services instead of overloading the "send_message" service like is now.

@azogue
Copy link
Copy Markdown
Member Author

azogue commented Apr 30, 2017

@balloob, I'm not sure what you mean by this, do you mean we should remove the notification component and create new services into the Telegram Bot component? So that the Telegram Bot component serves to send and receive messages, and not just to receive them?

Announcing new services like these:

  • telegram_bot/send_message
  • telegram_bot/send_photo
  • telegram_bot/send_document
  • telegram_bot/send_location
  • telegram_bot/edit_message
  • telegram_bot/edit_replymarkup
  • telegram_bot/edit_caption
  • telegram_bot/answer_callback_query

@balloob
Copy link
Copy Markdown
Member

balloob commented Apr 30, 2017

Yes, that's what I mean. But don't remove the notify telegram service, instead have that service just call telegram_bot/send_message

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line too long (80 > 79 characters)

Copy link
Copy Markdown
Member Author

@azogue azogue May 1, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm testing the requested changes, I hope tomorrow I'll have the time to finish the PR and the associated doc.

I have limited the configuration of a single platform ('webhooks' or 'polling') within the telegram_bot component, linking the notification services to the name 'telegram_bot / service_name', according to the previous comment.

The notify.telegram component now depends on telegram_bot and does not require the python-telegram module. Now it is only an optional "fast link" to the new notification services of the telegram_bot component, but allows backward compatibility for all service calls to notify.telegram with the old syntax.
Basically, it allows you to generate a customised shortcut to send notifications to a particular chat_id.
It would look like this:

"""
Telegram platform for notify component.

For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/notify.telegram/
"""
import logging
import voluptuous as vol

import homeassistant.helpers.config_validation as cv
from homeassistant.components.notify import (
    ATTR_MESSAGE, ATTR_TITLE, ATTR_DATA, ATTR_TARGET,
    PLATFORM_SCHEMA, BaseNotificationService)
from homeassistant.const import ATTR_LOCATION

_LOGGER = logging.getLogger(__name__)

DOMAIN = 'telegram_bot'
DEPENDENCIES = [DOMAIN]

ATTR_KEYBOARD = 'keyboard'
ATTR_INLINE_KEYBOARD = 'inline_keyboard'
ATTR_PHOTO = 'photo'
ATTR_DOCUMENT = 'document'

CONF_CHAT_ID = 'chat_id'

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
    vol.Required(CONF_CHAT_ID): cv.positive_int,
})


def get_service(hass, config, discovery_info=None):
    """Get the Telegram notification service."""
    chat_id = config.get(CONF_CHAT_ID)
    return TelegramNotificationService(hass, chat_id)


class TelegramNotificationService(BaseNotificationService):
    """Implement the notification service for Telegram."""

    def __init__(self, hass, chat_id):
        """Initialize the service."""
        self._chat_id = chat_id
        self.hass = hass

    def send_message(self, message="", **kwargs):
        """Send a message to a user."""

        service_data = dict(target=kwargs.get(ATTR_TARGET, self._chat_id))
        if ATTR_TITLE in kwargs:
            service_data.update({ATTR_TITLE: kwargs.get(ATTR_TITLE)})
        if message:
            service_data.update({ATTR_MESSAGE: message})
        data = kwargs.get(ATTR_DATA)

        # Get keyboard info
        if data is not None and ATTR_KEYBOARD in data:
            keys = data.get(ATTR_KEYBOARD)
            keys = keys if isinstance(keys, list) else [keys]
            service_data.update(keyboard=keys)
        elif data is not None and ATTR_INLINE_KEYBOARD in data:
            keys = data.get(ATTR_INLINE_KEYBOARD)
            keys = keys if isinstance(keys, list) else [keys]
            service_data.update(inline_keyboard=keys)

        # Send a photo, a document or a location
        if data is not None and ATTR_PHOTO in data:
            photos = data.get(ATTR_PHOTO, None)
            photos = photos if isinstance(photos, list) else [photos]
            for photo_data in photos:
                service_data.update(photo_data)
                self.hass.services.call(
                    DOMAIN, 'send_photo', service_data=service_data)
            return
        elif data is not None and ATTR_LOCATION in data:
            service_data.update(data.get(ATTR_LOCATION))
            return self.hass.services.call(
                DOMAIN, 'send_location', service_data=service_data)
        elif data is not None and ATTR_DOCUMENT in data:
            service_data.update(data.get(ATTR_DOCUMENT))
            return self.hass.services.call(
                DOMAIN, 'send_document', service_data=service_data)

        # Send message
        _LOGGER.debug('TELEGRAM NOTIFIER calling %s.send_message with %s',
                      DOMAIN, service_data)
        return self.hass.services.call(
            DOMAIN, 'send_message', service_data=service_data)

@azogue
Copy link
Copy Markdown
Member Author

azogue commented May 2, 2017

I'm testing the requested changes, I hope tomorrow I'll have the time to finish the PR and the associated doc.

I have limited the configuration of a single platform ('webhooks' or 'polling') within the telegram_bot component, linking the notification services to the name 'telegram_bot / service_name', according to the previous comment.

The notify.telegram component now depends on telegram_bot and does not require the python-telegram module. Now it is only an optional "fast link" to the new notification services of the telegram_bot component, but allows backward compatibility for all service calls to notify.telegram with the old syntax.
Basically, it allows you to generate a customised shortcut to send notifications to a particular chat_id.
It would look like this:

"""
Telegram platform for notify component.

For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/notify.telegram/
"""
import logging
import voluptuous as vol

import homeassistant.helpers.config_validation as cv
from homeassistant.components.notify import (
    ATTR_MESSAGE, ATTR_TITLE, ATTR_DATA, ATTR_TARGET,
    PLATFORM_SCHEMA, BaseNotificationService)
from homeassistant.const import ATTR_LOCATION

_LOGGER = logging.getLogger(__name__)

DOMAIN = 'telegram_bot'
DEPENDENCIES = [DOMAIN]

ATTR_KEYBOARD = 'keyboard'
ATTR_INLINE_KEYBOARD = 'inline_keyboard'
ATTR_PHOTO = 'photo'
ATTR_DOCUMENT = 'document'

CONF_CHAT_ID = 'chat_id'

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
    vol.Required(CONF_CHAT_ID): cv.positive_int,
})


def get_service(hass, config, discovery_info=None):
    """Get the Telegram notification service."""
    chat_id = config.get(CONF_CHAT_ID)
    return TelegramNotificationService(hass, chat_id)


class TelegramNotificationService(BaseNotificationService):
    """Implement the notification service for Telegram."""

    def __init__(self, hass, chat_id):
        """Initialize the service."""
        self._chat_id = chat_id
        self.hass = hass

    def send_message(self, message="", **kwargs):
        """Send a message to a user."""

        service_data = dict(target=kwargs.get(ATTR_TARGET, self._chat_id))
        if ATTR_TITLE in kwargs:
            service_data.update({ATTR_TITLE: kwargs.get(ATTR_TITLE)})
        if message:
            service_data.update({ATTR_MESSAGE: message})
        data = kwargs.get(ATTR_DATA)

        # Get keyboard info
        if data is not None and ATTR_KEYBOARD in data:
            keys = data.get(ATTR_KEYBOARD)
            keys = keys if isinstance(keys, list) else [keys]
            service_data.update(keyboard=keys)
        elif data is not None and ATTR_INLINE_KEYBOARD in data:
            keys = data.get(ATTR_INLINE_KEYBOARD)
            keys = keys if isinstance(keys, list) else [keys]
            service_data.update(inline_keyboard=keys)

        # Send a photo, a document or a location
        if data is not None and ATTR_PHOTO in data:
            photos = data.get(ATTR_PHOTO, None)
            photos = photos if isinstance(photos, list) else [photos]
            for photo_data in photos:
                service_data.update(photo_data)
                self.hass.services.call(
                    DOMAIN, 'send_photo', service_data=service_data)
            return
        elif data is not None and ATTR_LOCATION in data:
            service_data.update(data.get(ATTR_LOCATION))
            return self.hass.services.call(
                DOMAIN, 'send_location', service_data=service_data)
        elif data is not None and ATTR_DOCUMENT in data:
            service_data.update(data.get(ATTR_DOCUMENT))
            return self.hass.services.call(
                DOMAIN, 'send_document', service_data=service_data)

        # Send message
        _LOGGER.debug('TELEGRAM NOTIFIER calling %s.send_message with %s',
                      DOMAIN, service_data)
        return self.hass.services.call(
            DOMAIN, 'send_message', service_data=service_data)

@balloob
Copy link
Copy Markdown
Member

balloob commented May 2, 2017

Yeah that looks great 👍

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

visually indented line with same indent as next logical line

@azogue
Copy link
Copy Markdown
Member Author

azogue commented May 3, 2017

@balloob, I think I'm done.
All new services work as expected in the new doc, and I have tested every combination (no tests for this platform, I'm working with the webhooks platform). Doc has changed accordingly in the PR #2508

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If only 1 is allowed, we should only setup 1. So line 293 should be updated.

However, if we only allow 1, we should not have a PLATFORM_SCHEMA to begin with but instead have a CONFIG_SCHEMA.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please import built-ins at the top

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this do any I/O ? If so, you can't do it inside an async context

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If both platforms have the same dependency, let's remove it from platforms and move it to the component.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic is no longer needed, both have async_setup_platform now.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, not sure how this code sneaked in here but this can be removed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no need to create these wrappers since no one is extending this class. Just have the service handler call everything in the executor.

yield from hass.async_add_job(partial(notify_service.send_file, True, **kwargs))

@azogue
Copy link
Copy Markdown
Member Author

azogue commented May 4, 2017

@balloob, the changes are done.

I have manually tested both platforms: polling and webhooks. Apparently, both work properly.

I do not know if the change from PLATFORM_SCHEMA to CONFIG_SCHEMA has repercussions on the documentation pages (actually, the user configuration remains the same), since the parameters are being described on each platform, rather than on the component page.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't extend the BaseNotificationService

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please just internalize it at the once place where you use this function.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a leftover from the notify service, you can now pass hass in if you need it.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hardly see anyone use dicts like this. It's actually worse perf to create a dict like this compared to specifying it with dict syntax:

params = {
    'parse_mode': self._parse_mode,
    # etc…
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not know that the performance was worse!, I use a lot of that way of creating dictionaries (aesthetically I usually like it more ;-), I will try to change my style from now on...

@balloob
Copy link
Copy Markdown
Member

balloob commented May 5, 2017

Almost there, just saw a few small changes. Also noticed you got some conflicts, not sure what they are.

Are there any breaking changes for the config?

@azogue
Copy link
Copy Markdown
Member Author

azogue commented May 5, 2017

Are there any breaking changes for the config?

I understand not, since I do not think there is anyone who has defined both platforms (polling and webhooks) or multiple bots, although the change from PLATFORM_SCHEMA to CONFIG_SCHEMA I think stops allowing this configuration:

telegram_bot:
- platform: webhooks

  api_key: telegram_api_key
  allowed_chat_ids:

    - 12345
    - 67890

So for some specific user may be a problem, but is easily solved by eliminating the platform hyphen.

The other change, in component.notify.telegram, is that the api_key is no longer needed there, but adding it is not an error, so there is no ‘breaking changes’ there.

Also noticed you got some conflicts, not sure what they are.

I think they are simply representing my very limited experience with git, I'm learning slowly. I'll see how I can fix them.

@azogue
Copy link
Copy Markdown
Member Author

azogue commented May 5, 2017

@balloob, The only way I can quickly fix the mess is to make a new PR, so I've done that: PR #7454

Now I only need to close this one, right?

- Receive callback queries and produce `telegram_callback` events:
```
{'chat_instance': 'XXXXXXXXXXXXXXXXXXX',
 'data': '[/data sended]',
 'from': {'username': '[USERNAME]',
          'last_name': '[LAST_NAME]', 'first_name': '[FIRST_NAME]',
          'id': 123456789},
 'id': '1234567890123456789',
 'message': { original_msg }
```
- Customized for using any of both parsers (`markdown` and `html`) in any message with: `data: {'parse_mode': 'html'}`, with markdown as default, but can be globally customized with 'parse_mode' in yaml config.
- Inline keyboards with `data: {'inline_keyboard': [(text_btn1, data_callback_btn1), ...]}`
- Custom reply_markup (keyboard or inline_keyboard) for every type of message (message, photo, location & document).
- `disable_notification`, `disable_web_page_preview` and `reply_to_message_id` optional keyword args.
- Callback replies for edit messages, reply_markup keyboards and captions, and for answering callback queries with: `data: {'callback_query'|'edit_message'| 'edit_caption'|'edit_replymarkup': ...}`
- Line break between title and message fields: `'{}\n{}'.format(title, message)`
- Ablility to target multiple pre-authorized chat_ids (`target=[12345, 67890]`) when sending a message.
- Requested changes: move Telegram notification services to `telegram_bot` component and forward service calls from the telegram notify service to the telegram component. Added descriptions of the new services with a services.yaml file.
- Requested changes: CONFIG_SCHEMA instead of PLATFORM_SCHEMA; no need for async wrappers; no need to validate api_key getting the notification service; removed common requirements from platforms; built-ins at the top; I/O in async; removed async_platform_discovered; removed unused logic for setup_platform.
- Requested changes: TelegramNotificationService class does not inherit from the BaseNotificationService class; no need for a coroutine (async_get_service) to get the TelegramNotificationService; dict creation.
@MartinHjelmare
Copy link
Copy Markdown
Member

@azogue Please decide which PR you want to keep open, this one or #7454.

@balloob
Copy link
Copy Markdown
Member

balloob commented May 10, 2017

I think this is the old one.

@balloob balloob closed this May 10, 2017
@azogue azogue deleted the telegram-callbacks branch May 13, 2017 08:21
@azogue azogue mentioned this pull request Jun 3, 2017
@home-assistant home-assistant locked and limited conversation to collaborators Aug 12, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants