New Telegram Binding - Tester and Feedback welcome

We are working on it :slight_smile: I’m trying to support Belgadon with the binding.

What we did so far is to migrate the actions provided by the OH1 telegram action module to the OH2 framework and to make use of the TelegramBots API instead of using a http client directly which provides a better abstraction and saves us some code. Now, it’s not necessary anymore to use both the OH1 action to send messages and the OH2 binding to receive replies from the user.

I would like to present my proposal here to have a base for further discussions. I currently see two use-cases:

1. Use-case: your bot wants to send you a message (and wants an answer from the user)
This is very similar to what Belgadon already presented. I will just shows how it would look in a real working example.

Let’s say we have the following items

String telegramMessage "Telegram Message" { channel = "telegram:telegramBot:620b3747:lastMessageText" }
String telegramReplyId "Telegram Reply Id" { channel = "telegram:telegramBot:620b3747:replyId" }
Switch PresenceAnyone "Anyone [MAP(presence.map):%s]" <presence>

and this is our first rule:

rule "Nobody's at home"
when
   Item PresenceAnyone changed to OFF
then
    val actions = getActions("telegram","telegram:telegramBot:620b3747")
   actions.sendTelegram("MyOH2Bot", "No one is at home, but some lights are still on. Do you want me to turn off the lights?", "Reply_Lights", "Yes", "No")
end

Notice that the third arguments “Reply_Lights” is quite important because it acts as a connection between the sent message and the answer (we will see later)

The other arguments define the button names that will be shown. The alternative of using variable arguments would be to use exactly one argument like “[ Yes ] [ No ]” and to split that internally with String operations.

After this is send, it looks like this:

Then, we have a second rule

rule "Reply handler for lights"
when
    Item telegramReplyId received update Reply_Lights
then
    val actions = getActions("telegram","telegram:telegramBot:620b3747")

    if (telegramMessage.state.toString == "Yes")
    {
        gLights.sendCommand(OFF)
        actions.sendTelegramAnswer("MyOH2Bot", telegramReplyId.state.toString, "Ok, lights are *off* now.") 
    }
    else
    {
        actions.sendTelegramAnswer("MyOH2Bot", telegramReplyId.state.toString, "Ok, I'll leave them *on*.")
    }
end

Here, the “Reply_Lights” is again used in the rule to know for what request the Yes/No answer belongs to.

After the user pressed one of the buttons, the reply markup is removed and the answer is provided:

I pushed the changes for this prototype to Belgadons repository.

2. Use-case: Providing commands

This is not yet implemented, but I think it would be useful if the user could send commands to the bot via /sendcommand Bedroomlight ON
or to get a status: /status TemperatureLivingRoom with reply “The temperature in the “Living Room” is 21°C”
With /help or /list we could show the user a list of available commands and items.

The UI of the telegram client can even show you a list of available commands and you just have to tap on one of them (see Commands).

3 Likes

Wow, it sounds good. :grinning:
@ZzetT Any plans to offer in next time a jar file with your changes to test the binding?

I’m interested in this! Right now I can’t really think of a use-case for bots for my home (almost everything is automated and ‘automatically’ controlled), but this is a really good way for controlling your home fast.

Hey Alex, sounds great… Very nice work. Can’t wait to try it!

Just to let you know: OH is in a bit of movement at the moment. And the OH1 actions must be migrated over in a not so far future. If the new binding is capable of replacing the OH1 action, please submit a PR ASAP and I’ll prioritize the review.

