AirStreamCasting (beta)

Aplicación cliente

Se ha programado una aplicación android con código liberado

https://github.com/gurumelo/airstreamcasting/tree/master/cordova

Que se conecta por bluetooth a AirBeam. Que actúa como cliente y envía en tiempo real cada 10 segundos, o los que se determinen; foto, temperatura, humedad relativa y material particulado en aire PM 2.5; a un servidor, guardando los datos generados en una base de datos mongo. Que muestra un panel, y sin recarga, visibiliza los datos que el cliente android manda.

Puede ser instalada, activando Ajustes → Seguridad → Orígenes desconocidos y bajando el siguiente apk en tu móvil

https://github.com/gurumelo/airstreamcasting/raw/master/airstreamcasting.apk

La primera vez que sea abierta, nos muestra esta pantalla

  1. Rellenamos los campos de servidor y contraseña
  2. En el caso que aún no tengamos emparejado AirBeam, se acciona el botón “Emparejar AirBeam”. Con el AirBeam encendido, se empareja y se vuelve hacia atrás. Se acciona “Actualizar”, nos aparecerá AirBeam y pulsamos “Conectar”
  3. En el caso de que AirBeam ya lo tengamos emparejado, sólo tendremos que accionar “Conectar”

Se adentrará en la pantalla de toma de datos, se pulsaría el botón rojo de grabación y la aplicación, sin intervención, enviará cada 10 segundos los datos a

Aplicación servidor

El servidor está escrito en el lenguaje de programación node.js y se soporta sobre una base de datos mongoDB.

https://github.com/gurumelo/airstreamcasting/tree/master/www

Su instalación se realiza de la siguiente forma

git clone https://github.com/gurumelo/airstreamcasting
cd airstreamcasting/www
nano confi.json #Establecer una contraseña
npm install
node index.js

Una vez hecho, ya podemos mandar los datos desde android a servidor.

El panel web del servidor se percibe así

Añadiendo sensor CO a AirBeam

Beginning his research in 1962, Mr. Naoyoshi Taguchi became the first person in the world to succeed in the development of a semiconductor device which could detect low concentrations of combustible and reducing gases when used with a simple electrical circuit. Devices based on this technology are often called “TGS” (Taguchi Gas Sensors).[1]

“Todo comenzó a deshumanizarse el día en que las casas dejaron de tener corrales.”

Los sensores MQ, son una serie de coste muy contenido, calificados de semiconductores. Es decir, una resistencia calienta compuestos químicos, y éstos reaccionan, alterando su conductividad/resistencia ante la presencia de ciertos gases. Explicación no aproximada.

Detalles técnicos más aproximados pueden ser encontrados en su hoja técnica

AirBeam cuenta con una serie de ‘pines’ externos

En este caso vamos a usar un sensor MQ-7 que reacciona ante la presencia de CO, su disposición de pines es la siguiente


Usando 3 cables macho hembra, uniremos AirBeam con el sensor MQ-7 siguiendo este diagrama

Las partes físicas se encontrarían resueltas. Ahora habría que pasar a la parte lógica y añadirle algo de código al ‘firmware’ de AirBeam para que lea lo que el sensor MQ le relata.

“En el corral, había agua cristalina del pozo, el limonero siempre cargado, huevos de las gallinas ponedoras, leche de las cabras locas, transporte burro agradable y el perro compañía, siempre el perro compañía”

Como se detallaba en la reprogramación de AirBeam, se procederá de igual modo

En Arduino IDE usaremos este código modificado para tener en cuenta el CO

#include <SoftwareSerial.h>
#include <DHT.h>
#include <stdlib.h>

#define DHTPIN 9
#define DHTTYPE DHT22   // DHT 22  (AM2302)

int humi, cel, fah, kelv; 
unsigned long analogcount;
double analogtotal;

String inData;
unsigned long duration;
unsigned long starttime = 0;
unsigned long sampletime_ms = 1000;
unsigned long analogvalue = 0;
double hppcf = 0;
double ugm3 = 0;

int sensorPin = A1;
int sensorValue = 0;

DHT dht(DHTPIN, DHTTYPE);
SoftwareSerial mySerial(10, 11); //RX, TX

#define LEDPIN 13
#define BT_BUF_LEN 10
char bt_index = 0;
char bt_buffer[BT_BUF_LEN];
int8_t bt_connected = -1; // 0 = not connected (but been connected), 1 == connected, -1 == never been connected

uint8_t put_chr_buf(char c){
  // puts a character into the bt_buffer.
  // If the character is '\n' returns 1 (and doesn't put it into the buffer)
  // else returns 0
  if(c == '\n'){
      return 1;
  }
  if(bt_index >= BT_BUF_LEN - 2){
    return 0;
  }
  bt_buffer[bt_index] = c;
  bt_index++;
  bt_buffer[bt_index] = 0;
  return 0;
}

void analyze_buf(){
  // Determines if the buffer contains the SS notation
  if(bt_connected == -1){
    if(strncmp(bt_buffer, "SS=", 3) == 0){
      bt_connected = 0;
      Serial.println(F("1st Connect to BT"));
    }
  }
  else{
    if(strncmp(bt_buffer, "OK", 2) == 0){
    }
    else{
      Serial.println(F("ERROR: Unknown response:"));
      Serial.println(bt_buffer);
    }
    bt_connected = 0;
  }
  bt_buffer[0] = 0;
  bt_index = 0;
}

void update_bt_status(){
  // This should be called in the loop with at least a hundred milliescond delay before it is called again.
  // Determine if the BT module is connected or not.
  uint8_t temp = 0;
  if(mySerial.available()){
    while(mySerial.available()){
      temp = put_chr_buf(mySerial.read());
      if(temp){
        analyze_buf();
      }
    }
  }
  else{
    if(bt_connected >= 0){
      bt_connected = 1;
    }
  }
  
  // clear excess
  while(mySerial.available()){
    mySerial.read();
  }
  
  // Send out another signal for the next loop
  mySerial.println(F("BC:UI=01"));
  
  // Indicate connection status via the LED
  digitalWrite(LEDPIN, HIGH);
  if(bt_connected < 1){
    delay(100);
    digitalWrite(LEDPIN, LOW);
    delay(100);
  }
}

String readBTMAC() {
inData = "";
if (mySerial.available() > 0) {
Serial.println(mySerial.available());
int h = mySerial.available();
for (int i = 0; i < h; i++) {
inData += (char)mySerial.read();
}
inData.remove(23 ,24);
inData.remove(0, 11);
}
return inData;
}

void clear_bt_serial(){
  while(mySerial.available()){
    Serial.write(mySerial.read());
  }
}

void setup() {
  delay(3000);
  Serial.begin(115200);
  mySerial.begin(115200);
  mySerial.println("BC:BR=08");
  delay(100);
  
  mySerial.begin(19200);
  mySerial.println("BC:BR=08");
  delay(100);
  
  mySerial.begin(9600);
  mySerial.println("BC:BR=08");
  delay(100);
  
  mySerial.begin(19200);
  
  mySerial.println("BC:FT=00,00,00,01,03,0000");  // It will never try to autoconnect and will always be in discoverable mode.
  delay(100);
  mySerial.println(("BC:AD"));
  delay(100);
  readBTMAC();
  
  mySerial.print(("BC:NM=AirBeam-"));
  mySerial.println(inData);
  bt_buffer[0] = 0;
  pinMode(LEDPIN, OUTPUT);
  starttime = millis();

  pinMode(sensorPin, INPUT);
}

void loop() {
  analogvalue = analogvalue + analogRead(0);
  analogcount++;

  humi = dht.readHumidity();
  cel = dht.readTemperature();
  fah = ((cel * 9)/5) + 32;

  sensorValue = analogRead(sensorPin);
 
  update_bt_status();
  if ((millis()-starttime) > sampletime_ms)
  {
    starttime = millis(); // moved to create more regular periods.
    analogvalue = analogvalue/analogcount;
    analogtotal = (analogvalue*5.0)/1024;
    hppcf = (240.0*pow(analogtotal,6) - 2491.3*pow(analogtotal,5) + 9448.7*pow(analogtotal,4) - 14840.0*pow(analogtotal,3) + 10684.0*pow(analogtotal,2) + 2211.8*(analogtotal) + 7.9623);
    ugm3 = .518 + .00274 * hppcf;
    if(ugm3 < 0){
      ugm3 = 0;
    }
     
    Serial.println();
    Serial.print("AirBeam MAC: ");
    Serial.print(inData);
    Serial.print(" ");
    Serial.print(fah);
    Serial.print(F("F "));
    Serial.print(cel);
    Serial.print(F("C "));
    Serial.print(humi);
    Serial.print(F("RH "));
    Serial.print(F(" Analog Total: "));
    Serial.print(analogtotal);
    Serial.print(F(" hppcf: "));
    Serial.print(hppcf);
    Serial.print(F(" ugm^3: "));
    Serial.print(ugm3);
    Serial.print(F(" CO: "));
    Serial.print(sensorValue);
    Serial.println();
    
    analogvalue = 0;
    analogcount = 0;
    //lowpulseoccupancy = 0;
    
    if(bt_connected > 0){
     
      mySerial.print(ugm3);
      mySerial.print((";AirBeam:"));
      mySerial.print(inData);
      mySerial.print((";AirBeam-PM;Particulate Matter;PM;micrograms per cubic meter;µg/m³;0;12;35;55;150"));
      mySerial.print("\n");
  
      mySerial.print(cel);
      mySerial.print((";AirBeam:"));
      mySerial.print(inData);
      mySerial.print((";AirBeam-C;Temperature;C;degrees Celsius;C;0;10;20;30;40"));
      mySerial.print("\n");
      
      mySerial.print(humi);
      mySerial.print((";AirBeam:"));
      mySerial.print(inData);
      mySerial.print((";AirBeam-RH;Humidity;RH;percent;%;0;25;50;75;100"));
      mySerial.print("\n");
      
    }
    }
}

Se conecta Airbeam mediante USB a la máquina, se acciona botón de encendido de AirBeam. Esperamos unos segundos. Usamos el icono de subir y el código se compilará y será enviado a AirBeam.

Una vez hecho puede comprobarse los valores de salida de CO en Herramientas → Monitor serie . Esta opción permite vislumbrar los valores que AirBeam manda a cualquier artefacto al que esté conectado por USB.

Los que entienden de la materia coinciden en que los sensores MQ no deben ser usados para aplicaciones que requieran una gran exactitud o alarma, sin embargo, la posibilidad de ser usados para establecer una relación entre aumento de partículas en suspensión y provocado por la presencia de ciertos gases, pudiera ser válido. Por ejemplo, para descartar un aumento de partículas auspiciadas por humedad alta o establecer causa de partículas con emisión tráfico de motores de explosión. Lo pondremos a prueba para sacar algunas conclusiones erróneas.

En una posterior entrega, queda por configurar que la aplicación móvil Aircasting, muestre los valores de CO y puedan ser ‘mapeados’.

“Aparecieron una tarde de otoño primaveral unos hombres grises de la gran ciudad en el corral.

– ¿Es usted Asensio Giraldo?
– No, su nieto
– Dele esta carta del Gobernador Civil, este lodazal será expropiado, una carretera de grandes dimensiones, magna obra de ingeniería civil, pasará por aquí mismo, los automóviles son el progreso.

Asensito no entendió nada, pero eso del progreso sonaba muy mal”

Grados Celsius en AirBeam

Airbeam, proveniente del mundo estadounidense, saca por defecto valores de temperatura en grados Fahrenheit. Para que trabaje en grados Celsius, se requiere de una modificación del ‘firmware’ que ejecuta. Se describe el procedimiento.

Instalación de arduino IDE

En windows y Mac se baja desde https://www.arduino.cc/en/Main/Software y se instala de manera guiada

En Linux, tomando como base una distribución debian/ubuntu

apt-get install arduino

Reprogramando

Se baja la librería referente al sensor de temperatura y humedad

DHT.zip

Se descomprime el zip en un lugar visible

unzip DHT.zip

Se abre arduino IDE, según su sistema operativo, podrá encontrarse entre los diferentes menús.

En los menús de arriba, seleccionamos “Sketch → Importar librería → Add library”. Seleccionamos el directorio descomprimido ‘DHT’.

Copiamos y pegamos en Arduino IDE el siguiente código

#include <SoftwareSerial.h>
#include <DHT.h>
#include <stdlib.h>

#define DHTPIN 9
#define DHTTYPE DHT22   // DHT 22  (AM2302)

int humi, cel, fah, kelv; 
unsigned long analogcount;
double analogtotal;

String inData;
unsigned long duration;
unsigned long starttime = 0;
unsigned long sampletime_ms = 1000;
unsigned long analogvalue = 0;
double hppcf = 0;
double ugm3 = 0;

DHT dht(DHTPIN, DHTTYPE);
SoftwareSerial mySerial(10, 11); //RX, TX

#define LEDPIN 13
#define BT_BUF_LEN 10
char bt_index = 0;
char bt_buffer[BT_BUF_LEN];
int8_t bt_connected = -1; // 0 = not connected (but been connected), 1 == connected, -1 == never been connected

uint8_t put_chr_buf(char c){
  // puts a character into the bt_buffer.
  // If the character is '\n' returns 1 (and doesn't put it into the buffer)
  // else returns 0
  if(c == '\n'){
      return 1;
  }
  if(bt_index >= BT_BUF_LEN - 2){
    return 0;
  }
  bt_buffer[bt_index] = c;
  bt_index++;
  bt_buffer[bt_index] = 0;
  return 0;
}

void analyze_buf(){
  // Determines if the buffer contains the SS notation
  if(bt_connected == -1){
    if(strncmp(bt_buffer, "SS=", 3) == 0){
      bt_connected = 0;
      Serial.println(F("1st Connect to BT"));
    }
  }
  else{
    if(strncmp(bt_buffer, "OK", 2) == 0){
    }
    else{
      Serial.println(F("ERROR: Unknown response:"));
      Serial.println(bt_buffer);
    }
    bt_connected = 0;
  }
  bt_buffer[0] = 0;
  bt_index = 0;
}

void update_bt_status(){
  // This should be called in the loop with at least a hundred milliescond delay before it is called again.
  // Determine if the BT module is connected or not.
  uint8_t temp = 0;
  if(mySerial.available()){
    while(mySerial.available()){
      temp = put_chr_buf(mySerial.read());
      if(temp){
        analyze_buf();
      }
    }
  }
  else{
    if(bt_connected >= 0){
      bt_connected = 1;
    }
  }
  
  // clear excess
  while(mySerial.available()){
    mySerial.read();
  }
  
  // Send out another signal for the next loop
  mySerial.println(F("BC:UI=01"));
  
  // Indicate connection status via the LED
  digitalWrite(LEDPIN, HIGH);
  if(bt_connected < 1){
    delay(100);
    digitalWrite(LEDPIN, LOW);
    delay(100);
  }
}

String readBTMAC() {
inData = "";
if (mySerial.available() > 0) {
Serial.println(mySerial.available());
int h = mySerial.available();
for (int i = 0; i < h; i++) {
inData += (char)mySerial.read();
}
inData.remove(23 ,24);
inData.remove(0, 11);
}
return inData;
}

void clear_bt_serial(){
  while(mySerial.available()){
    Serial.write(mySerial.read());
  }
}

void setup() {
  delay(3000);
  Serial.begin(115200);
  mySerial.begin(115200);
  mySerial.println("BC:BR=08");
  delay(100);
  
  mySerial.begin(19200);
  mySerial.println("BC:BR=08");
  delay(100);
  
  mySerial.begin(9600);
  mySerial.println("BC:BR=08");
  delay(100);
  
  mySerial.begin(19200);
  
  mySerial.println("BC:FT=00,00,00,01,03,0000");  // It will never try to autoconnect and will always be in discoverable mode.
  delay(100);
  mySerial.println(("BC:AD"));
  delay(100);
  readBTMAC();
  
  mySerial.print(("BC:NM=AirBeam-"));
  mySerial.println(inData);
  bt_buffer[0] = 0;
  pinMode(LEDPIN, OUTPUT);
  starttime = millis();
}

void loop() {
  analogvalue = analogvalue + analogRead(0);
  analogcount++;

  humi = dht.readHumidity();
  cel = dht.readTemperature();
  fah = ((cel * 9)/5) + 32;
 
  update_bt_status();
  if ((millis()-starttime) > sampletime_ms)
  {
    starttime = millis(); // moved to create more regular periods.
    analogvalue = analogvalue/analogcount;
    analogtotal = (analogvalue*5.0)/1024;
    hppcf = (240.0*pow(analogtotal,6) - 2491.3*pow(analogtotal,5) + 9448.7*pow(analogtotal,4) - 14840.0*pow(analogtotal,3) + 10684.0*pow(analogtotal,2) + 2211.8*(analogtotal) + 7.9623);
    ugm3 = .518 + .00274 * hppcf;
    if(ugm3 < 0){
      ugm3 = 0;
    }
     
    Serial.println();
    Serial.print("AirBeam MAC: ");
    Serial.print(inData);
    Serial.print(" ");
    Serial.print(fah);
    Serial.print(F("F "));
    Serial.print(cel);
    Serial.print(F("C "));
    Serial.print(humi);
    Serial.print(F("RH "));
    Serial.print(F(" Analog Total: "));
    Serial.print(analogtotal);
    Serial.print(F(" hppcf: "));
    Serial.print(hppcf);
    Serial.print(F(" ugm^3: "));
    Serial.print(ugm3);
    Serial.println();
    
    analogvalue = 0;
    analogcount = 0;
    //lowpulseoccupancy = 0;
    
    if(bt_connected > 0){
      //mySerial.print(analogtotal);
      //mySerial.print((";AirBeam:"));
      //mySerial.print(inData);
      //mySerial.print((";AirBeam-PM-V;Particulate Matter;PM;Volts;V;0;1;2;3;4"));
      //mySerial.print("\n");
      
      //mySerial.print(hppcf);
      //mySerial.print((";AirBeam:"));
      //mySerial.print(inData);
      //mySerial.print((";AirBeam-PM-hppcf;Particulate Matter;PM;hundreds of particles per cubic foot;hppcf;0;3000;8000;13000;26000"));
      //mySerial.print("\n");
      
      mySerial.print(ugm3);
      mySerial.print((";AirBeam:"));
      mySerial.print(inData);
      mySerial.print((";AirBeam-PM;Particulate Matter;PM;micrograms per cubic meter;µg/m³;0;12;35;55;150"));
      mySerial.print("\n");
      
      //mySerial.print(fah);
      //mySerial.print((";AirBeam:"));
      //mySerial.print(inData);
      //mySerial.print((";AirBeam-F;Temperature;F;degrees Fahrenheit;F;0;25;50;75;100"));
      //mySerial.print("\n");
   
      mySerial.print(cel);
      mySerial.print((";AirBeam:"));
      mySerial.print(inData);
      mySerial.print((";AirBeam-C;Temperature;C;degrees Celsius;C;0;10;20;30;40"));
      mySerial.print("\n");
      
      mySerial.print(humi);
      mySerial.print((";AirBeam:"));
      mySerial.print(inData);
      mySerial.print((";AirBeam-RH;Humidity;RH;percent;%;0;25;50;75;100"));
      mySerial.print("\n");
      
    }
    }
}

En los menús de Arduino IDE, seleccionamos “Herramientas → Tarjeta → Arduino Leonardo”.

Conectamos AirBeam a la máquina mediante el cable USB y lo encendemos, esperamos unos segundos.

Accionamos el botón con una Flecha, “Cargar/Upload”

El firmware modificado se compilará y se subirá a la placa.

Comprobamos mediante la aplicación móvil.

Reconocimiento de AirBeam

Descripción

Airbeam es un dispositivo basado en arduino Leonardo, creado por habitatmap para la medición de temperatura, humedad y material particulado en aire PM 2.5. Se complementa con una aplicación móvil que se comunica mediante Bluetooth, permitiendo ‘mapear’ valores. Tanto el ‘firmware’ del dispositivo, la aplicación móvil, como el servicio web donde volcar los datos tomados, cuentan de licencias de libre uso y modificación.

https://github.com/HabitatMap/

Abriéndolo

Sensor de temperatura y humedad MaxDetect RHT03

Sensor PM 2.5 Shinyei PPD60PV
http://www.shinyei.co.jp/stc/eng/optical/main_ppd60pv.html

Tornillos regulables para la calibración del sensor PM 2.5

Ventilador extracción aire (bomba)

Pines exteriores para conexión de otros sensores o electrónica diversa