Receptor para sensores meteorlógicos Oregon

Para los aficionados a la meteorología el fabricante Oregon Scientific tiene una serie de dispositivos formados por sensores y receptores que permite saber la temperatura, humedad, velocidad y dirección del viento, cantidad de lluvia, sensor rayos UV … En el siguiente enlace podéis ver los dispositivos comercializados por Oregon: http://store.oregonscientific.com/es/estaciones-meteorologicas.html
Aunque Oregon si que dispone de diversas estaciones que recogen la información de todos sus sensores y permite volcarlos a un PC, la idea de este proyecto es poder publicar en tiempo real estos valores en Internet.
Los sensores de este fabricante son inalámbricos y emiten en la frecuencia de 433Mhz y una codificación Manchester. Nuestra pequeña estación meteorológica se encargará de estar escuchando la banda de 433Mhz y en cuanto se reciba una emisión de un sensor de Oregon, decodificarlo y enviarlo a un servidor en Internet.
Como servicio para recoger nuestra información utilizaremos https://data.sparkfun.com/, muy sencillo de configurar, utilizar y que conecta directamente con https://analog.io/
Listado de componentes de nuestro receptor
![]() |
Arduino Mega 2560: Para el proyecto vamos a usar uno de los arduinos más potentes con microcontrolador ATmel. No tanto por su cantidad de I/O o su tamaño de memoria, si no por su velocidad de procesamiento. |
![]() |
LCD Keypad Shield: Formado por una pantalla LCD 16×2 y una serie de botones nos va a permitir mostrar información tanto de la inicialización de nuestro receptor como de los datos recibidos de los sensores. |
![]() |
Interfaz Ethernet: Emplearemos la barata y fácil de utilizar ENC28J60. Existe otro tipo de hardware, como el Ethernet Shield o Wifi Shield, más caros y con características que no necesitamos en este proyecto, pero también se podría utilizar. |
![]() |
Receptor 433MHz: Será el encargado de recibir la señal emitida por los sensores Oregon en la frecuencia de 433MHz |
![]() |
Pequeña antena para aumentar el alcance de nuestro receptor. |
![]() |
Transformador 9v: Será el encargado de alimentar al Arduino de forma estable. |
![]() |
Cables preparados para conectar de forma sencilla los diferentes componentes con el Arduino |
Montaje del receptor
- LCD Shield
En un primer momento se utilizó para el montaje una pantalla LCD 16×2 I2C pero esto entraba en conflicto con el receptor de 433MHz con lo que se optó por un LCD 16×2 normal. El montaje del shield es bastante sencillo y solo tenemos que hacer coincidir las patillas del shield con el zócalo de nuestro Arduino Mega. Además nos proporciona unos botones que nos serán de utilidad para poder encender la luz de fondo del LCD.
- Interfaz Ethernet
En este proyecto utilizamos la gran conocida interfaz ENC28J60 de la que ya hemos hablado en el proyecto de medidor de consumo: http://www.gonzalogalvan.es/medidor-de-consumo-conectamos-a-internet/
Al utilizar un Arduino Mega, deberemos conectar nuestra interfaz a los pines SPI siguientes:
|
![]() |
- Receptor 433Mhz
El receptor deberemos conectarlo a una de las entradas digitales con interrupción de nuestro Arduino.
Nº Interrupción | int.0 | int.1 | int.2 | int.3 | int.4 | int.5 |
Pin Mega2560 | 2 | 3 | 21 | 20 | 19 | 18 |
Aquí una foto del receptor ya conectado con la antena puesta:
Programando nuestra estación meteorológica
Los sensores de Oregon emiten en 2 versiones de un protocolo propietario denominadas OSV2 y OSV3. Hay multitud de páginas comentando estos protocolos e implementaciones de su decodificación para Arduino. Algunos enlaces de interés sobre la codificación de Oregon:
- http://jeelabs.net/projects/cafe/wiki/Decoding_the_Oregon_Scientific_V2_protocol
- http://wmrx00.sourceforge.net/Arduino/OregonScientific-RF-Protocols.pdf
- http://www.mattlary.com/2012/06/23/weather-station-project/
Como el código es bastante extenso, solo voy a detallar ciertas partes interesantes que se deben entender. Al final del post tendréis un enlace para descargar el código fuente completo.
- Inicialización del pin con interrupción
Para mi montaje he elegido la interrupción 1 para conectar el receptor RF, así que para esa interrupción asociaremos la función ext_int_1 que será lanzada ante la detección de un cambio.
attachInterrupt(1, ext_int_1, CHANGE); |
La función ext_int_1 queda definida de la siguiente forma:
volatile word pulse; void ext_int_1(void) { static word last; // determine the pulse length in microseconds, for either polarity pulse = micros() - last; last += pulse; } |
- Captura de la emisión de los sensores mediante interrupción
Ya en el método loop() del programa, desactivaremos primero cualquier interrupción para coger el valor pulse recibido por el pin digital. Una vez guardado en una nueva variable, volveremos a activar las interrupciones. Para ello emplearemos las funciones cli() y sei(). Una web interesante sobre este tema http://www.allaboutcircuits.com/technical-articles/using-interrupts-on-arduino/
cli(); word p = pulse; pulse = 0; sei(); if (p != 0) { if (orscV2.nextPulse(p)) reportSerial("OSV2", orscV2); if (orscV3.nextPulse(p)) reportSerial("OSV3", orscV3); } |
- Decodificación de la información
Si revisáis el código , veréis que en la función reportSerial se realiza la detección del tipo de sensor y la decodificación de los datos. Será en esta función donde tendremos que ir añadiendo cada uno de los sensores que queramos tratar.
Para el caso del THGR228N, sensor utilizado en el proyecto, podéis ver como se prepara la información para mostrarlo en las dos lineas del LCD y la cadena para el envío al servidor de Internet.
// Inside Temp-Hygro : THGR228N,... if(data[0] == 0x1A && data[1] == 0x2D) { Serial.print("[THGR228N,...] Id:"); Serial.print(data[3], HEX); Serial.print(" ,Channel:"); Serial.print(channel(data)); Serial.print(" ,temp:"); Serial.print(temperature(data)); Serial.print(" ,hum:"); Serial.print(humidity(data)); Serial.print(" ,bat:"); Serial.print(battery(data)); float temperatureRec = temperature(data); byte channelRec = channel(data); byte humidityRec = humidity(data); byte batteryRec = battery(data); String(temperatureRec, 1).toCharArray(tempChar, 10); sprintf(lcdLine1, "%02X DI:%02X C:%02X ", data[0], data[3], channelRec); sprintf(lcdLine2, "T:%s H:%d B:%d ", tempChar, humidityRec, batteryRec); sprintf(postData, "type=%02X&id=%02X&channel=%02X&temp=%s&humidity=%d&battery=%d", data[0], data[3], channelRec, tempChar, humidityRec, batteryRec); if (millis() > timerRead + READ_RATE) { timerRead = millis(); pendienteEnvio = true; } } |
Para formatear los datos utilizó la función sprintf, que permite fácilmente trabajar con distintos tipos de variables.
- Envío al servidor y visualización en LCD
El proceso de envío es muy similar al ya realizado para el medidor de consumo eléctrico. Realizaremos un POST sobre la URL con las claves que nos haya proporcionado sparkfun. Concatenaremos la cadena postData que ya hemos preparado con los datos a enviar en el método anterior.
if (pendienteEnvio) { //Enviamos al servidor if (millis() > timerHttp + REQUEST_RATE) { timerHttp = millis(); Serial.println("\n REQ"); ether.browseUrl(PSTR("/input/###tu_clave_publica###?private_key=###clave_privada###&"), postData, website, procesarRespuesta); } lcd.setCursor(0, 0); lcd.print(lcdLine1); lcd.setCursor(0, 1); lcd.print(lcdLine2); } |
- Lectura del botón del Shield
Los botones que se encuentran en el Shield junto al LCD se leen mediante una entrada analógica, en los que cada uno de los botones tendrán una resistencia diferente y por tanto una lectura diferente.
uint8_t read_analog_buttons(void) { //RIGHT: 0 //DOWN: 308 //UP: 132 //LEFT: 481 //SELECT: 723 uint16_t lectura = analogRead(0); uint16_t k = (analogRead(0) - lectura); //gives the button a slight range to allow for a little contact resistance noise if (5 < abs(k)) return KEY_NONE; // double checks the keypress. If the two readings are not equal +/-k value after debounce delay, it tries again. if (lectura < 104) return KEY_RIGHT; if (lectura < 303) return KEY_UP; if (lectura < 479) return KEY_DOWN; if (lectura < 633) return KEY_LEFT; if (lectura < 864) return KEY_SELECT; return KEY_NONE; // default } |
Visualizando los datos recibidos
Si hemos creado bien nuestra cuenta en sparkfun, definiendo los campos que vamos a enviar desde el arduino y metiendo en nuestro programa la clave privada necesaria para que los datos queden registrados, empezaremos a ver en la web cada uno de los envíos realizados.
Podéis ver un ejemplo real en https://data.sparkfun.com/oregon, donde tenemos los datos del sensor THGR228N. En este caso se está recogiendo el estado de la batería, el canal en el que está emitiendo el sensor, la humedad, el Id del dispositivo, el tipo de dispositivo y la temperatura. El campo timestamp es incluido automáticamente con lo que evitamos necesitar tener un RTC en nuestro proyecto.
Desde la propia página podemos exportar la información en diversos formato y directamente conectar con AnalogIO para graficar nuestros datos de forma sencilla.
Aquí podemos ver un pequeño video del montaje final funcionando:
Próximo pasos …
Como podéis comprobar, ahora mismo el programa cargado en el Arduino solo decodifica y trata la información de un sensor de Oregon, habría que ir analizando la información del resto de sensores para ir extrayendo su información y enviarlo al servidor.
También se puede trabajar en la representación de la información en el LCD aunque hay que tener cuidado en realizar demasiadas tareas y mantener ocupado al Arduino en otras tareas diferentes a la decodificación de los mensajes.
Descarga del código fuente.
Del siguiente enlace podréis descarga el fuente completo del receptor: OregonWeather.ino
Si os es de utilidad o realizáis alguna mejora interesante como añadir nuevos sensores, por favor, comentar sobre este post para irlo completando y así poder aprender todos.
1 Comment
Hola Gonzalo
Muchas gracias por esta iformación que te has trabajado.
Estoy interesado en ponerlo en práctica pero yo tengo una torre MISOL 1 wireless y no sé si también es compatible tu documentación aquí expuesta para esta torre que también utiliza una transmisión inalámbrica de 433Mhz, pero que desconozco si usa una codificación Manchester.
Saludos