JavaRush /Java Blog /Random EN /Create a simple weather bot for Telegram in a few evening...
Philip J.
Level 40
Днепр

Create a simple weather bot for Telegram in a few evenings

Published in the Random EN group
Hi all! The topic of creating bots for Telegram is somewhat beaten up, and a lot of guides have been written (for example, this one ). Therefore, we'd better take a closer look at working with some third-party API, as this is a critical skill for any web developer. I must say right away that the application did not aim to provide the most functional and useful forecast, it makes no sense to compete with weather sites, it was important to learn how to work with remote connections and data parsing using Java. So, let's first find out what we need. Our application, in fact, consists of three logical parts:
  • accept message from user
  • process the message, and if it's a valid command, prepare the data for a response. In our case, prepare a weather forecast if the user has entered a valid city
  • send the finished information to the user in the chat
The first and third points are quite simple, and only apply to working with the Telegram API, those who wish can study the link left above. We will focus on the second point. APIs are used when some developers want to provide other developers with access to their data. Take, for example, Vkontakte. Everyone has a list of friends, it is stored somewhere in the database on VK servers. Suppose some programmer decided to create a game of checkers with friends. For his application to work correctly, the program must be able to get the list of friends of any player. To do this, the programmer finds the documentation for the VK API, and looks at what request needs to be made in order to get this list. This request is called an HTTP request. And the two most common HTTP requests are GET and POST. About them on the network is also enough, I will not stop. For our purposes, namely, to obtain weather forecast data, a simple GET request will suffice. If we make a GET request to a regular web server, it will often return an html code that the browser will convert into a user-friendly page by applying styles, scripts, etc. If we make such a request to the API server, the response is usually only raw data is returned without styles and scripts. In a browser window it looks like this: Create a simple weather bot for Telegram in a few evenings - 1This data is not intended for people, but for other programs, so there is nothing superfluous, except for the information itself, in such pages. Raw data is most often sent using one of two standards: JSON or XML. Each has its pros and cons, however, it is important to understand both. You have already seen JSON in the screenshot above, and XML looks like this: Create a simple weather bot for Telegram in a few evenings - 2After a short search, an English-language Open Weather Map project was found, which gives data for free, if you do not make more than 50 requests per minute. For us, this is quite enough, we register, we get a unique token (code) by which the server will know that we are not impostors, but decent future developers. We go to the page with the API documentation ( tyts ), and find out that a 5-day forecast for any city can be obtained by sending a request of the form.
https://api.openweathermap.org/data/2.5/forecast?q=(город)&APPID=(уникальный токен, полученный при регистрации)
You can see how the response to such a request looks in the browsertyts We have already found out that, in fact, you just need to follow the correct link and the server will return the necessary data. It remains to learn how to do it using Java. A simple GET request in Java looks like this:
//создаём строку со ссылкой на нужную page,
//я тут её склеиваю из заранее определённых констант, меняя только сам город
String urlString = API_CALL_TEMPLATE + city + API_KEY_TEMPLATE;
//создаём an object который будет содержать ссылку
URL urlObject = new URL(urlString);
//создаём соединение, используя an object
HttpURLConnection connection = (HttpURLConnection) urlObject.openConnection();
//выбираем тип requestа (GET)
connection.setRequestMethod("GET");
//тут мы указываем, данные о себе, что мы можем принять всё то,
//что примет и любой современный браузер
connection.setRequestProperty("User-Agent", "Mozilla/5.0");
//В начало ответа server всегда вставляет число, по которому можно судить, прошло ли всё хорошо.
//200 - значит OK
int responseCode = connection.getResponseCode();
//на несуществующий город or город с опечаткой, server выдаст code ответа 404,
//бросаем на него исключение, чтобы обработать на уровне повыше и предложить
//пользователю ввести город заново
if (responseCode == 404) {
     throw new IllegalArgumentException();
}
// создаём поток, вычитываем все строки, и склеиваем в одну большую строку,
//которую будем потом обрабатывать в других методах
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
     response.append(inputLine);
}
in.close();
return response.toString();
If the request was correct and the server was available, we'd end up with a sheet of data that mixes useful information with information that isn't needed right now. To conveniently extract the necessary data from JSON and XML, tons of libraries have been written for Java for every taste. Since I preferred JSON, I chose a very popular library called Jackson to process it. By the way, it is studied a little on CodeGym at some high levels. To process large amounts of JSON data, it is important to understand the structure of the document. Useful sites like this come to the rescue . On the left we have the original JSON, on the right - structured: Create a simple weather bot for Telegram in a few evenings - 3 It can be seen that the response consists of 5 top-level JSON objects, 2 of which are complex and are nodes for the following branches. The data we are interested in is stored in the list node.. Inside list is an array of 38 JSON strings, each describing the weather at a particular time. That is, it is such a tree-like structure, where there is a root, branches, twigs and even leaves :) And at the nodes, the branching takes place. Fortunately, Jackson can represent any valid JSON as a tree. Thus, knowing the name of the attribute we need (for example, air temperature), and at what level of the tree it is, getting it will not be any particular problem. To begin with, I extracted all the lines from the "list" array and added them to a separate list. Roughly speaking, I cut the data sheet into pieces, each of which is a separate forecast. Small parts are easier to keep in mind and operate on them.
//JsonNode - это один из узлов в древовидной иерархии, от которого идут ветви
//получаем узел, который называется "list"
JsonNode arrNode = new ObjectMapper().readTree(data).get("list");
//если это действительно массив узлов
if (arrNode.isArray()) {
//выполняем для каждого узла, который содержится в массиве
      for (final JsonNode objNode : arrNode) {
//в атрибуте "dt_txt" каждого маленького узла хранилось время прогноза, я отобрал данные за 9 утра и 6 вечера
                String forecastTime = objNode.get("dt_txt").toString();
                if (forecastTime.contains("09:00") || forecastTime.contains("18:00")) {
                weatherList.add(objNode.toString());
            }
      }
}
So we got a list of strings, in which each string is a JSON summary of the weather at a specific time. It remains to extract the desired and format. If we have a line like this:
"main":{"temp":261.45,"temp_min":259.086,"temp_max":261.45,"pressure":1023.48,"sea_level":1045.39,"grnd_level":1023.48,"humidity":79,"temp_kf":2.37}
then, it's a node called "main". To get any data from it, for example, sea level, the following code is enough:
ObjectMapper objectMapper = new ObjectMapper();
//line - это наша JSON-строка
mainNode = objectMapper.readTree(line).get("main");
String seaLevel = mainNode.get("sea_level");
Jackson allows you to immediately represent data in numerical format:
double seaLevel = mainNode.get("sea_level").asDouble();
Now we can extract any data from the forecast, and all that remains is to glue them together as we wish and send them to the user in Telegram. The full source code is on my github , but you can try the bot in action by following the link , or by finding @denifoBot in the Telegram search. The name of the city must be written in Latin transliteration, for example "Kyiv" or "Moscow". Thank you, if you have mastered it to the end, I accept reasonable criticism, as I am just learning and developing simple projects on github to compete with hungry talents from my city :) Bye everyone! PS I believe that there may be typos here, so you can send everything in a personal, well, or in a comment if you are really very angry :)
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION