Skip to content

Commit

Permalink
[telegram] Added support for long polling (openhab#8180)
Browse files Browse the repository at this point in the history
Closes openhab#7043
Signed-off-by: Christian Kittel <ckittel@gmx.de>
  • Loading branch information
EvilPingu authored and CSchlipp committed Sep 12, 2020
1 parent a5341d9 commit e74f374
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 26 deletions.
4 changes: 4 additions & 0 deletions bundles/org.openhab.binding.telegram/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ As described in the Telegram Bot API, this is the manual procedure needed in ord

- Open a browser and invoke `https://api.telegram.org/bot<token>/getUpdates` (where `<token>` is the authentication token previously obtained)
- Look at the JSON result to find the value of `id`: that's the chatID.

Note that if using a Telegram group chat, the group chatIDs are prefixed with a dash that must be included in the config (e.g. `-22334455`).
If this does not work for you (the JSON response may be empty), or you want to send to *more* than one recipient (= another chatID), the alternative is to contact (= open a chat with) a Telegram bot to respond with the chatID.
There's a number of them such as `@myidbot` or `@chatid_echo_bot` - open a chat, eventually tap `/start` and it will return the chatID you're looking for.
Expand Down Expand Up @@ -61,11 +62,14 @@ In order to send a message, an action must be used instead.
| `proxyHost` | None | No | Proxy host for telegram binding. |
| `proxyPort` | None | No | Proxy port for telegram binding. |
| `proxyType` | SOCKS5 | No | Type of proxy server for telegram binding (SOCKS5 or HTTP). Default: SOCKS5 |
| `longPollingTime` | 25 | No | Timespan for long polling the telegram API |

By default chat ids are bi-directionally, i.e. they can send and receive messages.
They can be prefixed with an access modifier:

- `<` restricts the chat to send only, i.e. this chat id can send messages to openHAB, but will never receive a notification.
- `>` restricts the chat to receive only, i.e. this chat id will receive all notifications, but messages from this chat id will be discarded.

To use the reply function, chat ids need to be bi-directional.

telegram.thing (no proxy):
Expand Down
4 changes: 3 additions & 1 deletion bundles/org.openhab.binding.telegram/pom.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

<modelVersion>4.0.0</modelVersion>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,5 @@ public class TelegramBindingConstants {
public static final String LASTMESSAGEUSERNAME = "lastMessageUsername";
public static final String CHATID = "chatId";
public static final String REPLYID = "replyId";
public static final String LONGPOLLINGTIME = "longPollingTime";
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public class TelegramConfiguration {
private @Nullable Integer proxyPort;
private @Nullable String proxyType;
private String parseMode = "";
private int longPollingTime;

public @Nullable String getBotUsername() {
return botUsername;
Expand Down Expand Up @@ -63,4 +64,8 @@ public String getParseMode() {
public @Nullable String getProxyType() {
return proxyType;
}

public int getLongPollingTime() {
return longPollingTime;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
import com.pengrad.telegrambot.model.request.ParseMode;
import com.pengrad.telegrambot.request.BaseRequest;
import com.pengrad.telegrambot.request.GetFile;
import com.pengrad.telegrambot.request.GetUpdates;
import com.pengrad.telegrambot.response.BaseResponse;

import okhttp3.OkHttpClient;
Expand Down Expand Up @@ -140,31 +141,15 @@ public void initialize() {
TelegramConfiguration config = getConfigAs(TelegramConfiguration.class);

String botToken = config.getBotToken();
authorizedSenderChatId.clear();
receiverChatId.clear();

for (String chatIdStr : config.getChatIds()) {
String trimmedChatId = chatIdStr.trim();
try {
if (trimmedChatId.startsWith("<")) {
// inbound only
authorizedSenderChatId.add(Long.valueOf(trimmedChatId.substring(1)));
} else if (trimmedChatId.startsWith(">")) {
// outbound only
receiverChatId.add(Long.valueOf(trimmedChatId.substring(1)));
} else {
// bi-directional (default)
Long chatId = Long.valueOf(trimmedChatId);
authorizedSenderChatId.add(chatId);
receiverChatId.add(chatId);
}
} catch (NumberFormatException e) {
logger.warn("The chat id {} is not a number and will be ignored", chatIdStr);
}
List<String> chatIds = config.getChatIds();
if (chatIds != null) {
createReceiverChatIdsAndAuthorizedSenderChatIds(chatIds);
}
if (config.getParseMode() != null && !config.getParseMode().isEmpty()) {
String parseModeAsString = config.getParseMode();
if (!parseModeAsString.isEmpty()) {
try {
parseMode = ParseMode.valueOf(config.getParseMode());
parseMode = ParseMode.valueOf(parseModeAsString);
} catch (IllegalArgumentException e) {
logger.warn("parseMode is invalid and will be ignored. Only Markdown or HTML are allowed values");
}
Expand Down Expand Up @@ -196,7 +181,37 @@ public void initialize() {
updateStatus(ThingStatus.UNKNOWN);
delayThingOnlineStatus();
TelegramBot localBot = bot = new TelegramBot.Builder(botToken).okHttpClient(botLibClient).build();
localBot.setUpdatesListener(this::handleUpdates, this::handleExceptions);
localBot.setUpdatesListener(this::handleUpdates, this::handleExceptions,
getGetUpdatesRequest(config.getLongPollingTime()));
}

private void createReceiverChatIdsAndAuthorizedSenderChatIds(List<String> chatIds) {
authorizedSenderChatId.clear();
receiverChatId.clear();

for (String chatIdStr : chatIds) {
String trimmedChatId = chatIdStr.trim();
try {
if (trimmedChatId.startsWith("<")) {
// inbound only
authorizedSenderChatId.add(Long.valueOf(trimmedChatId.substring(1)));
} else if (trimmedChatId.startsWith(">")) {
// outbound only
receiverChatId.add(Long.valueOf(trimmedChatId.substring(1)));
} else {
// bi-directional (default)
Long chatId = Long.valueOf(trimmedChatId);
authorizedSenderChatId.add(chatId);
receiverChatId.add(chatId);
}
} catch (NumberFormatException e) {
logger.warn("The chat id {} is not a number and will be ignored", chatIdStr);
}
}
}

private GetUpdates getGetUpdatesRequest(int longPollingTime) {
return new GetUpdates().timeout(longPollingTime * 1000);
}

private void handleExceptions(TelegramException exception) {
Expand All @@ -206,7 +221,9 @@ private void handleExceptions(TelegramException exception) {
BaseResponse localResponse = exception.response();
if (localResponse.errorCode() == 401) { // unauthorized
cancelThingOnlineStatusJob();
localBot.removeGetUpdatesListener();
if (localBot != null) {
localBot.removeGetUpdatesListener();
}
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Unauthorized attempt to connect to the Telegram server, please check if the bot token is valid");
return;
Expand All @@ -223,6 +240,10 @@ private void handleExceptions(TelegramException exception) {
}

private String getFullDownloadUrl(String fileId) {
final TelegramBot bot = this.bot;
if (bot == null) {
return "";
}
return bot.getFullFilePath(bot.execute(new GetFile(fileId)).file());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
</parameter>
<parameter name="chatIds" type="text" required="true" multiple="true">
<label>Chat Id(s)</label>
<description>One or more chat id(s). Access modifiers ("&lt;" for inbound only, "&gt;" for outbound only) can be used as prefix (optional).</description>
<description>One or more chat id(s). Access modifiers ("&lt;" for inbound only, "&gt;" for outbound only) can be
used as prefix (optional).</description>
</parameter>
<parameter name="parseMode" type="text" required="false">
<label>Parse Mode</label>
Expand Down Expand Up @@ -55,6 +56,11 @@
<default>SOCKS5</default>
<description>Enter your proxy type. Default: SOCKS5</description>
</parameter>
<parameter name="longPollingTime" type="integer" min="0" max="50" unit="s">
<label>Long Polling Time</label>
<description>Enter the long polling time in seconds.</description>
<default>25</default>
</parameter>
</config-description>
</thing-type>

Expand Down

0 comments on commit e74f374

Please sign in to comment.