Manufactura industrial
Internet industrial de las cosas | Materiales industriales | Mantenimiento y reparación de equipos | Programación industrial |
home  MfgRobots >> Manufactura industrial >  >> Manufacturing Technology >> Proceso de manufactura

Predicción de lluvia de bricolaje usando Arduino, Python y Keras

Componentes y suministros

Caja de plástico pequeña con tapas desmontables (la mía tiene tornillos)
× 1
tres portapilas AAA
× 1
tres pilas AAA recargables
× 1
panel solar pequeño de 6V
× 1
SparkFun Arduino Pro Mini 328 - 5V / 16MHz
× 1
diodo 1N4004
× 1
Transistor de uso general NPN
× 1
un sensor de lluvia
× 1
Módulo de comunicación serie HC-12
× 1
Módulo serie USB HC-12
× 1
Desglose del sensor atmosférico SparkFun - BME280
× 1
BH1750
× 1
PCB, cables, soldadura, conector roscado KF301-2P , conectores de pcb macho y hembra, pegamento
× 1
Regulador de 3.3V
× 1

Herramientas y máquinas necesarias

Adaptador FT232RL de USB a serie FTDI
Ejercicio
Soldador (genérico)
Destornilladores

Acerca de este proyecto

Primero, algunas palabras sobre este proyecto, la motivación, las tecnologías involucradas y el producto final que vamos a construir.

Entonces, el gran objetivo aquí es obviamente predecir la lluvia en el futuro (probaremos 6 horas). La predicción será un sí o un no (booleano en términos de programación). He buscado en tutoriales sobre este tema y no he encontrado uno que esté completo en todos los sentidos. Así que el mío llevará esto a un enfoque completamente nuevo y profundizará en todos sus aspectos. Para eso vamos a:

  • compilar la estación meteorológica nosotros mismos. La estación debe estar completamente fuera de la red con un panel solar y un modo de energía extremadamente baja (unas pocas docenas de microamperios por hora)
  • programa la estación para que recopile datos y los transmita cada diez minutos a una estación base
  • recopilar los datos en la estación base y almacenarlos (en una base de datos)
  • usando redes neuronales (Biblioteca de Keras) y otras bibliotecas de Python como pandas filtran, limpian y preprocesan los datos, luego los envían a una red neuronal para entrenar un "modelo" para predecir que lloverá o no.
  • finalmente predecir si va a llover o no en las próximas 6 horas y notificar a los usuarios por correo electrónico

Personalmente he utilizado esta estación meteorológica para recopilar datos (puede descargar los datos en los siguientes pasos si lo desea). Con solo unos 600 días de datos meteorológicos, el sistema puede predecir si lloverá o no en las próximas 6 horas con una precisión de alrededor del 80%, dependiendo de los parámetros, lo cual no es tan malo.

En este tutorial, lo guiaremos a través de todos los pasos necesarios para predecir la lluvia desde cero. Crearemos un producto final que hace un trabajo práctico, sin utilizar API de aprendizaje automático o meteorológicas externas. Aprenderemos a lo largo del camino cómo construir una estación meteorológica práctica (de baja potencia y fuera de la red) que realmente recopila datos durante largos períodos de tiempo sin mantenimiento. Después de eso, aprenderá a programarlo usando Arduino IDE. Cómo recopilar datos en una base de datos en una estación base (servidor). Y cómo procesar los datos (Pandas) y aplicar redes neuronales (Keras) y luego predecir la lluvia.

Paso 1:Piezas y herramientas para construir la estación

Partes:

1. Pequeña caja de plástico con tapas desmontables (la mía tiene tornillos). El tamaño de la caja debe ser lo suficientemente grande para que quepan los componentes pequeños y las baterías. Mi caja tiene 11 x 7 x 5 cm

2. tres portapilas AAA

3. tres pilas AAA recargables

4. Panel solar pequeño de 6V

5. Arduino Pro Mini 328p

6. un diodo, 1N4004 (para evitar la corriente inversa de las baterías al panel)

7. un pequeño transistor NPN y una resistencia de 1k (para encender y apagar los componentes)

8. un sensor de lluvia

9. Módulo de comunicación en serie HC-12

10. Módulo serie USB HC-12 (para la estación base)

11. Módulo de sensor bosch BME280 (para humedad, temperatura, presión)

12. Módulo sensor de luz BH1750

13. PCB, cables, soldadura, conector de tornillo enchufable KF301-2P, conectores de PCB macho y hembra, pegamento

14. Regulador de 3.3V

15. una estación base:una PC o una placa de desarrollo funcionando todo el tiempo. Su función es recopilar datos, entrenar el modelo de predicción de lluvia y hacer predicciones

Herramientas:

1. Adaptador FTDI de USB a serie FT232RL para programar el Arduino Pro Mini

2. IDE de Arduino

3. Perforar

4. Sierra de hoja fina

5. Destornilladores

6. Soldador

7. Cortador de alambre

Habilidades:

1. Soldadura, consulte este tutorial

2. Programación básica de arduino

3. Configuración del servicio Linux, instalación del paquete

4. Algunas habilidades de programación

Paso 2:construcción de la estación meteorológica

La estación meteorológica está compuesta por los siguientes conjuntos de componentes:

1. la caja con el panel solar pegado

2 . el PCB con la electrónica adentro

3. el soporte de la batería también en el interior

4. el BME280 y los sensores de luz y lluvia en el exterior

1. La caja necesita 4 agujeros, uno para los cables del panel solar, otros tres para los sensores que se colocarán en el exterior. Primero taladre los orificios, deben ser lo suficientemente grandes como para que los cables macho-hembra sobresalgan y vayan a los sensores. Después de perforar los orificios, pegue el panel a un lado de la caja y haga que los cables pasen por un orificio en el interior

2. La PCB contendrá el arduino, HC-12, regulador de 3.3V, diodo, transistor, resistencia y dos KF301-2P

  • Primero suelde los dos conectores de PCB hembra en el PCB para el arduino, suelde los conectores de PCB macho al arduino y coloque el arduino en el PCB
  • Se debe quitar el led arduino o al menos uno de sus pines. esto es muy importante porque el led consumirá una gran cantidad de energía. Tenga cuidado de no dañar otros componentes
  • suelde el transistor, la resistencia y el regulador de 3.3V
  • suelde los dos KF301-2P. Uno será para el panel solar, el otro para el soporte de la batería
  • suelde tres conectores de PCB hembra:para el sensor de luz, BME280 y el sensor de lluvia
  • suelde pequeños cables para conectar todos los componentes de la PCB (verifique las imágenes y el fritzing schamatic)

3. coloque 3 baterías AAA NiMH cargadas dentro del soporte y colóquelo dentro de la caja, conectando los cables en el conector KF301-2P

4. conecte el BME280 y los sensores de luz desde fuera de la caja a sus correspondientes conectores macho

Para el sensor de lluvia, suelde tres cables (Gnd, Vcc, señal) a él, y al otro lado suelde los pines macho que irán dentro de la caja a sus correspondientes conectores macho

Lo último sería colocar la estación en su posición final. Elegí una posición protegida de la lluvia y la nieve. Elegí cables más largos para el sensor de lluvia y lo coloqué por separado bajo la lluvia sobre un soporte estable. Para la caja principal, he elegido un tipo especial de cinta adhesiva (verifique las imágenes), pero cualquier cosa que sujete la caja servirá.

sketch.fzz

Paso 3:Código Arduino

En este paso, aprenderá qué bibliotecas externas se necesitan, revisaremos el código y cómo funciona y, por supuesto, podrá descargarlo o copiarlo y pegarlo en Arduino IDE y cargarlo en la estación meteorológica.

La función de la estación meteorológica es transmitir a una estación base cada 10 minutos datos sobre sus sensores.

Primero describamos lo que hace el programa de la estación meteorológica:

1. leer datos de sensores (humedad, temperatura, presión, lluvia, luz, voltaje)

2. transmite los datos codificados a través de una segunda línea serie de software.

Los datos codificados se ven así:

  H1:78 | T1:12 | PS1:1022 | L1:500 | R1:0 | V1:4010 |  

La declaración anterior significará que:la humedad de la estación "1" es del 78 por ciento, la temperatura de la estación 1 es de 12 grados, la presión es de 1022 bares, el nivel de luz es de 500 lux, la lluvia es 0 y el voltaje es de 4010 milivoltios

3. apagar los componentes auxiliares:sensores y dispositivo de comunicación

4. pone el arduino en modo de suspensión durante 10 minutos (esto hará que consuma menos 50 microamperios)

5. encienda los componentes y repita los pasos 1 a 4

Un pequeño ajuste adicional aquí, si el nivel de voltaje está por encima de 4.2 V, el arduino usará la función de suspensión normal "retraso (milisegundos)". Esto aumentará en gran medida el consumo de energía y disminuirá rápidamente el voltaje. Esto evita efectivamente que el panel solar sobrecargue las baterías.

Puede obtener el código de mi repositorio de Github aquí:https://github.com/danionescu0/home-automation/tre ...

O copiarlo y pegarlo desde abajo, de cualquier manera simplemente elimine la línea con "transmitSenzorData (" V ", sensores.voltaje);"

  #include "LowPower.h" 
#include "SoftwareSerial.h" #include "Wire.h" #include "Adafruit_Sensor.h" #include "Adafruit_BME280.h" #include "BH1750.h "SoftwareSerial serialComm (4, 5); // RX, TXAdafruit_BME280 bme; BH1750 lightMeter; const byte rainPin =A0; byte sensoresCode =1; / ** * nivel de voltaje que castigará al microcontrolador en sueño profundo en lugar de sueño regular * / int voltageDeepSleepThreshold =4200; const byte peripherialsPowerPin =6; char buffer [] ={'', '', '', '', '', '', ''}; struct sensorData {byte humedad; int temperatura; lluvia de bytes; int presión; voltaje largo; int luz; }; sensorData sensores; void setup () {Serial.begin (9600); serialComm.begin (9600); pinMode (periféricosPowerPin, SALIDA); digitalWrite (periféricosPowerPin, ALTO); retraso (500); if (! bme.begin ()) {Serial.println ("No se pudo encontrar un sensor BME280 válido, ¡verifique el cableado!"); while (1) {customSleep (100); }} Serial.println ("La inicialización finalizó con éxito"); retraso (50); digitalWrite (periféricosPowerPin, HIGH);} bucle vacío () {updateSenzors (); dato transmitido(); customSleep (75); } void updateSenzors () {bme.begin (); lightMeter.begin (); retraso (300); sensores.temperatura =bme.readTemperature (); sensores.presión =bme.readPressure () / 100.0F; sensores.humedad =bme.readHumidity (); sensores.luz =medidor de luz.readLightLevel (); sensores.voltaje =readVcc (); sensores lluvia =readRain ();} void transmitData () {emptyIncommingSerialBuffer (); Serial.print ("Temp:"); Serial.println (sensores.temperatura); Serial.print ("Húmedo:"); Serial.println (sensores.humedad); Serial.print ("Presión:"); Serial.println (sensores.presión); Serial.print ("Light:"); Serial.println (sensores.light); Serial.print ("Voltaje:"); Serial.println (sensores.voltaje); Serial.print ("Lluvia:"); Serial.println (sensores.rain); transmitSenzorData ("T", sensores.temperatura); transmitSenzorData ("H", sensores.humedad); transmitSenzorData ("PS", sensores.presión); transmitSenzorData ("L", sensores.luz); transmitSenzorData ("V", sensores.voltaje); transmitSenzorData ("R", sensors.rain);} void emptyIncommingSerialBuffer () {while (serialComm.available ()> 0) {serialComm.read (); retraso (5); }} void transmitSenzorData (tipo de cadena, valor int) {serialComm.print (tipo); serialComm.print (código de sensores); serialComm.print (":"); serialComm.print (valor); serialComm.print ("|"); delay (50);} void customSleep (long eightSecondCycles) {if (sensores.voltage> voltageDeepSleepThreshold) {delay (eightSecondCycles * 8000); regreso; } digitalWrite (periféricosPowerPin, BAJO); para (int i =0; i

Antes de cargar el código, descargue e instale las siguientes bibliotecas de arduino:

* Biblioteca BH1750:https://github.com/claws/BH1750 * Biblioteca LowPower:https://github.com/rocketscream/Low-Power

* Biblioteca Adafruit Sensor:https://github.com/adafruit/Adafruit_Sensor

* Biblioteca Adafruit BME280:https://github.com/adafruit/Adafruit_Sensor

Si no sabe cómo hacerlo, consulte este tutorial.

Paso 4:preparación de la estación base

La estación base constará de una computadora Linux (computadora de escritorio, computadora portátil o placa de desarrollo) con el HC-12 USB módulo adjunto. La computadora debe permanecer siempre encendida para recolectar datos cada 10 minutos de la estación.

He usado mi computadora portátil con Ubuntu 18.

Los pasos de instalación:

1. Instale anaconda. Anaconda es un administrador de paquetes de Python y nos facilitará trabajar con las mismas dependencias. Podremos controlar la versión de Python y cada versión de paquete

Si no sabe cómo instalarlo, consulte este:https://www.digitalocean.com/community/tutorials/h ... tutorial y siga los pasos 1 - 8

2. Instale mongoDb. MongoDb será nuestra base de datos principal para este proyecto. Almacenará datos sobre todas las series de tiempo de los sensores. No tiene esquema y para nuestro propósito es fácil de usar.

Para conocer los pasos de instalación, consulte su página:https://docs.mongodb.com/v3.4/tutorial/install-mon ...

He usado una versión anterior de mongoDb 3.4.6, si sigues el tutorial anterior obtendrás exactamente eso. En principio debería funcionar con la última versión.

[Opcionalmente] agregue un índice en el campo de fecha:

  Mongouse weather db.weather_station.createIndex ({"date":1})  

3. Descarga el proyecto desde aquí:https://github.com/danionescu0/home-automation. Usaremos la carpeta de predicción del clima

  sudo apt-get install gitgit clone https://github.com/danionescu0/home-automation.gi ...  

4. Cree y configure el entorno anaconda:

  cd weather-predict # crea un entorno anaconda llamado "weather" con python 3.6.2 conda create --name weather python =3.6.2 # activa environmentconda activa weather # instala todos los paquetes pip install -r requirements.txt  

Esto creará un nuevo entorno anaconda e instalará los paquetes necesarios. Algunos de los paquetes son:

Keras (capa de red neuronal de alto nivel, con esta biblioteca haremos todas nuestras predicciones de redes neuronales)

pandas (herramienta útil que manipula datos, la usaremos mucho)

pymongo (controlador python mongoDb)

sklearn (minería de datos y herramientas de análisis de datos)

Configurar el proyecto

El archivo de configuración se encuentra en la carpeta weather-predict y se llama config.py

1. si instala MongoDb de forma remota o en un puerto diferente, cambie el "host" o "puerto" en el

  mongodb ={'host':'localhost', 'port':27017} ...  

2. Ahora necesitamos conectar el adaptador de serie USB HC-12. Antes de ejecutar:

  ls -l / dev / tty *  

y debería obtener una lista de dispositivos montados.

Ahora inserte el HC-12 en un puerto USB y ejecute el mismo comando nuevamente. Debería ser una nueva entrada en esa lista, nuestro adaptador serial. Ahora cambie el puerto del adaptador en la configuración si es necesario

  serial ={'port':'/ dev / ttyUSB0', 'baud_rate':9600}  

Las otras entradas de configuración son algunas rutas de archivo predeterminadas, no es necesario realizar ningún cambio allí.

Paso 5:utilice la estación meteorológica en la práctica

Aquí discutiremos cosas básicas sobre la importación de mis datos de prueba, ejecutar algunas pruebas en ellos, configurar sus propios datos, mostrar algunos gráficos y configurar un correo electrónico con predicciones para las próximas horas.

Si desea saber más sobre cómo funciona, consulte el siguiente paso "¿Cómo funciona"

Importando mis datos ya recopilados

MongoDb viene con un comando cli para importar datos desde json:

  mongoimport -d weather -c weather_station --file sample_data / weather_station.json  

Esto importará el archivo de los datos de muestra a la base de datos "meteorológica" y la colección de "puntos de datos"

Una advertencia aquí, si usa mis datos recopilados y los combina con sus datos locales nuevos, la precisión podría disminuir debido a las pequeñas diferencias en el hardware (sensores) y los patrones climáticos locales.

Recopilación de datos nuevos

Una de las funciones de la estación base es almacenar los datos entrantes de la estación meteorológica en la base de datos para su posterior procesamiento. Para iniciar el proceso que escucha el puerto serie y se almacena en la base de datos, simplemente ejecute:

  conda activa weatherpython serial_listener.py # cada 10 minutos debería ver los datos de la estación meteorológica que llegan:[Sensor:tipo (temperatura), valor (14.3)] [Sensor:tipo (presión), valor ( 1056.0)] ...  

Generando el modelo de predicción

Supongo que ha importado mis datos o "ejecutó el script durante algunos años" para recopilar sus datos personalizados, por lo que en este paso procesaremos los datos para crear un modelo que se utilizará para predecir la lluvia futura.

  conda activa weatherpython train.py --days_behind 600 --test-file-percent 10 --datapoints-behind 8 --hour-granularity 6  

* El primer parámetro --days_behind significa cuántos datos en el pasado debería procesar el script. Se mide en días

* --test-file-percent significa la cantidad de datos que se deben considerar para fines de prueba, este es un paso regular en un algoritmo de aprendizaje automático

* --hour-granularity básicamente significa cuántas horas en el futuro querremos la predicción

* --datapoints-detrás de este parámetro se discutirá más adelante en la siguiente sección

Ver algunos gráficos de datos con todos los sensores de la estación meteorológica

Digamos que durante los últimos 10 días:

  conda activa los gráficos de python del tiempo - días atrás 10  

Predecir si lloverá en el próximo período

Predeciremos si va a llover y enviaremos una notificación por correo electrónico

  conda activa el tiempo python predict.py --datapoints-behind 8 --hour-granularity 6 --from-addr a_gmail_address --from-password gmail_password --to-addr a_email_destination  

Ejecute una predicción por lotes sobre los datos de prueba:

  python predict_batch.py ​​-f sample_data / test_data.csv  

Es importante utilizar los mismos parámetros que en la secuencia de comandos del tren anterior.

Para que la notificación por correo electrónico funcione, inicie sesión en su cuenta de Gmail y active Permitir aplicaciones menos seguras en ON. Tenga en cuenta que esto facilita que otros accedan a su cuenta.

Necesitará dos direcciones de correo electrónico, una dirección de Gmail con la opción anterior activada y otra dirección donde recibirá su notificación.

Si desea recibir notificaciones cada hora, coloque el script en crontab

Para ver cómo es posible todo esto, consulte el siguiente paso

Paso 6:¿Cómo funciona

En este último paso discutiremos varios aspectos de la arquitectura de este proyecto:

1. Descripción general del proyecto, discutiremos la arquitectura general y las tecnologías involucradas

2. Conceptos básicos de aprendizaje automático

3. Cómo se preparan los datos (el paso más importante)

4. Cómo funciona la API de envoltura de red neuronal real (Keras)

5. Mejoras futuras

Intentaré dar un ejemplo de código aquí, pero tenga en cuenta que no es 100% el código del proyecto. En el proyecto, el código es un poco más complicado con clases y estructura

1. Descripción general del proyecto, analizaremos la arquitectura general y las tecnologías involucradas

Como hablamos anteriormente, el proyecto tiene dos partes separadas. La estación meteorológica es autónoma, cuya única función es recopilar y transmitir datos. Y la estación base donde se llevará a cabo todo el entrenamiento y la predicción de recopilación.

Ventajas de la separación de la estación meteorológica y la estación base:

  • requisitos de energía, si la estación meteorológica también pudiera procesar los datos, necesitaría energía sustancial, tal vez grandes paneles solares o una fuente de energía permanente
  • portabilidad, debido a su pequeño tamaño, la estación meteorológica puede recopilar datos desde unos cientos de metros de distancia y usted puede cambiar su lugar fácilmente si es necesario
  • escalabilidad, puede aumentar la precisión de la predicción construyendo más de una estación meteorológica y distribuyéndolas alrededor de unos cientos de metros
  • de bajo costo, ya que es un dispositivo económico que puede construir fácilmente en caso de que uno se pierda o sea robado

La elección de la base de datos . Elegí mongoDb porque tiene buenas características:API sin esquema, gratuita y fácil de usar

Cada vez que se reciben los datos del sensor, los datos se guardan en la base de datos, y la entrada de datos se parece a esto:

  {"_id":"04_27_2017_06_17", "humedad":65, "fecha":ISODate ("2017-04-27T06:17:18Z"), "presión":1007, "temperatura":9, "lluvia":0, "luz":15}  

La base de datos almacena datos en formato BSON (similar a JSON), por lo que es fácil de leer y trabajar con ellos. He agregado los datos bajo un identificador que contiene la fecha formateada como una cadena de minutos, por lo que la agrupación más pequeña aquí es un minuto.

La estación meteorológica (cuando funciona correctamente) transmitirá un punto de datos cada 10 minutos. Un punto de datos es una colección de valores de "fecha", "humedad", "presión", "temperatura", "lluvia" y "luz".

El procesamiento de datos y la red neuronal elección de tecnología

Elegí Python para el backend porque muchas innovaciones importantes en redes neuronales se encuentran en Python. Una comunidad en crecimiento con muchos repositorios de Github, blogs de tutoriales y libros está aquí para ayudar.

