Estação Meteorológica IoT

Participantes:

Cláudio Luís Vieira Oliveira

Resumo do projeto:

Neste projeto será construída uma estação meteorológica a partir de um sistema microcontrolado, sensores de baixo custo e sensores construídos manualmente a partir de materiais de uso cotidiano, impressos em 3D e/ou recicláveis.

Descrição do projeto:

Considerando o contexto de Sistemas Embarcados e Internet das Coisas (IoT), podemos considerar que uma estação meteorológica consiste em um conjunto de sensores que realizar a obtenção de um conjunto de dados atmosféricos que possibilitarão a análise e provisão do tempo meteorológico. Este projeto visa a construção de uma estação meteorológica de baixo custo, de domínio público e com fins didáticos que poderá ser usada em disciplinas relacionadas ao ensino e experimentos de Ciência e a Climatologia, nos diferentes níveis de ensino (fundamental, médio e superior), visto que as soluções de estação meteorológicas disponíveis atualmente apresentam um custo elevado, inviabilizando o seu uso na grande maioria das instituições de ensino de rede pública.

Vivemos em um mundo em que sistemas automatizados são muito comuns. Robótica, sistemas inteligentes de vigilância, drones e Internet das Coisas estão presentes nas indústrias, vias públicas, agronegócios, serviços e, até mesmo, em nossas casas. Esses sistemas automatizados possuem alguns pilares, como o componente físico e eletrônico (hardware) baseadas em microcontroladores e a sua programação (software). Há várias plataformas de desenvolvimento de projetos automatizados, que nos auxilia, tanto na montagem da parte física quanto na programação.

Atualmente existem várias plataformas, de hardware e software abertos, focada em aplicações de Sistemas Embarcados e Internet das Coisas (IoT). Essas plataformas utilizam como base microcontroladores de baixo custo e baixo consumo de energia (Oliveira, e Zanetti, 2015). Além disso, existe uma grande oferta de sensores de baixo custo disponíveis no mercado, possibilitando a construção de dispositivos eficientes, mas com custos acessíveis. Com base nestas premissas é possível a construção de uma estação meteorológica voltada para fins acadêmicos (Oliveira, 2018).

Histórico do desenvolvimento:

A placa de desenvolvimento a ser utilizada é a Franzininho WiFi e a programação poderá ser realizada usando CircuitPython. Os dados ficarão disponíveis publicamente a partir de uma interface para a Internet desenvolvida em Node.js. Estes dados poderão ser usados para fins didáticos em disciplinas relacionadas a climatologia, ciências, estatística e matemática.

Os parâmetros a serem medidos pela estação meteorológica são mostrados na Tabela 1, salientando que este conjunto de sensores poderá ser ampliado conforme o andamento da etapa de pesquisa.

Tabela 1: Conjunto de parâmetros e sensores

Parâmetro Sensor
Temperatura / Umidade Relativa do Ar DHT11
Temperatura / Pressão Atmosférica BMP280
Luminosidade BH1750
Anemômetro Construção caseira (diy) usando materiais reciclados e/ou impressos em 3D e um reed switch.
Biruta (Direção do Vento) Construção caseira (diy) usando materiais reciclados e/ou impressos em 3D e 8 reed switchs.
Pluviômetro Construção caseira (diy) usando materiais reciclados e/ou impressos em 3D e um reed switch.

A construção do Anemômetro, Biruta e Pluviômetro usou peças impressas em 3D a partir do projeto “LTB Weather Station by RobWLakes”, disponível em https://www.thingiverse.com/thing:2849562.

Os materiais utilizados, a sequência de construção dos sensores e os programas desenvolvidos estarão disponibilizados em domínio público, permitindo que instituições de ensino a construam dentro projetos didático-pedagógicos que podem envolver alunos e professores. Além de possibilitar que o projeto seja ampliado e aperfeiçoado.

Hardware:

Circuito eletrônico

Figura 1: Circuito Eletrônico

