Bot de aviso de queimadas

Usando dados públicos para informar focos de calor nas redondezas

Matheus Duzzi Ribeiro
6 min readJan 8, 2021

Se você acompanha algum noticiário ou portal de notícias, com certeza está sabendo sobre as queimadas que estão acontecendo no centro-oeste brasileiro, especificamente na vegetação da Amazônia. Uma área gigantesca em chamas, provocando desde o perigo a vida de espécies como a onça-pintada até mesmo a do ser humano, afinal, existem inúmeras aglomerações de pessoas nessa região, sejam elas em cidades ou mesmo em fazendas.

Mas afinal, o que fazer para ajudar nesse momento tão difícil? Foi assim que surgiu a ideia desse projeto.

O objetivo aqui é bem simples, avisar as pessoas do quão distante existe um foco de calor, ou seja, uma queimada. Suponha que você seja um morador da cidade X, nosso objetivo é que você acorde e fale com o nosso chatbot:

“- Olá Bot de Queimadas, qual a queimada mais perto de mim?”

“- Olá, no momento a mais próxima está a 23 km”

Para isso iremos usar algumas bibliotecas bem interessantes do R chamadas rvest e stringr.

A biblioteca rvest permite que façamos buscas na internet e coletas de dados, ação comumente chamada de webscraping ou raspagem na web. Já stringr é usada como uma ferramenta de manipulação de textos, veremos adiante o motivo da importação delas.

Além dessas, importaremos também:

library(telegram)
library(telegram.bot)
library(geosphere)
library(readr)

As bibliotecas acima nos ajudarão no conceito de chatbot do Telegram e na manipulação de distâncias geográficas. Quanto a conta no telegram, recomendo que você entre em contato com o Bot Father que ele te explicará passo a passo de como fazer essa criação.

Boa, agora que você já tem a chave do seu Bot, podemos começar nosso projeto de fato:

bot <- TGBot$new(token = “your_key”)
bot$getMe()
bot$set_default_chat_id(“chat_id”)

No código acima você coloca a chave de acesso do seu bot e qual o chat_id da conversa, pra isso basta você mandar uma mensagem para o bot e rodar:

msgs <- bot$getUpdates()

Com isso você encontrará em msgs um dataframe com todas as configurações da conversa.

Agora que você montou a configuração inteira do bot, é hora de fazer ele conversar com você. Para isso você terá que ter em mente dois pontos principais:

  • A menos que você coloque ele para rodar em uma nuvem, ele vai ter que ficar rodando 24 horas.
  • Você precisa de tempo para digitar suas informações.
  • Ele precisa interpretar de algum jeito o que você falou e gerar uma devolutiva com informação pertinente ao objetivo do projeto, no caso, a distância do foco de calor mais próximo.

Bom, trabalharemos aqui com a hipótese de que você não deseja gastar com algum serviço como AWS ainda, ou seja, você deixará o algoritmo rodando. Recomendo que você procure mais sobre agendamento de tarefas, pode ser útil nesses casos.

Como primeiro comando, estaremos interessados em chamar o bot para conversar, para isso configuraremos o seguinte código:

 msgs <- bot$getUpdates()
ind = nrow(msgs)
while(ind == nrow(msgs)){
msgs <- bot$getUpdates()
Sys.sleep(1)
}

Com isso o algoritmo detecta quando você mandar alguma mensagem para acordar o bot, afinal, o histórico de mensagens vai ter aumentado um registro (no caso, uma linha). Dando sequência, queremos que nosso bot seja educado, não é mesmo?

 bot$sendMessage(“Bem vindo ao Bot de Queimadas!”)
Sys.sleep(3)
bot$sendMessage(‘Para iniciar o monitoramento, mande “start”’)
msgs <- bot$getUpdates()
ind_start = nrow(msgs)
while(ind_start == nrow(msgs)){
msgs <- bot$getUpdates()
Sys.sleep(1)
}
msgs <- bot$getUpdates()

Assim, ajustamos uma mensagem de boas vindas. Junto a isso, aproveitamos para ver se você não apertou algum botão sem querer e iniciou o serviço do bot.

Tendo a confirmação por uma mensagem de start, começamos nosso trabalho na WEB:

 aux = msgs$message$text %>% tail(1)
if(aux == “start”){
bot$sendMessage(‘Obrigado!’)
Sys.sleep(2)
bot$set_default_chat_id(“chat_id”)
bot$sendMessage(‘Agora insira seu CEP sem traço, por favor’)

msgs <- bot$getUpdates()
ind_cep = nrow(msgs)
while(ind_cep == nrow(msgs)){
msgs <- bot$getUpdates()
Sys.sleep(1)
}
}
msgs <- bot$getUpdates()

Veja, existem varias formas de como localizar um usuário, seja por endereço, CEP ou latitude e longitude. Entretanto, dificilmente você saberá sua latitude e longitude. Por outro lado, é muito mais fácil você saber o seu CEP, e mesmo que você não saiba, o site dos correios está ai para isso.


cep = as.numeric(msgs$message$text %>% tail(1))
url = paste(“https://www.mapacep.com.br/index.php?busca-cep=",cep)
url = gsub(“ “,””,url)
page <- read_html(url)
page %>%
html_nodes(xpath = ‘/html/body/main/div[3]/div/div[1]/p’) %>%
html_text() -> tab

Chegou a hora de desbravar o rvest! A menos que você tenha interesse em comprar a API do Google para captar a latitude e longitude por endereço essa é uma ferramenta bem útil. O que fazemos é:

  • Juntamos o CEP e um link que capta a latitude e longitude
  • Investigamos o código fonte
  • Captamos a tabela que o site retorna por CEP

Incrivel né? Mais incrível ainda é o que fazemos depois:

 latitude = str_extract(tab, “Latitude: -[0–9][0–9].[0–9][0–9][0–9][0–9][0–9][0–9][0–9]”)
latitude = as.numeric(gsub(“Latitude: “,””,latitude))
if(is.na(latitude) == TRUE){
latitude = str_extract(tab, “Latitude: -[0–9].[0–9][0–9][0–9][0–9][0–9][0–9][0–9]”)
latitude = as.numeric(gsub(“Latitude: “,””,latitude))
}
longitude = str_extract(tab, “Longitude: -[0–9][0–9].[0–9][0–9][0–9][0–9][0–9][0–9][0–9]”)
longitude = as.numeric(gsub(“Longitude: “,””,longitude))
if(is.na(longitude) == TRUE){
longitude = str_extract(tab, “longitude: -[0–9].[0–9][0–9][0–9][0–9][0–9][0–9][0–9]”)
longitude = as.numeric(gsub(“longitude: “,””,longitude))
}
cep_latlong = data.frame(latitude,longitude)

A “tabela” que o rvest retorna nesse caso é um grande texto. Mas não xingue o pobre rvest, nem mesmo o site que nos forneceram esses dados, é facilmente transformável em número como vemos a seguir, só tome cuidado pois existem latitudes e longitudes que podem ter 1 ou 2 números antes do ponto.

Ora ora, nosso bot está quase ganhando vida!

Agora vejamos, você já sabe a sua latitude e longitude, mas qual é a localização do foco de calor mais próximo?

Para conseguir esse tipo de dado captaremos os dados abertos fornecidos pelo INPE. Acho que cabe aqui o elogio para o brilhante trabalho que a equipe desse setor governamental vem fazendo, os dados estão em uma qualidade muito boa e você terá pouco trabalho de limpeza aqui.

 CSV_URL = ‘http://queimadas.dgi.inpe.br/queimadas/dados-abertos/download/?utm_campaign=dados-abertos&outputFormat=csv&utm_medium=landing-page&time=24h&utm_content=focos_brasil_24h&id=focos_brasil&utm_source=landing-page' foco_atual = read_csv(CSV_URL) if(nrow(foco_atual) == 0){
foco_atual = read.csv(‘http://queimadas.dgi.inpe.br/queimadas/dados-abertos/download/?utm_campaign=dados-abertos&outputFormat=csv&utm_medium=landing-page&time=48h&utm_content=focos_brasil_ac_48h&id=focos_brasil_ac&utm_source=landing-page')
bot$sendMessage(‘O sistema ainda não tem dados atualizados para o dia de hoje, mas estamos buscando nas referências de ontem’)
}

O que fazemos é somente a coleta do dado disponível mais recente, caso o de 24 horas ainda não esteja disponível pegamos o de 48 horas.


distancia = c()
for (i in 1:nrow(foco_atual)) {
distancia[i] = distm(c(cep_latlong$longitude[1], cep_latlong$latitude[1]), c(foco_atual$longitude[i], foco_atual$latitude[i]), fun = distHaversine)/1000
}

bot$sendMessage(‘Baseado nos dados atualizados 24 horas por dia fornecidos pelo INPE, temos a queimada mais perto em quilometros vista pelo seguinte numero’)
bot$sendMessage(format(round(min(distancia), 2), nsmall = 2))

ind = nrow(msgs)

Agora fica simples, afinal, com a biblioteca de cálculo de distância geográfica que importamos basta chamar uma função e coletar a distância mínima em quilômetros obtida. Mas você pode estar se perguntando, “Legal, mas isso vai rodar uma vez só”.

Dá uma olhadinha agora com o “while” envolvendo todo processo:

while (TRUE) {msgs <- bot$getUpdates()
ind = nrow(msgs)
while(ind == nrow(msgs)){
msgs <- bot$getUpdates()
Sys.sleep(1)
}


bot$sendMessage(“Bem vindo ao Bot de Queimadas!”)
Sys.sleep(3)
bot$sendMessage(‘Para iniciar o monitoramento, mande “start”’)
msgs <- bot$getUpdates()
ind_start = nrow(msgs)
while(ind_start == nrow(msgs)){
msgs <- bot$getUpdates()
Sys.sleep(1)
}
msgs <- bot$getUpdates()


aux = msgs$message$text %>% tail(1)
if(aux == “start”){
bot$sendMessage(‘Obrigado!’)
Sys.sleep(2)
bot$set_default_chat_id(“chat_id”)
bot$sendMessage(‘Agora insira seu CEP sem traço, por favor’)

msgs <- bot$getUpdates()
ind_cep = nrow(msgs)
while(ind_cep == nrow(msgs)){
msgs <- bot$getUpdates()
Sys.sleep(1)
}
}
msgs <- bot$getUpdates()


cep = as.numeric(msgs$message$text %>% tail(1))
url = paste(“https://www.mapacep.com.br/index.php?busca-cep=”,cep)
url = gsub(“ “,””,url)
page <- read_html(url)
page %>%
html_nodes(xpath = ‘/html/body/main/div[3]/div/div[1]/p’) %>%
html_text() -> tab


latitude = str_extract(tab, “Latitude: -[0–9][0–9].[0–9][0–9][0–9][0–9][0–9][0–9][0–9]”)
latitude = as.numeric(gsub(“Latitude: “,””,latitude))
if(is.na(latitude) == TRUE){
latitude = str_extract(tab, “Latitude: -[0–9].[0–9][0–9][0–9][0–9][0–9][0–9][0–9]”)
latitude = as.numeric(gsub(“Latitude: “,””,latitude))
}
longitude = str_extract(tab, “Longitude: -[0–9][0–9].[0–9][0–9][0–9][0–9][0–9][0–9][0–9]”)
longitude = as.numeric(gsub(“Longitude: “,””,longitude))
if(is.na(longitude) == TRUE){
longitude = str_extract(tab, “longitude: -[0–9].[0–9][0–9][0–9][0–9][0–9][0–9][0–9]”)
longitude = as.numeric(gsub(“longitude: “,””,longitude))
}
cep_latlong = data.frame(latitude,longitude)
CSV_URL = ‘http://queimadas.dgi.inpe.br/queimadas/dados-abertos/download/?utm_campaign=dados-abertos&outputFormat=csv&utm_medium=landing-page&time=24h&utm_content=focos_brasil_24h&id=focos_brasil&utm_source=landing-page'
foco_atual = read_csv(CSV_URL)
if(nrow(foco_atual) == 0){
foco_atual = read.csv(‘http://queimadas.dgi.inpe.br/queimadas/dados-abertos/download/?utm_campaign=dados-abertos&outputFormat=csv&utm_medium=landing-page&time=48h&utm_content=focos_brasil_ac_48h&id=focos_brasil_ac&utm_source=landing-page')
bot$sendMessage(‘O sistema ainda não tem dados atualizados para o dia de hoje, mas estamos buscando nas referências de ontem’)
}


distancia = c()
for (i in 1:nrow(foco_atual)) {
distancia[i] = distm(c(cep_latlong$longitude[1], cep_latlong$latitude[1]), c(foco_atual$longitude[i], foco_atual$latitude[i]), fun = distHaversine)/1000
}

bot$sendMessage(‘Baseado nos dados atualizados 24 horas por dia fornecidos pelo INPE, temos a queimada mais perto em quilometros vista pelo seguinte numero’)
bot$sendMessage(format(round(min(distancia), 2), nsmall = 2))

ind = nrow(msgs)
}

Prontinho, seu bot está pronto. Clique aqui e veja um vídeo de como será o resultado!

--

--

Matheus Duzzi Ribeiro
Matheus Duzzi Ribeiro

Written by Matheus Duzzi Ribeiro

Welcome to the dark side of data science

No responses yet