Merge PR #396: New Plugin: Telegram

master
Jenkins nymea 2021-02-26 10:28:12 +01:00
commit 7170f2b9bf
11 changed files with 444 additions and 0 deletions

10
debian/control vendored
View File

@ -693,6 +693,15 @@ Description: nymea.io plugin for Texas Instruments devices
This package will install the nymea.io plugin for Texas Instruments devices
Package: nymea-plugin-telegram
Architecture: any
Depends: ${shlibs:Depends},
${misc:Depends},
nymea-plugins-translations,
Description: nymea.io plugin for Telegram
This plugin allows nymea to send messages to telegram via the bot API.
Package: nymea-plugin-tplink
Architecture: any
Depends: ${shlibs:Depends},
@ -1128,6 +1137,7 @@ Depends: nymea-plugin-anel,
nymea-plugin-lifx,
nymea-plugin-mailnotification,
nymea-plugin-texasinstruments,
nymea-plugin-telegram,
nymea-plugin-nanoleaf,
nymea-plugin-netatmo,
nymea-plugin-networkdetector,

View File

@ -0,0 +1 @@
usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_integrationplugintelegram.so

View File

@ -57,6 +57,7 @@ PLUGIN_DIRS = \
tado \
tasmota \
tcpcommander \
telegram \
texasinstruments \
tplink \
tuya \

21
telegram/README.md Normal file
View File

@ -0,0 +1,21 @@
# Telegram
This plugin allows to send message to Telegram via the Telegram bot API.
https://core.telegram.org/bots/api
## Usage
In order to use the telegram plugin, a new bot must be created and the bot access token provided to nymea.
Instructions to create a telegram bot:
* Open a conversation to @BotFather
* Send the message `/newbot` to BotFather and follow the instructions until BotFather hands out the token for your bot.
* Now open a conversation to your bot and write it a message. The content of this message does not matter but it is important that at least one message has been sent to the bot in order for it to work.
* Alternatively, add the bot to a group chat and send a message to the group mentioning the bot with @<bot_name>. The content of this message does not matter as long as it contains a mention for the bot. This is required for the bot to see the message and allow nymea recognizing the group.
* Now return to nymea and set up a new telegram thing as usual, providing the token during the setup.

View File

@ -0,0 +1,182 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; version 3. This project is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "integrationplugintelegram.h"
#include "plugininfo.h"
#include "network/networkaccessmanager.h"
#include <QJsonDocument>
IntegrationPluginTelegram::IntegrationPluginTelegram(QObject* parent): IntegrationPlugin (parent)
{
}
IntegrationPluginTelegram::~IntegrationPluginTelegram()
{
}
void IntegrationPluginTelegram::discoverThings(ThingDiscoveryInfo *info)
{
QString token = info->params().paramValue(telegramDiscoveryTokenParamTypeId).toString();
QUrl url(QString("https://api.telegram.org/bot%1/getUpdates").arg(token));
QNetworkRequest request(url);
QNetworkReply *reply = hardwareManager()->networkManager()->get(request);
connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater);
connect(reply, &QNetworkReply::finished, info, [=](){
if (reply->error() != QNetworkReply::NoError) {
qCWarning(dcTelegram()) << "Error fetching channels from telegram API:" << reply->error() << reply->errorString();
info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Error connecting to Telegram."));
return;
}
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll(), &error);
if (error.error != QJsonParseError::NoError) {
qCWarning(dcTelegram()) << "Error parsing JSON reply from telegram API:" << error.error << error.errorString();
info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Unexpected data from Telegram."));
return;
}
if (!jsonDoc.toVariant().toMap().value("ok").toBool()) {
qCWarning(dcTelegram()) << "Json reply doesn't contain OK" << qUtf8Printable(jsonDoc.toJson(QJsonDocument::Indented));
info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("An error happened on the Telegram servers."));
return;
}
QVariantList entries = jsonDoc.toVariant().toMap().value("result").toList();
QList<int> addedChats;
foreach (const QVariant &entry, entries) {
QVariantMap messageMap = entry.toMap().value("message").toMap();
int chatId = messageMap.value("chat").toMap().value("id").toInt();
if (addedChats.contains(chatId)) {
continue;
}
QString chatName = QString("%1 %2")
.arg(messageMap.value("chat").toMap().value("first_name").toString())
.arg(messageMap.value("chat").toMap().value("last_name").toString());
QString type = messageMap.value("chat").toMap().value("type").toString();
if (type == "group") {
chatName = messageMap.value("chat").toMap().value("title").toString();
}
ThingDescriptor descriptor(telegramThingClassId, chatName, type == "group" ? "Group" : "Private");
ParamList params;
params << Param(telegramThingTokenParamTypeId, token);
params << Param(telegramThingChatIdParamTypeId, chatId);
descriptor.setParams(params);
Thing *existingThing = myThings().findByParams(params);
if (existingThing) {
descriptor.setThingId(existingThing->id());
}
addedChats.append(chatId);
info->addThingDescriptor(descriptor);
}
info->finish(Thing::ThingErrorNoError);
});
}
void IntegrationPluginTelegram::setupThing(ThingSetupInfo *info)
{
Thing *thing = info->thing();
qCDebug(dcTelegram()) << "Setting up telegram chat" << thing->name() << thing->id().toString();
QString token = info->thing()->paramValue(telegramThingTokenParamTypeId).toString();
// int chatId = info->thing()->paramValue(telegramThingChatIdParamTypeId).toInt();
QString url = QString("https://api.telegram.org/bot%1/getMe").arg(token);
QNetworkRequest request(url);
QNetworkReply *reply = hardwareManager()->networkManager()->get(request);
connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater);
connect(reply, &QNetworkReply::finished, info, [reply, info]() {
if (reply->error() != QNetworkReply::NoError) {
qCWarning(dcTelegram()) << "Error fetching user profile:" << reply->errorString() << reply->error();
//: Error setting up thing
info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Error connecting to Telegram."));
return;
}
qCDebug(dcTelegram()) << "Telegram" << info->thing()->name() << info->thing()->id().toString() << "setup complete";
info->finish(Thing::ThingErrorNoError);
});
}
void IntegrationPluginTelegram::executeAction(ThingActionInfo *info)
{
Thing *thing = info->thing();
Action action = info->action();
qCDebug(dcTelegram()) << "Executing action" << action.actionTypeId() << "for" << thing->name() << thing->id().toString();
QString token = info->thing()->paramValue(telegramThingTokenParamTypeId).toString();
int chatId = info->thing()->paramValue(telegramThingChatIdParamTypeId).toInt();
QString title = action.paramValue(telegramNotifyActionTitleParamTypeId).toString();
QString body = action.paramValue(telegramNotifyActionBodyParamTypeId).toString();
QString message = title + "\n" + body;
QString url = QString("https://api.telegram.org/bot%1/sendMessage?chat_id=%2&text=%3").arg(token).arg(chatId).arg(message);
QNetworkRequest request(url);
QNetworkReply *reply = hardwareManager()->networkManager()->get(request);
connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater);
connect(reply, &QNetworkReply::finished, info, [reply, info]{
if (reply->error() != QNetworkReply::NoError) {
qCWarning(dcTelegram()) << "Sending message failed for" << info->thing()->name() << info->thing()->id() << reply->errorString() << reply->error();
emit info->finish(Thing::ThingErrorHardwareNotAvailable);
return;
}
QByteArray data = reply->readAll();
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
if (error.error != QJsonParseError::NoError) {
qCWarning(dcTelegram()) << "Error reading reply from Telegram for" << info->thing()->name() << info->thing()->id().toString() << error.errorString();
qCWarning(dcTelegram()) << qUtf8Printable(data);
info->finish(Thing::ThingErrorHardwareFailure);
return;
}
QVariantMap replyMap = jsonDoc.toVariant().toMap();
if (!replyMap.value("ok").toBool()) {
qCWarning(dcTelegram()) << "Error sending message." << info->thing()->name() << info->thing()->id().toString();
info->finish(Thing::ThingErrorAuthenticationFailure, QT_TR_NOOP("The Telegram bot account seems to be disabled."));
return;
}
qCDebug(dcTelegram()) << "Message sent successfully";
info->finish(Thing::ThingErrorNoError);
});
}

View File

@ -0,0 +1,53 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; version 3. This project is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef INTEGRATIONPLUGINPUSHBULLET_H
#define INTEGRATIONPLUGINPUSHBULLET_H
#include "integrations/integrationplugin.h"
class IntegrationPluginTelegram: public IntegrationPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "io.nymea.IntegrationPlugin" FILE "integrationplugintelegram.json")
Q_INTERFACES(IntegrationPlugin)
public:
explicit IntegrationPluginTelegram(QObject *parent = nullptr);
~IntegrationPluginTelegram() override;
void discoverThings(ThingDiscoveryInfo *info) override;
void setupThing(ThingSetupInfo *info) override;
void executeAction(ThingActionInfo *info) override;
};
#endif

View File

@ -0,0 +1,68 @@
{
"displayName": "Telegram",
"name": "Telegram",
"id": "bc95b5c8-f2f1-4bcb-bf88-8d165ee06114",
"vendors": [
{
"displayName": "Telegram",
"name": "telegram",
"id": "45bb2595-4340-49df-8b88-8c6037c8d1c8",
"thingClasses": [
{
"id": "f71bac7a-90e1-4810-9c31-531ac5f596fb",
"name": "telegram",
"displayName": "Telegram messages",
"createMethods": ["discovery", "user"],
"interfaces": ["notifications"],
"discoveryParamTypes": [
{
"id": "2350bef6-d237-4bee-8e7e-6ab2c205f332",
"name": "token",
"displayName": "Bot access token",
"type": "QString"
}
],
"paramTypes": [
{
"id": "28e4c161-f77a-4baa-b415-dc693330756f",
"name": "token",
"displayName": "Bot access token",
"type": "QString"
},
{
"id": "9c1f9d6c-e15a-4b76-a441-f1b96812cc28",
"name": "chatId",
"displayName": "Chat ID",
"type": "QString"
}
],
"actionTypes": [
{
"id": "36b4ddf9-1a05-46c6-b0c9-2c3b8c835d42",
"name": "notify",
"displayName": "notify",
"paramTypes": [
{
"id": "891772ed-45bc-402e-828a-5349bedc29e5",
"name": "title",
"displayName": "title",
"type": "QString",
"inputType": "TextLine",
"defaultValue": ""
},
{
"id": "374d059f-feab-4c49-8d91-e6066f80ed5a",
"name": "body",
"displayName": "body",
"type": "QString",
"inputType": "TextArea",
"defaultValue": ""
}
]
}
]
}
]
}
]
}