* Para la parte de procesamiento de datos he usado Pandas ( https://pandas.pydata.org/ ) . Los pandas facilitan el trabajo con datos. Puede cargar tablas desde CSV, Excel, estructuras de datos de Python y reordenarlas, eliminar columnas, agregar columnas, indexar por columna y muchas otras transformaciones.

* Para trabajar con redes neuronales, he elegido Keras (https://keras.io/). Keras es un envoltorio de red neuronal de alto nivel sobre API de nivel más bajo como Tensorflow y se puede construir una red neuronal multicapa con una docena de líneas de código más o menos. Esta es una gran ventaja porque podemos construir algo útil sobre el gran trabajo de otras personas. Bueno, esto es lo básico de la programación, se basa en otros bloques de construcción más pequeños.

2. Conceptos básicos de aprendizaje automático

El alcance de este tutorial no es enseñar aprendizaje automático, sino simplemente describir uno de sus posibles casos de uso y cómo podemos aplicarlo de manera práctica a este caso de uso.

Las redes neuronales son estructuras de datos que se asemejan a las células cerebrales llamadas neuronas. La ciencia descubrió que un cerebro tiene células especiales llamadas neuronas que se comunican con otras neuronas mediante impulsos eléctricos a través de "líneas" llamadas axones. Si se estimulan lo suficiente (de muchas otras neuronas), las neuronas desencadenarán un impulso eléctrico más lejos en esta "red" que estimula a otras neuronas. Esto, por supuesto, es una simplificación excesiva del proceso, pero básicamente los algoritmos informáticos intentan replicar este proceso biológico.

En las redes neuronales de las computadoras, cada neurona tiene un "punto de activación" donde, si se estimula sobre ese punto, propagará la estimulación hacia adelante, si no, no lo hará. Para esto, cada neurona simulada tendrá un sesgo y cada axón un peso. Después de una inicialización aleatoria de estos valores, comienza un proceso llamado "aprendizaje", esto significa que en un bucle un algoritmo realizará estos pasos:

  • estimular las neuronas de entrada
  • propagar las señales a través de las capas de la red hasta las neuronas de salida
  • leer las neuronas de salida y comparar los resultados con los resultados deseados
  • ajustar el peso de los axones para obtener un mejor resultado la próxima vez
  • empezar de nuevo hasta alcanzar el número de bucles

Si quieres conocer más detalles sobre este proceso puedes consultar este artículo:https://mattmazur.com/2015/03/17/a-step-by-step-ba .... También hay numerosos libros y tutoriales disponibles.

Una cosa más, aquí usaremos un método de aprendizaje supervisado. Eso significa que también le enseñaremos al algoritmo las entradas y las salidas, de modo que, dado un nuevo conjunto de entradas, pueda predecir la salida.

3. Cómo se preparan los datos (el paso más importante)

En muchos problemas de aprendizaje automático y redes neuronales, la preparación de datos es una parte muy importante y cubrirá:

  • obtener los datos sin procesar
  • limpieza de datos:esto significará eliminar valores huérfanos, aberraciones u otras anomalías
  • agrupación de datos:tomar muchos puntos de datos y transformarlos en un punto de datos agregado
  • mejora de datos:agregar otros aspectos de los datos derivados de datos propios o de fuentes externas
  • dividir los datos en datos de prueba y de tren
  • Divida cada uno de los datos de prueba y tren en entradas y salidas. Normalmente, un problema tendrá muchas entradas y algunas salidas
  • cambiar la escala de los datos para que estén entre 0 y 1 (esto ayudará a la red a eliminar los sesgos de valor alto / bajo)

Obteniendo los datos sin procesar

En nuestro caso, obtener datos para MongoDb en python es realmente fácil. Dada nuestra colección de puntos de datos, solo estas líneas de código servirán

  client =MongoClient (host, port) .weather.datapoints cursor =client.find ({'$ and':[{'date':{'$ gte':start_date}}, {'date' :{'$ lte':end_date}}]}) data =list (cursor) ..  

Limpieza de datos

Los valores vacíos en el marco de datos se eliminan

dataframe =dataframe.dropna() 

Data grouping &data enhancing

This is a very important step, the many small datapoins will be grouped into intervals of 6 hours. For each group several metrics will be calculated on each of the sensors (humidity, rain, temperature, light, pressure)

  • min value
  • max value
  • mean
  • 70, 90, 30, 10 percentiles
  • nr of times there has been a rise in a sensor
  • nr of times there has been a fall in a sensor
  • nr of times there has been steady values in a sensor

All of these things will give the network information for a datapoint, so for each of the 6 hours intervals these things will be known.

From a dataframe that looks like this:

_id date humidity light pressure rain temperature 04_27_2017_03_08 2017-04-27 03:08:36 67.0 0.0 1007.0 0.0 11.004_27_2017_03_19 2017-04-27 03:19:05 66.0 0.0 1007.0 0.0 11.004_27_2017_03_29 2017-04-27 03:29:34 66.0 0.0 1007.0 0.0 11.0  

And the transformation will be:"

_id date humidity_10percentile humidity_30percentile humidity_70percentile humidity_90percentile humidity_avg ... temperature_avg temperature_fall temperature_max temperature_min temperature_rise temperature_steady ... 04_27_2017_0 2017-04-27 03:08:36 59.6 60.8 63.2 66.0 62.294118 ... 10.058824 2 11.0 9.0 1 1404_27_2017_1 2017-04-27 06:06:50 40.3 42.0 60.0 62.0 50.735294 ... 14.647059 3 26.0 9.0 11 2004_27_2017_2 2017-04-27 12:00:59 36.0 37.0 39.8 42.0 38.314286 ... 22.114286 1 24.0 20.0 5 29  

After this a new column named "has_rain" will be added. This will be the output (our predicted variable). Has rain will be 0 or 1 depending if the rain average is above a threshold (0.1). With pandas it's as simple as:

dataframe.insert(loc=1, column='has_rain', value=numpy.where(dataframe['rain_avg']> 0.1, 1, 0)) 

Data cleanup (again)

- we'll drop the date column because it's no use to us, and also remove datapoints where the minimum temperature is below 0 because our weather station it doesn't have a snow sensor, so we won't be able to measure if it snowed

dataframe =dataframe.drop(['date'], axis=1)dataframe =dataframe[dataframe['temperature_min']>=0] 

Data enhancing

Because data in the past might influence our prediction of the rain, we need for each of the dataframe rows to add columns reference to the past rows. This is because each of the row will serve as a training point, and if we want the prediction of the rain to take into account previous datapoints that's exactly what we should do:add more columns for datapoints in the past ex:

_id has_rain humidity_10percentile humidity_30percentile humidity_70percentile humidity_90percentile ... temperature_steady_4 temperature_steady_5 temperature_steady_6 temperature_steady_7 temperature_steady_8 ... 04_27_2017_3 0 36.0 44.8 61.0 63.0 ... NaN NaN NaN NaN NaN04_28_2017_0 0 68.0 70.0 74.0 75.0 ... 14.0 NaN NaN NaN NaN04_28_2017_1 0 40.0 45.0 63.2 69.0 ... 20.0 14.0 NaN NaN NaN04_28_2017_2 0 34.0 35.9 40.0 41.0 ... 29.0 20.0 14.0 NaN NaN04_28_2017_3 0 36.1 40.6 52.0 54.0 ... 19.0 29.0 20.0 14.0 NaN04_29_2017_0 0 52.0 54.0 56.0 58.0 ... 26.0 19.0 29.0 20.0 14.004_29_2017_1 0 39.4 43.2 54.6 57.0 ... 18.0 26.0 19.0 29.0 20.004_29_2017_2 1 41.0 42.0 44.2 47.0 ... 28.0 18.0 26.0 19.0 29.0  

So you see that for every sensor let's say temperature the following rows will be added:"temperature_1", "temperature_2".. meaning temperature on the previous datapoint, temperature on the previous two datapoints etc. I've experimented with this and I found that a optimum number for our 6 hour groupings in 8. That means 8 datapoints in the past (48 hours). So our network learned the best from datapoins spanning 48 hours in the past.

Data cleanup (again)

As you see, the first few columns has "NaN" values because there is nothing in front of them so they should be removed because they are incomplete.

Also data about current datapoint should be dropped, the only exception is "has_rain". the idea is that the system should be able to predict "has_rain" without knowing anything but previous data.

Splitting the data in train and test data

This is very easy due to Sklearn package:

from sklearn.model_selection import train_test_split ...main_data, test_data =train_test_split(dataframe, test_size=percent_test_data) ... 

This will split the data randomly into two different sets

Split each of the train and test data into inputs and outputs

Presuming that our "has_rain" interest column is located first

X =main_data.iloc[:, 1:].valuesy =main_data.iloc[:, 0].values  

Rescale the data so it's between 0 and 1

Again fairly easy because of sklearn

from sklearn.preprocessing import StandardScalerfrom sklearn.externals import joblib..scaler =StandardScaler()X =scaler.fit_transform(X) ...# of course we should be careful to save the scaled model for later reusejoblib.dump(scaler, 'model_file_name.save')  

4. How the actual neural network wrapper API works (Keras)

Building a multi layer neural network with Keras is very easy:

from keras.models import Sequentialfrom keras.layers import Densefrom keras.layers import Dropout ...input_dimensions =X.shape[1] optimizer ='rmsprop'dropout =0.05model =Sequential()inner_nodes =int(input_dimensions / 2)model.add(Dense(inner_nodes, kernel_initializer='uniform', activation='relu', input_dim=input_dimensions))model.add(Dropout(rate=dropout))model.add(Dense(inner_nodes, kernel_initializer='uniform', activation='relu'))model.add(Dropout(rate=dropout))model.add(Dense(1, kernel_initializer='uniform', activation='sigmoid'))model.compile(optimizer=optimizer, loss='mean_absolute_error', metrics=['accuracy']) model.fit(X, y, batch_size=1, epochs=50)...# save the model for later useclassifier.save('file_model_name') 

So what does this code mean? Here we're building a sequential model, that means sequentially all the layers will be evaluated.

a) we declare the input layer (Dense), here all the inputs from our dataset will be initializedm so the "input_dim" parameter must be equal to the row length

b) a Dropout layer is added. To understand the Dropout first we must understand what "overfitting" means:it's a state in which the network has learned too much particularities for a specific dataset and will perform badly when confronted to a new dataset. The dropout layer will disconnect randomly neurons at each iteration so the network won't overfit.

c) another layer of Dense is added

d) another Dropout

e) the last layer is added with one output dimension (it will predict only yes/no)

f) the model is "fitted" that means the learning process will begin, and the model will learn

Other parameters here:

  • activation functions (sigmoid, relu). This are functions that dictate when the neuron will transmit it's impulse further in the network. There are many, but sigmoid and relu are the most common. Check out this link for more details:https://towardsdatascience.com/activation-function...
  • kernel_initializer function (uniform). This means that all the weights are initialized with random uniform values
  • loss function (mean_absolute_error). This function measures the error comparing the network predicted result versus the ground truth. There are many alternatives:https://keras.io/losses/
  • metrics function (accuracy). It measures the performance of the model
  • optimiser functions (rmsprop). It optimizes how the model learn through backpropagation.
  • batch_size. Number of datapoints to take once by Keras before applying optimizer function
  • epochs:how many times the process it's started from 0 (to learn better)

There is no best configuration for any network or dataset, all these parameters can an should be tuned for optimal performance and will make a big difference in prediction success.

5. Future improvements

Let's start from the weather station , I can see a lot of improving work to be done here:

  • add a wind speed / direction sensor. This could be a very important sensor that i'm missing in my model
  • experiment with UV rays, gas and particle sensors
  • add at least two stations in the zone for better data (make some better averages)
  • collect a few more years of data, i've experimented with just a year and a half

Some processing improvements:

  • try to incorporate data from other sources into the model. You can start to import wind speed data and combine with the local station data for a better model. This website offers historical data:https://www.wunderground.com/history/
  • optimize the Keras model better by adjusting:layers, nr of neurons in layers, dropout percents, metrics functions, optimiser functions, loss functions, batch size, learning epochs
  • try other model architectures, for example i've experimented with LSTM (long short term memory) but it gived slightly poorer results)

To try different parameters on the learning model you can use

python train.py --days_behind 600 --test-file-percent 10 --datapoints-behind 6 --hour-granularity 6 --grid-search 

This will search through different "batch_size", "epoch", "optimizer" and "dropout" values, evaluate all and print out the best combination for your data.

If you have some feedback on my work please share it, thanks for staying till the end of the tutorial!

Step 7:Bonus:Using an Official Weather Dataset

I was wondering if I can get better results with a more reliable weather station, so i've searched a bit, and i've came across "Darksky AP I" (https://darksky.net/dev), this is a great tool that provides current and historical weather data with many more sensor data:

  • temperature
  • humidity
  • pressure
  • wind speed
  • wind gust
  • ub index
  • visibilitySo this beeing data from an official weather station, and having more parameters I thought it should perform better so i've gave it a try. To replicate my findings:

1.Download the data from darsky or import my MongoDb collection:

a) Download

  • to download your self, first create an account in darsky and get the API key
  • replace the API key in download_import/config.py
  • also in the config replace the geographic coordonates for the location you want to predict the rain
  • in a console activate "weather" anaconda environment and run:
python download_import/darksky.py -d 1000 

- the free version of the API is limited to 1000 requests per day so if you want more data you need to wait for a longer time

b) Import my downloaded data for Bucharest city

- in a console run

mongoimport -d weather -c darksky --file sample_data/darksky.json  

2. When you train the model specify that it should run on "darksy" dataset

python train.py -d 2000 -p 20 -dp 4 -hg 6 --data-source darksky 

3. To see the results run predict batch script as before

python predict_batch.py -f sample_data/test_data.csv 

You'll see that the overall prediction percent has gone from about 80% to 90%. Also the prediction accuracy when accounting only rainy days has gone up.

So yes, the dataset really matters.

Código

  • Code snippet #2
  • Fragmento de código n. ° 5
  • Code snippet #6
  • Code snippet #10
  • Code snippet #15
  • Code snippet #16
  • Code snippet #18
  • Code snippet #22
  • Code snippet #23
  • Code snippet #25
  • Code snippet #26
Code snippet #2Plain text
#include "LowPower.h"
#include "SoftwareSerial.h"#include "Wire.h"#include "Adafruit_Sensor.h"#include "Adafruit_BME280.h"#include "BH1750.h"SoftwareSerial serialComm(4, 5); // RX, TXAdafruit_BME280 bme; BH1750 lightMeter;const byte rainPin =A0;byte sensorsCode =1;/** * voltage level that will pun the microcontroller in deep sleep instead of regular sleep */int voltageDeepSleepThreshold =4200; const byte peripherialsPowerPin =6;char buffer[] ={' ',' ',' ',' ',' ',' ',' '};struct sensorData { byte humidity; int temperature; byte rain; int pressure; long voltage; int light; };sensorData sensors;void setup() { Serial.begin(9600); serialComm.begin(9600); pinMode(peripherialsPowerPin, OUTPUT); digitalWrite(peripherialsPowerPin, HIGH); retraso (500); if (!bme.begin()) { Serial.println("Could not find a valid BME280 sensor, check wiring!"); while (1) { customSleep(100); } } Serial.println("Initialization finished succesfully"); retraso (50); digitalWrite(peripherialsPowerPin, HIGH);}void loop() { updateSenzors(); transmitData(); customSleep(75); }void updateSenzors() { bme.begin(); lightMeter.begin(); retraso (300); sensors.temperature =bme.readTemperature(); sensors.pressure =bme.readPressure() / 100.0F; sensors.humidity =bme.readHumidity(); sensors.light =lightMeter.readLightLevel(); sensors.voltage =readVcc(); sensors.rain =readRain();}void transmitData(){ emptyIncommingSerialBuffer(); Serial.print("Temp:");Serial.println(sensors.temperature); Serial.print("Humid:");Serial.println(sensors.humidity); Serial.print("Pressure:");Serial.println(sensors.pressure); Serial.print("Light:");Serial.println(sensors.light); Serial.print("Voltage:");Serial.println(sensors.voltage); Serial.print("Rain:");Serial.println(sensors.rain); transmitSenzorData("T", sensors.temperature); transmitSenzorData("H", sensors.humidity); transmitSenzorData("PS", sensors.pressure); transmitSenzorData("L", sensors.light); transmitSenzorData("V", sensors.voltage); transmitSenzorData("R", sensors.rain);}void emptyIncommingSerialBuffer(){ while (serialComm.available()> 0) { serialComm.read(); retraso (5); }}void transmitSenzorData(String type, int value){ serialComm.print(type); serialComm.print(sensorsCode); serialComm.print(":"); serialComm.print(value); serialComm.print("|"); delay(50);}void customSleep(long eightSecondCycles){ if (sensors.voltage> voltageDeepSleepThreshold) { delay(eightSecondCycles * 8000); regreso; } digitalWrite(peripherialsPowerPin, LOW); for (int i =0; i
Fragmento de código n. ° 5 Texto sin formato
cd weather-predict # create anaconda environment named "weather" with python 3.6.2conda create --name weather python=3.6.2 # activate environmentconda activate weather# install all packages pip install -r requirements.txt 
Code snippet #6Plain text
mongodb ={ 'host':'localhost', 'port':27017}...
Code snippet #10Plain text
conda activate weatherpython serial_listener.py# every 10 minutes you should see data from the weather station coming in :[Sensor:type(temperature), value(14.3)][Sensor:type(pressure), value(1056.0)]...
Code snippet #15Plain text
{ "_id" :"04_27_2017_06_17", "humidity" :65, "date" :ISODate("2017-04-27T06:17:18Z"), "pressure" :1007, "temperature" :9, "rain" :0, "light" :15}
Code snippet #16Plain text
client =MongoClient(host, port).weather.datapoints cursor =client.find( {'$and' :[ {'date' :{'$gte' :start_date}}, {'date' :{'$lte' :end_date}} ]} )data =list(cursor)..
Code snippet #18Plain text
_id date humidity light pressure rain temperature 04_27_2017_03_08 2017-04-27 03:08:36 67.0 0.0 1007.0 0.0 11.004_27_2017_03_19 2017-04-27 03:19:05 66.0 0.0 1007.0 0.0 11.004_27_2017_03_29 2017-04-27 03:29:34 66.0 0.0 1007.0 0.0 11.0 
Code snippet #22Plain text
_id has_rain humidity_10percentile humidity_30percentile humidity_70percentile humidity_90percentile ... temperature_steady_4 temperature_steady_5 temperature_steady_6 temperature_steady_7 temperature_steady_8 ... 04_27_2017_3 0 36.0 44.8 61.0 63.0 ... NaN NaN NaN NaN NaN04_28_2017_0 0 68.0 70.0 74.0 75.0 ... 14.0 NaN NaN NaN NaN04_28_2017_1 0 40.0 45.0 63.2 69.0 ... 20.0 14.0 NaN NaN NaN04_28_2017_2 0 34.0 35.9 40.0 41.0 ... 29.0 20.0 14.0 NaN NaN04_28_2017_3 0 36.1 40.6 52.0 54.0 ... 19.0 29.0 20.0 14.0 NaN04_29_2017_0 0 52.0 54.0 56.0 58.0 ... 26.0 19.0 29.0 20.0 14.004_29_2017_1 0 39.4 43.2 54.6 57.0 ... 18.0 26.0 19.0 29.0 20.004_29_2017_2 1 41.0 42.0 44.2 47.0 ... 28.0 18.0 26.0 19.0 29.0 
Code snippet #23Plain text
from sklearn.model_selection import train_test_split ...main_data, test_data =train_test_split(dataframe, test_size=percent_test_data) ...
Code snippet #25Plain text
from sklearn.preprocessing import StandardScalerfrom sklearn.externals import joblib..scaler =StandardScaler()X =scaler.fit_transform(X) ...# of course we should be careful to save the scaled model for later reusejoblib.dump(scaler, 'model_file_name.save') 
Code snippet #26Plain text
from keras.models import Sequentialfrom keras.layers import Densefrom keras.layers import Dropout ...input_dimensions =X.shape[1] optimizer ='rmsprop'dropout =0.05model =Sequential()inner_nodes =int(input_dimensions / 2)model.add(Dense(inner_nodes, kernel_initializer='uniform', activation='relu', input_dim=input_dimensions))model.add(Dropout(rate=dropout))model.add(Dense(inner_nodes, kernel_initializer='uniform', activation='relu'))model.add(Dropout(rate=dropout))model.add(Dense(1, kernel_initializer='uniform', activation='sigmoid'))model.compile(optimizer=optimizer, loss='mean_absolute_error', metrics=['accuracy']) model.fit(X, y, batch_size=1, epochs=50)...# save the model for later useclassifier.save('file_model_name')
Github
https://github.com/claws/BH1750https://github.com/claws/BH1750
Github
https://github.com/rocketscream/Low-Powerhttps://github.com/rocketscream/Low-Power
Github
https://github.com/adafruit/Adafruit_Sensorhttps://github.com/adafruit/Adafruit_Sensor
Github
https://github.com/adafruit/Adafruit_BME280_Libraryhttps://github.com/adafruit/Adafruit_BME280_Library
Github
https://github.com/danionescu0/home-automationhttps://github.com/danionescu0/home-automation

Esquemas

sketch_KAtDa2VReF.fzz
Weather station arduino sketch
https://github.com/danionescu0/home-automation/tree/master/arduino-sketches/weatherStation

Proceso de manufactura

  1. Sensor de temperatura Python y Raspberry Pi
  2. Consola de edición de Photoshop DIY con Arduino Nano RP 2040
  3. Python Cambiar nombre de archivo y directorio usando os.rename()
  4. Sistema de asistencia que usa Arduino y RFID con Python
  5. Control remoto universal usando Arduino, 1Sheeld y Android
  6. Voltímetro de bricolaje con Arduino y un teléfono inteligente
  7. DIY Sensor infrarrojo de latidos del corazón con Arduino
  8. Medición de frecuencia y ciclo de trabajo con Arduino
  9. Voltímetro de bricolaje con Arduino y una pantalla Nokia 5110
  10. Sonda usando arduino y visualización en procesamiento IDE
  11. Control del brillo del LED usando Bolt y Arduino