├── mobile └── readme.txt ├── readme.txt ├── sensors ├── .DS_Store ├── MQ7 Arduino Library │ ├── .DS_Store │ └── CS_MQ7 │ │ ├── .DS_Store │ │ ├── CS_MQ7.cpp │ │ ├── CS_MQ7.h │ │ └── examples │ │ ├── .DS_Store │ │ └── CS_MQ7 │ │ └── CS_MQ7.pde ├── MQ7 Breakout │ ├── .DS_Store │ └── CS_MQ7 │ │ ├── .DS_Store │ │ ├── CS_MQ7.cpp │ │ ├── CS_MQ7.h │ │ └── examples │ │ ├── .DS_Store │ │ └── CS_MQ7 │ │ └── CS_MQ7.pde ├── MQ7 eagle files │ ├── COsensor03.brd │ └── COsensor03.sch ├── readme.textile └── readme.txt └── stationary ├── .DS_Store ├── XBeeScripts ├── pachube_functions.php ├── phptest.txt ├── wt.php └── xbeeupdate.php ├── arduino ├── current │ └── weatherTunnelSensorUnit │ │ ├── LCD copy.ino │ │ ├── LCD.ino │ │ ├── LEDs copy.ino │ │ ├── LEDs.ino │ │ ├── sensors copy.ino │ │ ├── sensors.ino │ │ ├── weatherTunnelSensorUnit copy.ino │ │ └── weatherTunnelSensorUnit.ino └── dev │ ├── ArduinoSoftwareRESET │ └── ArduinoSoftwareRESET.pde │ ├── Autoscroll_LCDtest │ └── Autoscroll_LCDtest.pde │ └── temperature_tmp102 │ └── temperature_tmp102.pde ├── readme.txt └── sensorDocs ├── ReprogrammingYourWeatherTunnelUnit.pdf └── sensorDoc_03a.pdf /mobile/readme.txt: -------------------------------------------------------------------------------- 1 | Citizen Sensor 2 | 3 | http://citizensensor.cc 4 | 5 | DIY environmental and air quality monitoring. Has been developed as both stationary and mobile units. 6 | 7 | *mobile* 8 | > operate as bluetooth peripheral for an Android application 9 | > arduino based 10 | > battery powered 11 | > updates output to LAYAR, google maps, and private social networks 12 | > pachube support coming 13 | 14 | Arduino + Bluetooth antenna talks to Android phone. Android phone beams data up to custom server. 15 | 16 | coming: - schematics / board design 17 | - Android app 18 | - arduino compatible circuit code -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | Citizen Sensor 2 | 3 | http://citizensensor.cc 4 | 5 | DIY environmental and air quality monitoring. Has been developed as both stationary and mobile units. 6 | 7 | Stationary units have been deployed all over world. CS was used in the "weather tunnel" project, exhibited at the national art museum of China, Beijing summer 2011. 8 | 9 | *stationary* 10 | > operate as stationary units connected to the internet via ethernet cable 11 | > arduino based 12 | > require wall power (7-12v DC power brick) 13 | > use pachube (some units live currently: https://pachube.com/feeds?user=weathertunnel) 14 | > schematic on Upverter: http://upverter.com/jmsaavedra/634b5640a5bbd8a7/Citizen-Sensor---Stationary-Version-02/ 15 | 16 | *mobile* 17 | > operate as bluetooth peripherals for an Android application 18 | > arduino based 19 | > battery powered 20 | > updates output to LAYAR, google maps, and private social networks 21 | > pachube support coming 22 | 23 | -------------------------------------------------------------------------------- /sensors/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmsaavedra/Citizen-Sensor/3c399e08289bcb9d6373831019956d3e6263dc70/sensors/.DS_Store -------------------------------------------------------------------------------- /sensors/MQ7 Arduino Library/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmsaavedra/Citizen-Sensor/3c399e08289bcb9d6373831019956d3e6263dc70/sensors/MQ7 Arduino Library/.DS_Store -------------------------------------------------------------------------------- /sensors/MQ7 Arduino Library/CS_MQ7/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmsaavedra/Citizen-Sensor/3c399e08289bcb9d6373831019956d3e6263dc70/sensors/MQ7 Arduino Library/CS_MQ7/.DS_Store -------------------------------------------------------------------------------- /sensors/MQ7 Arduino Library/CS_MQ7/CS_MQ7.cpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | CS_MQ7_02.h - Library for reading the MQ-7 Carbon Monoxide Sensor 4 | Breakout, as part of the Citizen Sensor project. 5 | http://citizensensor.cc 6 | 7 | Released into the public domain. 8 | 9 | Created by J Saavedra, October 2010. 10 | http://jos.ph 11 | 12 | */ 13 | 14 | #if (ARDUINO >= 100) 15 | #include "Arduino.h" 16 | #else 17 | #include 18 | #include "WProgram.h" 19 | #endif 20 | 21 | #include "CS_MQ7.h" 22 | 23 | CS_MQ7::CS_MQ7(int CoTogPin, int CoIndicatorPin){ 24 | 25 | pinMode(CoIndicatorPin, OUTPUT); 26 | pinMode(CoTogPin, OUTPUT); 27 | 28 | _CoIndicatorPin = CoIndicatorPin; 29 | _CoTogPin = CoTogPin; 30 | 31 | indicatorAttached = true; //we are using an LED to show heater 32 | 33 | time = 0; 34 | currTime = 0; 35 | prevTime = 0; 36 | currCoPwrTimer = 0; 37 | CoPwrState = LOW; 38 | currCoPwrTimer = 500; 39 | 40 | } 41 | 42 | CS_MQ7::CS_MQ7(int CoTogPin){ 43 | 44 | pinMode(CoTogPin, OUTPUT); 45 | 46 | indicatorAttached = false; //not using an LED 47 | 48 | _CoTogPin = CoTogPin; 49 | 50 | time = 0; 51 | currTime = 0; 52 | prevTime = 0; 53 | currCoPwrTimer = 0; 54 | CoPwrState = LOW; 55 | currCoPwrTimer = 500; 56 | 57 | } 58 | 59 | void CS_MQ7::CoPwrCycler(){ 60 | 61 | currTime = millis(); 62 | 63 | if (currTime - prevTime > currCoPwrTimer){ 64 | prevTime = currTime; 65 | 66 | if(CoPwrState == LOW){ 67 | CoPwrState = HIGH; 68 | currCoPwrTimer = 60000; //60 seconds at 5v 69 | } 70 | else{ 71 | CoPwrState = LOW; 72 | currCoPwrTimer = 90000; //90 seconds at 1.4v 73 | } 74 | if(indicatorAttached) digitalWrite(_CoIndicatorPin, CoPwrState); 75 | digitalWrite(_CoTogPin, CoPwrState); 76 | } 77 | } 78 | 79 | boolean CS_MQ7::currentState(){ 80 | 81 | if(CoPwrState == LOW){ 82 | return false; 83 | } 84 | else{ 85 | return true; 86 | } 87 | } -------------------------------------------------------------------------------- /sensors/MQ7 Arduino Library/CS_MQ7/CS_MQ7.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | CS_MQ7_02.h - Library for reading the MQ-7 Carbon Monoxide Sensor 4 | Breakout, as part of the Citizen Sensor project. 5 | http://citizensensor.cc 6 | 7 | Released into the public domain. 8 | 9 | Created by J Saavedra, October 2010. 10 | http://jos.ph 11 | 12 | */ 13 | 14 | #ifndef CS_MQ7_h 15 | #define CS_MQ7_h 16 | 17 | class CS_MQ7{ 18 | 19 | public: 20 | 21 | CS_MQ7(int CoTogPin, int CoIndicatorPin); 22 | CS_MQ7(int CoTogPin); 23 | void CoPwrCycler(); 24 | boolean currentState(); 25 | 26 | unsigned long time; 27 | unsigned long currTime; 28 | unsigned long prevTime; 29 | unsigned long currCoPwrTimer; 30 | 31 | boolean CoPwrState; 32 | boolean indicatorAttached; 33 | 34 | private: 35 | int _CoIndicatorPin; 36 | int _CoTogPin; 37 | 38 | }; 39 | 40 | #endif -------------------------------------------------------------------------------- /sensors/MQ7 Arduino Library/CS_MQ7/examples/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmsaavedra/Citizen-Sensor/3c399e08289bcb9d6373831019956d3e6263dc70/sensors/MQ7 Arduino Library/CS_MQ7/examples/.DS_Store -------------------------------------------------------------------------------- /sensors/MQ7 Arduino Library/CS_MQ7/examples/CS_MQ7/CS_MQ7.pde: -------------------------------------------------------------------------------- 1 | /* 2 | Citizen Sensor 3 | http://citizensensor.cc 4 | MQ-7 Carbon Monoxide Sensor 5 | Power Cycle + Analog Read 6 | 7 | for this example: 8 | - the "tog" pin of the breakout should be connected to digital pin 12. 9 | - the "out" pin of the breakout should be connected to analog pin 0. 10 | 11 | >> When the sensor is receiving 5v of power, the LED Indicator (Pin 13) will 12 | >> be ON. During this time data the data being output is NOT readable. 13 | >> When the sensor is receiving 1.4v or power, the LED Indicator will be 14 | >> OFF. This when the data being output is USABLE. 15 | 16 | */ 17 | 18 | #include 19 | 20 | CS_MQ7 MQ7(12, 13); // 12 = digital Pin connected to "tog" from sensor board 21 | // 13 = digital Pin connected to LED Power Indicator 22 | 23 | int CoSensorOutput = 0; //analog Pin connected to "out" from sensor board 24 | int CoData = 0; //analog sensor data 25 | 26 | void setup(){ 27 | 28 | Serial.begin(9600); 29 | } 30 | 31 | void loop(){ 32 | 33 | MQ7.CoPwrCycler(); 34 | 35 | 36 | /* your code here and below! */ 37 | 38 | if(MQ7.CurrentState() == LOW){ //we are at 1.4v, read sensor data! 39 | CoData = analogRead(CoSensorOutput); 40 | Serial.println(CoData); 41 | } 42 | else{ //sensor is at 5v, heating time 43 | Serial.println("sensor heating!"); 44 | } 45 | } 46 | 47 | -------------------------------------------------------------------------------- /sensors/MQ7 Breakout/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmsaavedra/Citizen-Sensor/3c399e08289bcb9d6373831019956d3e6263dc70/sensors/MQ7 Breakout/.DS_Store -------------------------------------------------------------------------------- /sensors/MQ7 Breakout/CS_MQ7/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmsaavedra/Citizen-Sensor/3c399e08289bcb9d6373831019956d3e6263dc70/sensors/MQ7 Breakout/CS_MQ7/.DS_Store -------------------------------------------------------------------------------- /sensors/MQ7 Breakout/CS_MQ7/CS_MQ7.cpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | CS_MQ7_02.h - Library for reading the MQ-7 Carbon Monoxide Sensor 4 | Breakout, as part of the Citizen Sensor project. 5 | http://citizensensor.cc 6 | 7 | Released into the public domain. 8 | 9 | Created by J Saavedra, October 2010. 10 | http://jos.ph 11 | 12 | */ 13 | 14 | #if (ARDUINO >= 100) 15 | #include "Arduino.h" 16 | #else 17 | #include 18 | #include "WProgram.h" 19 | #endif 20 | 21 | #include "CS_MQ7.h" 22 | 23 | CS_MQ7::CS_MQ7(int CoTogPin, int CoIndicatorPin){ 24 | 25 | pinMode(CoIndicatorPin, OUTPUT); 26 | pinMode(CoTogPin, OUTPUT); 27 | 28 | _CoIndicatorPin = CoIndicatorPin; 29 | _CoTogPin = CoTogPin; 30 | 31 | indicatorAttached = true; //we are using an LED to show heater 32 | 33 | time = 0; 34 | currTime = 0; 35 | prevTime = 0; 36 | currCoPwrTimer = 0; 37 | CoPwrState = LOW; 38 | currCoPwrTimer = 500; 39 | 40 | } 41 | 42 | CS_MQ7::CS_MQ7(int CoTogPin){ 43 | 44 | pinMode(CoTogPin, OUTPUT); 45 | 46 | indicatorAttached = false; //not using an LED 47 | 48 | _CoTogPin = CoTogPin; 49 | 50 | time = 0; 51 | currTime = 0; 52 | prevTime = 0; 53 | currCoPwrTimer = 0; 54 | CoPwrState = LOW; 55 | currCoPwrTimer = 500; 56 | 57 | } 58 | 59 | void CS_MQ7::CoPwrCycler(){ 60 | 61 | currTime = millis(); 62 | 63 | if (currTime - prevTime > currCoPwrTimer){ 64 | prevTime = currTime; 65 | 66 | if(CoPwrState == LOW){ 67 | CoPwrState = HIGH; 68 | currCoPwrTimer = 60000; //60 seconds at 5v 69 | } 70 | else{ 71 | CoPwrState = LOW; 72 | currCoPwrTimer = 90000; //90 seconds at 1.4v 73 | } 74 | if(indicatorAttached) digitalWrite(_CoIndicatorPin, CoPwrState); 75 | digitalWrite(_CoTogPin, CoPwrState); 76 | } 77 | } 78 | 79 | boolean CS_MQ7::currentState(){ 80 | 81 | if(CoPwrState == LOW){ 82 | return false; 83 | } 84 | else{ 85 | return true; 86 | } 87 | } -------------------------------------------------------------------------------- /sensors/MQ7 Breakout/CS_MQ7/CS_MQ7.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | CS_MQ7_02.h - Library for reading the MQ-7 Carbon Monoxide Sensor 4 | Breakout, as part of the Citizen Sensor project. 5 | http://citizensensor.cc 6 | 7 | Released into the public domain. 8 | 9 | Created by J Saavedra, October 2010. 10 | http://jos.ph 11 | 12 | */ 13 | 14 | #ifndef CS_MQ7_h 15 | #define CS_MQ7_h 16 | 17 | class CS_MQ7{ 18 | 19 | public: 20 | 21 | CS_MQ7(int CoTogPin, int CoIndicatorPin); 22 | CS_MQ7(int CoTogPin); 23 | void CoPwrCycler(); 24 | boolean currentState(); 25 | 26 | unsigned long time; 27 | unsigned long currTime; 28 | unsigned long prevTime; 29 | unsigned long currCoPwrTimer; 30 | 31 | boolean CoPwrState; 32 | boolean indicatorAttached; 33 | 34 | private: 35 | int _CoIndicatorPin; 36 | int _CoTogPin; 37 | 38 | }; 39 | 40 | #endif -------------------------------------------------------------------------------- /sensors/MQ7 Breakout/CS_MQ7/examples/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmsaavedra/Citizen-Sensor/3c399e08289bcb9d6373831019956d3e6263dc70/sensors/MQ7 Breakout/CS_MQ7/examples/.DS_Store -------------------------------------------------------------------------------- /sensors/MQ7 Breakout/CS_MQ7/examples/CS_MQ7/CS_MQ7.pde: -------------------------------------------------------------------------------- 1 | /* 2 | Citizen Sensor 3 | http://citizensensor.cc 4 | MQ-7 Carbon Monoxide Sensor 5 | Power Cycle + Analog Read 6 | 7 | for this example: 8 | - the "tog" pin of the breakout should be connected to digital pin 12. 9 | - the "out" pin of the breakout should be connected to analog pin 0. 10 | 11 | >> When the sensor is receiving 5v of power, the LED Indicator (Pin 13) will 12 | >> be ON. During this time data the data being output is NOT readable. 13 | >> When the sensor is receiving 1.4v or power, the LED Indicator will be 14 | >> OFF. This when the data being output is USABLE. 15 | 16 | */ 17 | 18 | #include 19 | 20 | CS_MQ7 MQ7(12, 13); // 12 = digital Pin connected to "tog" from sensor board 21 | // 13 = digital Pin connected to LED Power Indicator 22 | 23 | int CoSensorOutput = 0; //analog Pin connected to "out" from sensor board 24 | int CoData = 0; //analog sensor data 25 | 26 | void setup(){ 27 | 28 | Serial.begin(9600); 29 | } 30 | 31 | void loop(){ 32 | 33 | MQ7.CoPwrCycler(); 34 | 35 | 36 | /* your code here and below! */ 37 | 38 | if(MQ7.CurrentState() == LOW){ //we are at 1.4v, read sensor data! 39 | CoData = analogRead(CoSensorOutput); 40 | Serial.println(CoData); 41 | } 42 | else{ //sensor is at 5v, heating time 43 | Serial.println("sensor heating!"); 44 | } 45 | } 46 | 47 | -------------------------------------------------------------------------------- /sensors/MQ7 eagle files/COsensor03.brd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmsaavedra/Citizen-Sensor/3c399e08289bcb9d6373831019956d3e6263dc70/sensors/MQ7 eagle files/COsensor03.brd -------------------------------------------------------------------------------- /sensors/MQ7 eagle files/COsensor03.sch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmsaavedra/Citizen-Sensor/3c399e08289bcb9d6373831019956d3e6263dc70/sensors/MQ7 eagle files/COsensor03.sch -------------------------------------------------------------------------------- /sensors/readme.textile: -------------------------------------------------------------------------------- 1 | Citizen Sensor 2 | 3 | http://citizensensor.cc 4 | 5 | **MQ-7 Carbon Monoxide sensor** 6 | > schematics, .sch, .brd of PCB 7 | > arduino library to be used with the Citizen Sensor MQ-7 Breakout Kit. 8 | > http://thesis.jmsaavedra.com/kit/mq-7-breakout-kit-maker-faire-talk/ 9 | > www.instructables.com/id/Citizen-Sensor-MQ-7-Carbon-Monoxide-Breakout-Kit/ -------------------------------------------------------------------------------- /sensors/readme.txt: -------------------------------------------------------------------------------- 1 | Citizen Sensor 2 | 3 | http://citizensensor.cc 4 | 5 | **MQ-7 Carbon Monoxide sensor** 6 | > schematics, .sch, .brd of PCB 7 | > arduino library to be used with the Citizen Sensor MQ-7 Breakout Kit. 8 | > http://thesis.jmsaavedra.com/kit/mq-7-breakout-kit-maker-faire-talk/ 9 | > www.instructables.com/id/Citizen-Sensor-MQ-7-Carbon-Monoxide-Breakout-Kit/ -------------------------------------------------------------------------------- /stationary/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmsaavedra/Citizen-Sensor/3c399e08289bcb9d6373831019956d3e6263dc70/stationary/.DS_Store -------------------------------------------------------------------------------- /stationary/XBeeScripts/pachube_functions.php: -------------------------------------------------------------------------------- 1 | Api = $api; 46 | $this->Pachube = "www.pachube.com"; 47 | $this->Pachube_headers = array("X-PachubeApiKey: $this->Api"); 48 | } 49 | 50 | 51 | 52 | 53 | 54 | /********************* Methods *****************************/ 55 | 56 | // Update a Pachube manual feed 57 | 58 | public function updatePachube ( $url='', $data='' ) 59 | { 60 | if(empty($this->Api)) 61 | { 62 | return 401; 63 | } else 64 | { 65 | if(!empty($url)) 66 | { 67 | $request = $this->putRequestToPachube($url, $data); 68 | return $request; 69 | 70 | }else 71 | { 72 | return 998; 73 | } 74 | } 75 | } 76 | 77 | public function updatePachubeDatastream ( $feed='', $datastream='', $value='' ) 78 | { 79 | if(empty($this->Api)) 80 | { 81 | return 401; 82 | } else 83 | { 84 | if(is_numeric($feed) && is_numeric($datastream) && is_numeric($value)) 85 | { 86 | $url = "http://$this->Pachube/api/feeds/$feed/datastreams/$datastream.csv"; 87 | $request = $this->putRequestToPachube($url, $value); 88 | return $request; 89 | 90 | }else 91 | { 92 | return 998; 93 | } 94 | } 95 | } 96 | 97 | // Retrieve a Pachube feed 98 | 99 | public function retrieveData ( $url='', $type='' ) 100 | { 101 | if(empty($this->Api)) 102 | { 103 | //trigger_error(999); 104 | return "No API present"; 105 | } else 106 | { 107 | if(!empty($url)) 108 | { 109 | 110 | if (!empty($type)) { 111 | if ((strcmp(strtolower($type), "xml") == 0) || (strcmp(strtolower($type), "json") == 0) || (strcmp(strtolower($type), "csv") == 0)){ 112 | $url = "http://$this->Pachube/api/feeds/$url.$type"; 113 | } else { 114 | $url = ""; 115 | } 116 | } 117 | $request = $this->getRequestToPachube($url); 118 | return $request; 119 | 120 | } 121 | } 122 | } 123 | 124 | 125 | 126 | // Retrieve history 127 | 128 | public function retrieveHistory ( $url='' ) 129 | { 130 | if(!empty($url)) 131 | { 132 | if(function_exists(curl_init)) 133 | { 134 | $ch = curl_init(); 135 | curl_setopt($ch, CURLOPT_URL, $url); 136 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 137 | 138 | $data = curl_exec($ch); 139 | 140 | curl_close($ch); 141 | 142 | $data_array = explode(",",$data); 143 | return $data_array; 144 | } 145 | } 146 | else return "Invalid history URL"; 147 | } 148 | 149 | 150 | 151 | // Create feed 152 | 153 | public function createFeed ( $title='' ) 154 | { 155 | if(empty($this->Api)) 156 | { 157 | return -401; 158 | } else 159 | { 160 | if(!empty($title)) 161 | { 162 | $eeml = "$title"; 163 | 164 | $request = $this->createPachube( $eeml ); 165 | return $request; 166 | 167 | }else 168 | { 169 | return -1; 170 | } 171 | } 172 | } 173 | 174 | 175 | // delete a Pachube feed 176 | 177 | public function deletePachube ( $feed_id='' ) 178 | { 179 | if(empty($this->Api)) 180 | { 181 | return 401; 182 | } else 183 | { 184 | if(is_numeric($feed_id) ) 185 | { 186 | $url = "http://$this->Pachube/api/feeds/".$feed_id; 187 | $request = $this->deleteRequestToPachube($url); 188 | return $request; 189 | 190 | }else 191 | { 192 | return 998; 193 | } 194 | } 195 | } 196 | 197 | 198 | 199 | // debug status codes returned by updatePachube() 200 | 201 | 202 | public function debugStatusCode ( $status_code ){ 203 | 204 | switch ($status_code){ 205 | case 200: 206 | $msg = "Pachube feed successfully updated"; 207 | break; 208 | 209 | case 401: 210 | $msg = "Pachube API key was incorrect"; 211 | break; 212 | 213 | case 404: 214 | $msg = "Feed ID does not exist"; 215 | break; 216 | 217 | case 422: 218 | $msg = "Unprocessable Entity, semantic errors (CSV instead of XML?)"; 219 | break; 220 | 221 | case 997: 222 | $msg = "Could not create resource: no title provided."; 223 | break; 224 | 225 | case 998: 226 | $msg = "Error in feed ID, data type or data"; 227 | break; 228 | 229 | case 999: 230 | $msg = "curl library not installed"; 231 | break; 232 | 233 | default: 234 | $msg = "Status code not recognised: ".$status_code; 235 | break; 236 | } 237 | echo $msg; 238 | } 239 | 240 | 241 | 242 | public function showGraph ( $feed_id='', $datastream_id, $width='300', $height='200', $colour='FF0066', $label=true, $grid=true, $title='', $legend='', $stroke='4' ){ 243 | 244 | if(is_numeric($feed_id)){ 245 | 246 | if(is_numeric($feed_id) && is_numeric($datastream_id)){ 247 | 248 | $legend_param = empty($legend)? "" : "&l=$legend"; 249 | $grid_param = $grid? "&g=$grid" : ""; 250 | $label_param = $label? "&b=$label" : ""; 251 | $title_param = (strcmp($title,"")==0)? "" : "&t=$title"; 252 | 253 | echo "Pachube/feeds/$feed_id/datastreams/$datastream_id/history.png?w=$width&h=$height&c=$colour$label_param$grid_param$title_param$legend_param&s=$stroke\" width=\"$width\" height=\"$height\" border=\"1\" alt=\"powered by Pachube.com\">"; 254 | 255 | } 256 | } 257 | 258 | } 259 | 260 | 261 | 262 | public function getLatLon ( $search='') 263 | { 264 | if (!empty($search)) 265 | { 266 | if(function_exists(curl_init)) 267 | { 268 | 269 | $search = urlencode($search); 270 | $url = "http://$this->Pachube/api/feeds.json?order=created_at&q=$search"; 271 | 272 | $ch = curl_init(); 273 | curl_setopt($ch, CURLOPT_URL, $url); 274 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 275 | curl_setopt($ch, CURLOPT_HTTPHEADER, $this->Pachube_headers); 276 | 277 | $data = curl_exec($ch); 278 | 279 | $headers = curl_getinfo($ch); 280 | curl_close($ch); 281 | 282 | $json_data = json_decode($data,true); 283 | 284 | //var_dump ($json_data); 285 | 286 | $reported_locations = Array(); 287 | 288 | foreach ( $json_data["results"] as $result ) 289 | { 290 | //print_r ($result); 291 | $location = $result["location"]; 292 | 293 | $this_location = Array(); 294 | 295 | $this_location["lat"] = $location["lat"]; 296 | $this_location["lon"] = $location["lon"]; 297 | 298 | array_push($reported_locations, $this_location); 299 | 300 | } 301 | 302 | return $reported_locations; 303 | } 304 | } 305 | } 306 | 307 | private function _fputc($url,$data) 308 | { 309 | $_err = __CLASS__.'::'.__FUNCTION__."($url): "; 310 | // Create a stream 311 | $opts['http']['method'] = "PUT"; 312 | $opts['http']['header'] = "X-PachubeApiKey: ".$this->Api."\r\n"; 313 | $opts['http']['header'] .= "Content-Length: " . strlen($data) . "\r\n"; 314 | $opts['http']['content'] = $data; 315 | 316 | $context = stream_context_create($opts); 317 | 318 | // Open the file using the HTTP headers set above 319 | $ret=file_get_contents($url, false, $context); 320 | if($ret==false) die('
'.$_err.' failed file_get_contents('.$url.')'); 321 | return $ret; 322 | } 323 | 324 | private function putRequestToPachube ( $url, $data) 325 | { 326 | if(function_exists('curl_init')) 327 | { 328 | 329 | $putData = tmpfile(); 330 | fwrite($putData, $data); 331 | fseek($putData, 0); 332 | 333 | $ch = curl_init(); 334 | curl_setopt($ch, CURLOPT_URL, $url); 335 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 336 | curl_setopt($ch, CURLOPT_HTTPHEADER, $this->Pachube_headers); 337 | curl_setopt($ch, CURLOPT_INFILE, $putData); 338 | curl_setopt($ch, CURLOPT_INFILESIZE, strlen($data)); 339 | curl_setopt($ch, CURLOPT_PUT, true); 340 | 341 | curl_exec($ch); 342 | 343 | $headers = curl_getinfo($ch); 344 | fclose($putData); 345 | curl_close($ch); 346 | 347 | return $headers['http_code']; 348 | 349 | } 350 | 351 | if(function_exists('file_put_contents') && ini_get('allow_url_fopen')) 352 | { 353 | return $this->_fputc($url,$data); 354 | } 355 | 356 | return 999; 357 | } 358 | 359 | private function _fgetc($url) 360 | { 361 | // Create a stream 362 | $opts['http']['method'] = "GET"; 363 | $opts['http']['header'] = "X-PachubeApiKey: ".$this->Api."\r\n"; 364 | $context = stream_context_create($opts); 365 | 366 | // Open the file using the HTTP headers set above 367 | return file_get_contents($url, false, $context); 368 | } 369 | 370 | private function _curl($url) 371 | { 372 | $ch = curl_init(); 373 | curl_setopt($ch, CURLOPT_URL, $url); 374 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 375 | curl_setopt($ch, CURLOPT_HTTPHEADER, $this->Pachube_headers); 376 | 377 | $ret = curl_exec($ch); 378 | $headers = curl_getinfo($ch); 379 | curl_close($ch); 380 | 381 | return $ret; 382 | } 383 | 384 | // Actual request that retrieved Pachube data 385 | private function getRequestToPachube ( $url ) 386 | { 387 | if(function_exists('curl_init')) 388 | { 389 | return $this->_curl($url); 390 | } 391 | 392 | if(function_exists('file_get_contents') && ini_get('allow_url_fopen')) 393 | { 394 | return $this->_fgetc($url); 395 | } 396 | 397 | return 999; 398 | } 399 | 400 | 401 | 402 | 403 | // Actual request that creates the Pachube feed 404 | 405 | private function createPachube ( $eeml='' ) 406 | { 407 | $ret = -1; 408 | { 409 | if(function_exists(curl_init)) 410 | { 411 | $url = "http://$this->Pachube/api.xml"; 412 | 413 | $ch = curl_init(); 414 | curl_setopt($ch, CURLOPT_URL, $url); 415 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 416 | curl_setopt($ch, CURLOPT_HTTPHEADER, $this->Pachube_headers); 417 | curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); 418 | curl_setopt($ch, CURLOPT_POST, true); 419 | curl_setopt($ch, CURLOPT_HEADER, true); 420 | curl_setopt($ch, CURLOPT_POSTFIELDS, $eeml); 421 | 422 | $return = curl_exec($ch); 423 | 424 | $headers = curl_getinfo($ch); 425 | 426 | curl_close($ch); 427 | 428 | $status = $headers['http_code']; 429 | 430 | if ($status != 201) { 431 | $ret = -$status; 432 | } else { 433 | $ret = trim($this->stringBetween($return,"Location: http://$this->Pachube/api/feeds/","\n")); 434 | } 435 | } 436 | else 437 | { 438 | $ret = -999; 439 | } 440 | } 441 | 442 | return $ret; 443 | } 444 | 445 | 446 | // Actual request that makes the Pachube delete 447 | 448 | private function deleteRequestToPachube ( $url='') 449 | { 450 | $ret = -1; 451 | { 452 | if(function_exists(curl_init)) 453 | { 454 | $ch = curl_init(); 455 | curl_setopt($ch, CURLOPT_URL, $url); 456 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 457 | curl_setopt($ch, CURLOPT_HTTPHEADER, $this->Pachube_headers); 458 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE"); 459 | 460 | curl_exec($ch); 461 | 462 | $headers = curl_getinfo($ch); 463 | 464 | curl_close($ch); 465 | 466 | $ret = $headers['http_code']; 467 | 468 | } 469 | else 470 | { 471 | $ret = 999; 472 | } 473 | } 474 | 475 | return $ret; 476 | } 477 | 478 | 479 | 480 | private function stringBetween($content,$start,$end) 481 | 482 | { 483 | 484 | $r = explode($start, $content); 485 | if (isset($r[1])){ 486 | $r = explode($end, $r[1]); 487 | return $r[0]; 488 | } 489 | return ''; 490 | 491 | } 492 | 493 | public function environment($feed_id) 494 | 495 | { 496 | $data = json_decode($this->retrieveData ( $feed_id, "json" ), true); 497 | //print_r ($data); 498 | $return_data = (strcmp($data,"Unable to find specified resource.")==0) ? json_decode("{\"location\":{}\"datastreams\":[{}]}") : $data; 499 | return $return_data; 500 | } 501 | 502 | public function showEnvironmentGraph($environment, $datastream_id, $width='300', $height='200', $colour='FF0066', $label=true, $grid=true, $title='', $legend='', $stroke='4' ) 503 | 504 | { 505 | $feed_id = $environment['id']; 506 | $this->showGraph($feed_id, $datastream_id, $width, $height, $colour, $label, $grid, $title, $legend, $stroke ); 507 | } 508 | 509 | 510 | public function showEnvironmentMap( $environment, $width, $height, $google_map_key) 511 | 512 | { 513 | 514 | if (strcmp($environment, "") !=0){ 515 | 516 | $width.="px"; 517 | $height.="px"; 518 | 519 | $lat = $environment['location']['lat']; 520 | $lon = $environment['location']['lon']; 521 | $gmap_text = << 523 | END; 524 | 525 | echo $gmap_text; 526 | 527 | } 528 | 529 | } 530 | 531 | 532 | }?> -------------------------------------------------------------------------------- /stationary/XBeeScripts/phptest.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmsaavedra/Citizen-Sensor/3c399e08289bcb9d6373831019956d3e6263dc70/stationary/XBeeScripts/phptest.txt -------------------------------------------------------------------------------- /stationary/XBeeScripts/wt.php: -------------------------------------------------------------------------------- 1 | updatePachube ( $url, $data ); 32 | echo "1"; 33 | //$pachube->debugStatusCode($update_status); 34 | 35 | ?> -------------------------------------------------------------------------------- /stationary/XBeeScripts/xbeeupdate.php: -------------------------------------------------------------------------------- 1 | updatePachube ( $url, $data ); 32 | $pachube->debugStatusCode($update_status); 33 | 34 | ?> -------------------------------------------------------------------------------- /stationary/arduino/current/weatherTunnelSensorUnit/LCD copy.ino: -------------------------------------------------------------------------------- 1 | 2 | 3 | void lcdSetup(){ 4 | int scrollDelay = 400; //400 looks good 5 | lcd.begin(16,2); 6 | String IntroMsg = " Welcome to the Weather Tunnel Project! "; 7 | lcd.clear(); 8 | lcd.setCursor(0,0); 9 | lcd.print("Hello "+institutionName +"!"); 10 | delay(2000); 11 | for(int IntroMsgIndex = 0; IntroMsgIndex < institutionName.length(); IntroMsgIndex++){ 12 | lcd.scrollDisplayLeft(); 13 | delay(scrollDelay); 14 | } 15 | delay(100); 16 | lcd.clear(); 17 | lcd.setCursor(0,1); 18 | lcd.print(IntroMsg); 19 | delay(1000); 20 | for(int IntroMsgIndex = 0; IntroMsgIndex < 25; IntroMsgIndex++){ 21 | //if(IntroMsgIndex<38) lcd.print(IntroMsg.charAt(IntroMsgIndex)); 22 | lcd.scrollDisplayLeft(); 23 | delay(scrollDelay); 24 | } 25 | lcd.noAutoscroll(); 26 | lcd.clear(); 27 | lcd.setCursor(0,0); 28 | lcd.print("initializing"); 29 | lcdStatusBar(); 30 | lcdStatusBar(); 31 | lcdStatusBar(); 32 | } 33 | 34 | void lcdUpdater(int sensor, int reading){ 35 | 36 | if(sensor == 0){ 37 | lcd.setCursor(0,1); 38 | lcd.print("temp: "); 39 | } 40 | else if(sensor == 1){ 41 | lcd.setCursor(0,1); 42 | lcd.print("light: "); 43 | } 44 | else if(sensor == 2){ 45 | lcd.setCursor(0,1); 46 | lcd.print("humidity: "); 47 | } 48 | else if(sensor == 3){ 49 | lcd.setCursor(0,1); 50 | lcd.print("noise: "); 51 | } 52 | else if(sensor == 4){ 53 | lcd.setCursor(0,1); 54 | lcd.print("CO2: "); 55 | } 56 | else if(sensor == 5){ 57 | lcd.setCursor(0,1); 58 | lcd.print("CO: "); 59 | } 60 | else if(sensor == 6){ 61 | lcd.setCursor(0,1); 62 | lcd.print("Air Qual: "); 63 | } 64 | 65 | lcd.setCursor(0,0); 66 | if(sensor==0 || sensor==3){ 67 | lcd.print("SENSING> "); 68 | } 69 | else if(sensor==1 || sensor==4){ 70 | lcd.print("SENSING>> "); 71 | } 72 | else if(sensor==2 || sensor==5){ 73 | lcd.print("SENSING>>>"); 74 | } 75 | else if(sensor==6){ 76 | lcd.print("SENSING >>"); 77 | } 78 | 79 | lcd.setCursor(11,1); 80 | lcd.print(reading); 81 | lcd.setCursor(11,0); 82 | int timer = (millis() - lastConnectionTime)/1000; //time since last successful data upload 83 | lcd.print(timer); 84 | lcd.print("sec"); 85 | breatheGreenLED(); 86 | } 87 | 88 | void lcdEthernet(byte ip[], byte subnet[], byte gateway[], String feedAddr){ 89 | 90 | int infoDelay = 2000; 91 | //show IP address 92 | lcd.clear(); 93 | lcd.setCursor(0,0); 94 | lcd.print("Ethernet IP addr"); 95 | lcd.setCursor(0,1); 96 | for(int i=0; i<=3; i++){ 97 | lcd.print(int(ip[i])); 98 | if(i<3) lcd.print("."); 99 | } 100 | delay(infoDelay); 101 | 102 | //show subnet mask 103 | lcd.clear(); 104 | lcd.setCursor(0,0); 105 | lcd.print("Ethernet subnet"); 106 | lcd.setCursor(0,1); 107 | for(int i=0; i<=3; i++){ 108 | lcd.print(int(subnet[i])); 109 | if(i<3) lcd.print("."); 110 | } 111 | delay(infoDelay); 112 | 113 | //show gateway 114 | lcd.clear(); 115 | lcd.setCursor(0,0); 116 | lcd.print("Ethernet gateway"); 117 | lcd.setCursor(0,1); 118 | for(int i=0; i<=3; i++){ 119 | lcd.print(int(gateway[i])); 120 | if(i<3) lcd.print("."); 121 | } 122 | delay(infoDelay); 123 | 124 | //show gateway 125 | lcd.clear(); 126 | lcd.setCursor(0,0); 127 | lcd.print("Pachube Feed ID:"); 128 | lcd.setCursor(0,1); 129 | lcd.print(feedAddr); 130 | delay(infoDelay); 131 | } 132 | 133 | // --------------------------------- 134 | //These are debug message functions! 135 | void lcdConnect(){ 136 | lcd.setCursor(0,1); 137 | lcd.print("Connection opened "); 138 | lcd.setCursor(12,0); 139 | } 140 | 141 | void lcdPUT(){ 142 | lcd.setCursor(0,1); 143 | lcd.print("PUT req. started "); 144 | lcd.setCursor(13,0); 145 | } 146 | void lcdPachubeConnect(){ 147 | lcd.setCursor(0,1); 148 | lcd.print("API credentials "); 149 | lcd.setCursor(14,0); 150 | } 151 | 152 | void lcdDataPUT(){ 153 | lcd.setCursor(0,1); 154 | lcd.print("PUT Data "); 155 | lcd.setCursor(15,0); 156 | } 157 | 158 | void lcdStatusBar(){ 159 | lcd.print("."); 160 | delay(1000); 161 | } 162 | 163 | void lcdConnectionFail(){ 164 | Serial.println("*** connection failed ***"); 165 | lcd.clear(); 166 | lcd.setCursor(0,0); 167 | lcd.print("Connection Fail"); 168 | lcd.setCursor(0,1); 169 | lcd.print("chck IP/subnt/gt"); 170 | flashRedLED(); 171 | } 172 | 173 | void lcdResetNow(){ 174 | lcd.clear(); 175 | lcd.setCursor(0,1); 176 | lcd.print("RESETTING BOARD NOW"); 177 | flashRedLED(); 178 | } 179 | 180 | -------------------------------------------------------------------------------- /stationary/arduino/current/weatherTunnelSensorUnit/LCD.ino: -------------------------------------------------------------------------------- 1 | 2 | 3 | void lcdSetup(){ 4 | int scrollDelay = 400; //400 looks good 5 | lcd.begin(16,2); 6 | String IntroMsg = " Welcome to the Weather Tunnel Project! "; 7 | lcd.clear(); 8 | lcd.setCursor(0,0); 9 | lcd.print("Hello "+institutionName +"!"); 10 | delay(2000); 11 | for(int IntroMsgIndex = 0; IntroMsgIndex < institutionName.length(); IntroMsgIndex++){ 12 | lcd.scrollDisplayLeft(); 13 | delay(scrollDelay); 14 | } 15 | delay(100); 16 | lcd.clear(); 17 | lcd.setCursor(0,1); 18 | lcd.print(IntroMsg); 19 | delay(1000); 20 | for(int IntroMsgIndex = 0; IntroMsgIndex < 25; IntroMsgIndex++){ 21 | //if(IntroMsgIndex<38) lcd.print(IntroMsg.charAt(IntroMsgIndex)); 22 | lcd.scrollDisplayLeft(); 23 | delay(scrollDelay); 24 | } 25 | lcd.noAutoscroll(); 26 | lcd.clear(); 27 | lcd.setCursor(0,0); 28 | lcd.print("initializing"); 29 | lcdStatusBar(); 30 | lcdStatusBar(); 31 | lcdStatusBar(); 32 | } 33 | 34 | void lcdUpdater(int sensor, int reading){ 35 | 36 | if(sensor == 0){ 37 | lcd.setCursor(0,1); 38 | lcd.print("temp: "); 39 | } 40 | else if(sensor == 1){ 41 | lcd.setCursor(0,1); 42 | lcd.print("light: "); 43 | } 44 | else if(sensor == 2){ 45 | lcd.setCursor(0,1); 46 | lcd.print("humidity: "); 47 | } 48 | else if(sensor == 3){ 49 | lcd.setCursor(0,1); 50 | lcd.print("noise: "); 51 | } 52 | else if(sensor == 4){ 53 | lcd.setCursor(0,1); 54 | lcd.print("CO2: "); 55 | } 56 | else if(sensor == 5){ 57 | lcd.setCursor(0,1); 58 | lcd.print("CO: "); 59 | } 60 | else if(sensor == 6){ 61 | lcd.setCursor(0,1); 62 | lcd.print("Air Qual: "); 63 | } 64 | 65 | lcd.setCursor(0,0); 66 | if(sensor==0 || sensor==3){ 67 | lcd.print("SENSING> "); 68 | } 69 | else if(sensor==1 || sensor==4){ 70 | lcd.print("SENSING>> "); 71 | } 72 | else if(sensor==2 || sensor==5){ 73 | lcd.print("SENSING>>>"); 74 | } 75 | else if(sensor==6){ 76 | lcd.print("SENSING >>"); 77 | } 78 | 79 | lcd.setCursor(11,1); 80 | lcd.print(reading); 81 | lcd.setCursor(11,0); 82 | int timer = (millis() - lastConnectionTime)/1000; //time since last successful data upload 83 | lcd.print(timer); 84 | lcd.print("sec"); 85 | breatheGreenLED(); 86 | } 87 | 88 | void lcdEthernet(byte ip[], byte subnet[], byte gateway[], String feedAddr){ 89 | 90 | int infoDelay = 2000; 91 | //show IP address 92 | lcd.clear(); 93 | lcd.setCursor(0,0); 94 | lcd.print("Ethernet IP addr"); 95 | lcd.setCursor(0,1); 96 | for(int i=0; i<=3; i++){ 97 | lcd.print(int(ip[i])); 98 | if(i<3) lcd.print("."); 99 | } 100 | delay(infoDelay); 101 | 102 | //show subnet mask 103 | lcd.clear(); 104 | lcd.setCursor(0,0); 105 | lcd.print("Ethernet subnet"); 106 | lcd.setCursor(0,1); 107 | for(int i=0; i<=3; i++){ 108 | lcd.print(int(subnet[i])); 109 | if(i<3) lcd.print("."); 110 | } 111 | delay(infoDelay); 112 | 113 | //show gateway 114 | lcd.clear(); 115 | lcd.setCursor(0,0); 116 | lcd.print("Ethernet gateway"); 117 | lcd.setCursor(0,1); 118 | for(int i=0; i<=3; i++){ 119 | lcd.print(int(gateway[i])); 120 | if(i<3) lcd.print("."); 121 | } 122 | delay(infoDelay); 123 | 124 | //show gateway 125 | lcd.clear(); 126 | lcd.setCursor(0,0); 127 | lcd.print("Pachube Feed ID:"); 128 | lcd.setCursor(0,1); 129 | lcd.print(feedAddr); 130 | delay(infoDelay); 131 | } 132 | 133 | // --------------------------------- 134 | //These are debug message functions! 135 | void lcdConnect(){ 136 | lcd.setCursor(0,1); 137 | lcd.print("Connection opened "); 138 | lcd.setCursor(12,0); 139 | } 140 | 141 | void lcdPUT(){ 142 | lcd.setCursor(0,1); 143 | lcd.print("PUT req. started "); 144 | lcd.setCursor(13,0); 145 | } 146 | void lcdPachubeConnect(){ 147 | lcd.setCursor(0,1); 148 | lcd.print("API credentials "); 149 | lcd.setCursor(14,0); 150 | } 151 | 152 | void lcdDataPUT(){ 153 | lcd.setCursor(0,1); 154 | lcd.print("PUT Data "); 155 | lcd.setCursor(15,0); 156 | } 157 | 158 | void lcdStatusBar(){ 159 | lcd.print("."); 160 | delay(1000); 161 | } 162 | 163 | void lcdConnectionFail(){ 164 | Serial.println("*** connection failed ***"); 165 | lcd.clear(); 166 | lcd.setCursor(0,0); 167 | lcd.print("Connection Fail"); 168 | lcd.setCursor(0,1); 169 | lcd.print("chck IP/subnt/gt"); 170 | flashRedLED(); 171 | } 172 | 173 | void lcdResetNow(){ 174 | lcd.clear(); 175 | lcd.setCursor(0,1); 176 | lcd.print("RESETTING BOARD NOW"); 177 | flashRedLED(); 178 | } 179 | 180 | -------------------------------------------------------------------------------- /stationary/arduino/current/weatherTunnelSensorUnit/LEDs copy.ino: -------------------------------------------------------------------------------- 1 | 2 | 3 | //RESET function is at the bottom 4 | 5 | void setupLedFlash(){ 6 | pinMode(13, OUTPUT); 7 | pinMode(12, OUTPUT); 8 | for(int i=0; i<3; i++){ 9 | digitalWrite(13, HIGH); 10 | digitalWrite(12, LOW); 11 | delay(150); 12 | digitalWrite(13, LOW); 13 | digitalWrite(12, HIGH); 14 | delay(150); 15 | } 16 | digitalWrite(12, LOW); 17 | } 18 | 19 | void breatheGreenLED(){ 20 | for(int i=0; i<200; i++){ 21 | analogWrite(13, i); 22 | delay(8); 23 | } 24 | for(int i=199; i>0; i--){ 25 | analogWrite(13, i); 26 | delay(8); 27 | } 28 | analogWrite(13, 0); 29 | } 30 | 31 | 32 | void flashRedLED(){ 33 | pinMode(12, OUTPUT); 34 | for(int i=0; i<12; i++){ 35 | digitalWrite(12, HIGH); 36 | delay(250); 37 | digitalWrite(12, LOW); 38 | delay(250); 39 | } 40 | } 41 | 42 | void flashGreenLED(){ 43 | pinMode(13, OUTPUT); 44 | for(int i=0; i<3; i++){ 45 | digitalWrite(13, HIGH); 46 | delay(250); 47 | digitalWrite(13, LOW); 48 | delay(250); 49 | } 50 | } 51 | 52 | void softwareReset(){ 53 | //this function will pull the RESET PIN to LOW, causing the entire Arduino 54 | //and Ethernet Shield to reset themselves. 55 | Serial.println("Resetting board"); 56 | lcdResetNow(); 57 | digitalWrite(softwareResetPin, LOW); 58 | } 59 | 60 | -------------------------------------------------------------------------------- /stationary/arduino/current/weatherTunnelSensorUnit/LEDs.ino: -------------------------------------------------------------------------------- 1 | 2 | 3 | //RESET function is at the bottom 4 | 5 | void setupLedFlash(){ 6 | pinMode(13, OUTPUT); 7 | pinMode(12, OUTPUT); 8 | for(int i=0; i<3; i++){ 9 | digitalWrite(13, HIGH); 10 | digitalWrite(12, LOW); 11 | delay(150); 12 | digitalWrite(13, LOW); 13 | digitalWrite(12, HIGH); 14 | delay(150); 15 | } 16 | digitalWrite(12, LOW); 17 | } 18 | 19 | void breatheGreenLED(){ 20 | for(int i=0; i<200; i++){ 21 | analogWrite(13, i); 22 | delay(8); 23 | } 24 | for(int i=199; i>0; i--){ 25 | analogWrite(13, i); 26 | delay(8); 27 | } 28 | analogWrite(13, 0); 29 | } 30 | 31 | 32 | void flashRedLED(){ 33 | pinMode(12, OUTPUT); 34 | for(int i=0; i<12; i++){ 35 | digitalWrite(12, HIGH); 36 | delay(250); 37 | digitalWrite(12, LOW); 38 | delay(250); 39 | } 40 | } 41 | 42 | void flashGreenLED(){ 43 | pinMode(13, OUTPUT); 44 | for(int i=0; i<3; i++){ 45 | digitalWrite(13, HIGH); 46 | delay(250); 47 | digitalWrite(13, LOW); 48 | delay(250); 49 | } 50 | } 51 | 52 | void softwareReset(){ 53 | //this function will pull the RESET PIN to LOW, causing the entire Arduino 54 | //and Ethernet Shield to reset themselves. 55 | Serial.println("Resetting board"); 56 | lcdResetNow(); 57 | digitalWrite(softwareResetPin, LOW); 58 | } 59 | 60 | -------------------------------------------------------------------------------- /stationary/arduino/current/weatherTunnelSensorUnit/sensors copy.ino: -------------------------------------------------------------------------------- 1 | 2 | //the number of readings to be taken for averaging 3 | //analog sensors, each time they are called 4 | #define NUMREADINGS 25 5 | //debounce time 6 | #define DEBOUNCETIME 10 7 | 8 | //---------- temperature ---------- 9 | int getTemperature(){ 10 | byte tmp102comm = Wire.requestFrom(72,2); 11 | if (tmp102comm == 2) { 12 | byte msb = Wire.receive(); /* Whole degrees */ 13 | byte lsb = Wire.receive(); /* Fractional degrees */ 14 | int val = ((msb) << 4); /* MSB */ 15 | val |= (lsb >> 4); /* LSB */ 16 | float celsius = (val*0.0625)-5; 17 | float farenheit = (celsius*1.8) + 32; 18 | /*Serial.print("C: "); 19 | Serial.println(celsius); 20 | Serial.print("F: "); 21 | Serial.println(farenheit); 22 | Serial.println(); 23 | delay(1000);*/ 24 | return int(celsius); 25 | } 26 | } 27 | 28 | //---------- light ---------- 29 | int getLight(){ 30 | int lightVal = 0; 31 | lightVal = analogRead(2); 32 | delay(DEBOUNCETIME); 33 | return lightVal; 34 | } 35 | 36 | //---------- humidity ---------- 37 | int getHumidity(){ 38 | int humidityVal = 0; 39 | for(int i=0; i 0){ 56 | tempRead = abs(tempRead - 300); 57 | noiseVal = noiseVal + tempRead; 58 | ctr++; 59 | delay(DEBOUNCETIME); 60 | } 61 | } 62 | noiseVal = noiseVal/ctr; 63 | return noiseVal; 64 | } 65 | 66 | //---------- carbon dioxide ---------- 67 | int getCO2(){ 68 | int CO2Val = 0; 69 | for(int i=0; i> 4); /* LSB */ 16 | float celsius = (val*0.0625)-5; 17 | float farenheit = (celsius*1.8) + 32; 18 | /*Serial.print("C: "); 19 | Serial.println(celsius); 20 | Serial.print("F: "); 21 | Serial.println(farenheit); 22 | Serial.println(); 23 | delay(1000);*/ 24 | return int(celsius); 25 | } 26 | } 27 | 28 | //---------- light ---------- 29 | int getLight(){ 30 | int lightVal = 0; 31 | lightVal = analogRead(2); 32 | delay(DEBOUNCETIME); 33 | return lightVal; 34 | } 35 | 36 | //---------- humidity ---------- 37 | int getHumidity(){ 38 | int humidityVal = 0; 39 | for(int i=0; i 0){ 56 | tempRead = abs(tempRead - 300); 57 | noiseVal = noiseVal + tempRead; 58 | ctr++; 59 | delay(DEBOUNCETIME); 60 | } 61 | } 62 | noiseVal = noiseVal/ctr; 63 | return noiseVal; 64 | } 65 | 66 | //---------- carbon dioxide ---------- 67 | int getCO2(){ 68 | int CO2Val = 0; 69 | for(int i=0; i 63 | #include 64 | #include 65 | #include 66 | #include 67 | 68 | LiquidCrystal lcd(49, 45, 29, 27, 25, 23); 69 | 70 | CS_MQ7 MQ7(14, 6); //Citizen Sensor MQ-7 Carbon Monoxide Breakout instance 71 | int CoPrev = 0; //for storing CO Data 72 | 73 | Client client(server, 80); 74 | 75 | long lastConnectionTime = 0; // last time you connected to the server, in milliseconds 76 | boolean lastConnected = false; // state of the connection last time through the main loop 77 | const int postingInterval = 30000; //delay between updates to Pachube.com, in milliseconds 78 | const int softwareResetPin = 7; //connect this pin to RESET pin 79 | const long int resetInterval = 120000; //if no successful connection has been made in 2 min, RESET board 80 | 81 | void setup() { 82 | digitalWrite(softwareResetPin, HIGH); //softwareReset hack 83 | pinMode(softwareResetPin, OUTPUT); //softwareReset hack 84 | Serial.begin(9600); 85 | Serial.println("start setup"); 86 | lcdSetup(); 87 | Ethernet.begin(mac, ip); 88 | lcdEthernet(ip, subnet, gateway, feedAddr); 89 | Wire.begin(); 90 | lastConnectionTime = millis(); 91 | Serial.println("end setup"); 92 | delay(1000); 93 | setupLedFlash(); 94 | lcd.clear(); 95 | } 96 | 97 | void loop() { 98 | Serial.println("Reading Sensors..."); 99 | lcd.clear(); 100 | String dataString = " "; //will hold all sensor data 101 | 102 | // read the sensors: 103 | Serial.println("sensor 0 - temperature..."); //temperature 104 | int sensor0_reading = 0; 105 | sensor0_reading = getTemperature(); 106 | dataString = String(sensor0_reading); 107 | lcdUpdater(0, sensor0_reading); 108 | Serial.println(dataString); 109 | 110 | Serial.println("sensor 1 - light..."); //light 111 | int sensor1_reading = 0; 112 | sensor1_reading = getLight(); 113 | dataString += ","; 114 | dataString = dataString + String(sensor1_reading); 115 | lcdUpdater(1, sensor1_reading); 116 | Serial.println(dataString); 117 | 118 | Serial.println("sensor 2 - humidity..."); //humidity 119 | int sensor2_reading = getHumidity(); 120 | dataString += ","; 121 | dataString = dataString + String(sensor2_reading); 122 | lcdUpdater(2, sensor2_reading); 123 | Serial.println(dataString); 124 | 125 | Serial.println("sensor 3 - noise..."); //noise 126 | int sensor3_reading = getNoise(); 127 | dataString += ","; 128 | dataString = dataString + String(sensor3_reading); 129 | lcdUpdater(3, sensor3_reading); 130 | Serial.println(dataString); 131 | 132 | Serial.println("sensor 4 - CO2..."); //CO2 133 | //int sensor4_reading = analogRead(8); 134 | int sensor4_reading = getCO2(); 135 | dataString += ","; 136 | dataString = dataString + String(sensor4_reading); 137 | lcdUpdater(4, sensor4_reading); 138 | Serial.println(dataString); 139 | 140 | Serial.println("sensor 5 - CO..."); //CO 141 | //int sensor4_reading = analogRead(10); 142 | int sensor5_reading = getCO(); 143 | dataString += ","; 144 | dataString = dataString + String(sensor5_reading); 145 | lcdUpdater(5, sensor5_reading); 146 | Serial.println(dataString); 147 | 148 | Serial.println("sensor 6 - Air Qual..."); //Air Quality 149 | //int sensor4_reading = analogRead(10); 150 | int sensor6_reading = getAirQual(); 151 | dataString += ","; 152 | dataString = dataString + String(sensor6_reading); 153 | lcdUpdater(6, sensor6_reading); 154 | Serial.println(sensor6_reading); 155 | 156 | //if we have passed the timer interval set for posting (3000ms), 157 | //then send data! 158 | if(millis() - lastConnectionTime > postingInterval){ 159 | Serial.println("sendData!"); 160 | if(millis() - lastConnectionTime > resetInterval){ 161 | softwareReset(); //RESET ENTIRE BOARD 162 | } 163 | else{ 164 | sendData(dataString); 165 | } 166 | } 167 | // store the state of the connection for next time through 168 | // the loop: 169 | lastConnected = client.connected(); 170 | Serial.println("... end of loop ..."); 171 | } 172 | 173 | 174 | // make an HTTP connection to the server: 175 | void sendData(String thisData) { 176 | lcd.clear(); 177 | lcd.setCursor(0,0); 178 | lcd.print("Attempting "); 179 | lcd.setCursor(0,1); 180 | lcd.print("Connect and Send"); 181 | // if there's a successful connection: 182 | if (client.connect()) { 183 | Serial.println("connecting..."); 184 | lcd.setCursor(12,0); 185 | lcdConnect(); 186 | lcdStatusBar(); 187 | 188 | // send the HTTP PUT request. 189 | lcdPUT(); 190 | client.print("PUT /api/"+feedAddr+".csv HTTP/1.1\n"); 191 | lcdStatusBar(); 192 | 193 | lcdPachubeConnect(); 194 | client.print("Host: www.pachube.com\n"); 195 | // weather tunnel API key: mFgy2cgsyv4GKhw4G4EzNcpgpfhQJkg4JvCrNpOskwo 196 | client.print("X-PachubeApiKey: mFgy2cgsyv4GKhw4G4EzNcpgpfhQJkg4JvCrNpOskwo\n"); 197 | client.print("Content-Length: "); 198 | client.println(thisData.length(), DEC); 199 | lcdStatusBar(); 200 | 201 | // last pieces of the HTTP PUT request: 202 | client.print("Content-Type: text/csv\n"); 203 | client.println("Connection: close\n"); 204 | 205 | // here's the actual content of the PUT request: 206 | lcdDataPUT(); 207 | client.println(thisData); 208 | lcdStatusBar(); 209 | 210 | lcd.clear(); 211 | lcd.setCursor(0,0); 212 | lcd.print(" Data Sent! "); 213 | flashGreenLED(); 214 | // note the time that the connection was made: 215 | lastConnectionTime = millis(); 216 | 217 | Serial.println(); 218 | Serial.println("disconnecting."); 219 | client.stop(); 220 | } 221 | else { 222 | // if you couldn't make a connection: 223 | lcdConnectionFail(); 224 | } 225 | } 226 | 227 | -------------------------------------------------------------------------------- /stationary/arduino/current/weatherTunnelSensorUnit/weatherTunnelSensorUnit.ino: -------------------------------------------------------------------------------- 1 | /* 2 | ***_-_-_ weather tunnel sensor box v08 _-_-_*** 3 | 4 | Circuit: 5 | * Ethernet shield attached to digital pins 10, 50, 51, 52, 53 6 | * LCD Screen on pins 49, 45, 29, 27, 25, 23 7 | * LEDs: 12 (red), 13 (blue) 8 | * RESET pin connected to: pin 7 9 | 10 | Sensors: 11 | * ADMP401 ambient sound mic on pin A0 - +3v - GND 12 | * TEMT6000 ambient light on pin A2 - +5v - GND 13 | * humidity on pin A5 - +5v - GND 14 | * MQ-7 Carbon Monoxide sensor on pin A8 - +5v - GND - D14 15 | * MG-811 Carbon Dioxide sensor on pin A14 - +9v - GND 16 | * MQ-135 Air Quality sensor on pin A10 - +5v - GND 17 | * TMP102 Temperature sensor on pin D20 (SDA-BLUE) - D21 (SCL-WHITE) - +3v - GND 18 | 19 | joseph saavedra 20 | http://jos.ph 21 | january 2011 22 | */ 23 | 24 | // institution 25 | String institutionName = "Tester!"; 26 | 27 | // institution specific Pachube feed address 28 | String feedAddr = "23656"; //Test: 23656 29 | 30 | //unique ethernet shield MAC addr: 90-A2-DA-00-2D-A3 31 | //this number can be found printed on the bottom of your Arduino 32 | // fill in your ethernet shield's MAC address here: 33 | byte mac[] = { 34 | 0x90, 0xA2, 0xDA, 0x00, 0x2D, 0x16 }; 35 | 36 | 37 | //TEST IP: 192.168.2.2 38 | //Subnet Mask: 255.255.255.0 39 | //Router: 192.168.2.1 40 | 41 | //IP in Room 1100: 149.31.36.204 42 | //Subnet Mask: 255.255.255.0 43 | //Router: 149.31.36.1 44 | 45 | // IP address for the controller: 46 | byte ip[] = { 47 | 149, 31, 36, 204 }; 48 | 49 | // subnet mask -- if unneeded {255,255,255,0} works 50 | byte subnet[] = { 51 | 255, 255, 255, 0 }; 52 | 53 | // router address -- if unneeded {192,168,1,1} works 54 | byte gateway[] = { 55 | 149, 31, 36, 1 }; 56 | 57 | // Pachube server address: 58 | byte server[] = { 59 | // 209,40,205,190}; //THIS IS THE OLD ADDRESS 60 | 173,203,98,29}; //THIS IS THE NEW PACHUBE ADDRESS! 61 | 62 | #include 63 | #include 64 | #include 65 | #include 66 | #include 67 | 68 | LiquidCrystal lcd(49, 45, 29, 27, 25, 23); 69 | 70 | CS_MQ7 MQ7(14, 6); //Citizen Sensor MQ-7 Carbon Monoxide Breakout instance 71 | int CoPrev = 0; //for storing CO Data 72 | 73 | Client client(server, 80); 74 | 75 | long lastConnectionTime = 0; // last time you connected to the server, in milliseconds 76 | boolean lastConnected = false; // state of the connection last time through the main loop 77 | const int postingInterval = 30000; //delay between updates to Pachube.com, in milliseconds 78 | const int softwareResetPin = 7; //connect this pin to RESET pin 79 | const long int resetInterval = 120000; //if no successful connection has been made in 2 min, RESET board 80 | 81 | void setup() { 82 | digitalWrite(softwareResetPin, HIGH); //softwareReset hack 83 | pinMode(softwareResetPin, OUTPUT); //softwareReset hack 84 | Serial.begin(9600); 85 | Serial.println("start setup"); 86 | lcdSetup(); 87 | Ethernet.begin(mac, ip); 88 | lcdEthernet(ip, subnet, gateway, feedAddr); 89 | Wire.begin(); 90 | lastConnectionTime = millis(); 91 | Serial.println("end setup"); 92 | delay(1000); 93 | setupLedFlash(); 94 | lcd.clear(); 95 | } 96 | 97 | void loop() { 98 | Serial.println("Reading Sensors..."); 99 | lcd.clear(); 100 | String dataString = " "; //will hold all sensor data 101 | 102 | // read the sensors: 103 | Serial.println("sensor 0 - temperature..."); //temperature 104 | int sensor0_reading = 0; 105 | sensor0_reading = getTemperature(); 106 | dataString = String(sensor0_reading); 107 | lcdUpdater(0, sensor0_reading); 108 | Serial.println(dataString); 109 | 110 | Serial.println("sensor 1 - light..."); //light 111 | int sensor1_reading = 0; 112 | sensor1_reading = getLight(); 113 | dataString += ","; 114 | dataString = dataString + String(sensor1_reading); 115 | lcdUpdater(1, sensor1_reading); 116 | Serial.println(dataString); 117 | 118 | Serial.println("sensor 2 - humidity..."); //humidity 119 | int sensor2_reading = getHumidity(); 120 | dataString += ","; 121 | dataString = dataString + String(sensor2_reading); 122 | lcdUpdater(2, sensor2_reading); 123 | Serial.println(dataString); 124 | 125 | Serial.println("sensor 3 - noise..."); //noise 126 | int sensor3_reading = getNoise(); 127 | dataString += ","; 128 | dataString = dataString + String(sensor3_reading); 129 | lcdUpdater(3, sensor3_reading); 130 | Serial.println(dataString); 131 | 132 | Serial.println("sensor 4 - CO2..."); //CO2 133 | //int sensor4_reading = analogRead(8); 134 | int sensor4_reading = getCO2(); 135 | dataString += ","; 136 | dataString = dataString + String(sensor4_reading); 137 | lcdUpdater(4, sensor4_reading); 138 | Serial.println(dataString); 139 | 140 | Serial.println("sensor 5 - CO..."); //CO 141 | //int sensor4_reading = analogRead(10); 142 | int sensor5_reading = getCO(); 143 | dataString += ","; 144 | dataString = dataString + String(sensor5_reading); 145 | lcdUpdater(5, sensor5_reading); 146 | Serial.println(dataString); 147 | 148 | Serial.println("sensor 6 - Air Qual..."); //Air Quality 149 | //int sensor4_reading = analogRead(10); 150 | int sensor6_reading = getAirQual(); 151 | dataString += ","; 152 | dataString = dataString + String(sensor6_reading); 153 | lcdUpdater(6, sensor6_reading); 154 | Serial.println(sensor6_reading); 155 | 156 | //if we have passed the timer interval set for posting (3000ms), 157 | //then send data! 158 | if(millis() - lastConnectionTime > postingInterval){ 159 | Serial.println("sendData!"); 160 | if(millis() - lastConnectionTime > resetInterval){ 161 | softwareReset(); //RESET ENTIRE BOARD 162 | } 163 | else{ 164 | sendData(dataString); 165 | } 166 | } 167 | // store the state of the connection for next time through 168 | // the loop: 169 | lastConnected = client.connected(); 170 | Serial.println("... end of loop ..."); 171 | } 172 | 173 | 174 | // make an HTTP connection to the server: 175 | void sendData(String thisData) { 176 | lcd.clear(); 177 | lcd.setCursor(0,0); 178 | lcd.print("Attempting "); 179 | lcd.setCursor(0,1); 180 | lcd.print("Connect and Send"); 181 | // if there's a successful connection: 182 | if (client.connect()) { 183 | Serial.println("connecting..."); 184 | lcd.setCursor(12,0); 185 | lcdConnect(); 186 | lcdStatusBar(); 187 | 188 | // send the HTTP PUT request. 189 | lcdPUT(); 190 | client.print("PUT /api/"+feedAddr+".csv HTTP/1.1\n"); 191 | lcdStatusBar(); 192 | 193 | lcdPachubeConnect(); 194 | client.print("Host: www.pachube.com\n"); 195 | // weather tunnel API key: mFgy2cgsyv4GKhw4G4EzNcpgpfhQJkg4JvCrNpOskwo 196 | client.print("X-PachubeApiKey: mFgy2cgsyv4GKhw4G4EzNcpgpfhQJkg4JvCrNpOskwo\n"); 197 | client.print("Content-Length: "); 198 | client.println(thisData.length(), DEC); 199 | lcdStatusBar(); 200 | 201 | // last pieces of the HTTP PUT request: 202 | client.print("Content-Type: text/csv\n"); 203 | client.println("Connection: close\n"); 204 | 205 | // here's the actual content of the PUT request: 206 | lcdDataPUT(); 207 | client.println(thisData); 208 | lcdStatusBar(); 209 | 210 | lcd.clear(); 211 | lcd.setCursor(0,0); 212 | lcd.print(" Data Sent! "); 213 | flashGreenLED(); 214 | // note the time that the connection was made: 215 | lastConnectionTime = millis(); 216 | 217 | Serial.println(); 218 | Serial.println("disconnecting."); 219 | client.stop(); 220 | } 221 | else { 222 | // if you couldn't make a connection: 223 | lcdConnectionFail(); 224 | } 225 | } 226 | 227 | -------------------------------------------------------------------------------- /stationary/arduino/dev/ArduinoSoftwareRESET/ArduinoSoftwareRESET.pde: -------------------------------------------------------------------------------- 1 | 2 | //digitalPin 7 is connected to the RESET pin on Arduino 3 | //NOTE: you CANNOT program the board while they are connected 4 | //by default digitalPin 13 will blink upon reset, so stick an LED in there 5 | 6 | int interval = 5000; 7 | long int time = 0; 8 | 9 | void setup(){ 10 | digitalWrite(7, HIGH); //We need to set it HIGH immediately on boot 11 | pinMode(7,OUTPUT); //We can declare it an output ONLY AFTER it's HIGH 12 | // (( HACKHACKHACKHACK )) 13 | Serial.begin(9600); //So you can watch the time printed 14 | } 15 | 16 | 17 | void loop(){ 18 | 19 | time = millis(); 20 | 21 | Serial.println(time); 22 | 23 | if(time > interval){ 24 | Serial.println("RESET!"); 25 | digitalWrite(7, LOW); //Pulling the RESET pin LOW triggers the reset. 26 | } 27 | } 28 | 29 | -------------------------------------------------------------------------------- /stationary/arduino/dev/Autoscroll_LCDtest/Autoscroll_LCDtest.pde: -------------------------------------------------------------------------------- 1 | /* 2 | LCD example with Weather Tunnel interface pins -- 3 | http://www.arduino.cc/en/Tutorial/LiquidCrystal 4 | */ 5 | 6 | // include the library code: 7 | #include 8 | 9 | // initialize the library with the numbers of the interface pins 10 | LiquidCrystal lcd(49, 45, 29, 27, 25, 23); 11 | 12 | void setup() { 13 | // set up the LCD's number of columns and rows: 14 | lcd.begin(16,2); 15 | } 16 | 17 | void loop() { 18 | // set the cursor to (0,0): 19 | lcd.setCursor(0, 0); 20 | // print from 0 to 9: 21 | for (int thisChar = 0; thisChar < 10; thisChar++) { 22 | lcd.print(thisChar); 23 | delay(500); 24 | } 25 | 26 | // set the cursor to (16,1): 27 | lcd.setCursor(16,1); 28 | // set the display to automatically scroll: 29 | lcd.autoscroll(); 30 | // print from 0 to 9: 31 | for (int thisChar = 0; thisChar < 10; thisChar++) { 32 | lcd.print(thisChar); 33 | delay(500); 34 | } 35 | // turn off automatic scrolling 36 | lcd.noAutoscroll(); 37 | 38 | // clear screen for the next loop: 39 | lcd.clear(); 40 | } 41 | 42 | -------------------------------------------------------------------------------- /stationary/arduino/dev/temperature_tmp102/temperature_tmp102.pde: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | reading temperature from TMP102 sensor breakout from SFE 4 | 5 | for ArduinoMega // weather tunnel 6 | 7 | ADD0 to GND 8 | ALT unconnected 9 | 10 | V+ to 3v 11 | GND to GND 12 | SCL to Analog Input 5 -- WHITE WIRE 13 | SDA to Analog Input 4 -- BLUE WIRE 14 | */ 15 | 16 | #include 17 | byte tmp102comm; 18 | byte msb; 19 | byte lsb; 20 | int val; 21 | float celsius; 22 | float farenheit; 23 | 24 | void setup() 25 | { 26 | Serial.begin(9600); 27 | Wire.begin(); 28 | } 29 | 30 | void loop() 31 | { 32 | tmp102comm = Wire.requestFrom(72,2); 33 | if (tmp102comm == 2) { 34 | msb = Wire.receive(); /* Whole degrees */ 35 | lsb = Wire.receive(); /* Fractional degrees */ 36 | val = ((msb) << 4); /* MSB */ 37 | val |= (lsb >> 4); /* LSB */ 38 | celsius = val*0.0625; 39 | farenheit = (celsius*1.8) + 32; 40 | Serial.print("C: "); 41 | Serial.println(celsius); 42 | Serial.print("F: "); 43 | Serial.println(farenheit); 44 | Serial.println(); 45 | delay(1000); 46 | } 47 | } 48 | 49 | -------------------------------------------------------------------------------- /stationary/readme.txt: -------------------------------------------------------------------------------- 1 | Citizen Sensor 2 | 3 | http://citizensensor.cc 4 | 5 | DIY environmental and air quality monitoring. Has been developed as both stationary and mobile units. 6 | 7 | Stationary units have been deployed all over world. CS was used in the "weather tunnel" project, exhibited at the national art museum of China, Beijing summer 2011. 8 | 9 | *stationary* 10 | > operate as stationary units connected to the internet via ethernet cable 11 | > arduino based 12 | > require wall power (7-12v DC power brick) 13 | > use pachube (some units live currently: https://pachube.com/feeds?user=weathertunnel) 14 | > schematic on Upverter: http://upverter.com/jmsaavedra/634b5640a5bbd8a7/Citizen-Sensor---Stationary-Version-02/ 15 | 16 | more info: 17 | - http://thesis.jmsaavedra.com/prototypes/technology/weather-tunnel-project-at-translife-2011/ 18 | - http://tasml.parsons.edu/weathertunnel/sensor-information/ 19 | -------------------------------------------------------------------------------- /stationary/sensorDocs/ReprogrammingYourWeatherTunnelUnit.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmsaavedra/Citizen-Sensor/3c399e08289bcb9d6373831019956d3e6263dc70/stationary/sensorDocs/ReprogrammingYourWeatherTunnelUnit.pdf -------------------------------------------------------------------------------- /stationary/sensorDocs/sensorDoc_03a.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmsaavedra/Citizen-Sensor/3c399e08289bcb9d6373831019956d3e6263dc70/stationary/sensorDocs/sensorDoc_03a.pdf --------------------------------------------------------------------------------