14
telegram/meta.json Normal file
View File

@ -0,0 +1,14 @@
{
"title": "Telegram",
"tagline": "Send notifictions to Telegram.",
"icon": "telegram.svg",
"stability": "consumer",
"offline": false,
"technologies": [
"cloud"
],
"categories": [
"online-service",
"notification"
]
}

13
telegram/telegram.pro Normal file
View File

@ -0,0 +1,13 @@
include(../plugins.pri)
TARGET = $$qtLibraryTarget(nymea_integrationplugintelegram)
QT+= network
SOURCES += \
integrationplugintelegram.cpp
HEADERS += \
integrationplugintelegram.h

1
telegram/telegram.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 240 240"><defs><linearGradient id="a" x1=".667" x2=".417" y1=".167" y2=".75"><stop offset="0" stop-color="#37aee2"/><stop offset="1" stop-color="#1e96c8"/></linearGradient><linearGradient id="b" x1=".66" x2=".851" y1=".437" y2=".802"><stop offset="0" stop-color="#eff7fc"/><stop offset="1" stop-color="#fff"/></linearGradient></defs><circle cx="120" cy="120" r="120" fill="url(#a)"/><path fill="#c8daea" d="M98 175c-3.888 0-3.227-1.468-4.568-5.17L82 132.207 170 80"/><path fill="#a9c9dd" d="M98 175c3 0 4.325-1.372 6-3l16-15.558-19.958-12.035"/><path fill="url(#b)" d="M100.04 144.41l48.36 35.729c5.519 3.045 9.501 1.468 10.876-5.123l19.685-92.763c2.015-8.08-3.08-11.746-8.36-9.349l-115.59 44.571c-7.89 3.165-7.843 7.567-1.438 9.528l29.663 9.259 68.673-43.325c3.242-1.966 6.218-.91 3.776 1.258"/></svg>

After

Width:  |  Height:  |  Size: 855 B

View File

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
<context>
<name>IntegrationPluginTelegram</name>
<message>
<location filename="../integrationplugintelegram.cpp" line="58"/>
<location filename="../integrationplugintelegram.cpp" line="119"/>
<source>Error connecting to Telegram.</source>
<extracomment>Error setting up thing</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../integrationplugintelegram.cpp" line="65"/>
<source>Unexpected data from Telegram.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../integrationplugintelegram.cpp" line="70"/>
<source>An error happened on the Telegram servers.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../integrationplugintelegram.cpp" line="169"/>
<source>The Telegram bot account seems to be disabled.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Telegram</name>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/telegram/plugininfo.h" line="34"/>
<location filename="../../../build-nymea-plugins-Desktop-Debug/telegram/plugininfo.h" line="37"/>
<source>Access token</source>
<extracomment>The name of the ParamType (ThingClass: telegram, Type: discovery, ID: {2350bef6-d237-4bee-8e7e-6ab2c205f332})
----------
The name of the ParamType (ThingClass: telegram, Type: thing, ID: {28e4c161-f77a-4baa-b415-dc693330756f})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/telegram/plugininfo.h" line="40"/>
<source>Chat ID</source>
<extracomment>The name of the ParamType (ThingClass: telegram, Type: thing, ID: {9c1f9d6c-e15a-4b76-a441-f1b96812cc28})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/telegram/plugininfo.h" line="43"/>
<location filename="../../../build-nymea-plugins-Desktop-Debug/telegram/plugininfo.h" line="46"/>
<source>Telegram</source>
<extracomment>The name of the vendor ({45bb2595-4340-49df-8b88-8c6037c8d1c8})
----------
The name of the plugin Telegram ({bc95b5c8-f2f1-4bcb-bf88-8d165ee06114})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/telegram/plugininfo.h" line="49"/>
<source>Telegram messages</source>
<extracomment>The name of the ThingClass ({f71bac7a-90e1-4810-9c31-531ac5f596fb})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/telegram/plugininfo.h" line="52"/>
<source>body</source>
<extracomment>The name of the ParamType (ThingClass: telegram, ActionType: notify, ID: {374d059f-feab-4c49-8d91-e6066f80ed5a})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/telegram/plugininfo.h" line="55"/>
<source>notify</source>
<extracomment>The name of the ActionType ({36b4ddf9-1a05-46c6-b0c9-2c3b8c835d42}) of ThingClass telegram</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/telegram/plugininfo.h" line="58"/>
<source>title</source>
<extracomment>The name of the ParamType (ThingClass: telegram, ActionType: notify, ID: {891772ed-45bc-402e-828a-5349bedc29e5})</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
</TS>