El final La parte anterior .
Tabla de contenido:
Sensor fueraborda. Software
Hable sobre el software para el sensor en el extranjero. Después de eso, obtendrá un sistema completo con el que ya puede experimentar.
Permítame recordarle que el servidor es una unidad doméstica central que puede comunicarse con Internet a través de WiFi, y el cliente es un sensor remoto y listo para usar que transmite datos al servidor por el aire.
El código fuente tanto para el servidor como para el cliente está aquí .
Los textos fuente se proporcionan con comentarios detallados.
Casi nada necesita ser configurado en el cliente.
El transmisor de radio nRF24L01 +, más precisamente la biblioteca RadioHead, requiere que se especifiquen las direcciones del servidor y del cliente. Se proporcionan direcciones en caso de que tenga más de un servidor y cliente. Una dirección es cualquier número entero. Cuando un cliente envía un paquete de datos a un servidor, indica para qué servidor es este paquete. El servidor, conociendo su propia dirección, a su vez, determina si este paquete está destinado a él.
Por lo tanto, SERVER_ADDRESS
en el servidor y en el cliente debería ser el mismo, pero CLIENT_ADDRESS
para diferentes clientes debería ser diferente. En otras palabras, si conecta otro sensor nuevo a nuestro sistema en el futuro, entonces CLIENT_ADDRESS
deberá cambiarse para ello.
// #define SERVER_ADDRESS 10 #define CLIENT_ADDRESS 20 // !!!
El RF_CHANNEL
canal de radio RF_CHANNEL
debe ser el mismo para todos. Por defecto es 2. Cambié el número predeterminado, puede elegir cualquier otro.
La configuración del voltímetro para medir el voltaje de alimentación de la batería debe cambiarse:
// , const float r1 = 100400; // 100K const float r2 = 9960; // 10K // // http://localhost/arduino-secret-true-voltmeter/ const float typVbg = 1.082; // 1.0 -- 1.2
Para ahorrar energía, se utiliza la biblioteca Lightweight low power para Arduino .
Aquí están mis medidas de consumo real para el Arduino Pro Mini con esta lib:
- generalmente 25mA
- cuando se trabaja con DHT lo mismo
- con transmisión de radio 38 mA
- en LowPower.idle 15 mA
- en LowPower.powerdown 7.5 mA
El cliente toma medidas de temperatura, humedad y voltaje de suministro, agrupa todo esto en una estructura de datos, envía los datos al servidor y se "queda dormido". Si ocurrieron errores durante la transferencia, la transferencia se repite inmediatamente.
El servidor (central, unidad doméstica), a su vez, recibe datos, confirma la recepción y los procesa.
Base de datos, MySQL, PHP, servidor WWW
Después del trabajo realizado, tenemos un diseño completamente funcional de la estación meteorológica. Pero ahora hay diez centavos por docena de estaciones meteorológicas, las artesanías locales ya no están de moda. Después de todo, tenemos un Internet de las cosas.
Por lo tanto, hablaremos sobre cómo se realiza el acceso a su Internet, adjuntaremos una base de datos y una cara web a nuestra estación meteorológica.
La declaración del problema para la "cámara web":
- recibir y almacenar datos de la estación meteorológica: temperatura, humedad, presión atmosférica, voltaje de suministro
- mostrar estos datos
- construir gráficos
En este caso, necesitamos hosting con soporte para Apache, PHP y MySQL con el módulo mysqli. Y estas condiciones son satisfechas por casi cualquier alojamiento en el planeta Tierra. O, en lugar de alojar, su computadora desempeñará el papel de un servidor conectado a un enrutador de red doméstica y tendrá acceso a Internet.
Creación de base de datos.
Comencemos desde el principio, es decir, con el diseño y la creación de la base de datos.
Las bases de datos son su mundo y puede estudiarlo durante mucho tiempo, por lo que abordaremos brevemente solo aquellas cosas que necesitamos directamente.
Todos los scripts SQL se encuentran en el directorio weather-station/server/php-sql/
¿Dónde comienza el diseño de la base de datos? Con una representación lógica y física.
Vista lógica o esquema de base de datos:
- Tabla de temperatura y humedad DHT
- tabla de datos BMP del sensor de presión y temperatura
- las tablas indicadas no tienen ninguna relación entre sí; más precisamente, los enlaces no son necesarios.
El esquema físico se basa en un DBMS específico y tipos de datos. Es más fácil desmontar con un ejemplo específico. El make_tables.sql
SQL make_tables.sql
los esquemas lógicos y físicos.
Cada tabla debe tener un campo de tipo
id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT
El nombre del campo puede diferir en diferentes bases de datos, pero solo hay un sentido: este es un identificador único, una clave de registro. Para el futuro, si ve una base de datos en tablas que no tienen dicho contador, debe saber que esta base de datos fue diseñada por una persona muy alejada de la programación, probablemente de las humanidades.
Almacenamos los datos de los sensores del mismo tipo en una tabla; para sensores de otro tipo, creamos otra tabla. Esto complica un poco la base de datos y el enlace de PHP, pero simplifica la extensión o modificación de todo el sistema en el futuro.
Hay dos tablas en nuestro proyecto. La tabla arduino_dht
almacena datos de los sensores del tipo DHT (temperatura, humedad), la tabla arduino_bmp
almacena datos de los sensores del tipo BMP (temperatura, presión). Si en el futuro desea tener, por ejemplo, un sensor de gas o un detector de movimiento, cree tablas adicionales, no sea perezoso. Si conecta otro sensor del tipo DHT11 o DHT22, entonces no necesita crear una tabla adicional, use la tabla arduino_dht
. Espero que el principio sea claro: una entidad física separada es una tabla separada.
Si los datos de varios sensores del mismo tipo se almacenarán en una tabla, ¿cómo se pueden distinguir? Para hacer esto, ingrese un campo en cada tabla
idSensor INTEGER
De hecho, esto es CLIENT_ADDRESS
que registramos en el client/client.ino
para cada instancia del cliente-cliente remoto y en server/server.ino
para el sensor que está conectado directamente al servidor, la unidad central.
En los sistemas industriales, debería haber otra tabla: la correspondencia de idSensor
y su descripción verbal y legible. Por ejemplo, un sensor con idSensor
= 2 es "Temperatura, humedad en el apartamento" , etc. Pero en nuestro proyecto no nos complicaremos, solo recuerda que:
- un sensor con
idSensor
, es CLIENT_ADDRESS
, igual a 11 - este es el sensor de inicio en el servidor - la unidad central, - un sensor con
idSensor
, también es CLIENT_ADDRESS
, igual a 20; este es el primer (en nuestro proyecto y el único) cliente de sensor basado en ventanas.
Siguiente Las tablas almacenan los siguientes datos:
- ipRemote: dirección IP de la estación meteorológica (servidor) de donde provienen los datos, útil para depurar y monitorear,
- dateCreate: fecha en que se creó el registro,
- millis: útil para depurar, este es el tiempo en milisegundos desde el inicio del boceto en Arduino,
- temperatura - temperatura
- humedad - humedad
- voltaje - voltaje de suministro,
- presión - presión
- errores: la cantidad de errores (no utilizados). Estaba destinado a almacenar el número de errores de transmisión, etc., para que pueda evaluar de forma remota el estado de todo el sistema.
Como puede ver, las arduino_bmp
arduino_dht
y arduino_bmp
muy similares, la diferencia es solo en los campos de presión y humedad, y existe el deseo de volcar todo en un montón (tabla). Pero la primera forma normal no ordena hacer esto, muchos programadores principiantes trataron de evitarlo, pero ninguno de ellos tuvo éxito, y nosotros no lo haremos. Así es como no notar la ley de la gravitación universal, por el momento bien puede resultar.
La tabla arduino_error_log
útil para la depuración: es un registro de errores y otros mensajes del sistema.
La creación de una base de datos y su usuario con derechos se describe en make_db.sql
Esto se hace una vez, el nombre de la base de datos y el nombre de usuario pueden ser los suyos. Y lo que debe hacerse exactamente es establecer su contraseña.
PHP y servidor web
Todas las configuraciones de la interfaz web se almacenan en config.php
. Modifíquelo según la configuración de su base de datos.
Configura tu zona horaria en formato PHP
date_default_timezone_set('Europe/Prague')
Todas las zonas horarias disponibles se describen aquí .
Establezca su clave secreta para el acceso (como un número) que debe coincidir con la constante SOURCE_KEY
del bosquejo server.ino
$access_key = '***KEY***';
En nuestro servidor web no hay autorización, ingreso de contraseña, esto complicaría todo el diseño. Para un prototipo, esto no es necesario. Por lo tanto, toda la protección se basa en el archivo robots.txt
, la ausencia de index.php
y esta clave secreta para el acceso.
El script PHP principal weather.php
acepta una simple solicitud HTTP GET con datos y la almacena en las tablas de bases de datos correspondientes. Si la clave $access_key
no coincide, la solicitud será rechazada.
El weather-view.php
usa para ver tablas de datos y contiene hipervínculos a otros scripts de interfaz web. Llámalo así
http:
Por ejemplo
http:
weather-view.php
muestra etiquetas simples donde debe recordar que:
- el sensor con id 11 es el sensor de inicio en el servidor,
- El sensor con id 20 es un sensor de ventana.
El script function.php
contiene funciones comunes a todos los scripts PHP.
El chart-dht.php
es responsable de los gráficos usando Google Charts . Aquí, por ejemplo, hay un gráfico de la tensión de alimentación del sensor en el extranjero. El voltaje aumenta en un día soleado debido a la batería solar, y luego la fuente de alimentación de las baterías se descarga gradualmente.

export-dht.php
exporta datos de las tablas de la base de datos MySQL a un archivo CSV. Para mayor importación y análisis en hojas de cálculo.
export-voltage.php
exporta datos sobre el voltaje de suministro desde el sensor de ventana desde la base de datos MySQL a un archivo CSV. Útil para la depuración.
truncate.php
borra todas las tablas, es decir elimina todos nuestros datos Útil para la depuración. No hay enlaces a este script desde weather-view.php
, por lo que debe llamarlo a través de un enlace directo en la barra de direcciones de su navegador con $access_key
.
Al recibir datos, la función mysqli_real_escape_string()
se usa comúnmente para evitar que valores incorrectos ingresen a la base de datos.
No olvide poner robots.txt
en la raíz de su sitio para evitar que entre en los motores de búsqueda.
ESP8266, WiFi y transferencia de datos
Y ahora volvamos al boceto server.ino
, a la parte del mismo que se conecta al punto de acceso WiFi y envía datos al servidor web.
Como ya escribí, no pude encontrar una biblioteca normal para que Arduino controlara el módulo ESP8266 usando comandos AT, tuve que "cultivar colectivamente". Permítame también recordarle que debe actualizar una versión específica de firmware en ESP8266-01. Y ahora, cuando todo esté listo, veamos cómo funciona.
Para acceder al servidor web en el boceto server.ino
, debe cambiar estas constantes
const String DEST_HOST = " "; // habr.com const String DEST_PORT = " "; // 80 const String DEST_URL = "/ /weather.php"; const String SOURCE_KEY= " "; // $access_key config.php
En server.ino
en la función void setup()
, el ESP8266 se cambia primero al modo Station, es decir comienza a funcionar como un cliente WiFi
espSendCmd(«AT+CWMODE_CUR=1», «OK», 3000)
y luego conectarse al punto de acceso
espState = espConnectToWiFi()
Si no se produce la conexión, el intento se repite (una vez)
if ( espState != ESP_SUCCESS ) { delay(5000); Serial.println("WiFi not connected! Try again ..."); espConnectToWiFi(); }
Luego seleccione el modo de conexión única TCP / IP
espSendCmd("AT+CIPMUX=0", "OK", 2000)
Cuando se envían datos desde sensores del tipo DHT al servidor web, se utiliza una función que indica el type=dht
datos como type=dht
espSendData( "type=dht&t=" + String(dhtData.temperature) + "&h=" + String(dhtData.humidity) + "&v=" + String(dhtData.voltage) + "&s=" + String(CLIENT_ADDRESS) )
Cuando se envían datos desde sensores BMP a un servidor web, se utiliza la misma función con el tipo de datos indicado como type=bmp
espSendData( "type=bmp&t=" + String(temperature_bmp) + "&p=" + String(pressure_bmp) + "&s=" + String(CLIENT_ADDRESS) )
La función espSendData()
acepta una cadena de solicitud HTTP GET y la envía al servidor web según lo previsto.
Dentro de sí mismo, espSendData()
verifica la disponibilidad del módulo ESP enviándole el comando "AT", luego verifica la conexión WiFi y se vuelve a conectar si es necesario. Luego se envían los datos y se cierra la conexión TCP.
Aplicación de Android
Hoy en día, cuando todos pueden parpadear un LED, no sorprenderá a nadie con una estación meteorológica. Pero si la nave sabe cómo comunicarse con el servidor a través de WiFi, tiene una cara web y una aplicación móvil, ¡esto es algo! Por servidor aquí nos referimos, por supuesto, al servidor de aplicaciones, es decir en nuestro caso, este es un enlace PHP y un DBMS MySQL. No hay suficientes cerezas en el pastel, es decir, la aplicación de Android, que escribiremos ahora.
Arquitectura
La arquitectura de toda la plataforma de software de la estación meteorológica es simple:
- La parte del servidor (unidad central) de la estación meteorológica recopila datos de clientes de sensores remotos
- luego transfiere datos al servidor web de aplicaciones, que guarda estos datos en la base de datos
- La aplicación de Android (o cualquier otra aplicación remota: iOS, navegador) solicita datos de un servidor web y los muestra en la pantalla.
En la pantalla del dispositivo Android, mostraremos las lecturas actuales y más recientes del sensor.
HTTP GET y JSON
La pregunta que debe resolverse en primer lugar es cómo se transferirán los datos del servidor web a la aplicación de Android.
No hay necesidad de inventar nada aquí, todo ya ha sido inventado para nosotros: estos son HTTP GET y JSON.
En nuestro caso, una simple solicitud GET al servidor web puede compilarse y depurarse manualmente mientras la aplicación de Android aún no está lista.
En Java y Android, hay bibliotecas listas para procesar datos en formato JSON. JSON es un formato de texto legible por humanos, que es útil para la depuración.
Para generar datos actuales de los sensores de la estación meteorológica, cree un nuevo script PHP last-data-to-json.php en el servidor web.
Llamada de guión:
http://<>/last-data-to-json.php?k=<access_key>
donde <access_key>
, como recordamos, es la clave secreta de acceso a la base de datos.
Ejemplo de respuesta en formato JSON:
{ "DHT 11":{ "idSensor":"11", "dateCreate":"2016-04-20 18:06:03", "temperature":"19", "humidity":"26", "voltage":"5.01" }, "DHT 20":{ "idSensor":"20", "dateCreate":"2016-04-18 07:36:26", "temperature":"10", "humidity":"26", "voltage":"3.7" }, "BMP 11":{ "idSensor":"11", "dateCreate":"2016-04-20 18:06:22", "temperature":"19", "pressure":"987.97" } }
Hay que recordar que tenemos 3 sensores. Su identificación y tipo (DHT o BMP) están codificados en todo el código de la estación meteorológica. Este método de codificación hardcore es ideológicamente incorrecto, pero para un prototipo dibujado por la rodilla (donde se necesita una solución rápida y fácil) este es un compromiso razonable.
$idSensor = 11; // DHT $idSensor = 11; // BMP $idSensor = 20; // DHT
El last-data-to-json.php
toma los últimos datos de estos sensores heterogéneos de la base de datos y los empaqueta en el formato JSON. La selección de datos de la base de datos "desde el final" procede de esta manera:
SELECT <> FROM <> ORDER BY id DESC LIMIT 1;
Android
Ahora escribiremos una aplicación simple de Android que solicita, recibe, decodifica datos JSON y muestra información en la pantalla.
Nuestra aplicación de Android será lo más simple posible, solo la esencia de la tecnología. Más allá de este "esqueleto" ya será posible terminar con varias "bellezas".
Aquí hay una captura de pantalla de lo que debería resultar en

Como puede ver, la interfaz de usuario es solo espartana, basada en LinearLayout, nada más.
En la parte superior de TextView, se muestra la ID de los sensores y sus datos meteorológicos. El botón Actualizar inicia una segunda solicitud al servidor web. Lo siguiente en EditText es la única configuración del programa: esta es la URL de solicitud en el formulario
http://< >/last-data-to-json.php?k=<access_key>
¿Qué se debe tener en cuenta?
En el manifiesto, agregue líneas que permitan Internet y verifiquen el estado de la conexión de red:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.INTERNET" />
Trabajar con la red y recibir datos del sitio web es el siguiente.
Usamos AsyncTask para crear una tarea en segundo plano separada del hilo principal de la interfaz de usuario. Esta tarea en segundo plano toma la URL de solicitud y la usa para crear HttpURLConnection
.
Una vez establecida la conexión, AsyncTask carga el contenido de la página web (JSON) como InputStream. A continuación, InputStream se convierte en una cadena, que se decodifica con JSONObject y se muestra en la interfaz de usuario con el método onPostExecute()
.
En MainActivity.java cambie la URL a su:
private static final String defUrl = "http://host/dir/last-data-to-json.php?k=< >";
se usará de manera predeterminada la primera vez que ejecute una aplicación de Android.
Epílogo
Bueno, algo ya ha funcionado. Entonces puede optimizar algo, reemplazar algo, puede tirar todo, pero también pedir prestado algo.
Un gran punto separado es el consumo de energía . Recomiendo leer comentarios en publicaciones donde hay muchos consejos prácticos.
Hasta el infinito ... y más allá.