One question though: Is this binding already providing OH2 actions (like the MQTT binding does?
See: https://github.com/openhab/openhab2-addons/blob/master/addons/binding/org.openhab.binding.mqtt/src/main/java/org/openhab/binding/mqtt/action/MQTTActions.java)

Cheers, David

Yes, in my opinion the idea is to replace the OH1 Telegram actions completly. However, we still need some time I think to test it a bit more, to write documentations and make it “ready”. (It’s our first binding that we develop).
What exactly do you have in mind? By what time should we have it ready for review?
I guess you want to avoid the migration effort for the OH1 actions, right?

However, there is one thing were I’m not sure if we can replace it completly. The OH1 Telegram actions support and API where you can download a picture from a passwort protected location:

sendTelegramPhoto(String group, String photoURL, String caption, String username, String password)

But this is not supported by the library we are using here (since we are not directly using a HttpClient anymore). Not sure if this is a big problem.Ok, in the worst case, we have to use a HttpClient to download the picture first and to pass it to the TelegramBot Lib.

Yes, it is. That’s also why I was asking a few things in this thread (Actions).

1 Like

Take your time. But aiming at 2.5 would be sweet (around June).
And yes, with having this binding there is no point in converting the telegram OH1 action.

Awesome.

Thanks,
David

I have a general question to the OH architects.

Since we are using an external java library (TelegramBots) to simplify the implementation, this comes with the following costs:

  1. it uses an Apache Http Client (see DefaultAbsSender.java), but this comment seems to “forbid” this?
  2. Since the library is based on a Long polling approach, it uses at least two threads (see DefaultBotSession.java for implementation details), but the Coding guidelines explicitly state “Creation of threads must be avoided.”
  3. the license of the libary itself is MIT but it depends on other libraries like Jackson for xml processing based on Apache License 2.0

Do you see any problems with one of those points?

  1. Not cool. Ideally some shim adapter classes are used. If we have the http usage under full control, https certificates can be managed in a central place and so on.
  2. Not a problem. If there are alternatives like websockets etc those are preferred of course.
  3. Eclipse, Apache and MIT are all accepted licenses.

Cheers, David

Sorry for the long delay, but it took some time to rewrite the Telegram library so that it uses a Jetty client instead of an Apache client.

If you want to try it, just download the following jar and put it into your addons folder: https://github.com/Belgadon/openhab2-addons/releases/download/2.4.0.M5_telegramBot1/org.openhab.binding.telegram-2.4.0-SNAPSHOT.jar

You can find an example on how to use it in one of my previous posts. I’ll update the documentation soon.

6 Likes

Thanks, very good work.

I am testing the binding and so far it has been very useful, about using “/commands” would be great. Thanks again

Hi, I have to comment that when I don’t use the rule that contains the action for a few hours, when the rule is executed for the first time it doesn’t send the message to telegram until that rule is executed for second time. can you check it? thanks in advance

Is there a PR made to the openhab2-addons repo already? :slight_smile:
We recently merged a new xmpp client and mail client and telegram would be nice to have as well.

1 Like

I am using " sendTelegram(“botname”,“message to send”) " is this correct with the new binding ?

Just I am getting the error

[ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Virtual Send Telegram': An error occurred during the script execution: index=2, size=2

from my previously used telegram sending rule

Update :
found the cause when updating to this version I removed both
action.telegram 1.13.0 and binding.telegram (previous version)

and in error did not re install the action.telegram with binding.telegram 2.4.0

Please see my post from New Telegram Binding - Tester and Feedback welcome - #19 by ZzetT Compared to the old Telegram binding you have to write it in the following way:

val actions = getActions("telegram","telegram:telegramBot:(your bot id)")
actions.sendTelegram(“botname”,“message to send”)

Ok, I’ll update the documentation first and then will make a PR.

3 Likes

Hello!

I’m interested in you new binding, but I can’t get it to work :sweat:

I’va added the new .jar in the addons (as you said, no need of the action right?) and copy/pasted your items and rules changing only the BOT Id, but when I run the rule its says:

Rule 'Nobody's at home': 'sendTelegram' is not a member of 'org.eclipse.smarthome.core.thing.binding.ThingActions'; line 6, column 5, length 152

Futhermore, I can’t get the discovery on paperUI to create my bot things.
The binding is listed in the karaf console and is active.

Do you have any idea what could cause this?

Anyway thank you for your work, it looks very promising !

alterecoop.fr

If you can’t see the discovery in the PaperUI where do you get the bot id from?
Please note that the id I meant is the thing id you will see in the PaperUi after you did the following steps:
Configuration → Things → “Add” → Telegram Binding → Telegram Bot → add botToken/botUsername/chatIds → Ok
After that you should be able to see the Thing “Telegram Bot” saying “online” with your thing id.

It possible this binding whilst awaiting a reply is causing a heavy delay to openhab processing or openhab errors are causing heavy delays, ( the binding is working well , just looking how complex replys/interactions can get … )

Ok i got it to work, my error was a due to a bad apache configuration.

Thanks alot it’s very cool, it works like a charm!

alterecoop.fr

I’m currently not sure when I can go for a Pull Request. I’m having trouble to get the new OH environment running which I need to migrate the binding. I’m following the discussion from issue#5005 and have similar problems as other users.

On the other hand, I have the JAR running on the OH2.4 environemnt, but it randomly fails to send a message with the following stack trace:

org.telegram.telegrambots.meta.exceptions.TelegramApiException: Unable to execute sendmessage method
	at org.telegram.telegrambots.bots.DefaultAbsSender.sendApiMethod(DefaultAbsSender.java:750) ~[?:?]
	at org.telegram.telegrambots.meta.bots.AbsSender.execute(AbsSender.java:47) ~[?:?]
	at org.openhab.binding.telegram.bot.TelegramActions.sendTelegram(TelegramActions.java:156) ~[?:?]
	at org.openhab.binding.telegram.bot.TelegramActions.sendTelegram(TelegramActions.java:110) ~[?:?]
	at org.openhab.binding.telegram.bot.TelegramActions.sendTelegram(TelegramActions.java:171) ~[?:?]
	at org.openhab.binding.telegram.bot.TelegramActions.sendTelegram(TelegramActions.java:241) ~[?:?]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeOperation(XbaseInterpreter.java:1086) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeOperation(XbaseInterpreter.java:1061) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._invokeFeature(XbaseInterpreter.java:1047) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeFeature(XbaseInterpreter.java:992) ~[?:?]
	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:151) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:772) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:220) ~[?:?]
	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:447) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:228) ~[?:?]
	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluate(XbaseInterpreter.java:190) ~[?:?]
	at org.eclipse.smarthome.model.script.runtime.internal.engine.ScriptImpl.execute(ScriptImpl.java:82) ~[?:?]
	at org.eclipse.smarthome.model.rule.runtime.internal.engine.RuleEngineImpl.lambda$2(RuleEngineImpl.java:341) ~[?:?]
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:?]
	at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:?]
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) [?:?]
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) [?:?]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:?]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:?]
	at java.lang.Thread.run(Thread.java:748) [?:?]
Caused by: java.io.IOException: java.util.concurrent.ExecutionException: java.io.EOFException: HttpConnectionOverHTTP@792b4c(l:/192.168.178.60:42410 <-> r:api.telegram.org/149.154.167.220:443,closed=false)=>HttpChannelOverHTTP@1f8b522(exchange=HttpExchange@1a675de req=TERMINATED/null@null res=PENDING/null@null)[send=HttpSenderOverHTTP@b03f41(req=QUEUED,snd=COMPLETED,failure=null)[HttpGenerator@18040ee{s=START}],recv=HttpReceiverOverHTTP@10ba099(rsp=IDLE,failure=null)[HttpParser{s=CLOSED,0 of -1}]]<-DecryptedEndPoint@1332263{api.telegram.org/149.154.167.220:443<->/192.168.178.60:42410,OPEN,fill=-,flush=-,to=52951026/0}->HttpConnectionOverHTTP@792b4c(l:/192.168.178.60:42410 <-> r:api.telegram.org/149.154.167.220:443,closed=false)=>HttpChannelOverHTTP@1f8b522(exchange=HttpExchange@1a675de req=TERMINATED/null@null res=PENDING/null@null)[send=HttpSenderOverHTTP@b03f41(req=QUEUED,snd=COMPLETED,failure=null)[HttpGenerator@18040ee{s=START}],recv=HttpReceiverOverHTTP@10ba099(rsp=IDLE,failure=null)[HttpParser{s=CLOSED,0 of -1}]]->SocketChannelEndPoint@d056b3{api.telegram.org/149.154.167.220:443<->/192.168.178.60:42410,ISHUT,fill=-,flush=-,to=43/0}{io=0/0,kio=0,kro=1}->SslConnection@1f2fdf7{NEED_WRAP,eio=-1/-1,di=-1}=>HttpConnectionOverHTTP@792b4c(l:/192.168.178.60:42410 <-> r:api.telegram.org/149.154.167.220:443,closed=false)=>HttpChannelOverHTTP@1f8b522(exchange=HttpExchange@1a675de req=TERMINATED/null@null res=PENDING/null@null)[send=HttpSenderOverHTTP@b03f41(req=QUEUED,snd=COMPLETED,failure=null)[HttpGenerator@18040ee{s=START}],recv=HttpReceiverOverHTTP@10ba099(rsp=IDLE,failure=null)[HttpParser{s=CLOSED,0 of -1}]]
	at org.telegram.telegrambots.bots.DefaultAbsSender.sendHttpPostRequest(DefaultAbsSender.java:806) ~[?:?]
	at org.telegram.telegrambots.bots.DefaultAbsSender.sendMethodRequest(DefaultAbsSender.java:796) ~[?:?]
	at org.telegram.telegrambots.bots.DefaultAbsSender.sendApiMethod(DefaultAbsSender.java:747) ~[?:?]
	... 32 more
Caused by: java.util.concurrent.ExecutionException: java.io.EOFException: HttpConnectionOverHTTP@792b4c(l:/192.168.178.60:42410 <-> r:api.telegram.org/149.154.167.220:443,closed=false)=>HttpChannelOverHTTP@1f8b522(exchange=HttpExchange@1a675de req=TERMINATED/null@null res=PENDING/null@null)[send=HttpSenderOverHTTP@b03f41(req=QUEUED,snd=COMPLETED,failure=null)[HttpGenerator@18040ee{s=START}],recv=HttpReceiverOverHTTP@10ba099(rsp=IDLE,failure=null)[HttpParser{s=CLOSED,0 of -1}]]<-DecryptedEndPoint@1332263{api.telegram.org/149.154.167.220:443<->/192.168.178.60:42410,OPEN,fill=-,flush=-,to=52951026/0}->HttpConnectionOverHTTP@792b4c(l:/192.168.178.60:42410 <-> r:api.telegram.org/149.154.167.220:443,closed=false)=>HttpChannelOverHTTP@1f8b522(exchange=HttpExchange@1a675de req=TERMINATED/null@null res=PENDING/null@null)[send=HttpSenderOverHTTP@b03f41(req=QUEUED,snd=COMPLETED,failure=null)[HttpGenerator@18040ee{s=START}],recv=HttpReceiverOverHTTP@10ba099(rsp=IDLE,failure=null)[HttpParser{s=CLOSED,0 of -1}]]->SocketChannelEndPoint@d056b3{api.telegram.org/149.154.167.220:443<->/192.168.178.60:42410,ISHUT,fill=-,flush=-,to=43/0}{io=0/0,kio=0,kro=1}->SslConnection@1f2fdf7{NEED_WRAP,eio=-1/-1,di=-1}=>HttpConnectionOverHTTP@792b4c(l:/192.168.178.60:42410 <-> r:api.telegram.org/149.154.167.220:443,closed=false)=>HttpChannelOverHTTP@1f8b522(exchange=HttpExchange@1a675de req=TERMINATED/null@null res=PENDING/null@null)[send=HttpSenderOverHTTP@b03f41(req=QUEUED,snd=COMPLETED,failure=null)[HttpGenerator@18040ee{s=START}],recv=HttpReceiverOverHTTP@10ba099(rsp=IDLE,failure=null)[HttpParser{s=CLOSED,0 of -1}]]
	at org.eclipse.jetty.client.util.FutureResponseListener.getResult(FutureResponseListener.java:118) ~[?:?]
	at org.eclipse.jetty.client.util.FutureResponseListener.get(FutureResponseListener.java:101) ~[?:?]
	at org.eclipse.jetty.client.HttpRequest.send(HttpRequest.java:684) ~[?:?]
	at org.telegram.telegrambots.bots.DefaultAbsSender.sendHttpPostRequest(DefaultAbsSender.java:803) ~[?:?]
	at org.telegram.telegrambots.bots.DefaultAbsSender.sendMethodRequest(DefaultAbsSender.java:796) ~[?:?]
	at org.telegram.telegrambots.bots.DefaultAbsSender.sendApiMethod(DefaultAbsSender.java:747) ~[?:?]
	... 32 more
Caused by: java.io.EOFException: HttpConnectionOverHTTP@792b4c(l:/192.168.178.60:42410 <-> r:api.telegram.org/149.154.167.220:443,closed=false)=>HttpChannelOverHTTP@1f8b522(exchange=HttpExchange@1a675de req=TERMINATED/null@null res=PENDING/null@null)[send=HttpSenderOverHTTP@b03f41(req=QUEUED,snd=COMPLETED,failure=null)[HttpGenerator@18040ee{s=START}],recv=HttpReceiverOverHTTP@10ba099(rsp=IDLE,failure=null)[HttpParser{s=CLOSED,0 of -1}]]<-DecryptedEndPoint@1332263{api.telegram.org/149.154.167.220:443<->/192.168.178.60:42410,OPEN,fill=-,flush=-,to=52951026/0}->HttpConnectionOverHTTP@792b4c(l:/192.168.178.60:42410 <-> r:api.telegram.org/149.154.167.220:443,closed=false)=>HttpChannelOverHTTP@1f8b522(exchange=HttpExchange@1a675de req=TERMINATED/null@null res=PENDING/null@null)[send=HttpSenderOverHTTP@b03f41(req=QUEUED,snd=COMPLETED,failure=null)[HttpGenerator@18040ee{s=START}],recv=HttpReceiverOverHTTP@10ba099(rsp=IDLE,failure=null)[HttpParser{s=CLOSED,0 of -1}]]->SocketChannelEndPoint@d056b3{api.telegram.org/149.154.167.220:443<->/192.168.178.60:42410,ISHUT,fill=-,flush=-,to=43/0}{io=0/0,kio=0,kro=1}->SslConnection@1f2fdf7{NEED_WRAP,eio=-1/-1,di=-1}=>HttpConnectionOverHTTP@792b4c(l:/192.168.178.60:42410 <-> r:api.telegram.org/149.154.167.220:443,closed=false)=>HttpChannelOverHTTP@1f8b522(exchange=HttpExchange@1a675de req=TERMINATED/null@null res=PENDING/null@null)[send=HttpSenderOverHTTP@b03f41(req=QUEUED,snd=COMPLETED,failure=null)[HttpGenerator@18040ee{s=START}],recv=HttpReceiverOverHTTP@10ba099(rsp=IDLE,failure=null)[HttpParser{s=CLOSED,0 of -1}]]
	at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.earlyEOF(HttpReceiverOverHTTP.java:338) ~[?:?]
	at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:1557) ~[?:?]
	at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.shutdown(HttpReceiverOverHTTP.java:209) ~[?:?]
	at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.process(HttpReceiverOverHTTP.java:147) ~[?:?]
	at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.receive(HttpReceiverOverHTTP.java:73) ~[?:?]
	at org.eclipse.jetty.client.http.HttpChannelOverHTTP.receive(HttpChannelOverHTTP.java:133) ~[?:?]
	at org.eclipse.jetty.client.http.HttpConnectionOverHTTP.onFillable(HttpConnectionOverHTTP.java:155) ~[?:?]
	at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:281) ~[?:?]
	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:102) ~[?:?]
	at org.eclipse.jetty.io.ssl.SslConnection.onFillable(SslConnection.java:291) ~[?:?]
	at org.eclipse.jetty.io.ssl.SslConnection$3.succeeded(SslConnection.java:151) ~[?:?]
	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:102) ~[?:?]
	at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:118) ~[?:?]
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:762) ~[?:?]
	at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:680) ~[?:?]
	... 1 more

Maybe that explains the problem reported by dcevedo:

I’m not sure if this is something specific to Jetty. Since I had to change a lot from the original TelegramBot Java library to make it working with Jetty instead of the originally used Apache client. Of course, when I test my changes, it’s working fine and it’s sending/receiving messages, but if it is not stable, then I have to invest more time in debugging.

With the decision to not use an Apache client, the original Telegram bot library became more or less useless and is a big change for the project now. If we would leave the existing library as it is, it is much more reliable because it exists for quite a long time and many people have already used it. Using the modified library with my Jetty changes now brings up the question if that is still reliable enough and I assume that nobody will look at those changes when the Telegram binding itself is reviewed for the PR.

Maybe the problem is just a small setting issue in the Jetty client (since it’s a longrunning request) or it’s a problem in the library but wasn’t found earlier because the Apache client behaves differently. I don’t know, but it’s really difficult to decide on how to continue here (1. Invest more time in debugging, 2. Still try to use the original library with Apache client 3. Throw this library away and try to only implement the use-cases that will be supported by the OH binding - which is also a lot of effort ).