Telegram Automation

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
labrint
Posts: 379
Joined: 14 Jun 2017, 05:06
Location: Malta

Telegram Automation

Post by labrint » 28 Dec 2017, 10:42

[Mod edit: Topic name was originally Whatsapp & Telegram Automation, but it is actually almost exclusively about using the Telegram Bot API (https://core.telegram.org/bots/api).]

I need help to create an Autohotkey script able to send Whatsapp messages through API, preferably without the need to access web.whatsapp
Last edited by labrint on 29 Dec 2017, 07:03, edited 1 time in total.
gregster
Posts: 8921
Joined: 30 Sep 2013, 06:48

Re: Whatsapp Automation

Post by gregster » 28 Dec 2017, 10:45

Is there an (official and public) Whatsapp API? Last time I looked, I didn't find one...

Edit: there seem to be some hints: https://faq.whatsapp.com/de/iphone/26000030/?lang=en
And there seem to be commercial solutions... and WhatsApp itself is starting some business services. It probably depends on what you are looking for. A private message now and then (then you might get around with a free basis or test account of one of the commercial solutions) or do you plan some business application? Btw, the Telegram messenger is much more flexible and accessible in this regard, if this is an option for you.
User avatar
labrint
Posts: 379
Joined: 14 Jun 2017, 05:06
Location: Malta

Re: Whatsapp Automation

Post by labrint » 28 Dec 2017, 12:37

The Telegram app seems to have an extensive API, but the WhatsApp messenger is much more famous, and I am targetting older generations who are not very app savvy. The only reason they are likely to have Whatsapp is to communicate with their relatives.

There is no official API but I have seen that someone has done some automation using .Net on youtube. How did they manage to do this without an API?
gregster
Posts: 8921
Joined: 30 Sep 2013, 06:48

Re: Whatsapp Automation

Post by gregster » 28 Dec 2017, 12:54

I am not sure, but I didn't look into it very deeply. I just played around with the webapp - which is not very handy, because it will probably block your computer, at least temporarily. But I thought about running the webapp in a browser inside a virtual machine. Also, browser automation could be an option. Since Internet Explorer and COM isn't supported (at least not officially, but haven't tested it), using the Selenium webdriver with Firefox or Chrome might be a solution. But it would probably need some work. There might be other ways. I personally settled with Telegram in the end, because I didn't have the time to play around with it for a longer time.
I wish you luck that someone comes around with some better hints!

Btw, you say you are "targeting older generations"... sounds like some service to me. If it is a (more or less) commercial one, I think I read that WhatsApp/Facebook does want to control these very closely (at least in the near future).
Last edited by gregster on 28 Dec 2017, 13:11, edited 3 times in total.
User avatar
labrint
Posts: 379
Joined: 14 Jun 2017, 05:06
Location: Malta

Re: Whatsapp Automation

Post by labrint » 28 Dec 2017, 12:56

While you are here, could you hand me a working copy of your Telegram code? I will resort to it if all else fails. Thanks in advance :)
gregster
Posts: 8921
Joined: 30 Sep 2013, 06:48

Re: Whatsapp Automation

Post by gregster » 28 Dec 2017, 13:01

What are you looking for? Just sending simple messsages to some account or a full bot framework that can react to user messages? My code is still quite rough (but works for my private applications) but if you tell me what functions you are looking for, I can probably provide some code or hints. The telegram API is huge and I covered just what I needed myself so far.
User avatar
labrint
Posts: 379
Joined: 14 Jun 2017, 05:06
Location: Malta

Re: Whatsapp Automation

Post by labrint » 28 Dec 2017, 13:37

Basically, I need to send messages to my clients, NOT a bot. I have 500 clients coming to collect items every 2 months, and the moment I give them the items, I need my system to trigger an alarm to send them a reminder after 56 days to collect the next batch of items :)

I have my doubts how people will switch to Telegram from Whatsapp. Whatsapp is so popular! I could also use Facebook messages if there was a way to do it, but I looked through the API and it was super complicated and requires authentication.
gregster
Posts: 8921
Joined: 30 Sep 2013, 06:48

Re: Whatsapp Automation

Post by gregster » 28 Dec 2017, 13:57

In general, once it is all set up, it wouldn't be very complicated to just send messages from time to time with Telegram. But, for automation you still would have to register yourself as a 'bot' (in a broad sense) with Telegram to get an authenticated API token and your customers would each have to actively start a chat with your Bot (only once), to subscribe to your messages (you can send them a link to do that). Without a bot token, you won't have access to the API.

If you want to do it from your normal account, you probably would run into the exact problems like with WhatsApp.
I can walk you through setting up a 'bot' (it won't very complicated or take long) and sending messages, if you think it is worth the effort with Telegram. Btw, do you want to send all messages at the same time or do different customers get the alarm at different times?

Anyway, I have to run now, but I will be back tomorrow.
User avatar
labrint
Posts: 379
Joined: 14 Jun 2017, 05:06
Location: Malta

Re: Whatsapp Automation

Post by labrint » 28 Dec 2017, 14:47

Different clients would have different alarm date/time, but some clients might fall on same date and times and therefore I could pool the ones falling on same date/time to be sent messages together, so I wont have the script running more times than necessary.

I would be very happy if you could walk me through it. Thanks I appreciate your help. Perhaps someone else could use this as well, as it is very useful for small to medium business enterprises. I'm not in a huge rush, I still need to purchase a SIM card this week so that I could have a physical phone dedicated to this setup, at work.
User avatar
labrint
Posts: 379
Joined: 14 Jun 2017, 05:06
Location: Malta

Re: Whatsapp Automation

Post by labrint » 28 Dec 2017, 14:52

Also is this Telegram, and the use of bots, free? Does it have a hidden pricing plan?
gregster
Posts: 8921
Joined: 30 Sep 2013, 06:48

Re: Whatsapp Automation

Post by gregster » 29 Dec 2017, 04:01

Yes, I would think that this might be interesting for certain business owners - and also private users (I had already planned to post here an AHK wrapper for the Telegram API, but so far it didn't find the time) ; and of course, using Whatsapp would be more interesting because of its much wider, already existing, user base. But I read somewhere that they are planning to capitalize on business users in the future. So far, they seem to be in the early stages (https://faq.whatsapp.com/en/general/26000067), but it probably wouldn't hurt to register there to see what they are planning exactly and if their services would be worth it. There already seem to be commercial services which offer messaging via WhatsApp for businesses. I am sure they have some kind of access to the WhatsApp API, but they might have to pay for it themselves.

On the other hand, I don't think there is a hidden pricing plan with Telegram. It seems they are providing it to attract more users. I use it myself for several months now and I even set up multiple bots to send messages with "webscraped" information to myself and some friends - who installed Telegram to be able to get the messages. So far no costs or problems...

To just test this and to look if it is an option for you, you don't need an extra SIM card. Your script will be running anyway on your computer and your bot will be a separate user and not visibly connected to your normal account. But I recommed using the Telegram webapp for internet browsers or the desktop app (which you can connect to with your phone number) for testing purposes - it's easier to see the results of the first tests, although not necessary - without having to pick up the phone every time.
I will put together some information to get you started...
gregster
Posts: 8921
Joined: 30 Sep 2013, 06:48

Re: Whatsapp Automation

Post by gregster » 29 Dec 2017, 06:59

First - and easiest - step, creating a bot in Telegram:

Open Telegram and find Telegrams own 'BotFather' bot. Via search, or you could use the link t.me/botfather on your phone or https://web.telegram.org/#/im?p=@botfather in the browser app (first connect the app to your phone number on https://web.telegram.org - from that point on, it will be synced with your phone) and press 'Start'.

The BotFather bot is a quite helpful guy and will lead you through the process: Type /newbot and he will ask you for

* name (the name that will be displayed in Telegram, for example your company name, but can be changed later via BotFather) and
* username (a unique name that Telegram will use to identify your bot; this one has to end with the word 'bot' and cannot be changed later on)

of your bot. You can always create another bot or delete this one, if you change your mind.

Next, you already get your personal bot token. Copy and paste that to a text or ahk file. We will need that later on to send messages with the AHK script. Because until now, your bot is just idling. If someone talks to your bot, it will just ignore it.

If you like, upload a profile picture via /setuserpic or add a description with /setdescription and/or /setabouttext. But you can always come back later to the BotFather and edit your created bots.

Next step... sending a message...
User avatar
labrint
Posts: 379
Joined: 14 Jun 2017, 05:06
Location: Malta

Re: Whatsapp Automation

Post by labrint » 29 Dec 2017, 07:03

Thanks for the information. So far I have come up with the following code to send messages (I am assuming everyone seeing this knows how to get his chat_id, and API token, but if not please reply to this message);

Code: Select all

chatid := "XXXXXXX" ; replace XXXXXXX with your chat_id
text := "Testing"
param := "chat_id=" chatid "&text=" text
str =https://api.telegram.org/botXXXXXXX/sendmessage? ; replace XXXXXXX with your API token

;msgbox, % url_tovar(str, param) ; this is useful if you need to return data

url_tovar(str, param)

url_tovar(URL, param) { 
    WebRequest := ComObjCreate("WinHttp.WinHttpRequest.5.1")
    WebRequest.Open("POST", URL)
	WebRequest.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded")
    WebRequest.Send(param)
    res := WebRequest.ResponseText
    return res
}
I have several questions though;

1. How do I schedule messages to users on Telegram via the bot & HTTP request, rather than setting alarms on Autohotkey? I have encountered alarm bot, but it only sends scheduled messages to self.

2. How do I use HTTP requests to get messages from users in a format which is not JSON?

3. How can users use commands to trigger events on my autohotkey script?

I need to get more knowledge on this product to be able to get the maximum potential from it, but seriously, well done and thanks because it seems very useful!
gregster
Posts: 8921
Joined: 30 Sep 2013, 06:48

Re: Whatsapp Automation

Post by gregster » 29 Dec 2017, 07:54

Ah, nice, you are already jumping into it. So, you are already sending messages, right?

1. The scheduling has to be done by the AHK script. I am already experimenting on something like this, but I have to finetune it a bit to handle a large amount of users. I will come back to you on this. This is actually the trickiest part for myself.

2. The bot will always send JSON formatted text strings to you. To process them effectively, Coco's JSON library is quite handy ( https://autohotkey.com/boards/viewtopic.php?t=627 ). With it, you can transform the string to an AHK object and read the message texts without much parsing.

3. If you plan to add commands for your customers or get messages from them, you will have to call the GetUpdates method... often :D , lets say every second or every half second - or at least once every 24h, otherwise their messages will be lost and discarded by the Telegram servers. That could mean, your computer with your script has to be running 24/7. Alternatively, you could use a webserver for this task. But then you would have to program the whole bot in php or something like that - and that would be a question for another forum. (A webserver setup would probably the preferred solution for a 24/7 large-scale customer bot. I think there are php examples somewhere on the Telegram website.)

A very nice thing is to add buttons (or 'keyboards') for your customers. That way, they don't even have to type the commands (but they still can). In either way you will have to process these commands with your script (that could mean some amount of parsing with more complex messages) and then you can define actions accordingly to the result of your parsing.
Simple example:

Code: Select all

keyb=
( 
	{"keyboard":[ ["Command 1", "Command 2"], ["Command 3", "Command 4"] ], "resize_keyboard" : true } 
)
botToken  := "xxxxxxxxx:yyyyyyyyyyyyyyyyyyy"	; your token
chatID := "somechatId"
url := "https://api.telegram.org/bot" botToken "/sendMessage?text=Hello&chat_id=" chatID "&reply_markup=" keyb
json_message := URLDownloadToVar(url)   ; find this function at the next code box below
That would be a 'normal' keyboard, it is also possible to use 'inline keyboards' to put buttons directly under a message.

To get Updates, I call the function(s) beneath like update := GetUpdates(). The offset parameter is useful to tell Telegram to not deliver the same messages over and over to you. The latest offset you can get from actually parsing the JSON response and then use it for your next Update call.

Code: Select all

GetUpdates(offset="", updlimit=100, timeout=0)     
{							
	token := "yourbotToken"
	If (updlimit>100)
		updlimit := 100
	; Offset = Identifier of the first update to be returned.
	url := "https://api.telegram.org/bot" token "/getupdates?offset=" offset "&limit=" updlimit "&timeout=" timeout
	updjson := URLDownloadToVar(url)					
	return updjson
}
URLDownloadToVar(url,ByRef variable=""){			
	try
	{	
		hObject:=ComObjCreate("WinHttp.WinHttpRequest.5.1")
		hObject.Open("GET",url)
		hObject.Send()
		variable:=hObject.ResponseText
		return variable
	}
}
The result is JSON which I transform via the JSON lib into an object - oUpd := JSON.Load(update) - from that object you can extract the message/command sent by your customer (more) easily. You might have to loop through messages from different users (I can post an example later). Error-handling of these functions could surely be improved ;) It would also make sense to write these messages to a logfile with FileAppend.
User avatar
labrint
Posts: 379
Joined: 14 Jun 2017, 05:06
Location: Malta

Re: Whatsapp & Telegram Automation

Post by labrint » 29 Dec 2017, 12:32

Its cool how you managed to add the commands via AutoHotkey! I managed to create commands on Telegram but have not managed to actually do anything with them once pressed.

Coco's library will come in handy thanks.

I have also had a problem with the GetUpdate function in your script, could not manage to call it and make it work.
gregster
Posts: 8921
Joined: 30 Sep 2013, 06:48

Re: Whatsapp & Telegram Automation

Post by gregster » 29 Dec 2017, 13:14

I will take another look at it. Perhaps I missed something or did a bad copy & paste job out of my larger script. I will also add an example how to parse the commands.
gregster
Posts: 8921
Joined: 30 Sep 2013, 06:48

Re: Whatsapp & Telegram Automation

Post by gregster » 29 Dec 2017, 18:32

Well, the update function should work. Did you change the token variable to your bot's token?

Anyway, I will try to post a more complete script in which you will have to edit the token just once at the beginning of the script. Not really sure when, because I will be busy on the weekend, but soon. I just have to extract the important stuff from my very large script.
gregster
Posts: 8921
Joined: 30 Sep 2013, 06:48

Re: Telegram Automation

Post by gregster » 03 Jan 2018, 00:14

Happy new year!
Here is a cobbled together and superficially tested script that demonstrates some possibilities in Telegram messenger like getting 'Updates' (messages from users), simple parsing and calling corresponding functions, sending messages and creating custom keyboards or custom 'inline' keyboards (to be handled differently). My original script is much longer and more complex by now, but still chaotic and very specific for my needs (for example, I use a more complex parsing algorithm because I also implemented commands with multiple parameters). But I think that this might be a good starting point for you, if you are not there already.

Some things that you might want to add by and by:
*) user/customer management (--> scheduling individual messages)
*) log files
*) better parsing
*) ability to send pictures
*) (better) error-handling
*) 'help' command or an 'assistant'

I can probably help you with most of these things - I am working on it anyway for my own use cases.
I added some commentary to the script below, but if you have further questions, don't hesitate to ask.

To use the script, you have to include Coco's JSON lib (https://autohotkey.com/boards/viewtopic.php?t=627) and add the personal token of your Telegram bot at the top of your script. Also, for testing purposes you will have to add your own chat ID, because I added a (very basic) check for known/registered users.
In general, you can get all the updates from your bot (from everyone who starts a chat with it) and decide if you will answer all users/chat IDs or just your registered users/customers. It is generally possible to send something like personalized (registration) links to your customers, afaik.
Hope that helps.

Code: Select all

#include json.ahk																		; Coco's JSON library, get it here:   https://autohotkey.com/boards/viewtopic.php?t=627

botToken  :=  "xxxxxxxxx:yyyyyyyyyyyyyyyyyyy"					; add your Telegram bot token
chatID := xyz000001																		; add your chat ID for testing porposes

oCustomers := {}																; Object of user ids of registered customers -> add your customers, you can send them a personal registration link
oCustomers[chatID] := "My Name"											; add your chat id (and name) to the customer object for testing purposes
offset := ""																			; Telegram message offset

cmds := {	"Command1" : "somefunction"										; bundle commands (case insensitive) and corresponding script functions to call 
				, 	"Command2" : "somefunction"
				,   "Command3" : "somefunction"
				, 	"Show inline buttons" : "inlinebuttons"
				, 	"Remove keyboard" : "RemoveKeyb"  }

; add custom keyboard for testing
keyb=																		; json formatted string
( 
	{"keyboard":[ ["Command1", "Command2"], ["Show inline buttons", "Remove Keyboard"] ], "resize_keyboard" : true } 
)																			
url := "https://api.telegram.org/bot" botToken "/sendMessage?text=Keyboard added&chat_id=" chatID "&reply_markup=" keyb
json_message := URLDownloadToVar(url)   
	; msgbox % json_message

; Check for new updates 
 SetTimer, UpdateTimer, 1000							; every 1000 ms = 1 second
return
;---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Esc::ExitApp													; hit Escape to stop the script
;----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

UpdateTimer:																									; checks constantly for user input in your bot
stack := {}																										; message stack			

updates := GetUpdates(botToken, (offset+1))											; get (new) updates from your bot as JSON string; keep track of old messages  
	;msgbox % updates
oUpdates := JSON.Load(updates)											; create an AHK object from the JSON string
If oUpdates.ok																			; check if json answer was "ok" : true
{
		
	loop % oUpdates.result.MaxIndex()		; determine number of new messages (updates) 
			stack.Push(oUpdates.result[A_index])		; add all updates (=messages) to stack
	For key, msg in stack
	{
		from_id := first_name := mtext := last_name := username := ""
		if (msg.callback_query.data!="")									; inline buttons have to be handled differently than normal messages and normal keyboards
		{	
			from_id := msg.callback_query.from.id
			mtext := msg.callback_query.data
		}	
		else 																					; get message text or message from normal keyboard
		{		
			from_id := msg.message.from.id									; which ID sent the message?
			mtext := msg.message.text
					;first_name := msg.message.from.first_name
					;last_name := msg.message.from.last_name
					;username ;=  msg.message.from.username
		}
		offset := msg.update_id													; keep track of processed messages
	
		if oCustomers.Haskey(from_id)				; check for known users...   optional
		{	
				if cmds.Haskey(mtext)														; is message a known command?
				{
					fun := cmds[mtext]									;look up which function to call for a specific command
					%fun%(botToken, msg, from_id, mtext)			; call function
				}
				else
				{
					text := "Sorry... I don't know this command."				  
					;    url encoding for messages :  %0A = newline (\n)   	%2b = plus sign (+)		%0D for carriage return \r        single Quote ' : %27			%20 = space
					SendText(botToken, text, from_id)
				}
		}
		else
				Traytip, No, Unknown user, 3		
	}  ; end 'for' 
}
return

;--------------------------------------------------------  functions for user commands ---------------------------------------------------------------------------------------------------------
somefunction(botToken, msg, from_id, mtext) 
{
		if (msg.callback_query.id!="")						;  After the user presses a callback button, Telegram clients will display a progress bar until you call answerCallbackQuery 
		{	
			cbQuery_id := msg.callback_query.id
			; Notification and alert are optional
			url := "https://api.telegram.org/bot" botToken "/answerCallbackQuery?text=Notification&callback_query_id=" cbQuery_id "&show_alert=true"
			json_message := URLDownloadToVar(url)  
				;msgbox % json_message
		}
		text := "You chose " mtext				  
		SendText(botToken, text, from_id)        ;  url encoding for messages :  %0A = newline (\n)   	%2b = plus sign (+)		%0D for carriage return \r        single Quote ' : %27			%20 = space
		return
}
;--------------------------------------------------------------------
; add inline buttons
inlinebuttons(botToken, msg,  from_id, mtext="") 
{
	keyb=																	; json string:
	( 
		{"inline_keyboard":[ [{"text": "Command One" , "callback_data" : "Command1"}, {"text" : "Some button (Cmd3)",  "callback_data" : "Command3"} ] ], "resize_keyboard" : true } 
	)
	url := "https://api.telegram.org/bot" botToken "/sendMessage?text=Keyboard added&chat_id=" from_id "&reply_markup=" keyb
	json_message := URLDownloadToVar(url)   ; find this function at the next code box below
	return json_message		
}
;---------------------------------------------------------------------
; Remove custom keyboard 
 RemoveKeyb(botToken, msg, from_id, mtext="") 
 {
	keyb=
	( 
		{"remove_keyboard" : true } 
	)
	url := "https://api.telegram.org/bot" botToken "/sendMessage?text=Keyboard removed&chat_id=" from_id "&reply_markup=" keyb
	json_message := URLDownloadToVar(url)  
		;msgbox % json_message
	return
}	
;------------------------------------------  Telegram functions  --------------------------------------------------------------------------------------------------------
GetUpdates(token, offset="", updlimit=100, timeout=0)     
{							
	If (updlimit>100)
		updlimit := 100
	; Offset = Identifier of the first update to be returned.
	url := "https://api.telegram.org/bot" token "/getupdates?offset=" offset "&limit=" updlimit "&timeout=" timeout
	updjson := URLDownloadToVar(url)					
	return updjson
}
;------------------------------------------------
SendText(token, text, from_id, replyMarkup="",  parseMode="" )
{
		url := "https://api.telegram.org/bot" token "/sendmessage?chat_id=" from_ID "&text=" text "&reply_markup=" replyMarkup "&parse_mode=" parseMode
		json_message := URLDownloadToVar(url)
		return json_message
}
;----------------------------------- additional functions ------------------------------------------------------------------------------------------------------------------
URLDownloadToVar(url,ByRef variable=""){						; function originally by Maestrith, I think
	try																						; keep script from breaking if API is down or not reacting
	{	
		hObject:=ComObjCreate("WinHttp.WinHttpRequest.5.1")
		hObject.Open("GET",url)
		hObject.Send()
		variable:=hObject.ResponseText
		return variable
	}
}
(Hit 'Escape' key to stop the script)
User avatar
Frosti
Posts: 426
Joined: 27 Oct 2017, 14:30
Contact:

Re: Whatsapp & Telegram Automation

Post by Frosti » 02 Apr 2018, 15:48

Please gregster can you tell me how your bot works. I'm telling it all he needs (Token and ChatID) but there is no response from your script. And then I have problems to stop your script. Neither the escape key nor a right-click on the tray icon work.
I think the Telegram app is the next big thing that changes the internet. And we do not have a wrapper or a half or full bot in this forum yet. I tried it for myself. But my attempt makes me dissatisfied. My tries with Coco's Library have failed. I then developed a solution for myself through RegEx. But I also find these unsatisfactory. Nevertheless, I would like to show you my solution here, maybe I can animate you to direct your interest to the Telegram app. There are many critics about this app, but call me a social app that has such independence from governments and intelligence agencies. You also have to know something about the two financiers. They are one of the few we can trust, I think. One of the best things is the support! You write to people who do not get any money for their work, but they help you where they can - it takes only minutes to get answers. They help people in oppressive countries. Therefore, one must also accept that some evil people use this app, because it seems safe (the fighter of the ISIS in Irak).
Unfortunately there is no end-to-end encryption to the desktop app. I hope it will come. This looks like advertising, but I need a secure communication solution without having to program it to my own. I have to protect the data of my patients. And I do not trust any big company! I've been working on the topic for a year now, neither Threema nor Wire and others have convinced me. E-mail without encryption has been officially banned from us by the EU since this year. Not even my accountant wanted to install PGP for Email (God bless him!).

Code: Select all

;THE TELEGRAM MINI BOT VERSION 0.1 alpha by Ixiko 2018

;dies ist mein rudimentäres noch sehr einfach gehaltenes Script für die Entwicklung eines eigenen Bot's mit Hilfe der Telegram.api,
;welche ich sehr gelungen und unglaubig hilfreich für meinen zukünftigen professionellen Zweck finde
;This is my rudimentary yet very simple script for the development of a bot with the help of Telegram.api,
;which I find very successful and unbelievably helpful for my future professional purpose; i hope you like it to

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
;#Warn  ; Enable warnings to assist with detecting common errors.
#Persistent
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
SetBatchLines, -1
SetWinDelay, -1
CoordMode, ToolTip, Screen

#include %A_ScriptDir%\..\include\Telegram.ahk

;If !FileExist("MyBots.ini")
;			FirstStart()

IniRead, Bot1, MyBots.ini, TheBots, Bot1
IniRead, BotToken1, MyBots.ini, TheBots, %Bot1%_Token
IniRead, BotChatID1, MyBots.ini, TheBots, %Bot1%_ChatID
IniRead, BotSRefresh1, MyBots.ini, TheBots, %Bot1%_SlowRefresh						;this in seconds
IniRead, BotFRefresh1, MyBots.ini, TheBots, %Bot1%_FastRefresh						;also in seconds
IniRead, BotBackToSlow1, MyBots.ini, TheBots, %Bot1%_BackToSlow						;if there ist no answer after x seconds go back to slow respond mode
IniRead, lastmessage1, MyBots.ini, TheBots, %Bot1%_lastmessage						;here the last update_id of Telegram is saved


BotSRefresh1:= BotSRefresh1 * 1000
BotFRefresh1:= BotFRefresh1 * 1000
BotBackToSlow1:= BotBackToSlow1 * 1000

XSplash:= A_ScreenWidth - 100
XTT1:= A_ScreenWidth - 800
YSplash:= A_ScreenHeight - 100
TheCounter1 = 0
msend1:= 0

textus1 = I can not do much right now. I can't answer you to this question and I send you a 'hello' back. That's nice, is not it?

FileEncoding, UTF-8

OnExit, DasEnde

;{ local function for my Bot

CommandParse(msg) {

	fspace:= InStr(msg, A_Space)
	part1:= Trim(SubStr(msg, 2, fspace -1), A_Space)
	StringRight, part2, msg, StrLen(msg) - StrLen(part1)

return part
}

;}

GUpdate1:= Object()
RefreshTime1:= BotFRefresh1
SetTimer, Update_%Bot1%, %RefreshTime1%

;{ --- HotKey Section
^#b::ExitApp
;}

Return
; END OF AUTOEXECUTE AREA

Update_MiniVivi_bot:
;{
	TText1 = MiniVivi_bot Mini Server is running with BotToken: %BotToken1%`nTheCounter1= %TheCounter1%, LMessageID = %lastmessage1%, newID = %newid%,RefreshTime = %ResfreshTime1%`nMessageFrom = %Msgfrom1%, LMessage = %LMessage1%, answered = %msend%
	ToolTip, %TText1%, %XTT1%, 0, 1

	straw1:=Telegram_getUpdates(BotToken1)
	GUpdate1:= Telegram_parse2obj(straw1)

	newid:= GUpdate1["update_id"]

	If (lastmessage1 = GUpdate1["update_id"]) And (TheCounter1 = 1) {
				If ((A_TickCount-tickCount1) > BotBackToSlow1) {
						RefreshTime1:= BotSRefresh1
						SetTimer, Update_%Bot1%, %RefreshTime1%
						TheCounter1 = 0
				}
	} else if (lastmessage1 <> GUpdate1["update_id"]) {																											;this method is for incoming new messages, its saves important data to a file called TelegramMessage.log
				LMessage1:= GUpdate1["text"]
				lastmessage1:= GUpdate1["update_id"]
				MsgFrom1:= GUpdate1["username"]
				toWrite1:= "update_id: " . GUpdate1["update_id"] . ", username: " . GUpdate1["username"] . ", date: " . GUpdate1["date"] . ", text: " . GUpdate1["text"] . ", answered: "
				tickcount1:= A_TickCount
				TheCounter1 = 1
				SetTimer, Update_%Bot1%, Off						; off, because I want the time to answer
				If (MsgFrom1 = "HausarztClemenz") {
							gosub TheGodAnsweringMachine
				} else {
							gosub AnsweringMachine1
				}
	}

	If (GUpdate1 = "no_message") {
		SplashTextOn, 50,50 ,MiniVivi_bot, There's no message at the moment
		WinMove, MiniVivi_bot, , %XSplash%, %YSplash%
		SetTimer, SplashAus, 3000
	}


return
;}


TheGodAnsweringMachine:
;{
	msg1:= GUpdate1["text"]
	cid1:= GUpdate1["chat_id"]

	;{-## This is my stupid answer method, but it logs new unknown requests, in principle, everything that is still unknown, so that I can later make new functions
	;diese Methode muss deutlich flexibler werden. Keine KI, aber eine einfache Methode muss zum Editieren und Erstellen neuer Antwortmuster sollte sie beinhalten.
	;this method has to become much more flexible. No AI, but a simple method needs to be included to edit and create new response patterns.
		If (SubStr(msg1, 1, 1) = "`.") {

			fspace:= InStr(msg1, A_Space)
			part1:= Trim(SubStr(msg1, 2, fspace -1), A_Space)
			StringRight, part2, msg1, StrLen(msg1) - StrLen(part1) - 1

			If InStr(part1, "pat") {
					Telegram_SendMessage(BotToken1, cid1, "Ok ich öffne Dir die Akte des/der Patient/in " . part2)
					msend1 += 1
			}

		} else if (msg1 = "Hallo") {
			Telegram_SendMessage(BotToken1, cid1, "Ein hallo auch an Dich!")
			msend1 += 1
			answ = true
		} else if (msg1 = "Was kannst Du?") {
			Telegram_SendMessage(BotToken1, cid1, textus1)
			msend1 += 1
			answ = true
		} else {
			;an diese Position muss später eine Funktion (z.B. "CheckUnknownRequest" genannt) um auf doppelte Anfragen zu überprüfen, ich könnte einen Zähler integrieren
			;this position must later have a function (for example, called CheckUnknownRequest) to check for duplicate requests, I could integrate a counter for each duplicate

			Telegram_SendMessage(BotToken1, cid1, "Ich kann Deine Anfrage/Satz nicht verstehen. Ich speichere diese aber um vielleicht später darauf antworten zu können. Vielen Dank das Du mir geschrieben hast.")
			answ = false																										;if this is logged, then the request was processed, but could not be answered
		}
	;}

	;{-## ; Routine for storing received messages
	; Routine zum Abspeichern eingangener Nachrichten

		If (answ = false) {
			FileAppend, %toWrite1%`n, %Bot1%_UnknownRequests.txt
		}

		toWrite1:= toWrite1 . answ
		FileAppend, %toWrite1%`n, TelegramMessage.log
		IniWrite, %lastmessage1%,  MyBots.ini, TheBots, %Bot1%_lastmessage


;}
	RefreshTime1:= BotFRefresh1
	SetTimer, Update_%Bot1%, %RefreshTime1%
return
;}


AnsweringMachine1:
;{
	RefreshTime1:= BotFRefresh1
	SetTimer, Update_%Bot1%, %RefreshTime1%
return
;}

SplashAus:
;{
	SplashTextOff
	SetTimer, SplashOff, off

return
;}

DasEnde:
;{
	Progress, B2 cW00FFFF cB008080 w400 s18, , Du hast den Telegram Mini Botserver beendet., TMiniBot, Futura Bk Bt
	i=100
	Loop 100 {
		p:= i - A_Index
		Progress,  %p%
		Sleep, 10
	}
	Progress, Off

ExitApp
;}

Code: Select all

;Telegram Bot Functions Library! (hopefully easy to understand)
;by Ixiko December 2017 (please sorry for my english - hope someone will correct this)
/*
the Telegram Api supports GET und POST HTTP methods

this function library will return all informations it receives from Telegram as associative Arrays
	for example if you use GetMe you will receive an array with the following contents:
		Value:= array["update_id"] or Value:= array_you_choose.first_name
		I have chosen the same keys that can be read in the Api description at telegram.org
			So I hope the output values are easier to understand.


*/


;{-- Telgram.api Commands

Telegram_GetChatID(BotToken) {

		global nooption
		url = https://api.telegram.org/bot%botToken%/get
		straw:=DownloadToString(url, "utf-8")

		if straw = nooption
			return obj:="no_message"

		obj:= Telegram_parse2obj(straw)

	return obj
}

Telegram_getUpdates(BotToken, offset = "") {  ;GetMessages incl. all id's , tags and so on

		global nooption
		obj:= Object()
		url = https://api.telegram.org/bot%BotToken%/getUpdates?offset=%offset%
		straw:=DownloadToString(url, "utf-8")

		if straw = nooption
			return "no_message"


	return strawxx
}

Telegram_getMe(BotToken) { ;getting your id; first_name , Username(bot-name)

		url = https://api.telegram.org/bot%botToken%/getMe
		straw:=DownloadToString(url, "utf-8")

		idn:= ExtractFromString(straw, "id" . """:" , "`," , 1, 0, 0)
		ib:= ExtractFromString(straw, "is_bot" . """:" , "`," , 1, 0, 0)
		fn:= ExtractFromString(straw, "first_name" . """:""" , "`," , 1, 0, 1)
		un:= ExtractFromString(straw, "username" . """:""" , "`}" , 1, 0, 1)

		GetMe:= Object("id", idn, "is_bot", ib, "first_name", fn, "username", un)

	return GetMe
}

Telegram_SendMessage(BotToken, chat_id, msg) { ;Send a message to the chat_id you received through the Telegram_getUpdates () function

	;url:= "https://api.telegram.org/bot" . BotToken . "/sendmessage?chat_id=" . Chat_ID . "%&text=" . msg . "`""
	url = https://api.telegram.org/bot%BotToken%/sendmessage?chat_id=%chat_id%&text=%msg%
	straw:=DownloadToString(url, "utf-8")

	return straw
}

;}



;{-- additional important Telegram_funtions - these do not belong to the official telegram.api

Telegram_parse2obj(str) { ;this is my first telegram_json wrapper, is slow but works
   ;in the first i used json2obj but the function json2obj did not find the last part of the telegram message
   ;I understand the RegEx method only inadequate therefore I parse with my awkward function
   ;I hope someone find a way to speed up my function. At the moment I do not have the time to learn enough about RegEx.

;{ -DEFINITION OF REPLACE STRINGS AND REPLACE WITH - FIRST REPLACE CHAR'S LIKE {}[]()" THEN REPLACE WORDS
   rps1 = `n
   rw1 =
   rps2  = `r
   rw2  =
   rps3  = `{
   rw3 =
   rps4 = `}
   rw4 =
   rps5 = `]
   rw5 =
   rps6 = `"
   rw6 =
   rps7 = message:
   rw7 =
   rps8 = from:
   rw8 =
   rps9 = chat:id
   rw9 = chat_id
   rps10 = chat: id
   rw10 = chat_id
   rps11 = result:`[
   rw11 =
   rps12 = `\u00fc
   rw12 = ü
   
;}

      arr:= Object()
      str:= RegExReplace(str, "((?:{)[\s\S][^{}]+(?:}))", "", "", 1, 1)
      i:= 0
		str1:= str
      Loop, 12
      {
			  i += 1
			  r = % rps%i%
			  w = % rw%i%
			  StringReplace, str, str, %r%, %w%, All
      }

	;For a better overview when debugging I exchanged the comma against linefeed
	StringReplace, str, str, `, , `n, All

      Loop, Parse, str, `n
      {
               lf:=Trim(A_LoopField)
               if (lf <> "") {
					   dpoint:=Instr(lf, "`:")
					   key:= Substr(lf, 1, dpoint - 1)
					   value:= SubStr(lf, dpoint + 1, StrLen(lf) - dpoint)
					   arr[key]:= value
				}
	  }

return arr
}

Telegram_collectMessage(msg) {

	global Telegram_Brain		;i call it Brain, but its no brain, its only a collection of Messages and possible answers you can teach your bot
	global MyCommandList


return MyCommand
}

;}
 dsdw1


;{-- currently not implemented functions
Telegram_setWebhook(url, certificate, max_connections, allowed_updates) {
; url as string , certificate as InputFile (optional), max_connections as Integer (optional), allowed_updates as Array of String
; url must be https - enabled! currently used ports are  443, 80, 88, 8443


}

;}



;{-- Useful functions for Telegram commands

DownloadToString(url, encoding="utf-8") {

	;wonderful function by nnik Posted 24 January 2013 - 09:41 PM
	;https://autohotkey.com/board/topic/89509-bestimmten-inhalt-einer-webseite-auslesen-und-in-txt-schreiben/
  static a := "AutoHotkey/" A_AhkVersion
  if (!DllCall("LoadLibrary", "str", "wininet") || !(h := DllCall("wininet\InternetOpen", "str", a, "uint", 1, "ptr", 0, "ptr", 0, "uint", 0, "ptr")))
    return 0
  c := s := 0, o := ""
  if (f := DllCall("wininet\InternetOpenUrl", "ptr", h, "str", url, "ptr", 0, "uint", 0, "uint", 0x80000000, "ptr", 0, "ptr"))
  {
    while (DllCall("wininet\InternetQueryDataAvailable", "ptr", f, "uint*", s, "uint", 0, "ptr", 0) && s>0)
    {
      VarSetCapacity(b, s, 0)
      DllCall("wininet\InternetReadFile", "ptr", f, "ptr", &b, "uint", s, "uint*", r)
      o .= StrGet(&b, r>>(encoding="utf-16"||encoding="cp1200"), encoding)
    }
    DllCall("wininet\InternetCloseHandle", "ptr", f)
  }
  DllCall("wininet\InternetCloseHandle", "ptr", h)
  return o
}

ExtractFromString(string, ParseString1, ParseString2, offset, cutleft, cutright ) {
	;if extracted string contains signs before and after - use cutleft as a number of signs to cut from left side of string after the end of the beginning of the last parsestring ....

	Len1:=StrLen(ParseString1)
	PosFound:=InStr(string, ParseString1, , offset) + Len1 + cutleft
	Length:=InStr(string, ParseString2, , PosFound + offset) - PosFound - cutright

	If (Pos1 = 0) or (Pos2 = 0)
			return "no match"

return SubStr(string, PosFound, Length)
}

URLDownloadToVar(url,method) {
	hObject:=ComObjCreate("WinHttp.WinHttpRequest.5.1")
	hObject.Open(method,url)
	hObject.Send()
	return hObject.ResponseText
}

;}

