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

We 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 Telegrams is somewhat hackneyed, 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, since this is a critical skill for any web developer. I’ll say right away that the application did not set out to provide the most functional and useful forecast; there is no point in competing with weather sites; it was important to learn how to work with remote connections and data parsing using Java. So, let's find out what we need first. Our application essentially consists of three logical parts:
  • accept message from user
  • process the message, and, if it is a valid command, prepare data for the response. In our case, prepare a weather forecast if the user entered the correct city
  • send ready information to the user in chat
The first and third points are quite simple, and only concern working with the Telegram API; those interested can study the link left above. We will focus on the second point. APIs are used when some developers want to provide access to their data to other developers. Let's take VKontakte, for example. Everyone has a list of friends, it is stored somewhere in a database on VK servers. Let's say that some programmer decided to create a checkers game with friends. For his application to work correctly, the program must be able to obtain 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 to get this list. This request is called an HTTP request. And the two most common HTTP requests are GET and POST. There is also enough about them on the Internet, I won’t stop you. For our purposes, namely obtaining weather forecast data, a simple GET request will be sufficient. If we make a GET request to a regular web server, it will often return html code, which the browser converts into a user-friendly page, 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 the browser window it looks something like this: We 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 extra in such pages except the information itself. 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: We create a simple weather bot for Telegram in a few evenings - 2After a short search, the English-language Open Weather Map project was found, which provides data for free if you do not make more than 50 requests per minute. This is quite enough for us, we register, we receive 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 browser. We have already found out that, in fact, you just need to follow the correct link and the server will provide the necessary data. All that remains is to learn how to do this 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 will receive a sheet of data in which useful information is mixed with information that is not needed now. To conveniently extract the necessary data from JSON and XML, tons of libraries have been written for Java to suit 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 in JavaRush at some high levels. To process large amounts of JSON data, it is important to understand the structure of the document. Helpful sites like this one come to the rescue . On the left we have the original JSON, on the right - the structured one: We 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 lines, each describing the weather at a certain time. That is, it is a kind of tree-like structure, where there is a root, branches, twigs and even leaves :) And at the nodes the branching takes place. Luckily, 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 located, getting it will not be much of a problem. First, I extracted all the lines from the "list" array and added them to a separate list. Roughly speaking, I cut the sheet with the data into pieces, each of which is a separate forecast. Small parts are easier to keep in mind and operate with.
//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 line represents a JSON weather report at a certain time. All that remains is to extract what you want and format it. 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 this is 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 numeric format:
double seaLevel = mainNode.get("sea_level").asDouble();
Now we can extract any data from the forecast, and all that remains is to glue it together as desired and send it to the user in Telegram. The full source code is on my github , but you can try the bot in action using 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 made it to the end, I accept reasonable criticism, since I’m just learning and developing simple projects on GitHub in order 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 private message, or in a comment if you are really angry :)
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION