CO2 Sensor

From MiOS
(Difference between revisions)
Jump to: navigation, search
 
 
(6 intermediate revisions by one user not shown)
Line 1: Line 1:
 +
[[Category:Hardware]]
 +
==Requirements==
 +
 +
===Hardware===
 +
 +
http://www.appliedsensor.com/products/indoor-air-monitor.html
 +
 +
aka:
 +
 +
Voltcraft CO-20 USB
 +
 +
MSR CO2 Air Guard USB
 +
 +
Butterfly Indoor Air Monitor USB
 +
 +
Dwyer AQStick model ASQ-1
 +
 +
eNasco Indoor Air monitor USB
 +
 +
FRAKTA CO2-Air Gard USB
 +
 +
Sentinel-Haus Institut RaumluftWächter
 +
 +
===Software===
 +
 +
Windows XP
 +
 +
AirMonitor application: http://www.appliedsensor.com/download/
 +
 +
CVS (CO2/VOC Sensor plugin for MiOS): https://docs.google.com/open?id=0Bz4omZm4gYcsaktBUkMyajZqV00
 +
 +
 +
==Installation==
 +
 +
Connect the USB stick to your Windows XP computer.
 +
 +
Install the AirMonitor software.
 +
 +
In AirMonitor: activate the 'Support Tools' menu item: Hold down the left CTRL-key and double-click on the right top logo.
 +
 +
In AirMonitor: Support Tools -> Edit knobs: activate 'Act as server', adjust the port to your needs (see ...\AirMonitor\engineering.txt for details).
 +
 +
Install CVS, restart LuaUPnP.
 +
 +
Configure CVS: Set ServerIP, ServerPort, UpdateInterval (seconds, default: 60 s), restart LuaUPnP.
 +
   
 +
 +
==Limitations==
 +
 +
Only one sensor per server is supported.
 +
 +
If the connection to the server fails/is lost, CVS doesn't try to re/establish the connection again, but fails with an error message.
 +
 +
 +
==Further reading==
 +
 +
http://forum.micasaverde.com/index.php/topic,4705.0.html
 +
 +
http://code.google.com/p/airsensor-linux-usb/wiki/About
 +
 +
 +
==Screenshots==
 +
 
[[File:CVS1.jpg]]
 
[[File:CVS1.jpg]]
  
[[File:CVS2.jpg]]
+
[[File:CVS2.jpg|400px]]
 +
 
 +
[[File:CVS3.jpg|400px]]
 +
 
 +
[[File:CVS4.jpg|400px]]
 +
 
 +
[[File:CVS5.jpg]]
 +
 
 +
 
 +
==Using the CO-20 sensor with the Raspberry Pi==
 +
 
 +
 
 +
[[File:RPi_CO-20.jpg|400px]]
 +
 
 +
 
 +
===Installation===
 +
 
 +
Raspberry Pi instructions:
 +
 
 +
sudo apt-get install libusb-dev
 +
gcc -o air air.c -lusb
 +
sudo ./air
 +
 
 +
MiOS instructions:
 +
 
 +
Create a Temperature sensor and use it as a container for the ppm values from the Raspberry Pi/CO-20 combo.
 +
 
 +
===air.c source code===
 +
 
 +
Written by Rodric Yates, based on airsensor-linux-usb, modified for MiOS by Ap15e (published with permission from Rodric Yates).
 +
 
 +
Modify
 +
 
 +
sprintf( command, "wget -O /dev/null 'http://192.168.178.116:3480/data_request?id=variableset&DeviceNum=480&serviceId=urn:upnp-org:serviceId:TemperatureSensor1&Variable=CurrentTemperature&Value=%d'", rresult);
 +
 
 +
to your needs (Vera's IP address, device number of the Temperature sensor).
 +
 
 +
 
 +
<source lang="text">
 +
#include <assert.h>
 +
#include <signal.h>
 +
#include <stdio.h>
 +
#include <stdlib.h>
 +
#include <string.h>
 +
#include <usb.h>
 +
#include <asm/byteorder.h>
 +
#include <sys/types.h>
 +
#include <sys/wait.h>
 +
#include <time.h>
 +
 
 +
#define AQ_GREEN  1000
 +
#define AQ_YELLOW 1500
 +
#define AQ_RED    4000
 +
 
 +
#define GREEN  0
 +
#define YELLOW 1
 +
#define RED    2
 +
#define BLINK  3
 +
 
 +
char *airqual[] = { "GREEN", "YELLOW", "RED" };
 +
 
 +
struct usb_dev_handle *devh;
 +
 
 +
 
 +
void release_usb_device(int dummy) {
 +
    int ret;
 +
    ret = usb_release_interface(devh, 0);
 +
    usb_close(devh);
 +
    exit(ret);
 +
}
 +
 
 +
struct usb_device* find_device(int vendor, int product) {
 +
    struct usb_bus *bus;
 +
 
 +
    for (bus = usb_get_busses(); bus; bus = bus->next) {
 +
      struct usb_device *dev;
 +
 
 +
      for (dev = bus->devices; dev; dev = dev->next) {
 +
if (dev->descriptor.idVendor == vendor
 +
    && dev->descriptor.idProduct == product)
 +
  return dev;
 +
      }
 +
    }
 +
    return NULL;
 +
}
 +
 
 +
 
 +
int main(int argc, char **argv)
 +
{
 +
  int ret, reteth0, retwlan0,vendor, product;
 +
  struct usb_device *dev;
 +
  char buf[1000];
 +
  char command[2048];
 +
 
 +
  FILE *fp;
 +
  char eth0mac[32];
 +
  char wlan0mac[32];
 +
  char eth0ip[32];
 +
  char wlan0ip[32];
 +
  char hostname[] = "raspberrypi" ;
 +
  char brokername[] = "api.cosm.com";
 +
  char portname [] = "1883";
 +
//  char topicname [] = "pi";
 +
  char topicname [] = "Your-Data-Feed-e.g./v2/feeds/91754/datastreams/AirPollution.csv";
 +
  char cosmapikey [] = "My-Cosm-API-Key";
 +
  char *mac;
 +
 +
 
 +
 +
  /*
 +
    Check endianess of the router.  The Voltcraft stick is little endian.
 +
    The TP-Link router is big endian.
 +
  */
 +
 
 +
  /*   
 +
  int x = 1;
 +
  if (*(char *)&x == 1) {
 +
    fprintf(stderr, "Little Endian\n");
 +
  } else {
 +
    fprintf(stderr, "Big Endian\n");
 +
  }
 +
  */
 +
 
 +
  vendor  = 0x03eb;
 +
  product = 0x2013;
 +
  dev = NULL;
 +
 
 +
  usb_init();
 +
 
 +
  while (1) {
 +
 
 +
#if 0
 +
    hostname = "raspberrypi";
 +
    fp = popen("uci get system.@system[0].hostname", "r");
 +
    if (fp != NULL) {
 +
      while (fgets(hostname, sizeof(hostname)-1, fp) != NULL) {
 +
printf("hostname %s\n", hostname);
 +
      }
 +
      hostname[strlen(hostname)-1] = '\0';
 +
    }
 +
#endif
 +
 
 +
    eth0mac[0] = '\0';
 +
    wlan0mac[0] = '\0';
 +
    eth0ip[0]  = '\0';
 +
    wlan0ip[0]  = '\0';
 +
   
 +
 
 +
    // eth0 ip
 +
    fp = popen("ip addr list eth0 | grep inet | grep -v 192.168.3.3 \
 +
| awk '{ print $2 }' ", "r");
 +
 
 +
 
 +
    //  fp = popen("ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}' ", "r");
 +
    if (fp != NULL) {
 +
      while (fgets(eth0ip, sizeof(eth0ip)-1, fp) != NULL) {
 +
printf("eth0ip %s\n", eth0ip);
 +
eth0ip[strlen(eth0ip)-1] = '\0';
 +
      }
 +
    }
 +
    pclose(fp);
 +
    // eth0 mac
 +
    fp = popen("ifconfig eth0 | grep eth0 | awk '{ print $5 }'", "r");
 +
    if (fp != NULL) {
 +
      while (fgets(eth0mac, sizeof(eth0mac)-1, fp) != NULL) {
 +
 
 +
      }
 +
      eth0mac[strlen(eth0mac)-1] = '\0';
 +
      printf("eth0mac %s\n", eth0mac);
 +
    }
 +
    pclose(fp);
 +
    // wlan0 ip
 +
    fp = popen("ifconfig wlan0 | grep 'inet addr:' \
 +
| cut -d: -f2 | awk '{ print $1}'  ", "r");
 +
    if (fp != NULL) {
 +
      while (fgets(wlan0ip, sizeof(wlan0ip)-1, fp) != NULL) {
 +
printf("wlan0ip %s\n", wlan0ip);
 +
wlan0ip[strlen(wlan0ip)-1] = '\0';
 +
      }
 +
    }
 +
    pclose(fp);
 +
    // wlan0 mac
 +
    fp = popen("ifconfig wlan0 | grep wlan0 | awk '{ print $5 }'", "r");
 +
 
 +
    if (fp != NULL) {
 +
      while (fgets(wlan0mac, sizeof(wlan0mac)-1, fp) != NULL) {
 +
printf("wlan0mac %s\n", wlan0mac);
 +
      }
 +
      wlan0mac[strlen(wlan0mac)-1] = '\0';
 +
    }
 +
    pclose(fp);
 +
 
 +
    retwlan0 = -1;
 +
    reteth0 = -1;
 +
 
 +
 
 +
 
 +
    do {
 +
      usb_set_debug(0);
 +
      usb_find_busses();
 +
      usb_find_devices();
 +
      dev = find_device(vendor, product);
 +
      printf("No device found ... sleeping ...\n");
 +
      sleep(10);
 +
    }  while (dev == NULL);
 +
 
 +
    assert(dev);
 +
 
 +
    printf("device found\n");
 +
 
 +
    devh = usb_open(dev);
 +
    assert(devh);
 +
 
 +
    signal(SIGTERM, release_usb_device);
 +
 
 +
    ret = usb_get_driver_np(devh, 0, buf, sizeof(buf));
 +
    if (ret == 0) {
 +
      // printf("interface 0 already claimed by driver \"%s\", attempting to detach it\n", buf);
 +
      ret = usb_detach_kernel_driver_np(devh, 0);
 +
      // printf("usb_detach_kernel_driver_np returned %d\n", ret);
 +
    }
 +
    ret = usb_claim_interface(devh, 0);
 +
    if (ret != 0) {
 +
      printf("claim failed with error %d\n", ret);
 +
      continue;
 +
      // exit(1);
 +
    }
 +
 +
 
 +
 
 +
    // int c0 = 104;
 +
    // int c1 = 37;
 +
 
 +
    unsigned char c0 = 104;
 +
    unsigned char c1 = 37;
 +
 
 +
    unsigned short iresult=BLINK;
 +
    unsigned short oresult=BLINK;
 +
    unsigned short rresult=0;
 +
    while(0==0){
 +
 
 +
      memcpy(buf, "\x40\x68\x2a\x54\x52\x0a\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40", 0x0000010);
 +
 
 +
      ret = usb_interrupt_write(devh, 0x00000002, buf, 0x0000010, 1000);
 +
      // usleep(94*1000);
 +
      ret = usb_interrupt_read(devh, 0x00000081, buf, 0x0000010, 1000);
 +
      if ( !((ret == 0) || (ret == 16))) {
 +
printf("device not ok: Unplug it, and plug it back in again.\n");
 +
exit;
 +
      }
 +
 
 +
      if (ret == 0) {
 +
ret = usb_interrupt_read(devh, 0x00000081, buf, 0x0000010, 1000);
 +
      }
 +
 
 +
      memcpy(&iresult,buf+2,2);
 +
      iresult = __le16_to_cpu(iresult);
 +
      printf("iresult %d (%X) ret %d\n", iresult, iresult, ret);
 +
      sleep(1);
 +
 
 +
      ret = usb_interrupt_read(devh, 0x00000081, buf, 0x0000010, 1000);
 +
      printf("2 ret %d\n", ret);
 +
 
 +
      if (iresult > 15000) {
 +
 
 +
printf("bogus iresult %d, skipping ...\n", iresult);
 +
continue;
 +
 
 +
      }
 +
 
 +
      rresult = iresult;
 +
 
 +
      if ( iresult < AQ_GREEN ) {
 +
iresult = GREEN;
 +
      } else {
 +
if ( iresult < AQ_YELLOW ) {       
 +
  iresult = YELLOW;
 +
} else {
 +
  iresult = RED;
 +
}
 +
      }
 +
 
 +
      if ( rresult < 15000) {
 +
 
 +
time_t t = time(NULL);
 +
struct tm tm = *localtime(&t);
 +
 
 +
printf("now: %d-%d-%d %d:%d:%d\n", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
 +
 
 +
printf("%s\n", airqual[iresult]);
 +
 
 +
//sprintf( command, "mosquitto_pub -i generic-client-identifier-change-as-needed -h %s -p %s -q 0 -u %s -t \"%s\" -m \"%d\" ", brokername, portname, cosmapikey, topicname, rresult);
 +
 
 +
sprintf( command, "wget -O /dev/null 'http://192.168.178.116:3480/data_request?id=variableset&DeviceNum=480&serviceId=urn:upnp-org:serviceId:TemperatureSensor1&Variable=CurrentTemperature&Value=%d'", rresult);
 +
 
 +
printf("command: %s\n", command);
 +
ret = system(command);
 +
 
 +
if ( WEXITSTATUS(ret) == 0 ) {
 +
  oresult = iresult;
 +
} else {
 +
  printf("Send error...will retry...\n");
 +
  oresult = BLINK;
 +
}
 +
 
 +
      }
 +
      sleep(20);
 +
    }
  
[[File:CVS3.jpg]]
+
  }
  
[[File:CVS4.jpg]]
+
}
 +
</source>

Latest revision as of 02:43, 15 June 2013

Contents

[edit] Requirements

[edit] Hardware

http://www.appliedsensor.com/products/indoor-air-monitor.html

aka:

Voltcraft CO-20 USB

MSR CO2 Air Guard USB

Butterfly Indoor Air Monitor USB

Dwyer AQStick model ASQ-1

eNasco Indoor Air monitor USB

FRAKTA CO2-Air Gard USB

Sentinel-Haus Institut RaumluftWächter

[edit] Software

Windows XP

AirMonitor application: http://www.appliedsensor.com/download/

CVS (CO2/VOC Sensor plugin for MiOS): https://docs.google.com/open?id=0Bz4omZm4gYcsaktBUkMyajZqV00


[edit] Installation

Connect the USB stick to your Windows XP computer.

Install the AirMonitor software.

In AirMonitor: activate the 'Support Tools' menu item: Hold down the left CTRL-key and double-click on the right top logo.

In AirMonitor: Support Tools -> Edit knobs: activate 'Act as server', adjust the port to your needs (see ...\AirMonitor\engineering.txt for details).

Install CVS, restart LuaUPnP.

Configure CVS: Set ServerIP, ServerPort, UpdateInterval (seconds, default: 60 s), restart LuaUPnP.


[edit] Limitations

Only one sensor per server is supported.

If the connection to the server fails/is lost, CVS doesn't try to re/establish the connection again, but fails with an error message.


[edit] Further reading

http://forum.micasaverde.com/index.php/topic,4705.0.html

http://code.google.com/p/airsensor-linux-usb/wiki/About


[edit] Screenshots

CVS1.jpg

CVS2.jpg

CVS3.jpg

CVS4.jpg

CVS5.jpg


[edit] Using the CO-20 sensor with the Raspberry Pi

RPi CO-20.jpg


[edit] Installation

Raspberry Pi instructions:

sudo apt-get install libusb-dev
gcc -o air air.c -lusb
sudo ./air 

MiOS instructions:

Create a Temperature sensor and use it as a container for the ppm values from the Raspberry Pi/CO-20 combo.

[edit] air.c source code

Written by Rodric Yates, based on airsensor-linux-usb, modified for MiOS by Ap15e (published with permission from Rodric Yates).

Modify

sprintf( command, "wget -O /dev/null 'http://192.168.178.116:3480/data_request?id=variableset&DeviceNum=480&serviceId=urn:upnp-org:serviceId:TemperatureSensor1&Variable=CurrentTemperature&Value=%d'", rresult);

to your needs (Vera's IP address, device number of the Temperature sensor).


#include <assert.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <usb.h>
#include <asm/byteorder.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
 
#define AQ_GREEN  1000
#define AQ_YELLOW 1500
#define AQ_RED    4000
 
#define GREEN  0
#define YELLOW 1 
#define RED    2
#define BLINK  3
 
char *airqual[] = { "GREEN", "YELLOW", "RED" };
 
struct usb_dev_handle *devh;
 
 
void release_usb_device(int dummy) {
    int ret;
    ret = usb_release_interface(devh, 0);
    usb_close(devh);
    exit(ret);
}
 
struct usb_device* find_device(int vendor, int product) {
    struct usb_bus *bus;
 
    for (bus = usb_get_busses(); bus; bus = bus->next) {
      struct usb_device *dev;
 
      for (dev = bus->devices; dev; dev = dev->next) {
if (dev->descriptor.idVendor == vendor
    && dev->descriptor.idProduct == product)
  return dev;
      }
    }
    return NULL;
}
 
 
int main(int argc, char **argv)
{
  int ret, reteth0, retwlan0,vendor, product;
  struct usb_device *dev;
  char buf[1000];
  char command[2048];
 
  FILE *fp;
  char eth0mac[32];
  char wlan0mac[32];
  char eth0ip[32];
  char wlan0ip[32];
  char hostname[] = "raspberrypi" ;
  char brokername[] = "api.cosm.com";
  char portname [] = "1883";
//  char topicname [] = "pi";
  char topicname [] = "Your-Data-Feed-e.g./v2/feeds/91754/datastreams/AirPollution.csv";
  char cosmapikey [] = "My-Cosm-API-Key";
  char *mac;
 
 
 
  /*
    Check endianess of the router.  The Voltcraft stick is little endian.
    The TP-Link router is big endian.
  */
 
  /*     
  int x = 1;
  if (*(char *)&x == 1) {
    fprintf(stderr, "Little Endian\n");
  } else {
     fprintf(stderr, "Big Endian\n");
  }
  */
 
  vendor  = 0x03eb;
  product = 0x2013; 
  dev = NULL;
 
  usb_init();
 
  while (1) {
 
#if 0
    hostname = "raspberrypi"; 
    fp = popen("uci get system.@system[0].hostname", "r");
    if (fp != NULL) {
      while (fgets(hostname, sizeof(hostname)-1, fp) != NULL) {
printf("hostname %s\n", hostname);
      }
      hostname[strlen(hostname)-1] = '\0';
    }
#endif
 
    eth0mac[0] = '\0';
    wlan0mac[0] = '\0';
    eth0ip[0]  = '\0';
    wlan0ip[0]  = '\0';
 
 
    // eth0 ip
    fp = popen("ip addr list eth0 | grep inet | grep -v 192.168.3.3 \
| awk '{ print $2 }' ", "r");
 
 
    //  fp = popen("ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}' ", "r");
    if (fp != NULL) {
      while (fgets(eth0ip, sizeof(eth0ip)-1, fp) != NULL) {
printf("eth0ip %s\n", eth0ip);
eth0ip[strlen(eth0ip)-1] = '\0';
      }
    }
    pclose(fp);
    // eth0 mac
    fp = popen("ifconfig eth0 | grep eth0 | awk '{ print $5 }'", "r");
    if (fp != NULL) {
      while (fgets(eth0mac, sizeof(eth0mac)-1, fp) != NULL) {
 
      }
      eth0mac[strlen(eth0mac)-1] = '\0';
      printf("eth0mac %s\n", eth0mac);
    }
    pclose(fp);
    // wlan0 ip
    fp = popen("ifconfig wlan0 | grep 'inet addr:' \
| cut -d: -f2 | awk '{ print $1}'   ", "r");
    if (fp != NULL) {
      while (fgets(wlan0ip, sizeof(wlan0ip)-1, fp) != NULL) {
printf("wlan0ip %s\n", wlan0ip);
wlan0ip[strlen(wlan0ip)-1] = '\0';
      }
    }
    pclose(fp);
    // wlan0 mac
    fp = popen("ifconfig wlan0 | grep wlan0 | awk '{ print $5 }'", "r");
 
    if (fp != NULL) {
      while (fgets(wlan0mac, sizeof(wlan0mac)-1, fp) != NULL) {
printf("wlan0mac %s\n", wlan0mac);
      }
      wlan0mac[strlen(wlan0mac)-1] = '\0';
    }
    pclose(fp);
 
    retwlan0 = -1;
    reteth0 = -1;
 
 
 
    do {
      usb_set_debug(0);
      usb_find_busses();
      usb_find_devices();
      dev = find_device(vendor, product);
      printf("No device found ... sleeping ...\n");
      sleep(10);
    }  while (dev == NULL);
 
    assert(dev);
 
    printf("device found\n");
 
    devh = usb_open(dev);
    assert(devh);
 
    signal(SIGTERM, release_usb_device);
 
    ret = usb_get_driver_np(devh, 0, buf, sizeof(buf));
    if (ret == 0) {
      // printf("interface 0 already claimed by driver \"%s\", attempting to detach it\n", buf);
      ret = usb_detach_kernel_driver_np(devh, 0);
      // printf("usb_detach_kernel_driver_np returned %d\n", ret);
    }
    ret = usb_claim_interface(devh, 0);
    if (ret != 0) {
      printf("claim failed with error %d\n", ret);
      continue;
      // exit(1);
    }
 
 
 
    // int c0 = 104;
    // int c1 = 37;
 
    unsigned char c0 = 104;
    unsigned char c1 = 37;
 
    unsigned short iresult=BLINK;
    unsigned short oresult=BLINK;
    unsigned short rresult=0;
    while(0==0){
 
      memcpy(buf, "\x40\x68\x2a\x54\x52\x0a\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40", 0x0000010);
 
      ret = usb_interrupt_write(devh, 0x00000002, buf, 0x0000010, 1000);
      // usleep(94*1000);
      ret = usb_interrupt_read(devh, 0x00000081, buf, 0x0000010, 1000);
      if ( !((ret == 0) || (ret == 16))) {
printf("device not ok: Unplug it, and plug it back in again.\n");
exit;
      }
 
      if (ret == 0) {
ret = usb_interrupt_read(devh, 0x00000081, buf, 0x0000010, 1000);
      }
 
      memcpy(&iresult,buf+2,2);
      iresult = __le16_to_cpu(iresult);
      printf("iresult %d (%X) ret %d\n", iresult, iresult, ret);
      sleep(1);
 
      ret = usb_interrupt_read(devh, 0x00000081, buf, 0x0000010, 1000);
      printf("2 ret %d\n", ret);
 
      if (iresult > 15000) {
 
printf("bogus iresult %d, skipping ...\n", iresult);
continue;
 
      }
 
      rresult = iresult;
 
      if ( iresult < AQ_GREEN ) {
iresult = GREEN;
      } else {
if ( iresult < AQ_YELLOW ) {        
  iresult = YELLOW;
} else {
  iresult = RED;
}
      }
 
      if ( rresult < 15000) {
 
time_t t = time(NULL);
struct tm tm = *localtime(&t);
 
printf("now: %d-%d-%d %d:%d:%d\n", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
 
printf("%s\n", airqual[iresult]);
 
//sprintf( command, "mosquitto_pub -i generic-client-identifier-change-as-needed -h %s -p %s -q 0 -u %s -t \"%s\" -m \"%d\" ", brokername, portname, cosmapikey, topicname, rresult);
 
sprintf( command, "wget -O /dev/null 'http://192.168.178.116:3480/data_request?id=variableset&DeviceNum=480&serviceId=urn:upnp-org:serviceId:TemperatureSensor1&Variable=CurrentTemperature&Value=%d'", rresult);
 
printf("command: %s\n", command);
ret = system(command);
 
if ( WEXITSTATUS(ret) == 0 ) {
  oresult = iresult;
} else {
  printf("Send error...will retry...\n");
  oresult = BLINK;
}
 
      }
      sleep(20);
    }
 
  }
 
}
Personal tools