gregster
Posts: 8921
Joined: 30 Sep 2013, 06:48

Re: Whatsapp & Telegram Automation

Post by gregster » 03 Apr 2018, 01:17

Hi Frosti, nice to see some interest in the subject.
Frosti wrote:There are many critics about this app, but call me a social app that has such independence from governments and intelligence agencies. You also have to know something about the two financiers. They are one of the few we can trust, I think.
While I like the Telegram app and its botting capabilities very much, that sounds like a bold statement. Even, if the Durovs seem like honest guys, there is no guarantee that they really are. And the FSB - and probably not only them - are putting heavy pressure on them to hand them the keys. Even if they do not, there is no guarantee that some secret service or hacker won't find a weak spot/bug to exploit already tomorrow. That is the same for every messenger app - all I am saying is: This is just an app - and it is not saver or more trustable than any other messenger app. And with things like patient data I still would be extremely careful.

That said, I use my telegram bots on a daily basis - still for private use cases, but also thinking of using them professionally - but the handling of customer data is surely a difficult subject that stopped me, so far. I might rather switch to a webserver/php approach, If I want to implement some customer/commercial-use-bot.
Frosti wrote:I think the Telegram app is the next big thing that changes the internet. And we do not have a wrapper or a half or full bot in this forum yet. I tried it for myself. But my attempt makes me dissatisfied. My tries with Coco's Library have failed. I then developed a solution for myself through RegEx. But I also find these unsatisfactory.
I have only glanced over your bot so far (will test it later), but what are the reasons of your dissatifaction? If you could expand a bit on that, people might have an easier time to recommend improvements.
I am surprised that Coco's library didn't work for you. I use it a lot - for a whole range of APIs, not only telegram. While it surely could have bugs or weaknesses, it works well for me with Telegram and my other use cases. So, how did it fail? Didn't it work at all? What did you try?
Before programming my own parser, I would have surely tried a lot :D But there is at least one pitfall, that you have to be aware of, if I remember correctly. The class JSON makes the the term json a reference (?) to super-global object. That means, if you are using some other variable/object called json in your script, it will most probably mess things up. (That is a general thing with classes in AHK - I remember how I was chasing for the reason of some mystery bugs, when I used another class, a while back. I nearly lost my mind over it :shh: ).
Frosti wrote:Please gregster can you tell me how your bot works. I'm telling it all he needs (Token and ChatID) but there is no response from your script. And then I have problems to stop your script. Neither the escape key nor a right-click on the tray icon work.
Well, that sounds odd :shock: . Like you can see, it is a rather short script that doesn't do very much. I just re-downloaded it, added my credentials and the json lib to the script directory, and it worked. labrint never reported back after I posted it, but if I didn't miss something hardcoded in the script that would mess it up on another machine, it should work.
At least, it shouldn't freeze - that is something I rarely experienced at all with AHK scripts in 12+ years.

I don't think the reason could be the included JSON class by Coco. But you could remove the #include-line for testing. The script should still start and show the message "Keyboard added" and a custom keyboard in the bot/chat you specified. (Of course, without a JSON parser, it wouldn't be able to react to user messages after that)

If I would have to guess, the most likely reason seems to be the URLDownloadToVar function, although I never had problems with the WinHTTP 5.1 COM interface, so far - I use it also with other APIs. Perhaps it gets stuck somehow... does this function work in other scripts for you - or not at all? I saw that you use some other function (with another technique/interface) - here you can see a comparison of the different techniques we use: WinHTTP versus WinINet https://msdn.microsoft.com/en-us/librar ... s.85).aspx . Perhaps there is some firewall setting or security program on your system that prevents the use of the WinHTTP 5.1 COM interface - or perhaps something is broken. One would have to investigate some more, if this function would be the reason of your problems

That said, I replaced URLDownloadToVar() from my script with the DownloadToString() function you are using - and as I expected, my script still worked. (For testing, I only replaced the contents of my function with the contents of the other - so that I didn't have to change any function calls in other parts of the script.)
So, if you are willing to test a little, I would be interested in the results. While I personally use my Class-based Telegram wrapper (still looking like a trainwreck, incomplete and with lazy error handling; and therefore not posted yet), I also rely there on the URLDownloadToVar function I used above. If it could cause problems on other systems, I might investigate it further and/or replace it with a more robust function.

Btw, which AHK and windows versions are you using? I use AHK 64bit (ver 1.1.28) on Win 10 64bit - but when I wrote the script above, I was still using Win 7 64bit.



One other thing that caught my eye when glancing over your script, was the usage of the global variable nooption in two functions. I didn't understand what you trying to do there - but perhaps you are using them in other script parts that you didn't post? So far, it just looks like an empty variable. At some point you are then doing this:

Code: Select all

	straw:=DownloadToString(url, "utf-8")

		if straw = nooption
			return obj:="no_message"
That means, you are comparing the contents of the variable straw with the literal string "nooption" - and not with the (not existing !?) contents of the variable nooption (because you are using traditional if-syntax without parentheses here: Compare If ). Whatever these contents might be...
Perhaps you wanted to use If-expression syntax instead to see if the response is empty?? But even if there are no messages, I don't think straw would be empty - Telegram still returns {"ok":true,"result":[]}, when there are no new updates. straw could be empty (or 0), though, if the download function fails for some reason.
But anyway, that's all a minor thing (and perhaps the remains of something or something not fully implemented yet) and I didn't really look very closely so far, so I might be wrong with my observations. Just wanted to leave a note about it.

Happy botting!
Post Reply

Return to “Ask for Help (v1)”