Lista de materiais:

  • 1 Franzininho WiFi.
  • 1 BMP280.
  • 1 BH1750.
  • 1 DHT11.
  • 10 Reed switch.
  • 10 Resistores de 10kOhms.
  • 1 Resistor de 4,7kOhms.
  • 1 Protoboard.
  • Cabos de ligação.

Software/Firmware:

A programa para o Franzininho WiFi foi escrito em CircuitPython e, basicamente, obtém as informações dos sensores e os envia para a IBM Cloud em intervalos regulares.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
import board
import busio
import neopixel_write
import digitalio
import time
import wifi
import socketpool
import ssl
import adafruit_requests
import adafruit_dht
import adafruit_bmp280
import adafruit_bh1750
import math

_TICKS_PERIOD = const(1<<29)
_TICKS_MAX = const(_TICKS_PERIOD-1)
_TICKS_HALFPERIOD = const(_TICKS_PERIOD//2)

def ticks_diff(ticks1, ticks2):
  diff = (int(ticks1) - int(ticks2)) & _TICKS_MAX
  diff = ((diff + _TICKS_HALFPERIOD) & _TICKS_MAX) - _TICKS_HALFPERIOD
  return diff

neo = digitalio.DigitalInOut(board.NEOPIXEL)
neo.direction = digitalio.Direction.OUTPUT
pixel_off = bytearray([0, 0, 0])
neopixel_write.neopixel_write(neo, pixel_off)

# Sensores de temperatura, umidade, pressão e luminosidade
dht = adafruit_dht.DHT11(board.IO17)
i2c = busio.I2C(scl=board.IO9, sda=board.IO8)
bh = adafruit_bh1750.BH1750(i2c)
bmp = adafruit_bmp280.Adafruit_BMP280_I2C(i2c, address=0x76)
bmp.sea_level_pressure = 1013.25

# Direção do Vento
dir_pino = [board.IO33, board.IO34, board.IO35, board.IO36, board.IO37, board.IO38, board.IO39, board.IO40]
dir_obj = []
direcao  = ['N', 'NE', 'L', 'SE', 'S', 'SO', 'O', 'NO']
for i in range(8):
  dir_obj.append(digitalio.DigitalInOut(dir_pino[i]))
  dir_obj[i].direction = digitalio.Direction.INPUT
dir_vento = '..'

# Velocidade do Vento (Anemômetro)
vel_obj = digitalio.DigitalInOut(board.IO15)
vel_obj.direction = digitalio.Direction.INPUT
vel_veloc = 0.0
vel_raio = 6.5 / 100 # Raio em metros
vel_inicio = True
vel_tinicio = 0
vel_anterior = False

# Pluviometro
plu_obj = digitalio.DigitalInOut(board.IO14)
plu_obj.direction = digitalio.Direction.INPUT
plu_reset = False
plu_momento_real = 0
plu_momento_atual = 0
plu_cont = 0
plu_anterior = 0
plu_area = (math.pi*(0.045*0.045))*1000
plu_volume_chuva_mm = 0.0

# Envio dos dados
envio_timer = False
envio_inicio = 0
envio_fim = 0

# Conexao a rede e criação do soquete
print('Conectando...')
wifi.radio.connect('CasaClaudio1', 'c1l2v6o8')
print('Conectado, usando o IP', wifi.radio.ipv4_address)
GET_URL = 'https://clvoliveira.mybluemix.net/franzininho'
soquete = socketpool.SocketPool(wifi.radio)
req = adafruit_requests.Session(soquete, ssl.create_default_context())

try:
  # Laço principal
  while True:
    neopixel_write.neopixel_write(neo, bytearray([0, 0, 55]))
    try:
      # Leitura dos sensores de temperatura, umidade, pressão e luminosidade
      temp = dht.temperature
      umid = dht.humidity
      temp = (temp + bmp.temperature) / 2
      pres = bmp.pressure
      lum = bh.lux
      # Fim-Leitura dos sensores de temperatura, umidade, pressão e luminosidade
      
      # Leitura da direção do vento
      for i in range(8):
        #print (i, dir_obj[i].value)
        if dir_obj[i].value == True:
          dir_vento = direcao[i]
      # Fim-Leitura da direção do vento
      
      # Leitura da velocidade do vento
      vel_atual = vel_obj.value
      if vel_atual == True and vel_anterior == False:
        if vel_inicio == True:
          vel_tinicio = time.monotonic()
          vel_inicio = False
          time.sleep(0.001)
        else:
          vel_tfim = time.monotonic()
          vel_duracao = ticks_diff(an_tfim, an_tinicio)
          if vel_duracao > 0:
            vel_veloc = ((vel_raio * 3.1416 * 2 / 1000) / (vel_duracao / 3600))
            print ('Tempo', vel_duracao, 'Velocidade', vel_veloc, 'km/h')
          else:
            print ('AnNoRead', vel_tinicio, vel_tfim)
          vel_inicio = True
      vel_anterior = vel_atual
      # Fim-Leitura da velocidade do vento
      
      # Leitura do pluviômetro
      plu_ciclo = ticks_diff(plu_momento_atual, plu_momento_real)
      if plu_reset == False:
        plu_momento_atual= time.monotonic()
        plu_reset = True
      if plu_ciclo <= 600:
        plu_valor = plu_obj.value
        if plu_valor == 1 and plu_anterior == 0:
          plu_cont = plu_cont + 1
          print('plu_cont: ', plu_cont)
          sleep(0.001)
        plu_anterior = plu_valor
      else:
        plu_momento_real= time.monotonic()
        plu_volume_chuva_mm = (plu_cont * 6) * plu_area
        cont_pluv = 0
        plu_reset = False
      # Fim-Leitura do pluviômetro
      
      # Envio dos dados
      if envio_timer == False:
        envio_inicio = time.monotonic()
        envio_timer = True
      envio_fim = time.monotonic()
      ciclo_envio = ticks_diff(envio_fim, envio_inicio)
      if ciclo_envio >= 600:
        envio_timer = False
        ciclo_envio = 0
        envio_inicio = 0
        envio_fim = 0
        print('temp={:.1f}, umid={:.1f}, pres={:.1f}, lum={:.1f}, dir={}, vel={:.1f}, plu={:.1f}'.format(temp, umid, pres, lum, dir_vento, vel_veloc, plu_volume_chuva_mm))
        neopixel_write.neopixel_write(neo, bytearray([55, 0, 0]))
        print('\nEnviando requisição...')
        resp = req.get('{}?temp={:.1f}&umid={:.1f}&pres={:.1f}&lum={:.1f}, dir={}, vel={:.1f}, plu={:.1f}'.format(GET_URL, temp, umid, pres, lum, dir_vento, vel_veloc, plu_volume_chuva_mm))
        print('Resposta:', resp.json())
        resp.close()
        neopixel_write.neopixel_write(neo, pixel_off)
      # Fim-Envio dos dados
      time.sleep(0.001)
    except RuntimeError:
      print ('Erro leitura sensor! Tentando novamente...')
      neopixel_write.neopixel_write(neo, pixel_off)
      time.sleep(5.0)
except KeyboardInterrupt:
  dht.exit()
  neopixel_write.neopixel_write(neo, pixel_off)

 

A aplicação em nuvem foi desenvolvida em Node.js / Node-Red e disponibilizada na IBM Cloud, através do link https://clvoliveira.mybluemix.net/ui. Na Figura 2 é apresentado um exemplo do dashboard criado para exibir os dados enviados, para a nuvem, pela estação meteorológica.

Figura 2: Aplicação em Nuvem

 

 

Referências:

CircuitPython (Documentação). Disponível em https://circuitpython.readthedocs.io/en/latest/README.html, acesso em 7/12/2021.

Franzininho WiFi (Documentação). Disponível em https://docs.franzininho.com.br/docs/franzininho-wifi/franzininho-wifi/#, acesso em 7/12/2021.

Oliveira, C. Estação Meteorológica usando NodeMCU/LUA. 2018. Disponível em https://github.com/clvoliveira/nodemcu-weather-station, acesso em 6/12/2021.

Oliveira, C.; Zanetti, H. Arduino descomplicado: como elaborar projetos de eletrônica. São Paulo: Editora Érica, 2015.