Commit 80c24043 authored by Jan Luc Tavares's avatar Jan Luc Tavares
Browse files

concluidas as funcionalidades basicas: envio de str com a ultima medida e...

concluidas as funcionalidades basicas: envio de str com a ultima medida e imagens com medidas dos últimos períodos
parent dbcd5b0f
......@@ -4,9 +4,8 @@
#
# O objetivo inicial é escrever um MVP para comunicacao dos dados das EMM.
#
# TODO: * Fazer funcao de selecionar estacao
# * Escrever texto e interacoes de "boas-vindas"
# * Escrever texto do "tchau" (ele tambem deve remover o usuario do BD)
# TODO:
# * Implementar alguma estrategia para que nao se realize tantos downloads e que seja mais rápido.
#
#
#
......@@ -19,6 +18,7 @@ import os
import urllib #biblioteca necessaria para a codificacao do texto em forma de url
from dbhelper import DBHelper
from secretoken import tokensecret
from importa_dados import coleta, plot_periodo
db = DBHelper()
......@@ -85,6 +85,13 @@ def send_message(text, chat_id, reply_markup=None):
if reply_markup:
url += "&reply_markup={}".format(reply_markup)
get_url(url)
def send_pic(chat_id, file):
url=URL+ "sendPhoto"
files = {'photo': open('{}/{}'.format(os.getcwd(),file), 'rb')}
data = {'chat_id' : chat_id}
requests.post(url, files=files, data=data)
def build_keyboard(items):
'''
......@@ -99,8 +106,9 @@ def build_keyboard(items):
#######################################################################
def boas_vindas(chat_id, entrada=None):
text = "Oi!\nVocê está falando com o Bot das Estações Meteorológicas Modulares\nReceba minhas sinceras boas-vindas!\nConfira os comandos em /ajuda"
send_message(text, chat_id)
text = "Oi!\nVocê está falando com o Bot das Estações Meteorológicas Modulares\nReceba minhas sinceras boas-vindas!\n Escolha uma estação ou confira os comandos em /ajuda"
keyboard = build_keyboard(["/selecionar"])
send_message(text, chat_id, keyboard)
def ajuda(chat_id,entrada=None):
text="Comandos: \n/start - Boas-vindas\n/ajuda - Receba essa lista de comandos\n/selecionar - Selecione a estacao de seu interesse\n/tchau - Cancele o recebimento das minhas mensagens \n\nDepois de escolher a estação, você poderá escolher o perído de tempo para visualizar dados e selecionar o tipo de dado de seu interesse \n/ultimo - Veja a última medida realizada\n/dia - Veja a medida do último dia\n/semana - Veja a medida da ultima semana\n/mes - Veja a medida do último mês"
......@@ -109,8 +117,7 @@ def ajuda(chat_id,entrada=None):
def sel_emm1(chat_id,entrada=None):
text = "Selecione a estação que você deseja receber os dados"
ids,estacoes = lista_emm()
for item in estacoes:
estacoes[estacoes.index(item)] = "estação " + item
estacoes = ["estação " + item for item in estacoes]
keyboard = build_keyboard(estacoes)
send_message(text, chat_id,keyboard)
......@@ -134,20 +141,115 @@ def tchau(chat_id,entrada=None):
def ultimo(chat_id,entrada=None):
text = "Ainda nao tenho essa funcionalidade :( \n me desgupe \n hashtag xatiado" #placeholder apenas
estacao = db.get_items(chat_id, 'padrao')
try:
send_message("Sua paciência será recompensada. \n",chat_id)
text = "Selecione o tipo de dado de seu interesse"
tipos, dados = coleta(estacao[0])
tipos = ["Último {}".format(tipo) for tipo in tipos]
tipos.append("Último de todos")
keyboard = build_keyboard(tipos)
except:
text = "Parece que você ainda não selecionou nenhuma estação"
keyboard = build_keyboard(["/selecionar", "/ajuda"])
send_message(text,chat_id, keyboard)
def ultimo2(chat_id, entrada=None):
try:
escolha = entrada.split()[1] # a 'escolha' é a segunda palavra da resposta.
estacao = db.get_items(chat_id, 'padrao') # verifica qual a estacao cadastrada para o usuario
tipos, dados = coleta(estacao[0]) # faz a aquisicao dos dados
if escolha == "de":
text = "Data da medida: {} \nSensor: Valor medido: \n".format(dados[tipos[0]][-1])
for tipo in tipos:
text = text + "{} ------- {}\n".format(tipo,dados[tipo][-1])
elif escolha in tipos:
text = "Data da medida: {} \n".format(dados[tipos[0]][-1])
text = text + "Sensor: {} ------- Valor medido: {}".format(escolha, dados[escolha][-1])
else:
text = "Não encontrei o sensor que você pediu :(\n"
tipos = ["Último {}".format(tipo) for tipo in tipos]
except:
text = "Você tem certeza que selecionou uma estação em \selecionar?\n Tente escolher uma estação novamente ¯\(o_o)/¯ "
send_message(text,chat_id)
def dia(chat_id,entrada=None):
text = "Ainda nao tenho essa funcionalidade :( \n me desgupe \n hashtag xatiado" #placeholder apenas
send_message(text,chat_id)
estacao = db.get_items(chat_id, 'padrao')
try:
send_message("Espera um pouquinho porque eu sou um nenê ainda e demoro um pouco. \n",chat_id)
text = "Selecione o tipo de dado de seu interesse"
tipos, dados = coleta(estacao[0])
tipos = ["Dia do {}".format(tipo) for tipo in tipos]
keyboard = build_keyboard(tipos)
except:
text = "Parece que você ainda não selecionou nenhuma estação"
keyboard = build_keyboard(["/selecionar", "/ajuda"])
send_message(text,chat_id, keyboard)
def dia2(chat_id,entrada=None):
try:
escolha = entrada.split()[2] # a 'escolha' é a terceira palavra da resposta.
estacao = db.get_items(chat_id, 'padrao') # verifica qual a estacao cadastrada para o usuario
tipos, dados = coleta(estacao[0]) # faz a aquisicao dos dados
plot_periodo(dados[tipos[0]], dados[escolha], escolha, 'dia')
send_pic(chat_id,"dia.png")
except:
text = "Deu ruim.\nOu você escolheu um tipo de dado que não temos ou não selecionou estação ainda.\n\n\selecionar"
send_message(text, chat_id)
def semana(chat_id,entrada=None):
text = "Ainda nao tenho essa funcionalidade :( \n me desgupe \n hashtag xatiado" #placeholder apenas
send_message(text,chat_id)
estacao = db.get_items(chat_id, 'padrao')
try:
send_message("Sabe, né? Essa é a parte que mais demora.\n", chat_id)
text = "Selecione o tipo de dado de seu interesse"
tipos, dados = coleta(estacao[0])
tipos = ["Semana do {}".format(tipo) for tipo in tipos]
keyboard = build_keyboard(tipos)
except:
text = "Parece que você ainda não selecionou nenhuma estação"
keyboard = build_keyboard(["/selecionar", "/ajuda"])
send_message(text,chat_id, keyboard)
def semana2(chat_id,entrada=None):
try:
escolha = entrada.split()[2] # a 'escolha' é a terceira palavra da resposta.
estacao = db.get_items(chat_id, 'padrao') # verifica qual a estacao cadastrada para o usuario
tipos, dados = coleta(estacao[0]) # faz a aquisicao dos dados
plot_periodo(dados[tipos[0]], dados[escolha], escolha, 'semana')
send_pic(chat_id,"semana.png")
except:
text = "Deu ruim.\nOu você escolheu um tipo de dado que não temos ou não selecionou estação ainda.\n\n\selecionar"
send_message(text, chat_id)
def mes(chat_id,entrada=None):
text = "Ainda nao tenho essa funcionalidade :( \n me desgupe \n hashtag xatiado" #placeholder apenas
send_message(text,chat_id)
estacao = db.get_items(chat_id, 'padrao')
try:
text = "Selecione o tipo de dado de seu interesse"
tipos, dados = coleta(estacao[0])
tipos = ["Mês do {}".format(tipo) for tipo in tipos]
keyboard = build_keyboard(tipos)
except:
text = "Parece que você ainda não selecionou nenhuma estação"
keyboard = build_keyboard(["/selecionar", "/ajuda"])
send_message(text,chat_id, keyboard)
def mes2(chat_id,entrada=None):
try:
escolha = entrada.split()[2] # a 'escolha' é a terceira palavra da resposta.
estacao = db.get_items(chat_id, 'padrao') # verifica qual a estacao cadastrada para o usuario
tipos, dados = coleta(estacao[0]) # faz a aquisicao dos dados
plot_periodo(dados[tipos[0]], dados[escolha], escolha, 'mes')
send_pic(chat_id,"mes.png")
except:
text = "Deu ruim.\nOu você escolheu um tipo de dado que não temos ou não selecionou estação ainda.\n\n\selecionar"
send_message(text, chat_id)
entradas = { "/start" : boas_vindas,
"/ajuda": ajuda ,
......@@ -155,9 +257,13 @@ entradas = { "/start" : boas_vindas,
"estação":sel_emm2,
"/tchau": tchau,
"/ultimo": ultimo,
"Último":ultimo2,
"/dia": dia,
"Dia":dia2,
"/semana": semana,
"Semana":semana2,
"/mes": mes,
"Mês":mes2
}
# Fim da definicao de respostas possiveis
......
############################### Sobre #################################
# Programa capaz de baixar e graficar dados das EMM.
# Programa capaz de baixar e graficar os dados das emm.
#
# Por enquanto ele é apenas um exemplo que usa as bibliotecas bokeh e pandas.
# Trocarei provavelmente para matplotlib para exportar direto para png.
#
# TODO: 0. Tornar o código 'importavel' para ser usado pelo codigo principal do bot.
# 1. (C) Graficar direto para uma imagem.
# 2.(D) Realizar a conversao do CSV diretamente atraves da utilizacao da
# biblioteca Pandas.
#
#
# Referência sobre o Pyplot: http://matplotlib.org/users/pyplot_tutorial.html
#
from matplotlib import pyplot as plt
import requests
from bokeh.plotting import figure, output_file, show
#from bokeh.io import export_png, export_svgs
from bokeh.models import DatetimeTickFormatter
import pandas as pd
def coleta(estacao):
'''
Faz download de todos os dados da EMM determinada pelo numero inteiro 'estacao'.
Retorna lista e dataframe do pandas.
Retorna lista e dicionário.
A lista contem o cabecalho do arquivo CSV baixado, representando cada tipo de dado que a EMM envia.
O dataframe do Pandas contem todos os dados obtidos e os dados de tempo sao convertidos para serem lidos pelo programa.
O dicionario contem todos os dados obtidos identificados pelos "tipos" como chaves.
'''
endereco = 'http://dados.cta.if.ufrgs.br/emm/api/get/csv/rawsensordata/' + str(estacao)
endereco = 'http://dados.cta.if.ufrgs.br/emm/api/get/csv/rawsensordata/{}'.format(estacao)
rawData = requests.get(endereco)
rawData = rawData.text
# Com isso, obtivemos o conteúdo COMPLETO dos dados de uma estacao.
#######################################################################
# Abaixo pegaremos esses dados e construiremos um dicionario com chaves
# determinadas pela primeira linha do .CSV e listas contendo as colunas
# do arquivo em sequencia.
#
# Acabo de descobrir que poderia ter feito um trabalho mais elegante ao
# usar a biblioteca "Pandas".
lines = rawData.split("\n")
tipos = lines[0].split(";")
lines = rawData.split("\n") # cria array com todas as linhas do csv
tipos = lines[0].split(";") # cria array com todos os tipos de dados, definidos na primeira linha
tipos = [tipo.replace("\r", "") for tipo in tipos] # remove sinal indesejado nas chaves do dicionario
dados = {}
j=0
......@@ -51,47 +32,26 @@ def coleta(estacao):
sensor.append(lines[i].split(";")[j])
j = j + 1
dados[tipo] = sensor
#######################################################################
############### Convertendo os dados para um dataframe do pandas
dataf = pd.DataFrame(dados)
dataf[tipos[0]] = pd.to_datetime(dataf[tipos[0]], format="%Y-%m-%d %H:%M:%S")
return tipos, dataf
tipos, dataf = coleta(2)
sensor = 1 # Este numero determina qual será o sensor que escolhemos. Na ordem de aparicao no .CSV
#######################################################################
################ Graficando os dados obtidos ##########################
colors = ["Blue", "DarkOliveGreen", "BlueViolet", "Brown", "CadetBlue", "Coral"]
output_file("./parametros.html")
p = figure(title="Dados das EMM", x_axis_label="data", y_axis_label="valores")
p.line(dataf[tipos[0]],dataf[tipos[sensor]], legend=(tipos[sensor]), line_width=2, line_color = colors[3])
p.xaxis.formatter=DatetimeTickFormatter(
hours=["%d %b %Y - %k:%M"],
days=["%d %b %Y - %k:%M"],
months=["%d %b %Y - %k:%M"],
years=["%d %b %Y - %k:%M"],
)
################
# Exportando png e svg ainda nao funciona, pois retorna:
# "RuntimeError: PhantomJS is not present in PATH..."
# REF: http://bokeh.pydata.org/en/latest/docs/user_guide/export.html
#
#export_png(p, filename="plot.png")
#
#p.output_backend = "svg"
#export_svgs(p, filename="plot.svg")
show(p)
return tipos, dados
def plot_periodo(datas, dados_sensor, tipo, periodo):
'''
Toma todas as datas e todas as medidas de certo tipo.
Faz o gráfico das últimas medidas completando o 'periodo'
Como atualmente os dados sao medidos a cada 5 minutos, para o dia faz o plot dos últimos 288 pontos (quantidade de intervalos de 5minutos em um dia).
'''
if periodo == "dia":
per = 288 # 288 *5minutos == dia
elif periodo == 'semana':
per = 2016 # 2016 * 5minutos == semana
elif periodo == 'mes':
per = 60480 #60480 *5minutos == mes
plt.plot_date(datas[-per:], dados_sensor[-per:], 'r--') # plota os últimos "per" pontos.
plt.xlabel(tipo)
plt.ylabel('valor medido (u.a.)')
plt.title('Último "dia" de medidas do {}'.format(tipo))
plt.grid(True)
plt.savefig("{}.png".format(periodo))
plt.show()
Bot das EMM para Telegram
====================================================
Repositório: https://git.cta.if.ufrgs.br/emm/emm-bot
Decidimos realizar a construção do BOT no Telegram, por ser uma plataforma simples, bem documentada e amplamente utilizada. Objetiva-se, porém, permitir uma adaptabilidade fácil a outros meios.
Objetiva-se a capacidade de informar os parâmetros medidos pelas estações meteorológicas de forma muito simples e acessível.
### Sobre o TOKEN ###
Foi criado um código chamado "secretoken.py" contendo o TOKEN de acesso ao sistema do Telegram. Esse token permite que o bot utilize o serviço do Telegram e, por esse motivo, deve ser mantido em segredo. Dessa forma, realizamos um
>from secretoken import tokensecret
E não realizamos o upload do secretoken.py para o servidor. Nesse arquivo consta apenas o código de acesso para o BOT. Você pode criar o seu token usando o "BotFather":https://core.telegram.org/bots#botfather.
----------------------------------------------------
Todo o código é disponibilizado sob a licença GPLv3.
Jan Luc Tavares,
Agosto de 2017.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment