Migrated 7th article
This commit is contained in:
parent
d14763d63a
commit
bf3f2693b5
5 changed files with 302 additions and 0 deletions
BIN
static/img/telegram-1.jpg
Normal file
BIN
static/img/telegram-1.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
BIN
static/img/telegram-2.png
Normal file
BIN
static/img/telegram-2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 186 KiB |
BIN
static/img/telegram-3.png
Normal file
BIN
static/img/telegram-3.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 128 KiB |
BIN
static/img/telegram-4.png
Normal file
BIN
static/img/telegram-4.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
|
@ -0,0 +1,302 @@
|
||||||
|
[//]: # (title: Build a bot to communicate with your smart home over Telegram)
|
||||||
|
[//]: # (description: Integrate Telegram and Platypush to design chat-based automation flow.)
|
||||||
|
[//]: # (image: /img/telegram-1.jpg)
|
||||||
|
[//]: # (published: 2020-01-03)
|
||||||
|
|
||||||
|
You’ve got your smart home fully set up. You regularly like to show off with your friends how cool it is to turn on
|
||||||
|
light bulbs, play videos and movies with a hint to your voice assistant, make coffee, and adjust the thermostat with a
|
||||||
|
tap on an app. Congratulations!
|
||||||
|
|
||||||
|
But if you’re an automation enthusiast who rarely settles, you’ve probably grown frustrated with the number of apps
|
||||||
|
you’ll have to download and the number of interfaces you’ll have to master to control your gadgets.
|
||||||
|
|
||||||
|
You’ll probably have an app for the lights, one for your media center, one for your smart shades, one for your
|
||||||
|
thermostat, and a Google Home app that zealously (and hopelessly) tries to put all of them in the same place.
|
||||||
|
|
||||||
|
Probably, most of these apps won’t communicate with the others, and probably many of them won’t work if you aren’t on
|
||||||
|
the same network as your gadget.
|
||||||
|
|
||||||
|
Wouldn’t it be cool if we could control everything from the same interface, without cluttering our phones or computers
|
||||||
|
with tons of apps, through an interface that is accessible both from mobile and desktop devices as well as through
|
||||||
|
external scripts/integrations, whether you are on your home network or outdoor? An interface that was both lightweight
|
||||||
|
and straightforward to use?
|
||||||
|
|
||||||
|
But wait, hasn’t such an interface been around for a while, under the name of messaging or chat? After all, wouldn’t it
|
||||||
|
be cool to control our house, gadgets, and cloud services through the same interface that we use to send cat pictures to
|
||||||
|
our friends, and through a bot completely tailored to our needs, without all the boilerplate/frustration that usually
|
||||||
|
comes with third-party bots?
|
||||||
|
|
||||||
|
## Chat-powered smart homes
|
||||||
|
|
||||||
|
Enter the world of chatbot-powered smart homes.
|
||||||
|
|
||||||
|
In this story, I’ll show you how to easily set up commands and routines on top of existing smart home installations.
|
||||||
|
|
||||||
|
Many messaging apps and platforms exist out there, but so far the efforts of many of them (Facebook Messenger,
|
||||||
|
Whatsapp, Hangouts, etc.) in providing a usable developer’s API have been disappointing, to say the least.
|
||||||
|
|
||||||
|
Gone are the golden days when everyone used XMPP or IRC as their messaging backbone and it was easy to integrate with
|
||||||
|
services that all spoke the same language: today’s messaging apps’ world is extremely fragmented.
|
||||||
|
|
||||||
|
Moreover, as it’s in the interest of many of the big players to create walled gardens that don’t communicate with the
|
||||||
|
rest of the world, the most-used solutions out there don’t come with officially supported APIs/developer interfaces.
|
||||||
|
|
||||||
|
Not only: some of the big players out there actively discourage users from using anything either than the official app
|
||||||
|
to interact with the
|
||||||
|
platform ([Whatsapp, I’m looking at you](https://news.softpedia.com/news/WhatsApp-Permanently-Bans-Users-of-Unofficial-Clients-475013.shtml)).
|
||||||
|
|
||||||
|
In this extremely fragmented world made of several unconnected islands, Telegram represents a welcome exception. Their
|
||||||
|
[official bot API](https://core.telegram.org/bots/api) is well-documented and supported, and it’s very easy for anyone
|
||||||
|
who knows a bit of programming to build integrations.
|
||||||
|
|
||||||
|
## Create the bot
|
||||||
|
|
||||||
|
It’s quite easy to create a new bot on Telegram:
|
||||||
|
|
||||||
|
- Open a conversation with the [BotFather](https://t.me/botfather).
|
||||||
|
|
||||||
|
- Type `/start` followed by `/newbot` to create a new bot. Give your bot a display name and a username.
|
||||||
|
|
||||||
|
- You’ll be provided with a link to start a conversation with your bot and a unique API key. Store it somewhere as we’ll
|
||||||
|
use it soon to configure the Platypush plugin.
|
||||||
|
|
||||||
|
![BotFather interaction](../img/telegram-2.png)
|
||||||
|
|
||||||
|
## Configuring your bot in Platypush
|
||||||
|
|
||||||
|
- Install Platypush with the HTTP and Telegram extensions:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
pip install 'platypush[http,telegram]'
|
||||||
|
[sudo] apt-get install redis-server
|
||||||
|
[sudo] systemctl start redis
|
||||||
|
[sudo] systemctl enable redis
|
||||||
|
```
|
||||||
|
|
||||||
|
- Play a bit with it if you haven’t done so yet. Find a few things that you’d like to manage/automate — lights, music,
|
||||||
|
media, sensors, database, robots, smart plugs… — and install/configure the associated extensions.
|
||||||
|
|
||||||
|
In this article, we’ll see how to configure our newly-created bot to control Philips Hue lights, music playback, and
|
||||||
|
PiCamera streaming.
|
||||||
|
|
||||||
|
- Add the Telegram configuration to your `~/.config/platypush/config.yaml` file:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
chat.telegram:
|
||||||
|
api_token: <your bot token>
|
||||||
|
|
||||||
|
backend.chat.telegram:
|
||||||
|
enabled: true
|
||||||
|
```
|
||||||
|
|
||||||
|
The [backend](https://platypush.readthedocs.io/en/latest/platypush/backend/chat.telegram.html) enables you to receive
|
||||||
|
events (like new messages, attachments, requests, etc.) and create custom hooks on them.
|
||||||
|
|
||||||
|
The [plugin](https://platypush.readthedocs.io/en/latest/platypush/plugins/chat.telegram.html) enables you to write to
|
||||||
|
chats, programmatically send messages and attachments, administer channels, etc.
|
||||||
|
|
||||||
|
Let’s say that we want the bot to implement the following commands:
|
||||||
|
|
||||||
|
- `/start`: Welcome the new user.
|
||||||
|
- `/help`: Show the available commands.
|
||||||
|
- `/lights_on`: Turn on the lights.
|
||||||
|
- `/lights_off`: Turn off the lights.
|
||||||
|
- `/music_play`: Play a music resource/URL.
|
||||||
|
- `/music_pause`: Toggle the playback pause state.
|
||||||
|
- `/music_next`: Play the next song.
|
||||||
|
- `/music_prev`: Play the previous song.
|
||||||
|
- `/start_streaming`: Start remote streaming on the PiCamera.
|
||||||
|
- `/stop_streaming`: Stop remote streaming on the PiCamera.
|
||||||
|
|
||||||
|
All we have to do is to create event hooks in the Platypush `config.yaml`. In this context, you’ll need to:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
pip install 'platypush[hue,mpd,picamera]'
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Hue lights configuration
|
||||||
|
light.hue:
|
||||||
|
# Hue bridge IP address
|
||||||
|
bridge: 192.168.1.10
|
||||||
|
|
||||||
|
# Default groups to control
|
||||||
|
groups:
|
||||||
|
- Living Room
|
||||||
|
|
||||||
|
# MPD/Mopidy configuration
|
||||||
|
music.mpd:
|
||||||
|
host: localhost
|
||||||
|
port: 6600
|
||||||
|
|
||||||
|
# PiCamera configuration
|
||||||
|
camera.pi:
|
||||||
|
vflip: False
|
||||||
|
hflip: False
|
||||||
|
```
|
||||||
|
|
||||||
|
- Create a script (e.g. `~/.config/platypush/scripts/bot.py`) to handle the logic of your hooks:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from platypush.event.hook import hook
|
||||||
|
from platypush.utils import run
|
||||||
|
|
||||||
|
from platypush.message.event.chat.telegram import CommandMessageEvent
|
||||||
|
|
||||||
|
available_cmds = [
|
||||||
|
'/lights_on',
|
||||||
|
'/lights_off',
|
||||||
|
'/music_play [resource]',
|
||||||
|
'/music_pause',
|
||||||
|
'/music_prev',
|
||||||
|
'/music_next',
|
||||||
|
'/start_streaming',
|
||||||
|
'/stop_streaming',
|
||||||
|
]
|
||||||
|
|
||||||
|
# /start command handler
|
||||||
|
@hook(CommandMessageEvent, command='start')
|
||||||
|
def on_start_cmd(event, **context):
|
||||||
|
run('chat.telegram.send_message', chat_id=event.chat_id,
|
||||||
|
text='Welcome! Type /help to see the available commands')
|
||||||
|
|
||||||
|
# /help command handler
|
||||||
|
@hook(CommandMessageEvent, command='help')
|
||||||
|
def on_help_cmd(event, **context):
|
||||||
|
run('chat.telegram.send_message', chat_id=event.chat_id,
|
||||||
|
text='Available commands:\n\n' + '\n'.join(available_cmds))
|
||||||
|
|
||||||
|
# /lights_on command handler
|
||||||
|
@hook(CommandMessageEvent, command='lights_on')
|
||||||
|
def on_lights_on_cmd(event, **context):
|
||||||
|
run('light.hue.on')
|
||||||
|
run('chat.telegram.send_message', chat_id=event.chat_id,
|
||||||
|
text='Lights turned on')
|
||||||
|
|
||||||
|
# /lights_off command handler
|
||||||
|
@hook(CommandMessageEvent, command='lights_off')
|
||||||
|
def on_lights_off_cmd(event, **context):
|
||||||
|
run('light.hue.off')
|
||||||
|
run('chat.telegram.send_message', chat_id=event.chat_id,
|
||||||
|
text='Lights turned off')
|
||||||
|
|
||||||
|
# /music_play command handler
|
||||||
|
@hook(CommandMessageEvent, command='music_play')
|
||||||
|
def on_music_play_cmd(event, **context):
|
||||||
|
if event.cmdargs:
|
||||||
|
run('music.mpd.play', resource=event.cmdargs[0])
|
||||||
|
else:
|
||||||
|
run('music.mpd.play')
|
||||||
|
|
||||||
|
run('chat.telegram.send_message', chat_id=event.chat_id,
|
||||||
|
text='Playing music')
|
||||||
|
|
||||||
|
# /music_pause command handler
|
||||||
|
@hook(CommandMessageEvent, command='music_pause')
|
||||||
|
def on_music_pause_cmd(event, **context):
|
||||||
|
run('music.mpd.pause')
|
||||||
|
run('chat.telegram.send_message', chat_id=event.chat_id,
|
||||||
|
text='Music paused')
|
||||||
|
|
||||||
|
# /music_prev command handler
|
||||||
|
@hook(CommandMessageEvent, command='music_prev')
|
||||||
|
def on_music_prev_cmd(event, **context):
|
||||||
|
run('music.mpd.previous')
|
||||||
|
run('chat.telegram.send_message', chat_id=event.chat_id,
|
||||||
|
text='Playing previous track')
|
||||||
|
|
||||||
|
# /music_next command handler
|
||||||
|
@hook(CommandMessageEvent, command='music_next')
|
||||||
|
def on_music_next_cmd(event, **context):
|
||||||
|
run('music.mpd.next')
|
||||||
|
run('chat.telegram.send_message', chat_id=event.chat_id,
|
||||||
|
text='Playing next track')
|
||||||
|
|
||||||
|
# /start_streaming command handler
|
||||||
|
@hook(CommandMessageEvent, command='start_streaming')
|
||||||
|
def on_start_streaming_cmd(event, **context):
|
||||||
|
run('camera.pi.start_streaming', listen_port=2222)
|
||||||
|
run('chat.telegram.send_message', chat_id=event.chat_id,
|
||||||
|
text='Camera stream started - check it with vlc tcp/h264://hostname:2222')
|
||||||
|
|
||||||
|
# /stop_streaming command handler
|
||||||
|
@hook(CommandMessageEvent, command='stop_streaming')
|
||||||
|
def on_stop_streaming_cmd(event, **context):
|
||||||
|
run('camera.pi.stop_streaming')
|
||||||
|
run('chat.telegram.send_message', chat_id=event.chat_id,
|
||||||
|
text='Camera stream stopped')
|
||||||
|
```
|
||||||
|
|
||||||
|
- Start Platypush:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# Manual start
|
||||||
|
platypush
|
||||||
|
|
||||||
|
# Service start
|
||||||
|
systemctl --user start platypush.service
|
||||||
|
```
|
||||||
|
|
||||||
|
- Open a conversation with your bot on Telegram through the link provided by the BotFather and start playing with it:
|
||||||
|
|
||||||
|
![Bot interaction](../img/telegram-3.png)
|
||||||
|
|
||||||
|
You can also invite the bot to a chat group if you want to share it with multiple users - now your friends can finally
|
||||||
|
easily mess the lights in your house!
|
||||||
|
|
||||||
|
## Securing access
|
||||||
|
|
||||||
|
Right now the bot is accessible by anyone — you probably don’t want that. You can configure the Telegram back end so it
|
||||||
|
only accepts messages from a specific list of chat IDs. (In Telegram, the chat_id is used both for private users and
|
||||||
|
groups).
|
||||||
|
|
||||||
|
Send a message to the bot and open the Platypush logs or check its standard output: you should see some messages like
|
||||||
|
this:
|
||||||
|
|
||||||
|
```
|
||||||
|
2020-01-03 19:09:32,701| INFO|platypush|Received event: {"type": "event", "target": "turing", "origin": "turing", "id": "***", "args": {"type": "platypush.message.event.chat.telegram.CommandMessageEvent", "chat_id": your_chat_id, "message": {"text": "/help", ...}, "user": {"user_id": your_user_id, "username": "****", "is_bot": false, "link": "https://t.me/you", "language_code": "en", "first_name": "***", "last_name": "***"}, "command": "help", "cmdargs": []}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Copy the `chat_id` associated with your user in the backend configuration:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
backend.chat.telegram:
|
||||||
|
authorized_chat_ids:
|
||||||
|
- your_user_id
|
||||||
|
```
|
||||||
|
|
||||||
|
The bot will now reply with an error if you try to send a message from an unauthorized user.
|
||||||
|
|
||||||
|
![Secured bot interaction](../img/telegram-4.png)
|
||||||
|
|
||||||
|
## Conclusions
|
||||||
|
|
||||||
|
We have only explored one specific feature of the Telegram integration in this article: the ability of the bot to react
|
||||||
|
to [`CommandMessageEvent`](https://platypush.readthedocs.io/en/latest/platypush/events/chat.telegram.html#platypush.message.event.chat.telegram.CommandMessageEvent)
|
||||||
|
events, run actions, and reply with text messages.
|
||||||
|
|
||||||
|
As you can see from
|
||||||
|
the [list of supported Telegram events](https://platypush.readthedocs.io/en/latest/platypush/events/chat.telegram.html)
|
||||||
|
you can do more, such as:
|
||||||
|
|
||||||
|
- Create hooks when someone shares contact info. Ever thought of letting a bot automatically store the new contacts sent
|
||||||
|
to you by your friends via chat?
|
||||||
|
|
||||||
|
- Create hooks when you share a photo, video, or image file. For example, automatically download all media files sent to
|
||||||
|
a chat to your hard drive or a remote Dropbox folder.
|
||||||
|
|
||||||
|
- Run actions on text messages instead of commands. You can use
|
||||||
|
the [`TextMessageEvent`](https://platypush.readthedocs.io/en/latest/platypush/events/chat.telegram.html#platypush.message.event.chat.telegram.TextMessageEvent),
|
||||||
|
for example, if you prefer to type “turn on the lights” instead of `/lights_on`.
|
||||||
|
|
||||||
|
- Take a picture from the camera and send it to yourself through
|
||||||
|
the [`send_photo`](https://platypush.readthedocs.io/en/latest/platypush/events/chat.telegram.html#platypush.message.event.chat.telegram.TextMessageEvent)
|
||||||
|
action.
|
||||||
|
|
||||||
|
- Automatically moderate chat groups through
|
||||||
|
the [`chat.telegram`](https://platypush.readthedocs.io/en/latest/platypush/plugins/chat.telegram.html) actions.
|
||||||
|
|
||||||
|
- You can also deploy multiple bots, e.g. per device, so you can run actions on a specific device from the associated
|
||||||
|
chat, or instead, use a single bot as entry point and deliver messages to other devices over MQTT, Kafka, or HTTP API.
|
||||||
|
|
||||||
|
As long as there’s a plugin for it, you can now do it through your chat bot.
|
Loading…
Reference in a new issue