├── .gitignore ├── LICENSE ├── README.md ├── data ├── README.md ├── examples │ ├── add.php │ └── data.csv ├── sck_sensor_data.php └── sensors │ └── db.json ├── enclosure ├── 3dmodel │ └── SCK-1.1_model.stl ├── Basic_case-2013 │ ├── SCK-1.0 │ │ ├── SCK-1.0_acrylic.dxf │ │ └── SCK-1.0_case.stl │ ├── SCK-1.1 │ │ ├── SCK-1.1_acrylic.dxf │ │ ├── SCK-1.1_case.3dm │ │ └── SCK-1.1_case.stl │ ├── SCK_basic-1.jpg │ ├── SCK_basic-2.jpg │ ├── SCK_basic-3.jpg │ └── SCK_basic-4.jpg ├── Enclosure.jpg ├── Simple_base │ └── SCK-1.1_simple_base.stl ├── Smart Citizen SCK Mock-Up ├── case │ ├── SCK-1.1_case.stl │ ├── SCK-1.1_case_acrylic.dxf │ ├── SCK-1.1_case_clip.stl │ ├── SCK-1.1_case_complete.stp │ └── case.jpg ├── dummybaseplate2.stl ├── readme.md └── simple.png ├── hardware ├── Goteo │ ├── README.md │ ├── v1.0 │ │ ├── Ambient_Board_v1.0 │ │ │ ├── SCK_Ambient_v1.0.brd │ │ │ └── SCK_Ambient_v1.0.sch │ │ ├── Base_Board_v1.0 │ │ │ ├── SCK_Base_v1.0.brd │ │ │ └── SCK_Base_v1.0.sch │ │ └── README.md │ └── v1.01 │ │ ├── Ambient_Board_v1.0 │ │ ├── SCK_Ambient_v1.0.brd │ │ └── SCK_Ambient_v1.0.sch │ │ ├── Base_Board_v1.01 │ │ ├── SCK_Base_v1.01.brd │ │ └── SCK_Base_v1.01.sch │ │ └── README.md ├── Kickstarter │ ├── README.md │ └── v1.1b │ │ ├── Ambient_Board_v1.1b │ │ ├── Ambient_Board_v1.1b.brd │ │ ├── Ambient_Board_v1.1b.pdf │ │ └── Ambient_Board_v1.1b.sch │ │ ├── Base_Board_v1.1b │ │ ├── Base_Board_v1.1b.brd │ │ ├── Base_Board_v1.1b.pdf │ │ └── Base_Board_v1.1b.sch │ │ └── README.md ├── LICENSE └── README.md ├── sck-commands.md ├── sck_beta_v0_8_7_SDCARD ├── AccumulatorFilter.h ├── Constants.h ├── README.md ├── SCKAmbient.ino ├── SCKBase.ino ├── SDUpdate.ino ├── TemperatureDecoupler.h └── sck_beta_v0_8_7_SDCARD.ino ├── sck_beta_v0_9 ├── AccumulatorFilter.h ├── Constants.h ├── SCKAmbient.cpp ├── SCKAmbient.h ├── SCKBase.cpp ├── SCKBase.h ├── SCKServer.cpp ├── SCKServer.h ├── TemperatureDecoupler.h └── sck_beta_v0_9.ino └── utilities ├── README.md ├── SCK_check ├── SCK_check.ino ├── SCKlibs.cpp └── SCKlibs.h ├── SCK_testing ├── SCKtester ├── readme.md ├── shot.png └── wifly │ └── wifly.ino ├── Wifly_Rescue ├── SCKBase.ino └── Wifly_Rescue.ino ├── Wifly_Update ├── SCKBase.ino └── Wifly_Update.ino └── wifly_terminal ├── SCKBase.ino └── wifly_terminal.ino /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | 12 | # Fortran module files 13 | *.mod 14 | 15 | # Compiled Static libraries 16 | *.lai 17 | *.la 18 | *.a 19 | *.lib 20 | 21 | # Mac OS 22 | .DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Smart Citizen Kit 2 | ================= 3 | 4 | **NOTE:** [Click here](https://github.com/fablabbcn/smartcitizen-kit-20) for the newer version of SCK 2.0+ 5 | 6 | **Smart Citizen Kit BETA version for the Ambient Sensor Board.** 7 | 8 | SCK 9 | 10 | 11 | ### Download 12 | 13 | * Download the latest firmware release [here](https://github.com/fablabbcn/Smart-Citizen-Kit/releases/latest). 14 | 15 | ### Hardware 16 | 17 | * Firmware for the [SmartCitizen Ambient Kit](http://smartcitizen.me/pages/sck) 1.0 and 1.1. 18 | 19 | * More hardware info [here](https://github.com/fablabbcn/Smart-Citizen-Kit/tree/master/hardware). 20 | 21 | ### Quick start 22 | 23 | * Visit the project main documentation [docs.smartcitizen.me](http://docs.smartcitizen.me) 24 | 25 | ### Loading Firmware 26 | 27 | **The firmware is totally compatible with Arduino. You can upload the firmware using the [Arduino IDE](http://arduino.cc/en/main/software).** 28 | 29 | * For SmartCitizen Kit version 1.0 select `Tools/Boards/Arduino Leonardo` on the Arduino IDE (ATmega 32U4 at 16Mhz) 30 | 31 | * For SmartCitizen Kit version 1.1 select `Tools/Boards/Lylipad Arduino USB` on the Arduino IDE (ATmega 32U4 at 8Mhz) 32 | 33 | ### Versions 34 | 35 | The current firmware version in use is `0.9.4`. 36 | 37 | We currently support the SD card version on as a diferent firmware `SDCARD`, currently `0.8.7 SDCARD`. 38 | 39 | You can see the release history [here](https://github.com/fablabbcn/Smart-Citizen-Kit/releases) 40 | 41 | You can see the hardware versions [here](https://github.com/fablabbcn/Smart-Citizen-Kit/blob/master/hardware/README.md) 42 | 43 | ### Advance References 44 | 45 | * Setup commands reference in [sck-commands.md](https://github.com/fablabbcn/Smart-Citizen-Kit/blob/master/sck-commands.md) 46 | 47 | * Basic documentation for creating your own Sensor Boards [here](https://github.com/fablabbcn/Smart-Citizen-Kit/wiki/Making-a-Shield) 48 | 49 | * [Slideshow](https://speakerdeck.com/pral2a/smart-citizen-hardware-and-software) with project technical details 50 | 51 | ### Support and issues 52 | 53 | * Forum [forum.smartcitizen.me](http://forum.smartcitizen.me) 54 | 55 | ### Contributions 56 | 57 | * We are working on improving the firmware documentation for developers but still we encourage you to Fork the project and do a Pull request with your contributions. 58 | 59 | ## License 60 | 61 | All the software unless stated is released under [GNU GPL v3.0](https://github.com/fablabbcn/smartcitizen-kit/blob/master/LICENSE) and the hardware design files under [CERN OHL v1.2](https://github.com/fablabbcn/smartcitizen-kit/blob/master/hardware/LICENSE) 62 | -------------------------------------------------------------------------------- /data/README.md: -------------------------------------------------------------------------------- 1 | Smart Citizen Data 2 | ================== 3 | 4 | **This is a basic example for creating your custom server backend for smartcitizen** 5 | 6 | *Note this is aimed at learning, not production ready code.* 7 | 8 | Check the complete documentation at http://docs.smartcitizen.me/#/start/how-to-store-data-in-your-own-database 9 | 10 | -------------------------------------------------------------------------------- /data/examples/add.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /data/examples/data.csv: -------------------------------------------------------------------------------- 1 | 2015-04-06 10:38:00, 25, 20, 0, 112.5, 200, 3000, 78.6, 0, 10 2 | 2015-04-06 10:38:00, 25, 20, 0, 112.5, 200, 3000, 78.6, 0, 10 3 | 2015-04-06 10:38:00, 25, 20, 0, 112.5, 200, 3000, 78.6, 0, 10 4 | 2015-04-06 10:38:00, 25, 20, 0, 112.5, 200, 3000, 78.6, 0, 10 5 | -------------------------------------------------------------------------------- /data/sck_sensor_data.php: -------------------------------------------------------------------------------- 1 | 35 | * 36 | * SCKSensorData is free software: you can redistribute it and/or modify 37 | * it under the terms of the GNU Lesser General Public License as 38 | * published by the Free Software Foundation, either version 3 of 39 | * the License, or (at your option) any later version. 40 | * 41 | * SCKSensorData is distributed in the hope that it will be useful, 42 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 43 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 44 | * GNU Lesser General Public License for more details. 45 | * 46 | * You should have received a copy of the GNU Lesser General Public 47 | * License along with SCKSensorData. If not, see 48 | * . 49 | * 50 | */ 51 | 52 | 53 | class SCKSensorData 54 | { 55 | 56 | 57 | /** 58 | * SCK11Calibration 59 | * 60 | * Calibrates to propper SI units an SCK datapoint 61 | * 62 | * @param array $rawBat Indexed array containing a SCK 1.1 datapoint 63 | * @return array Indexed arrary with a SCK datapoint calibrated 64 | * 65 | */ 66 | 67 | public function SCK11Convert($rawData) 68 | { 69 | 70 | $data = array(); 71 | 72 | if (self::isValidDateTimeString($rawData['timestamp'])) { //Check calibration.... 73 | 74 | $data['timestamp'] = $rawData['timestamp']; 75 | 76 | $data['temp'] = self::tempConversion($rawData['temp']); 77 | $data['hum'] = self::humConversion($rawData['hum']); 78 | $data['noise'] = self::noiseConversion($rawData['noise']); 79 | $data['co'] = self::coConversion($rawData['co']); 80 | $data['no2'] = self::no2Conversion($rawData['no2']); 81 | $data['light'] = self::lightConversion($rawData['light']); 82 | $data['bat'] = self::batConversion($rawData['bat']); 83 | $data['panel'] = self::panelConversion($rawData['panel']); 84 | $data['nets'] = $rawData['nets']; 85 | 86 | return $data; 87 | 88 | } else { 89 | 90 | return false; 91 | 92 | } 93 | 94 | } 95 | 96 | /** 97 | * tempConversion 98 | * 99 | * Temperature calibration for SHT21 based on the datasheet: 100 | * https://github.com/fablabbcn/Smart-Citizen-Kit/wiki/Datasheets/HTU-21D.pdf 101 | * 102 | * Formula can be tune depending on the SCK enclosure. 103 | * 104 | * 105 | * @param float $rawTemp 106 | * @return float Temperature in ºC 107 | * 108 | */ 109 | 110 | public function tempConversion($rawTemp) 111 | { 112 | return round(-53 + 175.72 / 65536.0 * $rawTemp, 2); 113 | } 114 | 115 | /** 116 | * humConversion 117 | * 118 | * Humidity calibration for SHT21 based on the datasheet: 119 | * https://github.com/fablabbcn/Smart-Citizen-Kit/wiki/Datasheets/HTU-21D.pdf 120 | * 121 | * Formula can be tune depending on the SCK enclosure. 122 | * 123 | * 124 | * @param float $rawHum 125 | * @return float Rel. Humidity in % 126 | * 127 | */ 128 | 129 | public function humConversion($rawHum) 130 | { 131 | return round(7 + 125.0 / 65536.0 * $rawHum, 2); 132 | } 133 | 134 | /** 135 | * noiseConversion 136 | * 137 | * Noise calibration for SCK1.1 sound sensor. Converts mV in to dBs. 138 | * Based on a linear regresion from a lookup table (db.json) obtained after real measurements from our test facility. 139 | * 140 | * 141 | * @param float $rawSound 142 | * @return float noise as sound pressure in dB 143 | * 144 | */ 145 | 146 | public function noiseConversion($rawSound) 147 | { 148 | $dbTable = json_decode(file_get_contents("./sensors/db.json"), true); 149 | return round(self::tableCalibration($dbTable, $rawSound), 2); 150 | } 151 | 152 | /** 153 | * coConversion 154 | * 155 | * CO values rescaling. For obtaining ppm check: 156 | * 157 | * @param float $rawCO 158 | * @return float sensor resistance in KOhm 159 | * 160 | */ 161 | 162 | public function coConversion($rawCO) 163 | { 164 | return round($rawCO / 1000, 2); 165 | } 166 | 167 | /** 168 | * no2Conversion 169 | * 170 | * NO2 values rescaling. For obtaining ppm check: 171 | * 172 | * returns k0hm 173 | * @param float $rawNO2 174 | * @return float sensor resistance in KOhm 175 | * 176 | */ 177 | 178 | public function no2Conversion($rawNO2) 179 | { 180 | return round($rawNO2 / 1000, 2); 181 | } 182 | 183 | /** 184 | * lightConversion 185 | * 186 | * Light values rescaling. 187 | * 188 | * returns lux 189 | * @param float $rawLight 190 | * @return float light level in lux 191 | * 192 | */ 193 | 194 | public function lightConversion($rawLight) 195 | { 196 | return round($rawLight / 10, 2); 197 | } 198 | 199 | /** 200 | * batConversion 201 | * 202 | * Battery values rescaling. 203 | * 204 | * @param float $rawBat 205 | * @return float battery level in % 206 | * 207 | */ 208 | 209 | 210 | public function batConversion($rawBat) 211 | { 212 | return round($rawBat / 10, 2); 213 | } 214 | 215 | /** 216 | * panelConversion 217 | * 218 | * Solar panel values rescaling. 219 | * 220 | * @param float $rawBat 221 | * @return float Tension in volts 222 | * 223 | */ 224 | 225 | public function panelConversion($rawBat) 226 | { 227 | return round($rawBat / 100, 2); 228 | } 229 | 230 | /** 231 | * isValidDateTimeString 232 | * 233 | * Check if a string is a valid time stamp 234 | * 235 | * @param string $str_dt 236 | * @return bool 237 | * 238 | */ 239 | 240 | private function isValidDateTimeString($str_dt) 241 | { 242 | $date1 = DateTime::createFromFormat('Y-m-d G:i:s', $str_dt); 243 | $date2 = DateTime::createFromFormat('Y-m-d H:i:s', $str_dt); 244 | return $date1 && ($date1->format('Y-m-d G:i:s') == $str_dt || $date2->format('Y-m-d H:i:s') == $str_dt); 245 | } 246 | 247 | /** 248 | * tableCalibration 249 | * 250 | * Calculates a point based on a linear regresion from a look up table 251 | * 252 | * @param array $refTable 253 | * @param float $rawValue 254 | * @return float 255 | * 256 | */ 257 | 258 | private function tableCalibration($refTable, $rawValue) 259 | { 260 | for ($i = 0; $i < sizeof($refTable) - 1; $i++) { 261 | $prevValueRef = $refTable[$i][0]; 262 | $nextValueRef = $refTable[$i + 1][0]; 263 | if ($rawValue >= $prevValueRef && $rawValue < $nextValueRef) { 264 | $prevValueOutput = $refTable[$i][1]; 265 | $nextValueOutput = $refTable[$i + 1][1]; 266 | $result = self::linearRegression($rawValue, $prevValueOutput, $nextValueOutput, $prevValueRef, $nextValueRef); 267 | return $result; 268 | } 269 | } 270 | } 271 | 272 | /** 273 | * linearRegression 274 | * * 275 | * @param float $valueInput 276 | * @param float $prevValueOutput 277 | * @param float $nextValueOutput 278 | * @param float $prevValueRef 279 | * @param float $nextValueRef 280 | * @return float 281 | * 282 | */ 283 | 284 | private function linearRegression($valueInput, $prevValueOutput, $nextValueOutput, $prevValueRef, $nextValueRef) 285 | { 286 | $slope = ($nextValueOutput - $prevValueOutput) / ($nextValueRef - $prevValueRef); 287 | $result = $slope * ($valueInput - $prevValueRef) + $prevValueOutput; 288 | return $result; 289 | } 290 | 291 | 292 | 293 | } 294 | 295 | ?> -------------------------------------------------------------------------------- /data/sensors/db.json: -------------------------------------------------------------------------------- 1 | [ 2 | [ 3 | 0, 4 | 50 5 | ], 6 | [ 7 | 2, 8 | 55 9 | ], 10 | [ 11 | 3, 12 | 57 13 | ], 14 | [ 15 | 6, 16 | 58 17 | ], 18 | [ 19 | 20, 20 | 59 21 | ], 22 | [ 23 | 40, 24 | 60 25 | ], 26 | [ 27 | 60, 28 | 61 29 | ], 30 | [ 31 | 75, 32 | 62 33 | ], 34 | [ 35 | 115, 36 | 63 37 | ], 38 | [ 39 | 150, 40 | 64 41 | ], 42 | [ 43 | 180, 44 | 65 45 | ], 46 | [ 47 | 220, 48 | 66 49 | ], 50 | [ 51 | 260, 52 | 67 53 | ], 54 | [ 55 | 300, 56 | 68 57 | ], 58 | [ 59 | 375, 60 | 69 61 | ], 62 | [ 63 | 430, 64 | 70 65 | ], 66 | [ 67 | 500, 68 | 71 69 | ], 70 | [ 71 | 575, 72 | 72 73 | ], 74 | [ 75 | 660, 76 | 73 77 | ], 78 | [ 79 | 720, 80 | 74 81 | ], 82 | [ 83 | 820, 84 | 75 85 | ], 86 | [ 87 | 900, 88 | 76 89 | ], 90 | [ 91 | 975, 92 | 77 93 | ], 94 | [ 95 | 1050, 96 | 78 97 | ], 98 | [ 99 | 1125, 100 | 79 101 | ], 102 | [ 103 | 1200, 104 | 80 105 | ], 106 | [ 107 | 1275, 108 | 81 109 | ], 110 | [ 111 | 1320, 112 | 82 113 | ], 114 | [ 115 | 1375, 116 | 83 117 | ], 118 | [ 119 | 1400, 120 | 84 121 | ], 122 | [ 123 | 1430, 124 | 85 125 | ], 126 | [ 127 | 1450, 128 | 86 129 | ], 130 | [ 131 | 1480, 132 | 87 133 | ], 134 | [ 135 | 1500, 136 | 88 137 | ], 138 | [ 139 | 1525, 140 | 89 141 | ], 142 | [ 143 | 1540, 144 | 90 145 | ], 146 | [ 147 | 1560, 148 | 91 149 | ], 150 | [ 151 | 1580, 152 | 92 153 | ], 154 | [ 155 | 1600, 156 | 93 157 | ], 158 | [ 159 | 1620, 160 | 94 161 | ], 162 | [ 163 | 1640, 164 | 95 165 | ], 166 | [ 167 | 1660, 168 | 96 169 | ], 170 | [ 171 | 1680, 172 | 97 173 | ], 174 | [ 175 | 1690, 176 | 98 177 | ], 178 | [ 179 | 1700, 180 | 99 181 | ], 182 | [ 183 | 1710, 184 | 100 185 | ], 186 | [ 187 | 1720, 188 | 101 189 | ], 190 | [ 191 | 1745, 192 | 102 193 | ], 194 | [ 195 | 1770, 196 | 103 197 | ], 198 | [ 199 | 1785, 200 | 104 201 | ], 202 | [ 203 | 1800, 204 | 105 205 | ], 206 | [ 207 | 1815, 208 | 106 209 | ], 210 | [ 211 | 1830, 212 | 107 213 | ], 214 | [ 215 | 1845, 216 | 108 217 | ], 218 | [ 219 | 1860, 220 | 109 221 | ], 222 | [ 223 | 1875, 224 | 110 225 | ] 226 | ] -------------------------------------------------------------------------------- /enclosure/3dmodel/SCK-1.1_model.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fablabbcn/smartcitizen-kit-10/5d343f7c37d714c69dcb57fa3f7c47099750bee6/enclosure/3dmodel/SCK-1.1_model.stl -------------------------------------------------------------------------------- /enclosure/Basic_case-2013/SCK-1.0/SCK-1.0_case.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fablabbcn/smartcitizen-kit-10/5d343f7c37d714c69dcb57fa3f7c47099750bee6/enclosure/Basic_case-2013/SCK-1.0/SCK-1.0_case.stl -------------------------------------------------------------------------------- /enclosure/Basic_case-2013/SCK-1.1/SCK-1.1_case.3dm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fablabbcn/smartcitizen-kit-10/5d343f7c37d714c69dcb57fa3f7c47099750bee6/enclosure/Basic_case-2013/SCK-1.1/SCK-1.1_case.3dm -------------------------------------------------------------------------------- /enclosure/Basic_case-2013/SCK-1.1/SCK-1.1_case.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fablabbcn/smartcitizen-kit-10/5d343f7c37d714c69dcb57fa3f7c47099750bee6/enclosure/Basic_case-2013/SCK-1.1/SCK-1.1_case.stl -------------------------------------------------------------------------------- /enclosure/Basic_case-2013/SCK_basic-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fablabbcn/smartcitizen-kit-10/5d343f7c37d714c69dcb57fa3f7c47099750bee6/enclosure/Basic_case-2013/SCK_basic-1.jpg -------------------------------------------------------------------------------- /enclosure/Basic_case-2013/SCK_basic-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fablabbcn/smartcitizen-kit-10/5d343f7c37d714c69dcb57fa3f7c47099750bee6/enclosure/Basic_case-2013/SCK_basic-2.jpg -------------------------------------------------------------------------------- /enclosure/Basic_case-2013/SCK_basic-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fablabbcn/smartcitizen-kit-10/5d343f7c37d714c69dcb57fa3f7c47099750bee6/enclosure/Basic_case-2013/SCK_basic-3.jpg -------------------------------------------------------------------------------- /enclosure/Basic_case-2013/SCK_basic-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fablabbcn/smartcitizen-kit-10/5d343f7c37d714c69dcb57fa3f7c47099750bee6/enclosure/Basic_case-2013/SCK_basic-4.jpg -------------------------------------------------------------------------------- /enclosure/Enclosure.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fablabbcn/smartcitizen-kit-10/5d343f7c37d714c69dcb57fa3f7c47099750bee6/enclosure/Enclosure.jpg -------------------------------------------------------------------------------- /enclosure/Simple_base/SCK-1.1_simple_base.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fablabbcn/smartcitizen-kit-10/5d343f7c37d714c69dcb57fa3f7c47099750bee6/enclosure/Simple_base/SCK-1.1_simple_base.stl -------------------------------------------------------------------------------- /enclosure/Smart Citizen SCK Mock-Up: -------------------------------------------------------------------------------- 1 | Smart Citizen SCK Mock-Up that can be 3D printed for testing and fitting so the real hardware won't need to be used. 2 | -------------------------------------------------------------------------------- /enclosure/case/SCK-1.1_case.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fablabbcn/smartcitizen-kit-10/5d343f7c37d714c69dcb57fa3f7c47099750bee6/enclosure/case/SCK-1.1_case.stl -------------------------------------------------------------------------------- /enclosure/case/SCK-1.1_case_clip.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fablabbcn/smartcitizen-kit-10/5d343f7c37d714c69dcb57fa3f7c47099750bee6/enclosure/case/SCK-1.1_case_clip.stl -------------------------------------------------------------------------------- /enclosure/case/SCK-1.1_case_complete.stp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fablabbcn/smartcitizen-kit-10/5d343f7c37d714c69dcb57fa3f7c47099750bee6/enclosure/case/SCK-1.1_case_complete.stp -------------------------------------------------------------------------------- /enclosure/case/case.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fablabbcn/smartcitizen-kit-10/5d343f7c37d714c69dcb57fa3f7c47099750bee6/enclosure/case/case.jpg -------------------------------------------------------------------------------- /enclosure/readme.md: -------------------------------------------------------------------------------- 1 | Smartcitizen Kit Enclosure 2 | ==== 3 | 4 | 5 | ## Enclosure (info [video](https://vimeo.com/145620646)) 6 | ![Enclosure](Enclosure.jpg) 7 | 8 | ## Simple base 9 | ![Simple base](simple.png) -------------------------------------------------------------------------------- /enclosure/simple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fablabbcn/smartcitizen-kit-10/5d343f7c37d714c69dcb57fa3f7c47099750bee6/enclosure/simple.png -------------------------------------------------------------------------------- /hardware/Goteo/README.md: -------------------------------------------------------------------------------- 1 | Smart-Citizen-Kit 2 | ================= -------------------------------------------------------------------------------- /hardware/Goteo/v1.0/README.md: -------------------------------------------------------------------------------- 1 | Smart-Citizen-Kit 2 | ================= 3 | 4 | Eagles files of Goteo.org campaign 5 | 6 | [http://www.goteo.org/project/smart-citizen-sensores-ciudadanos?lang=en 7 | ](http://www.goteo.org/project/smart-citizen-sensores-ciudadanos?lang=en) 8 | 9 | Smart Citizen Kit BETA version 10 | - Base Board v1.0 11 | - Ambient Sensor Board v1.0 12 | 13 | The SCK is a piece of hardware comprised by two printed-circuit boards: an interchangeable daughterboard or shield, and an arduino-compatible data-processing board. 14 | 15 | The sensor board carries sensors that measure air composition (CO and NO2), temperature, light intensity, sound levels, and humidity. Once it's set up, the ambient board is able to stream data measured by the sensors over Wi-Fi using the FCC-certified, wireless module on the data-processing board. 16 | 17 | LICENSE: GPL v.0.3 -------------------------------------------------------------------------------- /hardware/Goteo/v1.01/README.md: -------------------------------------------------------------------------------- 1 | Smart-Citizen-Kit 2 | ================= 3 | 4 | Eagles files of Goteo.org campaign, 2n release 5 | 6 | [http://www.goteo.org/project/smart-citizen-sensores-ciudadanos?lang=en 7 | ](http://www.goteo.org/project/smart-citizen-sensores-ciudadanos?lang=en) 8 | 9 | Smart Citizen Kit BETA version 10 | - Base Board v1.01 11 | - Ambient Sensor Board v1.01 12 | 13 | The SCK is a piece of hardware comprised by two printed-circuit boards: an interchangeable daughterboard or shield, and an arduino-compatible data-processing board. 14 | 15 | The sensor board carries sensors that measure air composition (CO and NO2), temperature, light intensity, sound levels, and humidity. Once it's set up, the ambient board is able to stream data measured by the sensors over Wi-Fi using the FCC-certified, wireless module on the data-processing board. 16 | 17 | LICENSE: GPL v.0.3 -------------------------------------------------------------------------------- /hardware/Kickstarter/README.md: -------------------------------------------------------------------------------- 1 | Smart-Citizen-Kit 2 | ================= -------------------------------------------------------------------------------- /hardware/Kickstarter/v1.1b/Ambient_Board_v1.1b/Ambient_Board_v1.1b.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fablabbcn/smartcitizen-kit-10/5d343f7c37d714c69dcb57fa3f7c47099750bee6/hardware/Kickstarter/v1.1b/Ambient_Board_v1.1b/Ambient_Board_v1.1b.pdf -------------------------------------------------------------------------------- /hardware/Kickstarter/v1.1b/Base_Board_v1.1b/Base_Board_v1.1b.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fablabbcn/smartcitizen-kit-10/5d343f7c37d714c69dcb57fa3f7c47099750bee6/hardware/Kickstarter/v1.1b/Base_Board_v1.1b/Base_Board_v1.1b.pdf -------------------------------------------------------------------------------- /hardware/Kickstarter/v1.1b/README.md: -------------------------------------------------------------------------------- 1 | Smart-Citizen-Kit 2 | ================= 3 | 4 | Eagles files of the Kickstarter campaign 5 | 6 | [https://www.kickstarter.com/projects/acrobotic/the-smart-citizen-kit-crowdsourced-environmental-m 7 | ](https://www.kickstarter.com/projects/acrobotic/the-smart-citizen-kit-crowdsourced-environmental-m) 8 | 9 | Smart Citizen Kit BETA version 10 | - Base Board v1.1b 11 | - Ambient Sensor Board v1.1b 12 | 13 | The SCK is a piece of hardware comprised by two printed-circuit boards: an interchangeable daughterboard or shield, and an arduino-compatible data-processing board. 14 | 15 | The sensor board carries sensors that measure air composition (CO and NO2), temperature, light intensity, sound levels, and humidity. Once it's set up, the ambient board is able to stream data measured by the sensors over Wi-Fi using the FCC-certified, wireless module on the data-processing board. 16 | 17 | LICENSE: GPL v.0.3 -------------------------------------------------------------------------------- /hardware/LICENSE: -------------------------------------------------------------------------------- 1 | CERN Open Hardware Licence v1.2 2 | 3 | Preamble 4 | 5 | Through this CERN Open Hardware Licence ("CERN OHL") version 1.2, CERN 6 | wishes to provide a tool to foster collaboration and sharing among 7 | hardware designers. The CERN OHL is copyright CERN. Anyone is welcome 8 | to use the CERN OHL, in unmodified form only, for the distribution of 9 | their own Open Hardware designs. Any other right is reserved. Release 10 | of hardware designs under the CERN OHL does not constitute an 11 | endorsement of the licensor or its designs nor does it imply any 12 | involvement by CERN in the development of such designs. 13 | 14 | 1. Definitions 15 | 16 | In this Licence, the following terms have the following meanings: 17 | 18 | “Licence” means this CERN OHL. 19 | 20 | “Documentation” means schematic diagrams, designs, circuit or circuit 21 | board layouts, mechanical drawings, flow charts and descriptive text, 22 | and other explanatory material that is explicitly stated as being made 23 | available under the conditions of this Licence. The Documentation may 24 | be in any medium, including but not limited to computer files and 25 | representations on paper, film, or any other media. 26 | 27 | “Documentation Location” means a location where the Licensor has 28 | placed Documentation, and which he believes will be publicly 29 | accessible for at least three years from the first communication to 30 | the public or distribution of Documentation. 31 | 32 | “Product” means either an entire, or any part of a, device built using 33 | the Documentation or the modified Documentation. 34 | 35 | “Licensee” means any natural or legal person exercising rights under 36 | this Licence. 37 | 38 | “Licensor” means any natural or legal person that creates or modifies 39 | Documentation and subsequently communicates to the public and/ or 40 | distributes the resulting Documentation under the terms and conditions 41 | of this Licence. 42 | 43 | A Licensee may at the same time be a Licensor, and vice versa. 44 | 45 | Use of the masculine gender includes the feminine and neuter genders 46 | and is employed solely to facilitate reading. 47 | 48 | 2. Applicability 49 | 50 | 2.1. This Licence governs the use, copying, modification, 51 | communication to the public and distribution of the Documentation, and 52 | the manufacture and distribution of Products. By exercising any right 53 | granted under this Licence, the Licensee irrevocably accepts these 54 | terms and conditions. 55 | 56 | 2.2. This Licence is granted by the Licensor directly to the Licensee, 57 | and shall apply worldwide and without limitation in time. The Licensee 58 | may assign his licence rights or grant sub-licences. 59 | 60 | 2.3. This Licence does not extend to software, firmware, or code 61 | loaded into programmable devices which may be used in conjunction with 62 | the Documentation, the modified Documentation or with Products, unless 63 | such software, firmware, or code is explicitly expressed to be subject 64 | to this Licence. The use of such software, firmware, or code is 65 | otherwise subject to the applicable licence terms and conditions. 66 | 67 | 3. Copying, modification, communication to the public and distribution 68 | of the Documentation 69 | 70 | 3.1. The Licensee shall keep intact all copyright and trademarks 71 | notices, all notices referring to Documentation Location, and all 72 | notices that refer to this Licence and to the disclaimer of warranties 73 | that are included in the Documentation. He shall include a copy 74 | thereof in every copy of the Documentation or, as the case may be, 75 | modified Documentation, that he communicates to the public or 76 | distributes. 77 | 78 | 3.2. The Licensee may copy, communicate to the public and distribute 79 | verbatim copies of the Documentation, in any medium, subject to the 80 | requirements specified in section 3.1. 81 | 82 | 3.3. The Licensee may modify the Documentation or any portion thereof 83 | provided that upon modification of the Documentation, the Licensee 84 | shall make the modified Documentation available from a Documentation 85 | Location such that it can be easily located by an original Licensor 86 | once the Licensee communicates to the public or distributes the 87 | modified Documentation under section 3.4, and, where required by 88 | section 4.1, by a recipient of a Product. However, the Licensor shall 89 | not assert his rights under the foregoing proviso unless or until a 90 | Product is distributed. 91 | 92 | 3.4. The Licensee may communicate to the public and distribute the 93 | modified Documentation (thereby in addition to being a Licensee also 94 | becoming a Licensor), always provided that he shall: 95 | 96 | a) comply with section 3.1; 97 | 98 | b) cause the modified Documentation to carry prominent notices stating 99 | that the Licensee has modified the Documentation, with the date and 100 | description of the modifications; 101 | 102 | c) cause the modified Documentation to carry a new Documentation 103 | Location notice if the original Documentation provided for one; 104 | 105 | d) make available the modified Documentation at the same level of 106 | abstraction as that of the Documentation, in the preferred format for 107 | making modifications to it (e.g. the native format of the CAD tool as 108 | applicable), and in the event that format is proprietary, in a format 109 | viewable with a tool licensed under an OSI-approved license if the 110 | proprietary tool can create it; and 111 | 112 | e) license the modified Documentation under the terms and conditions 113 | of this Licence or, where applicable, a later version of this Licence 114 | as may be issued by CERN. 115 | 116 | 3.5. The Licence includes a non-exclusive licence to those patents or 117 | registered designs that are held by, under the control of, or 118 | sub-licensable by the Licensor, to the extent necessary to make use of 119 | the rights granted under this Licence. The scope of this section 3.5 120 | shall be strictly limited to the parts of the Documentation or 121 | modified Documentation created by the Licensor. 122 | 123 | 4. Manufacture and distribution of Products 124 | 125 | 4.1. The Licensee may manufacture or distribute Products always 126 | provided that, where such manufacture or distribution requires a 127 | licence under this Licence the Licensee provides to each recipient of 128 | such Products an easy means of accessing a copy of the Documentation 129 | or modified Documentation, as applicable, as set out in section 3. 130 | 131 | 4.2. The Licensee is invited to inform any Licensor who has indicated 132 | his wish to receive this information about the type, quantity and 133 | dates of production of Products the Licensee has (had) manufactured 134 | 135 | 5. Warranty and liability 136 | 137 | 5.1. DISCLAIMER – The Documentation and any modified Documentation are 138 | provided "as is" and any express or implied warranties, including, but 139 | not limited to, implied warranties of merchantability, of satisfactory 140 | quality, non-infringement of third party rights, and fitness for a 141 | particular purpose or use are disclaimed in respect of the 142 | Documentation, the modified Documentation or any Product. The Licensor 143 | makes no representation that the Documentation, modified 144 | Documentation, or any Product, does or will not infringe any patent, 145 | copyright, trade secret or other proprietary right. The entire risk as 146 | to the use, quality, and performance of a Product shall be with the 147 | Licensee and not the Licensor. This disclaimer of warranty is an 148 | essential part of this Licence and a condition for the grant of any 149 | rights granted under this Licence. The Licensee warrants that it does 150 | not act in a consumer capacity. 151 | 152 | 5.2. LIMITATION OF LIABILITY – The Licensor shall have no liability 153 | for direct, indirect, special, incidental, consequential, exemplary, 154 | punitive or other damages of any character including, without 155 | limitation, procurement of substitute goods or services, loss of use, 156 | data or profits, or business interruption, however caused and on any 157 | theory of contract, warranty, tort (including negligence), product 158 | liability or otherwise, arising in any way in relation to the 159 | Documentation, modified Documentation and/or the use, manufacture or 160 | distribution of a Product, even if advised of the possibility of such 161 | damages, and the Licensee shall hold the Licensor(s) free and harmless 162 | from any liability, costs, damages, fees and expenses, including 163 | claims by third parties, in relation to such use. 164 | 165 | 6. General 166 | 167 | 6.1. Except for the rights explicitly granted hereunder, this Licence 168 | does not imply or represent any transfer or assignment of intellectual 169 | property rights to the Licensee. 170 | 171 | 6.2. The Licensee shall not use or make reference to any of the names 172 | (including acronyms and abbreviations), images, or logos under which 173 | the Licensor is known, save in so far as required to comply with 174 | section 3. Any such permitted use or reference shall be factual and 175 | shall in no event suggest any kind of endorsement by the Licensor or 176 | its personnel of the modified Documentation or any Product, or any 177 | kind of implication by the Licensor or its personnel in the 178 | preparation of the modified Documentation or Product. 179 | 180 | 6.3. CERN may publish updated versions of this Licence which retain 181 | the same general provisions as this version, but differ in detail so 182 | far this is required and reasonable. New versions will be published 183 | with a unique version number. 184 | 185 | 6.4. This Licence shall terminate with immediate effect, upon written 186 | notice and without involvement of a court if the Licensee fails to 187 | comply with any of its terms and conditions, or if the Licensee 188 | initiates legal action against Licensor in relation to this 189 | Licence. Section 5 shall continue to apply. 190 | -------------------------------------------------------------------------------- /hardware/README.md: -------------------------------------------------------------------------------- 1 | Smart Citizen Kit 2 | ================= 3 | 4 | ###Smart Citizen Kit Ambient Sensor Board versions 5 | 6 | 7 | | Smart Citizen Kit | | SCK 1.0 (Goteo Board) | SCK 1.1 (Kickstarter Board) | 8 | |:-----------|:---------:|:---------------------------:|:---------------------------:| 9 | | **Data Board** | | | | 10 | | **MCU** | | ATMEGA32U4 | ATMEGA32U4 | 11 | | **Clock** | | 16Mhz | 8Mhz | 12 | | **WiFi** | | Microchip RN-131 802.11 b/g | Microchip RN-131 802.11 b/g | 13 | | **Firmware** | | https://github.com/fablabbcn/Smart-Citizen-Kit | https://github.com/fablabbcn/Smart-Citizen-Kit | 14 | | **Design files** | | https://github.com/fablabbcn/Smart-Citizen-Kit/tree/master/hardware/Goteo/v1.01 | https://github.com/fablabbcn/Smart-Citizen-Kit/tree/master/hardware/Kickstarter | 15 | | **Ambient Board** | | | | 16 | | **Light** | *Part* | PVD-P8001 | BH1730FVC | 17 | | | *Type* | LDR Analog Light Sensor | Digital Ambient Light Sensor | 18 | | | *Units* | % | Lux | 19 | | | *Datasheet* | https://github.com/fablabbcn/Smart-Citizen-Kit/wiki/Datasheets/PDV-P8001.pdf | https://github.com/fablabbcn/Smart-Citizen-Kit/wiki/Datasheets/BH-1730FCV.pdf | 20 | | | Firmware | `SCKAmbient::getLight();` | `SCKAmbient::getLight():` | 21 | | **Temp** | *Part* | DHT22 | HPP828E031 (SHT21) | 22 | | | *Type* | Digital Temperature and Relative Humidity Sensor | Digital Temperature and Relative Humidity Sensor | 23 | | | *Units* | ºC | ºC | 24 | | | *Datasheet* | https://github.com/fablabbcn/Smart-Citizen-Kit/wiki/Datasheets/DHT22.pdf | https://github.com/fablabbcn/Smart-Citizen-Kit/wiki/Datasheets/HTU-21D.pdf | 25 | | | Firmware | `SCKAmbient::getDHT22();` `SCKAmbient::getHumidity();` | `SCKAmbient::getSHT21();` `SCKAmbient::getTemperature();` | 26 | | **Humidity** | *Part* | DHT22 | HPP828E031 (SHT21) | 27 | | | *Type* | Digital Temperature and Relative Humidity Sensor | Digital Temperature and Relative Humidity Sensor | 28 | | | *Units* | % Rel | % Rel | 29 | | | *Datasheet* | https://github.com/fablabbcn/Smart-Citizen-Kit/wiki/Datasheets/DHT22.pdf | https://github.com/fablabbcn/Smart-Citizen-Kit/wiki/Datasheets/HTU-21D.pdf | 30 | | | Firmware | `SCKAmbient::getDHT22();` `SCKAmbient::getHumidity();` | `SCKAmbient::getSHT21();` `SCKAmbient::getHumidity();` | 31 | | **Noise** | *Part* | POM-3044P-R | POM-3044P-R | 32 | | | *Type* | Electret microphone with envelop follower sound pressure sensor | Electret microphone with envelop follower sound pressure sensor | 33 | | | *Units* | dB | dB | 34 | | | *Datasheet* | https://github.com/fablabbcn/Smart-Citizen-Kit/wiki/Datasheets/POM-3044P-R.pdf | https://github.com/fablabbcn/Smart-Citizen-Kit/wiki/Datasheets/POM-3044P-R.pdf | 35 | | | *Firmware* | `SCKAmbient::getNoise();` | `SCKAmbient::getNoise();` | 36 | | **CO** | *Part* | MICS-5525 | MiCS-4514 | 37 | | | *Type* | MOS CO gas sensor | MOS CO and NO2 gas sensor | 38 | | | *Units* | kOhm (ppm) | kOhm (ppm) | 39 | | | *Datasheet* | https://github.com/fablabbcn/Smart-Citizen-Kit/wiki/Datasheets/MICS-5525_CO.pdf | https://github.com/fablabbcn/Smart-Citizen-Kit/wiki/Datasheets/MiCS-4514_CO_NO2.pdf | 40 | | | *Firmware* | `SCKAmbient::getMICS();` | `SCKAmbient::getMICS();` | 41 | | **NO2** | *Part* | MICS-2710 | MiCS-4514 | 42 | | | *Type* | MOS NO2 gas sensor | MOS CO and NO2 gas sensor | 43 | | | *Units* | kOhm (ppm) | kOhm (ppm) | 44 | | | *Datasheet* | https://github.com/fablabbcn/Smart-Citizen-Kit/wiki/Datasheets/MICS-2710_NO2.pdf | https://github.com/fablabbcn/Smart-Citizen-Kit/wiki/Datasheets/MiCS-4514_CO_NO2.pdf | 45 | | | *Firmware* | `SCKAmbient::getMICS();` | `SCKAmbient::getMICS();` | 46 | -------------------------------------------------------------------------------- /sck-commands.md: -------------------------------------------------------------------------------- 1 | ## SCK Serial Commands 2 | 3 | The Smart Citizen Kit can be managed over a basic serial protocol. You just need the **Arduino IDE Serial Monitor** or any other **Serial Utility** like **Screen** in order to use it. 4 | 5 | #### How to use it. 6 | 7 | * Connect to your kit using any serial utility, any baud-rate should work but `115200` is recommendable. 8 | * Send the starting commands. 9 | * Notice all the commands except the starting commands require a carriage return at the end: `CR` or `\r` . 10 | * Call any command you want, change `XXX` with the corresponding value. 11 | 12 | ### Basic SCK setup commands 13 | 14 | This commands are commands to talk directly to the Wi-Fi module (RN-XV WiFly) own interface. 15 | 16 | * `$$$` Wake up the module and enter WiFly commands mode 17 | * `set wlan ssid XXX\r` Add a new SSID to memory 18 | * `set wlan phrase XXX\r` Add a new phrase to memory 19 | * `set wlan key XXX\r` Add a new key to memory 20 | * `set wlan auth XXX\r` Add an authentication method into memory 21 | * `set wlan ext_antenna XXX\r` Add an antenna type into memory 22 | * `set sys iofunc 0x7` Disable the Wi-Fi module blue LED's 23 | * `exit\r` Go back to normal operational mode 24 | 25 | ### Special SCK commands 26 | 27 | This commands are commands to talk talk to the SCK configuration interface. 28 | 29 | * `###` Wake up the module and enter SCK commands mode 30 | * `get mac\r` Get the MAC address of the kit 31 | * `get time update\r` Retrieve the sensor update interval 32 | * `set time update XXX\r` Update the sensor update interval 33 | * `get number updates\r` Retrieve the max number of bulk updates allowed 34 | * `set number updates XXX\r` Update the max number of bulk updates allowed 35 | * `get apikey\r` Retrieve the kit APIKEY 36 | * `set apikey XXX\r` Update the kit APIKEY 37 | * `get wlan ssid\r` Retrieve the SSID saved on the kit 38 | * `get wlan phrase\r` Retrieve the phrase and KEY saved on the kit 39 | * `get wlan auth\r` Retrieve the authentication methods saved on the kit 40 | * `get wlan ext_antenna\r` Retrieve the antenna types saved on the kit 41 | * `get all\r` Retrieve all config saved on the kit in a single line (`|version|MAC|ssid1 ssid2,pass1 pass2,auth1 auth2,ant1 ant2|hardcodedNets|timeUpdate|numPosts|`) 42 | * `post data\r` Retrieve sensor readings and post them to server if network connection is available. 43 | * `clear nets\r` Remove all saved Wi-Fi configuration information (except hardcoded) 44 | * `clear memory\r` Remove all configuration information 45 | * `exit\r` Goes back to normal operational mode 46 | * `#data\r` Retrieves sensor readings stored in memory 47 | -------------------------------------------------------------------------------- /sck_beta_v0_8_7_SDCARD/AccumulatorFilter.h: -------------------------------------------------------------------------------- 1 | // 2 | // AccumulatorFilter.h 3 | // AccumulatorFilter 4 | // 5 | // Created by Oriol Ferrer Mesià on 09/06/13. 6 | // 7 | // 8 | 9 | #ifndef AccumulatorFilter_AccumulatorFilter_h 10 | #define AccumulatorFilter_AccumulatorFilter_h 11 | 12 | #define GHETTO_VAL 0.02f 13 | class AccumulatorFilter{ 14 | 15 | public: 16 | 17 | AccumulatorFilter(){ 18 | val = GHETTO_VAL; 19 | upSpeed = 0.5f; 20 | } 21 | 22 | void setup(float upSpeed_){ 23 | val = 0.0f; 24 | upSpeed = upSpeed_; 25 | } 26 | 27 | void goUp(){ 28 | //Serial.println( "goUP!"); 29 | if (val <= GHETTO_VAL){ 30 | val = GHETTO_VAL; 31 | } 32 | val *= (1.0f + upSpeed * 2.0f * (1.0f - val) ); 33 | } 34 | 35 | void goDown(){ 36 | //Serial.println( "goDown!"); 37 | if (val >= 1.0f - GHETTO_VAL){ 38 | val = 1.0f - GHETTO_VAL; 39 | } 40 | val /= (1.0f + upSpeed * 2.0f * (1.0f - val) ); 41 | } 42 | 43 | float getVal(){ 44 | return val; 45 | } 46 | 47 | float getSpeed(){ 48 | return upSpeed; 49 | } 50 | 51 | float upSpeed; 52 | float val; 53 | }; 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /sck_beta_v0_8_7_SDCARD/Constants.h: -------------------------------------------------------------------------------- 1 | #define debuggSCK false 2 | #define decouplerComp true 3 | #define DataRaw false 4 | 5 | #define AWAKE 4 //Despertar WIFI 6 | #define PANEL A8 //Entrada panel 7 | #define BAT A7 //Entrada bateria 8 | 9 | #define IO0 5 //MICS5525_HEATHER 10 | #define IO1 13 //MICS2710_HEATHER 11 | #define IO2 9 //MICS2710_ALTAIMPEDANCIA 12 | #define IO3 10 //MICS2710_ALTAIMPEDANCIA 13 | #define FACTORY 7 //factory RESET/AP RN131 14 | #define CONTROL 12 //Control Mode 15 | 16 | #define S0 A4 //MICS_5525 17 | #define S1 A5 //MICS_2710 18 | #define S2 A2 //SENS_5525 19 | #define S3 A3 //SENS_2710 20 | #define S4 A0 //MICRO 21 | #define S5 A1 //LDR 22 | 23 | #define DEFAULT_TIME_UPDATE "30" //Tiempo entre actualizacion y actualizacion 24 | #define DEFAULT_MIN_UPDATES "1" //Minimo numero de actualizaciones antes de postear 25 | 26 | #define POST_MAX 20 //Maximo numero de posteos a la vez 27 | 28 | //Direcciones I2C 29 | #define RTC_ADDRESS 0x68 // Direcion de la RTC 30 | #define E2PROM 0x50 // Direcion de la EEPROM 31 | 32 | #if F_CPU == 8000000 33 | #define MCP1 0x2E // Direcion del mcp1 Potenciometros que controlan los MICS 34 | #define MCP2 0x2F // Direcion del mcp2 Potenciometros que controlan la ganancia del microfono 35 | #define MCP3 0x2D // Direcion del mcp3 Ajuste carga bateria 36 | #define bh1730 0x29 // Direcion del sensor de luz 37 | #define Temperature 0x40 // Direcion del sht21 38 | #define ADXL 0x53 //ADXL345 device address 39 | #else 40 | #define MCP1 0x2F // Direcion del mcp1 MICS 41 | #define MCP2 0x2E // Direcion del mcp2 REGULADORES 42 | #endif 43 | 44 | //Espacio reservado para los parametros de configuracion del SCK 45 | #define EE_ADDR_TIME_VERSION 0 //32BYTES 46 | #define EE_ADDR_TIME_UPDATE 32 //16BYTES Tiempo entre actualizacion y actualizacion de los sensores en segundos 47 | #define EE_ADDR_NUMBER_UPDATES 48 //4BYTES Numero de actualizaciones antes de postear 48 | 49 | 50 | #define MICS_5525 0x00 51 | #define MICS_2710 0x01 52 | 53 | #define Rc0 10. //Ohm Resistencia medica de corriente en el sensor MICS_5525/MICS_5524 54 | 55 | #if F_CPU == 8000000 56 | #define Rc1 39. //Ohm Resistencia medica de corriente en el sensor MICS_2714 57 | #else 58 | #define Rc1 10. //Ohm Resistencia medica de corriente en el sensor MICS_2710 59 | #endif 60 | 61 | #if F_CPU == 8000000 62 | float Vcc = 3300.; //mV 63 | #define VMIC0 2734. 64 | #define VMIC1 2734. 65 | #else 66 | float Vcc = 5000.; //mV 67 | #define VMIC0 5000. 68 | #define VMIC1 2500. 69 | #endif 70 | 71 | #define reference 2560. 72 | 73 | #if F_CPU == 8000000 74 | #define VAL_MAX_BATTERY 4200 75 | #define VAL_MIN_BATTERY 3000 76 | #else 77 | #define VAL_MAX_BATTERY 4050 78 | #define VAL_MIN_BATTERY 3000 79 | #endif 80 | 81 | 82 | #define DHTLIB_INVALID_VALUE -999 83 | 84 | -------------------------------------------------------------------------------- /sck_beta_v0_8_7_SDCARD/README.md: -------------------------------------------------------------------------------- 1 | Smart Citizen Kit firmware for SD 2 | ================================= 3 | 4 | **Smart Citizen Kit SD firmware version for the Ambient Sensor Board.** 5 | 6 | This firmware is aimed to people wanting to log data in off-line mode, without internet connectivity, storing data on the built-in micro SD. 7 | 8 | 9 | ##Steps 10 | 11 | 1. **microSD**: We recomend formating **micro SD** cards using the official SD tool you can download [here](https://www.sdcard.org/downloads/formatter_4/). 12 | 13 | 2. **RTC**: Place a **CR1220** cell battery on your kit. Before uploading the SD firmware use the on-line configuration tool at [smartcitizen.me](https://smartcitizen.me) to set your Wi-Fi credentials. Your kit will connect to the internet and sync its the internal clock with our remote servers. 14 | 15 | 3. You can now install the **SD firmware** using the Arduino IDE. Ready! 16 | 17 | 18 | ##Installation 19 | 20 | 21 | **The firmware is totally compatible with Arduino. You can upload the firmware using the [Arduino IDE](http://arduino.cc/en/main/software).** 22 | 23 | ####Dependencies: 24 | 25 | In order to compile and upload the firmware you will need to install the **SdFat** library for Arduino. 26 | 27 | Download the library [here](https://github.com/greiman/SdFat) and install the library following the [instructions](http://arduino.cc/en/Guide/Libraries). 28 | 29 | ####Boards: 30 | 31 | * For SmartCitizen Kit version 1.0 select `Tools/Boards/Arduino Leonardo` on the Arduino IDE (ATmega 32U4 at 16Mhz) 32 | 33 | * For SmartCitizen Kit version 1.1 select `Tools/Boards/Lylipad Arduino USB` on the Arduino IDE (ATmega 32U4 at 8Mhz) 34 | 35 | ##SD data format 36 | 37 | 38 | When using the **SD firmware** on the SCK, data is stored as **CSV** (comma separated) file on the SD card. 39 | 40 | This is an example of the output file once opened on a spreadsheet application: 41 | 42 | | Temperature | Humidity| Light | Battery | Solar Panel | CO | NO2 | Noise| UTC | 43 | |-------------|---------|---------|---------|-------------|--------|------|------|----------------------| 44 | | 2821.20 | 4072.00 | 4413.10 | 96.40 | 0.00 | 94.67 | 0.65 | 5.23 | 2000-01-01 00:00:02 | 45 | | 2784.40 | 4236.80 | 5936.70 | 96.10 | 0.00 | 278.27 | 1.05 | 2.39 | 2000-01-01 00:00:02 | 46 | 47 | ###Data Import 48 | 49 | You can import the recorded data in to [smartcitizen.me](http://smartcitizen.me). 50 | 51 | In your device page you will find the **Import SD** along with the Edit and Configure options. 52 | 53 | ![image](https://smartcitizen.me/img/sck-sd-import.png) 54 | 55 | Using a microSD card reader get the **post.csv** file from your card, select it and click import. Data will be imported in to your device, data existing on the file already imported will be skipped. Your kit should be running the latest SD firmware and the SCK time (RTC) should be set in order data can be imported. 56 | 57 | ###Data Conversions 58 | 59 | The data stored is automatically converted to the proper units in firmware. 60 | 61 | If you prefer to do the conversions manually set `DataRaw false` in the `Constants.h` file and apply the formulas on the following table: 62 | 63 | 64 | | ID | Sensor | Units | Conversion Formula 65 | |-----|--------------|-------|---------------------------------------------| 66 | | 0 | Temperature | ºC | T = -53 + 175.72 / 65536.0 * ( Traw * 10 ) | 67 | | 1 | Humidity | %Rel | H = 7 + 125.0 / 65536.0 * ( Hraw * 10 ) | 68 | | 2 | Light | Lux | L = Lraw / 10 | 69 | | 3 | Battery | % | Not required | 70 | | 4 | Panel | mV | Not required | 71 | | 5 | CO | kOhm | Not required | 72 | | 6 | NO2 | kOhm | Not required | 73 | | 7 | Noise | dB | Apply the conversion table from mV to dB: [CSV](https://gist.github.com/pral2a/d767cc45874361fd38bf) 74 | | 8 | Date | DD:MM:YY | Not required | 75 | | 9 | Time | hh:mm:ss | Not required | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /sck_beta_v0_8_7_SDCARD/SCKAmbient.ino: -------------------------------------------------------------------------------- 1 | 2 | //Valores por defecto de la resistencia en vacio de los MICS 3 | float RoCO = 750000; 4 | float RoNO2 = 2200; 5 | 6 | #if ((decouplerComp)&&(F_CPU > 8000000 )) 7 | #include "TemperatureDecoupler.h" 8 | TemperatureDecoupler decoupler; //use this object to compensate for charger generated heat affecting temp values 9 | #endif 10 | 11 | float RsCO = 0; 12 | float RsNO2 = 0; 13 | 14 | #define RES 256 //Resolucion de los potenciometros digitales 15 | 16 | #if F_CPU == 8000000 17 | #define R1 12 //Kohm 18 | #else 19 | #define R1 82 //Kohm 20 | #endif 21 | 22 | #define P1 100 //Kohm 23 | 24 | float k= (RES*(float)R1/100)/1000; //Constante de conversion a tension de los reguladores 25 | float kr= ((float)P1*1000)/RES; //Constante de conversion a resistencia de potenciometrosen ohmios 26 | 27 | #if F_CPU == 8000000 28 | uint16_t lastHumidity; 29 | uint16_t lastTemperature; 30 | int accel_x=0; 31 | int accel_y=0; 32 | int accel_z=0; 33 | #else 34 | int lastHumidity; 35 | int lastTemperature; 36 | #endif 37 | 38 | 39 | 40 | void sckWriteVH(byte device, long voltage ) { 41 | int data=0; 42 | 43 | #if F_CPU == 8000000 44 | int temp = (int)(((voltage/0.41)-1000)*k); 45 | #else 46 | int temp = (int)(((voltage/1.2)-1000)*k); 47 | #endif 48 | 49 | if (temp>RES) data = RES; 50 | else if (temp<0) data=0; 51 | else data = temp; 52 | #if F_CPU == 8000000 53 | sckWriteMCP(MCP1, device, data); 54 | #else 55 | sckWriteMCP(MCP2, device, data); 56 | #endif 57 | } 58 | 59 | 60 | float sckReadVH(byte device) { 61 | int data; 62 | #if F_CPU == 8000000 63 | data=sckReadMCP(MCP1, device); 64 | float voltage = (data/k + 1000)*0.41; 65 | #else 66 | data=sckReadMCP(MCP2, device); 67 | float voltage = (data/k + 1000)*1.2; 68 | #endif 69 | 70 | return(voltage); 71 | } 72 | 73 | void sckWriteRL(byte device, long resistor) { 74 | int data=0x00; 75 | data = (int)(resistor/kr); 76 | #if F_CPU == 8000000 77 | sckWriteMCP(MCP1, device + 6, data); 78 | #else 79 | sckWriteMCP(MCP1, device, data); 80 | #endif 81 | } 82 | 83 | float sckReadRL(byte device) 84 | { 85 | #if F_CPU == 8000000 86 | return (kr*sckReadMCP(MCP1, device + 6)); //Devuelve en Ohms 87 | #else 88 | return (kr*sckReadMCP(MCP1, device)); //Devuelve en Ohms 89 | #endif 90 | } 91 | 92 | void sckWriteRGAIN(byte device, long resistor) { 93 | int data=0x00; 94 | data = (int)(resistor/kr); 95 | sckWriteMCP(MCP2, device, data); 96 | } 97 | 98 | float sckReadRGAIN(byte device) 99 | { 100 | return (kr*sckReadMCP(MCP2, device)); //Devuelve en Ohms 101 | } 102 | 103 | void sckWriteGAIN(long value) 104 | { 105 | if (value == 100) 106 | { 107 | sckWriteRGAIN(0x00, 10000); 108 | sckWriteRGAIN(0x01, 10000); 109 | } 110 | else if (value == 1000) 111 | { 112 | sckWriteRGAIN(0x00, 10000); 113 | sckWriteRGAIN(0x01, 100000); 114 | } 115 | else if (value == 10000) 116 | { 117 | sckWriteRGAIN(0x00, 100000); 118 | sckWriteRGAIN(0x01, 100000); 119 | } 120 | delay(100); 121 | } 122 | 123 | float sckReadGAIN() 124 | { 125 | return (sckReadRGAIN(0x00)/1000)*(sckReadRGAIN(0x01)/1000); 126 | } 127 | 128 | void sckGetVcc() 129 | { 130 | float temp = average(S3); 131 | analogReference(INTERNAL); 132 | delay(100); 133 | Vcc = (float)(average(S3)/temp)*reference; 134 | analogReference(DEFAULT); 135 | delay(100); 136 | } 137 | 138 | void sckHeat(byte device, int current) 139 | { 140 | float Rc=Rc0; 141 | byte Sensor = S2; 142 | if (device == MICS_2710) { Rc=Rc1; Sensor = S3;} 143 | 144 | float Vc = (float)average(Sensor)*Vcc/1023; //mV 145 | float current_measure = Vc/Rc; //mA 146 | float Rh = (sckReadVH(device)- Vc)/current_measure; 147 | float Vh = (Rh + Rc)*current; 148 | 149 | sckWriteVH(device, Vh); 150 | #if debuggSCK 151 | if (device == MICS_2710) Serial.print("MICS2710 corriente: "); 152 | else Serial.print("MICS5525 corriente: "); 153 | Serial.print(current_measure); 154 | Serial.println(" mA"); 155 | if (device == MICS_2710) Serial.print("MICS2710 correccion VH: "); 156 | else Serial.print("MICS5525 correccion VH: "); 157 | Serial.print(sckReadVH(device)); 158 | Serial.println(" mV"); 159 | Vc = (float)average(Sensor)*Vcc/1023; //mV 160 | current_measure = Vc/Rc; //mA 161 | if (device == MICS_2710) Serial.print("MICS2710 corriente corregida: "); 162 | else Serial.print("MICS5525 corriente corregida: "); 163 | Serial.print(current_measure); 164 | Serial.println(" mA"); 165 | Serial.println("Heating..."); 166 | #endif 167 | 168 | } 169 | 170 | float sckReadRs(byte device) 171 | { 172 | byte Sensor = S0; 173 | float VMICS = VMIC0; 174 | if (device == MICS_2710) {Sensor = S1; VMICS = VMIC1;} 175 | float RL = sckReadRL(device); //Ohm 176 | float VL = ((float)average(Sensor)*Vcc)/1023; //mV 177 | if (VL > VMICS) VL = VMICS; 178 | float Rs = ((VMICS-VL)/VL)*RL; //Ohm 179 | #if debuggSCK 180 | if (device == MICS_5525) Serial.print("MICS5525 Rs: "); 181 | else Serial.print("MICS2710 Rs: "); 182 | Serial.print(VL); 183 | Serial.print(" mV, "); 184 | Serial.print(Rs); 185 | Serial.println(" Ohm"); 186 | #endif; 187 | return Rs; 188 | } 189 | 190 | float sckReadMICS(byte device) 191 | { 192 | float Rs = sckReadRs(device); 193 | float RL = sckReadRL(device); //Ohm 194 | 195 | /*Correccion de impedancia de carga*/ 196 | if ((Rs <= (RL - 1000))||(Rs >= (RL + 1000))) 197 | { 198 | if (Rs < 2000) sckWriteRL(device, 2000); 199 | else sckWriteRL(device, Rs); 200 | delay(100); 201 | Rs = sckReadRs(device); 202 | } 203 | return Rs; 204 | } 205 | 206 | void sckGetMICS(){ 207 | 208 | /*Correccion de la tension del Heather*/ 209 | sckHeat(MICS_5525, 32); //Corriente en mA 210 | sckHeat(MICS_2710, 26); //Corriente en mA 211 | 212 | RsCO = sckReadMICS(MICS_5525); 213 | RsNO2 = sckReadMICS(MICS_2710); 214 | 215 | } 216 | 217 | #if F_CPU == 8000000 218 | uint16_t sckReadSHT21(uint8_t type){ 219 | uint16_t DATA = 0; 220 | Wire.beginTransmission(Temperature); 221 | Wire.write(type); 222 | Wire.endTransmission(); 223 | Wire.requestFrom(Temperature,2); 224 | unsigned long time = millis(); 225 | while (!Wire.available()) if ((millis() - time)>500) return 0x00; 226 | DATA = Wire.read()<<8; 227 | while (!Wire.available()); 228 | DATA = (DATA|Wire.read()); 229 | DATA &= ~0x0003; 230 | return DATA; 231 | } 232 | 233 | void sckGetSHT21() 234 | { 235 | #if DataRaw 236 | lastTemperature = sckReadSHT21(0xE3); // Datos en RAW para conversion por plataforma 237 | lastHumidity = sckReadSHT21(0xE5); // Datos en RAW para conversion por plataforma 238 | #else 239 | //T = -53 + 175.72 / 65536.0 * ( Traw * 10 ) 240 | lastTemperature = (-50 + 175.72 / 65536.0 * ( sckReadSHT21(0xE3))) * 10 ; 241 | //H = 7 + 125.0 / 65536.0 * ( Hraw * 10 ) 242 | lastHumidity = (4 + 125.0 / 65536.0 * ( sckReadSHT21(0xE5))) * 10 ; 243 | #endif 244 | 245 | #if debuggSCK 246 | Serial.print("SHT21: "); 247 | Serial.print("Temperatura: "); 248 | Serial.print(lastTemperature/10.); 249 | Serial.print(" C, Humedad: "); 250 | Serial.print(lastHumidity/10.); 251 | Serial.println(" %"); 252 | #endif 253 | } 254 | 255 | void sckWriteADXL(byte address, byte val) { 256 | Wire.beginTransmission(ADXL); //start transmission to device 257 | Wire.write(address); // write register address 258 | Wire.write(val); // write value to write 259 | Wire.endTransmission(); //end transmission 260 | } 261 | 262 | //reads num bytes starting from address register on device in to buff array 263 | void sckrReadADXL(byte address, int num, byte buff[]) { 264 | Wire.beginTransmission(ADXL); //start transmission to device 265 | Wire.write(address); //writes address to read from 266 | Wire.endTransmission(); //end transmission 267 | 268 | Wire.beginTransmission(ADXL); //start transmission to device 269 | Wire.requestFrom(ADXL, num); // request 6 bytes from device 270 | 271 | int i = 0; 272 | unsigned long time = millis(); 273 | while (!Wire.available()) 274 | { 275 | if ((millis() - time)>500) 276 | { 277 | for(int i=0; i1000) temp=1000; 468 | if (temp<0) temp=0; 469 | return temp; 470 | #endif 471 | } 472 | 473 | 474 | unsigned int sckGetNoise() { 475 | 476 | #if F_CPU == 8000000 477 | #define GAIN 10000 478 | sckWriteGAIN(GAIN); 479 | delay(100); 480 | #endif 481 | 482 | float mVRaw = (float)((average(S4))/1023.)*Vcc; 483 | float dB = 0; 484 | 485 | #if F_CPU == 8000000 486 | #if DataRaw==false 487 | //dB = 0.0222*mVRaw + 58.006; 488 | //aplicar aqui conversion 489 | if(mVRaw<=5){ 490 | dB = (5+44*mVRaw)/5; 491 | }else if(mVRaw<=15){ 492 | dB = (195 + 8*mVRaw)/5; 493 | }else if(mVRaw<=40){ 494 | dB = (1220 + 4*mVRaw)/20; 495 | }else if(mVRaw <= 300){ 496 | //y=69.242283950617+0.038618827160494x 497 | dB = (69.242283950617 + 0.038618827160494*mVRaw); 498 | }else if(mVRaw <= 950){ 499 | //y=76.744423542059+0.013363343187315x 500 | dB = (76.744423542059+0.013363343187315*mVRaw); 501 | } else { 502 | //y=80.167357356927+0.0085240259833374x 503 | dB = (80.167357356927+0.0085240259833374*mVRaw); 504 | } 505 | #endif 506 | #else 507 | #if DataRaw==false 508 | dB = 9.7*log( (mVRaw*200)/1000. ) + 40; // calibracion para ruido rosa // energia constante por octava 509 | if (dB<50) dB = 50; // minimo con la resolucion actual! 510 | #endif 511 | #endif 512 | 513 | #if debuggSCK 514 | Serial.print("nOISE = "); 515 | Serial.print(mVRaw); 516 | #if DataRaw==false 517 | Serial.print(" mV nOISE = "); 518 | Serial.print(dB); 519 | Serial.print(" dB, GAIN = "); 520 | #else 521 | Serial.print(" mV GAIN = "); 522 | #endif 523 | Serial.println(GAIN); 524 | #endif 525 | 526 | #if DataRaw 527 | return mVRaw; 528 | #else 529 | return dB*100; 530 | #endif 531 | } 532 | 533 | unsigned long sckGetCO() 534 | { 535 | return RsCO; 536 | } 537 | 538 | unsigned long sckGetNO2() 539 | { 540 | return RsNO2; 541 | } 542 | 543 | 544 | -------------------------------------------------------------------------------- /sck_beta_v0_8_7_SDCARD/SCKBase.ino: -------------------------------------------------------------------------------- 1 | boolean connected; 2 | 3 | #define buffer_length 32 4 | static char buffer[buffer_length]; 5 | 6 | #define TWI_FREQ 400000L //Frecuencia bus I2C 7 | 8 | void sckBegin() { 9 | Wire.begin(); 10 | TWBR = ((F_CPU / TWI_FREQ) - 16) / 2; 11 | Serial.begin(115200); 12 | Serial1.begin(9600); 13 | pinMode(IO0, OUTPUT); //VH_MICS5525 14 | pinMode(IO1, OUTPUT); //VH_MICS2710 15 | pinMode(IO2, OUTPUT); //MICS2710_ALTAIMPEDANCIA 16 | pinMode(AWAKE, OUTPUT); 17 | pinMode(MOSI, OUTPUT); 18 | pinMode(SCK, OUTPUT); 19 | pinMode(FACTORY, OUTPUT); 20 | pinMode(CONTROL, INPUT); 21 | digitalWrite(AWAKE, HIGH); 22 | digitalWrite(FACTORY, LOW); 23 | #if ((decouplerComp)&&(F_CPU > 8000000 )) 24 | decoupler.setup(); 25 | #endif 26 | #if F_CPU == 8000000 27 | sckWriteCharge(350); 28 | 29 | sckWriteVH(MICS_5525, 2700); //VH_MICS5525 Inicial 30 | digitalWrite(IO0, HIGH); //VH_MICS5525 31 | 32 | sckWriteVH(MICS_2710, 1700); //VH_MICS5525 Inicial 33 | digitalWrite(IO1, HIGH); //VH_MICS2710 34 | digitalWrite(IO2, LOW); //RADJ_MICS2710 PIN ALTA IMPEDANCIA 35 | 36 | pinMode(IO3, OUTPUT); 37 | digitalWrite(IO3, HIGH); //Alimentacion de los MICS 38 | 39 | #if ADXLEnabled 40 | sckWriteADXL(0x2D, 0x08); 41 | // sckWriteADXL(0x31, 0x00); //2g 42 | // sckWriteADXL(0x31, 0x01); //4g 43 | sckWriteADXL(0x31, 0x02); //8g 44 | // sckWriteADXL(0x31, 0x03); //16g 45 | #endif 46 | 47 | #else 48 | sckWriteVH(MICS_5525, 2400); //VH_MICS5525 Inicial 49 | digitalWrite(IO0, HIGH); //VH_MICS5525 50 | 51 | sckWriteVH(MICS_2710, 1700); //VH_MICS5525 Inicial 52 | digitalWrite(IO1, HIGH); //VH_MICS2710 53 | digitalWrite(IO2, LOW); //RADJ_MICS2710 PIN ALTA IMPEDANCIA 54 | #endif 55 | 56 | sckWriteRL(MICS_5525, 100000); //Inicializacion de la carga del MICS5525 57 | sckWriteRL(MICS_2710, 100000); //Inicializacion de la carga del MICS2710 58 | } 59 | 60 | void sckConfig(){ 61 | 62 | if (!sckCompareDate(__TIME__, sckReadData(EE_ADDR_TIME_VERSION, 0, 0))) 63 | { 64 | sckRTCadjust(sckDate(__DATE__,__TIME__)); 65 | #if debuggEnabled 66 | Serial.println(F("Resetting...")); 67 | #endif 68 | for(uint16_t i=0; i<60; i++) sckWriteEEPROM(i, 0x00); //Borrado de la memoria 69 | sckWriteData(EE_ADDR_TIME_VERSION, 0, __TIME__); 70 | sckWriteData(EE_ADDR_TIME_UPDATE, 0, DEFAULT_TIME_UPDATE); 71 | sckWriteData(EE_ADDR_NUMBER_UPDATES, 0, DEFAULT_MIN_UPDATES); 72 | } 73 | 74 | } 75 | 76 | float average(int anaPin) { 77 | int lecturas = 100; 78 | long total = 0; 79 | float average = 0; 80 | for(int i=0; iRES) data=RES; 106 | Wire.beginTransmission(deviceaddress); 107 | address=(address<<4)|bitRead(data, 8) ; 108 | Wire.write(address); 109 | Wire.write(lowByte(data)); 110 | Wire.endTransmission(); 111 | delay(4); 112 | } 113 | 114 | int sckReadMCP(int deviceaddress, uint16_t address ) { 115 | byte rdata = 0xFF; 116 | int data = 0x0000; 117 | Wire.beginTransmission(deviceaddress); 118 | address=(address<<4)|B00001100; 119 | Wire.write(address); 120 | Wire.endTransmission(); 121 | Wire.requestFrom(deviceaddress,2); 122 | unsigned long time = millis(); 123 | while (!Wire.available()) if ((millis() - time)>500) return 0x00; 124 | rdata = Wire.read(); 125 | data=rdata<<8; 126 | while (!Wire.available()); 127 | rdata = Wire.read(); 128 | data=data|rdata; 129 | return data; 130 | } 131 | 132 | #if F_CPU == 8000000 133 | float sckReadCharge() { 134 | float resistor = kr*sckReadMCP(MCP3, 0x00)/1000; 135 | float current = 1000./(2+((resistor * 10)/(resistor + 10))); 136 | #if debuggSCK 137 | Serial.print("Resistor : "); 138 | Serial.print(resistor); 139 | Serial.print(" kOhm, "); 140 | Serial.print("Current : "); 141 | Serial.print(current); 142 | Serial.println(" mA"); 143 | #endif 144 | return(current); 145 | } 146 | 147 | void sckWriteCharge(int current) { 148 | if (current < 100) current = 100; 149 | else if (current > 500) current = 500; 150 | float Rp = (1000./current)-2; 151 | float resistor = Rp*10/(10-Rp); 152 | sckWriteMCP(MCP3, 0x00, (uint8_t)(resistor*1000/kr)); 153 | #if debuggSCK 154 | Serial.print("Rc : "); 155 | Serial.print(Rp + 2); 156 | Serial.print(" kOhm, "); 157 | Serial.print("Rpot : "); 158 | Serial.print(resistor); 159 | Serial.print(" kOhm, "); 160 | Serial.print("Current : "); 161 | Serial.print(current); 162 | Serial.println(" mA"); 163 | #endif 164 | } 165 | #endif 166 | 167 | void sckWriteEEPROM(uint16_t eeaddress, uint8_t data ) { 168 | uint8_t retry = 0; 169 | while ((sckReadEEPROM(eeaddress)!=data)&&(retry<10)) 170 | { 171 | EEPROM.write(eeaddress, data); 172 | delay(6); 173 | retry++; 174 | } 175 | } 176 | 177 | byte sckReadEEPROM(uint16_t eeaddress ) { 178 | return EEPROM.read(eeaddress); 179 | } 180 | 181 | 182 | void sckWriteintEEPROM(uint16_t eeaddress, uint16_t data ) 183 | { 184 | sckWriteEEPROM(eeaddress , highByte(data)); 185 | sckWriteEEPROM(eeaddress + 1, lowByte(data)); 186 | } 187 | 188 | uint16_t sckReadintEEPROM(uint16_t eeaddress) 189 | { 190 | return (sckReadEEPROM(eeaddress)<<8)+ sckReadEEPROM(eeaddress + 1); 191 | } 192 | 193 | char* sckReadData(uint16_t eeaddress, uint16_t pos, uint8_t dec) 194 | { 195 | eeaddress = eeaddress + buffer_length * pos; 196 | uint8_t temp = sckReadEEPROM(eeaddress); 197 | uint16_t i; 198 | for ( i = eeaddress; ((temp!= 0x00)&&(temp<0x7E)&&(temp>0x1F)&&((i - eeaddress)0)) 204 | { 205 | if ((i - eeaddress)500) return false; 235 | Wire.read(); 236 | return true; 237 | } 238 | 239 | 240 | char* sckDate(const char* date, const char* time){ 241 | int j = 0; 242 | for (int i = 7; date[i]!=0x00; i++) 243 | { 244 | buffer[j] = date[i]; 245 | j++; 246 | } 247 | buffer[j] = '-'; 248 | j++; 249 | // Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec 250 | switch (date[0]) { 251 | case 'J': 252 | if (date[1] == 'a') buffer[j] = '1'; 253 | else if (date[2] == 'n') buffer[j] = '6'; 254 | else buffer[j] = '7'; 255 | break; 256 | case 'F': 257 | buffer[j] = '2'; 258 | break; 259 | case 'A': 260 | if (date[1] == 'p') buffer[j] = '4'; 261 | else buffer[j] = '8'; 262 | break; 263 | case 'M': 264 | if (date[2] == 'r') buffer[j] = '3'; 265 | else buffer[j] = '5'; 266 | break; 267 | case 'S': 268 | buffer[j] = '9'; 269 | break; 270 | case 'O': 271 | buffer[j] = '1'; 272 | buffer[j+1] = '0'; 273 | j++; 274 | break; 275 | case 'N': 276 | buffer[j] = '1'; 277 | buffer[j+1] = '1'; 278 | j++; 279 | break; 280 | case 'D': 281 | buffer[j] = '1'; 282 | buffer[j+1] = '2'; 283 | j++; 284 | break; 285 | } 286 | j++; 287 | buffer[j] = '-'; 288 | j++; 289 | for (int i = 4; date[i]!=' '; i++) 290 | { 291 | buffer[j] = date[i]; 292 | j++; 293 | } 294 | buffer[j] = ' '; 295 | j++; 296 | for (int i = 0; time[i]!=0x00; i++) 297 | { 298 | buffer[j] = time[i]; 299 | j++; 300 | } 301 | buffer[j]=0x00; 302 | return buffer; 303 | } 304 | 305 | boolean sckRTCadjust(char *time) { 306 | byte rtc[6] = { 307 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 308 | }; 309 | byte count = 0x00; 310 | byte data_count=0; 311 | while (time[count]!=0x00) 312 | { 313 | if(time[count] == '-') data_count++; 314 | else if(time[count] == ' ') data_count++; 315 | else if(time[count] == ':') data_count++; 316 | else if ((time[count] >= '0')&&(time[count] <= '9')) 317 | { 318 | rtc[data_count] =(rtc[data_count]<<4)|(0x0F&time[count]); 319 | } 320 | else break; 321 | count++; 322 | } 323 | if (data_count == 5) 324 | { 325 | #if F_CPU == 8000000 326 | Wire.beginTransmission(RTC_ADDRESS); 327 | Wire.write((int)0); 328 | Wire.write(rtc[5]); 329 | Wire.write(rtc[4]); 330 | Wire.write(rtc[3]); 331 | Wire.write(0x00); 332 | Wire.write(rtc[2]); 333 | Wire.write(rtc[1]); 334 | Wire.write(rtc[0]); 335 | Wire.endTransmission(); 336 | delay(4); 337 | Wire.beginTransmission(RTC_ADDRESS); 338 | Wire.write(0x0E); //Address 339 | Wire.write(0x00); //Value 340 | Wire.endTransmission(); 341 | #else 342 | Wire.beginTransmission(RTC_ADDRESS); 343 | Wire.write((int)0); 344 | Wire.write(rtc[5]); 345 | Wire.write(rtc[4]); 346 | Wire.write(rtc[3]); 347 | Wire.write(0x00); 348 | Wire.write(rtc[2]); 349 | Wire.write(rtc[1]); 350 | Wire.write(rtc[0]); 351 | Wire.write((int)0); 352 | Wire.endTransmission(); 353 | return true; 354 | #endif 355 | return true; 356 | } 357 | return false; 358 | } 359 | 360 | char* sckRTCtime() { 361 | Wire.beginTransmission(RTC_ADDRESS); 362 | Wire.write((int)0); 363 | Wire.endTransmission(); 364 | Wire.requestFrom(RTC_ADDRESS, 7); 365 | uint8_t seconds = (Wire.read() & 0x7F); 366 | uint8_t minutes = Wire.read(); 367 | uint8_t hours = Wire.read(); 368 | Wire.read(); 369 | uint8_t day = Wire.read(); 370 | uint8_t month = Wire.read(); 371 | uint8_t year = Wire.read(); 372 | buffer[0] = '2'; 373 | buffer[1] = '0'; 374 | buffer[2] = (year>>4) + '0'; 375 | buffer[3] = (year&0x0F) + '0'; 376 | buffer[4] = '-'; 377 | buffer[5] = (month>>4) + '0'; 378 | buffer[6] = (month&0x0F) + '0'; 379 | buffer[7] = '-'; 380 | buffer[8] = (day>>4) + '0'; 381 | buffer[9] = (day&0x0F) + '0'; 382 | buffer[10] = ' '; 383 | buffer[11] = (hours>>4) + '0'; 384 | buffer[12] = (hours&0x0F) + '0'; 385 | buffer[13] = ':'; 386 | buffer[14] = (minutes>>4) + '0'; 387 | buffer[15] = (minutes&0x0F) + '0'; 388 | buffer[16] = ':'; 389 | buffer[17] = (seconds>>4) + '0'; 390 | buffer[18] = (seconds&0x0F) + '0'; 391 | buffer[19] = 0x00; 392 | return buffer; 393 | } 394 | 395 | 396 | uint16_t sckGetPanel(){ 397 | #if F_CPU == 8000000 398 | uint16_t value = 11*average(PANEL)*Vcc/1023.; 399 | if (value > 500) value = value + 120; //Tension del diodo de proteccion 400 | else value = 0; 401 | #else 402 | uint16_t value = 3*average(PANEL)*Vcc/1023.; 403 | if (value > 500) value = value + 750; //Tension del diodo de proteccion 404 | else value = 0; 405 | #endif 406 | #if debuggSCK 407 | Serial.print("Panel = "); 408 | Serial.print(value); 409 | Serial.println(" mV"); 410 | #endif 411 | return value; 412 | } 413 | 414 | uint16_t sckGetBattery() { 415 | uint16_t temp = average(BAT); 416 | #if F_CPU == 8000000 417 | float voltage = Vcc*temp/1023.; 418 | voltage = voltage + (voltage/180)*100; 419 | #else 420 | float voltage = Vcc*temp/1023.; 421 | #endif 422 | temp = map(voltage, VAL_MIN_BATTERY, VAL_MAX_BATTERY, 0, 1000); 423 | if (temp>1000) temp=1000; 424 | if (temp<0) temp=0; 425 | #if debuggSCK 426 | Serial.print("Vbat: "); 427 | Serial.print(voltage); 428 | Serial.print(" mV, "); 429 | Serial.print("Battery level: "); 430 | Serial.print(temp/10.); 431 | Serial.println(" %"); 432 | #endif 433 | return temp; 434 | } 435 | 436 | #define COMMAND_MODE_GUARD_TIME 250 // in milliseconds 437 | 438 | boolean sckSleep() { 439 | delay(COMMAND_MODE_GUARD_TIME); 440 | Serial1.print(F("$$$")); 441 | delay(COMMAND_MODE_GUARD_TIME); 442 | Serial1.println(); 443 | Serial1.println(); 444 | Serial1.println(F("sleep")); 445 | } 446 | 447 | char* itoa(int32_t number) 448 | { 449 | byte count = 0; 450 | uint32_t temp; 451 | if (number < 0) { 452 | temp = number*(-1); 453 | count++; 454 | } 455 | while ((temp/10)!=0) 456 | { 457 | temp = temp/10; 458 | count++; 459 | } 460 | int i; 461 | if (number < 0) { 462 | temp = number*(-1); 463 | } 464 | else temp = number; 465 | for (i = count; i>=0; i--) 466 | { 467 | buffer[i] = temp%10 + '0'; 468 | temp = temp/10; 469 | } 470 | if (number < 0) { 471 | buffer[0] = '-'; 472 | } 473 | buffer[count + 1] = 0x00; 474 | return buffer; 475 | } 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | -------------------------------------------------------------------------------- /sck_beta_v0_8_7_SDCARD/SDUpdate.ino: -------------------------------------------------------------------------------- 1 | void txSD() { 2 | Serial.println("*** txSD ***"); 3 | // if the file opened okay, write to it: 4 | if (myFile.open("post.csv", FILE_WRITE)) { 5 | #if debuggEnabled 6 | Serial.println(F("Writing...")); 7 | #endif 8 | float dec = 0; 9 | for (int i=0; i<8; i++) 10 | { 11 | if (i<4) dec = 10; 12 | else if (i<7) dec = 1000; 13 | else if (i<8) dec = 100; 14 | else dec = 1; 15 | 16 | //myFile.print(i); 17 | //myFile.print(" "); 18 | myFile.print(SENSORvalue[i]/dec); 19 | myFile.print(","); 20 | } 21 | myFile.print(sckRTCtime()); 22 | myFile.println(); 23 | // close the file: 24 | myFile.close(); 25 | #if debuggEnabled 26 | Serial.println(F("Closing...")); 27 | #endif 28 | } 29 | } 30 | 31 | char* SENSOR[10]={ 32 | "Temperature", 33 | "Humidity", 34 | "Light", 35 | "Battery", 36 | "Solar Panel", 37 | "Carbon Monxide", 38 | "Nitrogen Dioxide", 39 | "Noise", 40 | "Wifi Spots", 41 | "UTC" 42 | }; 43 | 44 | char* UNITS[10]={ 45 | #if F_CPU == 8000000 46 | #if DataRaw 47 | " C RAW", 48 | " % RAW", 49 | #else 50 | " C", 51 | " %", 52 | #endif 53 | #else 54 | " C", 55 | " %", 56 | #endif 57 | #if F_CPU == 8000000 58 | " lx", 59 | #else 60 | " %", 61 | #endif 62 | " %", 63 | " V", 64 | " kOhm", 65 | " kOhm", 66 | #if DataRaw 67 | " mV", 68 | #else 69 | " dB", 70 | #endif 71 | "", 72 | "" 73 | }; 74 | 75 | void updateSensorsSD() { 76 | #if F_CPU == 8000000 77 | sckGetVcc(); 78 | sckGetSHT21(); 79 | SENSORvalue[0] = lastTemperature; // C 80 | SENSORvalue[1] = lastHumidity; // % 81 | #else 82 | if (sckDHT22(IO3)) 83 | { 84 | SENSORvalue[0] = lastTemperature; // C 85 | SENSORvalue[1] = lastHumidity; // % 86 | } 87 | #endif 88 | sckGetMICS(); 89 | SENSORvalue[2] = sckGetLight(); // % 90 | SENSORvalue[3] = sckGetBattery(); //% 91 | SENSORvalue[4] = sckGetPanel(); // % 92 | SENSORvalue[5] = sckGetCO(); //Ohm 93 | SENSORvalue[6] = sckGetNO2(); //Ohm 94 | SENSORvalue[7] = sckGetNoise(); //dB 95 | } 96 | 97 | void txDebugSD() { 98 | Serial.println("*** txDebugSD ***"); 99 | float dec = 0; 100 | for(int i=0; i<8; i++) 101 | { 102 | if (i<4) dec = 10; 103 | else if (i<7) dec = 1000; 104 | else if (i<8) dec = 100; 105 | else dec = 1; 106 | Serial.print(SENSOR[i]); 107 | Serial.print(": "); 108 | Serial.print((SENSORvalue[i])/dec); 109 | Serial.println(UNITS[i]); 110 | } 111 | Serial.print(SENSOR[9]); 112 | Serial.print(": "); 113 | Serial.println(sckRTCtime()); 114 | Serial.println(F("*******************")); 115 | } 116 | 117 | void txHeader() { 118 | Serial.println("*** txHeader ***"); 119 | // if the file opened okay, write to it: 120 | if (myFile.open("post.csv", FILE_WRITE)) { 121 | #if debuggEnabled 122 | Serial.println(F("Writing...")); 123 | #endif 124 | for (int i=0; i<8; i++) 125 | { 126 | myFile.print(SENSOR[i]); 127 | myFile.print(" ("); 128 | myFile.print(UNITS[i]); 129 | myFile.print(") "); 130 | myFile.print(", "); 131 | } 132 | myFile.print(SENSOR[9]); 133 | myFile.println(); 134 | // close the file: 135 | myFile.close(); 136 | #if debuggEnabled 137 | Serial.println(F("Closing...")); 138 | #endif 139 | } 140 | } 141 | 142 | 143 | -------------------------------------------------------------------------------- /sck_beta_v0_8_7_SDCARD/TemperatureDecoupler.h: -------------------------------------------------------------------------------- 1 | // 2 | // TemperatureDecoupler.h 3 | // SmartCitizen 4 | // 5 | // Created by Oriol Ferrer Mesià on 03/06/13. 6 | // 7 | // 8 | 9 | #ifndef SmartCitizen_TemperatureDecoupler_h 10 | #define SmartCitizen_TemperatureDecoupler_h 11 | 12 | #define BATTERY_HEATUP_MAX 11 13 | #define BATTERY_CHARGE_THRESHOLD 980 14 | #include 15 | #include "AccumulatorFilter.h" 16 | 17 | 18 | class TemperatureDecoupler{ 19 | 20 | public: 21 | 22 | void setup(){ 23 | _prevBattery = 0; 24 | filter.setup(0.3); 25 | } 26 | 27 | void update( uint16_t battery ){ 28 | 29 | //Serial.println( "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #" ); 30 | 31 | bool charging = false; 32 | bool doNothing = false; 33 | if (battery == _prevBattery){ 34 | //doNothing; 35 | if ( battery > BATTERY_CHARGE_THRESHOLD ){ 36 | charging = true; 37 | //Serial.println( "Battery same val > 980! charging!"); 38 | }else{ 39 | charging = false; 40 | //Serial.println( "Battery same val < 980! NOT charging!"); 41 | } 42 | }else{ 43 | if ( battery > _prevBattery || battery > BATTERY_CHARGE_THRESHOLD ){ //battery is charging! 44 | //Serial.println( "Battery charging!"); 45 | charging = true; 46 | }else{ //battery is being drained 47 | //Serial.println( "Battery dis-charging!"); 48 | charging = false; 49 | } 50 | } 51 | 52 | if (!doNothing){ 53 | if(charging) 54 | filter.goUp(); 55 | else 56 | filter.goDown(); 57 | } 58 | 59 | //Serial.print(F("battery: ")); Serial.println( battery ); 60 | //Serial.print(F("_prevBattery: ")); Serial.println( _prevBattery ); 61 | //Serial.print(F("filter: ")); Serial.println( filter.getVal() ); 62 | 63 | //Serial.println( "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #" ); 64 | //store last bat reading for future comparing 65 | _prevBattery = battery; 66 | lastChargingState = charging; 67 | } 68 | 69 | short int getCompensation(){ 70 | return (short int) (filter.getVal() * BATTERY_HEATUP_MAX); 71 | } 72 | 73 | short int _prevBattery; 74 | AccumulatorFilter filter; 75 | bool lastChargingState; //true == up, false == down 76 | 77 | }; 78 | 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /sck_beta_v0_8_7_SDCARD/sck_beta_v0_8_7_SDCARD.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "Constants.h" 6 | 7 | #define USBEnabled true 8 | #define sensorEnabled true 9 | #define debuggEnabled true 10 | #define ADXLEnabled false 11 | 12 | uint32_t timetransmit = 0; 13 | uint32_t TimeUpdate = 0; //Variable temporal de tiempo entre actualizacion y actualizacion de los sensensores 14 | uint32_t NumUpdates = 0; //Numero de actualizaciones antes de postear 15 | 16 | SdFat sd; 17 | SdFile myFile; 18 | long SENSORvalue[8]; 19 | boolean csvInit = false; 20 | 21 | void setup() { 22 | 23 | delay(5000); 24 | 25 | sckBegin(); 26 | sckConfig(); 27 | sckSleep(); 28 | #if debuggEnabled 29 | Serial.print(F("Initializing SD card...")); 30 | #endif 31 | if (!sd.begin(11)) { 32 | #if debuggEnabled 33 | Serial.println(F("initialization failed!")); 34 | #endif 35 | return; 36 | } 37 | #if debuggEnabled 38 | Serial.println(F("initialization done.")); 39 | #endif 40 | if (!sd.exists("post.csv")) { 41 | #if debuggEnabled 42 | Serial.println(F("Creating post.csv...")); 43 | #endif 44 | myFile.open("post.csv", FILE_WRITE); 45 | myFile.close(); 46 | delay(1000); 47 | txHeader(); 48 | 49 | } else{ 50 | #if debuggEnabled 51 | Serial.println(F("post.csv exists ...")); 52 | #endif 53 | } 54 | 55 | timetransmit = millis(); 56 | TimeUpdate = atol(sckReadData(EE_ADDR_TIME_UPDATE, 0, 0)); //Tiempo entre transmision y transmision en segundos 57 | } 58 | 59 | void loop() { 60 | #if sensorEnabled 61 | if ((millis()-timetransmit) >= (unsigned long)TimeUpdate*1000) 62 | { 63 | Serial.println("*** loop ***"); 64 | timetransmit = millis(); 65 | TimeUpdate = atol(sckReadData(EE_ADDR_TIME_UPDATE, 0, 0)); 66 | updateSensorsSD(); 67 | txSD(); 68 | #if USBEnabled 69 | txDebugSD(); 70 | #endif 71 | } 72 | #endif 73 | } 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /sck_beta_v0_9/AccumulatorFilter.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | AccumulatorFilter.h 4 | AccumulatorFilter 5 | Created by Oriol Ferrer Mesià on 09/06/13. 6 | 7 | */ 8 | 9 | #ifndef AccumulatorFilter_AccumulatorFilter_h 10 | #define AccumulatorFilter_AccumulatorFilter_h 11 | 12 | #define GHETTO_VAL 0.02f 13 | class AccumulatorFilter{ 14 | 15 | public: 16 | 17 | AccumulatorFilter(){ 18 | val = GHETTO_VAL; 19 | upSpeed = 0.5f; 20 | } 21 | 22 | void setup(float upSpeed_){ 23 | val = 0.0f; 24 | upSpeed = upSpeed_; 25 | } 26 | 27 | void goUp(){ 28 | //Serial.println( "goUP!"); 29 | if (val <= GHETTO_VAL){ 30 | val = GHETTO_VAL; 31 | } 32 | val *= (1.0f + upSpeed * 2.0f * (1.0f - val) ); 33 | } 34 | 35 | void goDown(){ 36 | //Serial.println( "goDown!"); 37 | if (val >= 1.0f - GHETTO_VAL){ 38 | val = 1.0f - GHETTO_VAL; 39 | } 40 | val /= (1.0f + upSpeed * 2.0f * (1.0f - val) ); 41 | } 42 | 43 | float getVal(){ 44 | return val; 45 | } 46 | 47 | float getSpeed(){ 48 | return upSpeed; 49 | } 50 | 51 | float upSpeed; 52 | float val; 53 | }; 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /sck_beta_v0_9/Constants.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Constants.h 4 | Defines ATMEGA32U4 pins and other SENSORS and COMUNICATIONS static parameters. 5 | 6 | */ 7 | 8 | #define debugEnabled true 9 | #define decouplerComp true //Only for version Goteo 1.0 10 | 11 | #if F_CPU == 8000000 12 | #define FirmWare "1.1-0.9.4" 13 | #else 14 | #define FirmWare "1.0-0.9.4" 15 | #endif 16 | 17 | /* 18 | 19 | WIFI AND SERVER STATICS - WiFly, Http server parameters. 20 | 21 | */ 22 | // WiFly Auth Modes 23 | #define OPEN "0" 24 | #define WEP "1" 25 | #define WPA "2" 26 | #define MIXED "3" 27 | #define WPA2 "4" 28 | #define WEP64 "8" 29 | 30 | #define EXT_ANT "1" // External Antenna 31 | #define INT_ANT "0" // Internal Antenna 32 | 33 | /* 34 | 35 | WIFLY Firmware Setting 36 | 37 | */ 38 | 39 | #define networks 0 40 | #if (networks > 0) 41 | static char* mySSID[networks] = { 42 | "SSID1" , "SSID2" }; 43 | static char* myPassword[networks] = { 44 | "PASS1" , "PASS2" }; 45 | static char* wifiEncript[networks] = { 46 | WPA2 , WPA2 }; 47 | static char* antennaExt[networks] = { 48 | INT_ANT , INT_ANT }; 49 | #endif 50 | 51 | #define TWI_FREQ 400000L //Frecuencia bus I2C 52 | 53 | #define WIFLY_LATEST_VERSION 475 54 | #define DEFAULT_WIFLY_FIRMWARE "ftp update wifly3-475.img" 55 | #define DEFAULT_WIFLY_FTP_UPDATE "set ftp address 198.175.253.161" 56 | 57 | /* 58 | 59 | ARDUINO ports definitions - GPIOS and ADCs 60 | 61 | */ 62 | 63 | #define AWAKE 4 // WIFLY AWAKE 64 | #define PANEL A8 // PANEL LEVEL 65 | #define BAT A7 // BAT LEVEL 66 | 67 | #define IO0 5 // MICS5525_HEATHER 68 | #define IO1 13 // MICS2710_HEATHER 69 | #define IO2 9 // MICS2710_HIGH_IMPEDANCE 70 | #define IO3 10 // MICS2710_HIGH_IMPEDANCE 71 | #define FACTORY 7 // WIFLY - Factory RESET/AP RN131 72 | #define CONTROL 12 // WIFLY - CONTROL 73 | 74 | #define S0 A4 //MICS_5525 75 | #define S1 A5 //MICS_2710 76 | #define S2 A2 //SENS_5525 77 | #define S3 A3 //SENS_2710 78 | #define S4 A0 //MICRO 79 | #define S5 A1 //LDR 80 | 81 | 82 | /* 83 | 84 | SENSOR READINGS - Defaults 85 | 86 | */ 87 | 88 | #define DEFAULT_TIME_UPDATE 60 //Time between update and update 89 | #define MIN_TIME_UPDATE 10 //Minimum time between updates (minimum time to read all the sensors) 90 | #define MAX_TIME_UPDATE 3600 //Max time between updates (one hour) 91 | #define DEFAULT_MIN_UPDATES 1 //Minimum number of updates before posting 92 | #define POST_MAX 20 //Max number of postings at a time 93 | #define DEFAULT_MODE_SENSOR NORMAL //Type sensors capture (OFFLINE, NOWIFI, NORMAL, ECONOMIC) 94 | 95 | /* 96 | 97 | i2c ADDRESSES 98 | 99 | */ 100 | #define RTC_ADDRESS 0x68 // Direction of the RTC 101 | #define E2PROM 0x50 // Direction of the EEPROM 102 | 103 | #if F_CPU == 8000000 104 | #define MCP1 0x2E // Direction of the mcp1 Potenciometers that control the MICS 105 | #define MCP2 0x2F // Direction of the mcp2 Potenciometers that control the microfone pickup 106 | #define bh1730 0x29 // Direction of the light sensor 107 | #define Temperature 0x40 // Direction of the sht21 108 | #define ADXL 0x53 //ADXL345 device address 109 | #else 110 | #define MCP1 0x2F // Direction of the mcp1 MICS 111 | #define MCP2 0x2E // Direction of the mcp2 REGULATORS 112 | #endif 113 | 114 | #if F_CPU == 8000000 115 | #define R1 12 //Kohm 116 | #else 117 | #define R1 82 //Kohm 118 | #endif 119 | 120 | #define P1 100 //Kohm 121 | 122 | 123 | /* 124 | 125 | Internal EEPROM Memory Addresses 126 | 127 | */ 128 | 129 | #define MAX_MEMORY 571 //Memory size 130 | 131 | // SCK Configuration Parameters 132 | #define EE_ADDR_TIME_VERSION 0 //32BYTES 133 | #define EE_ADDR_TIME_UPDATE 32 //4BYTES Time between update and update of the sensors in seconds 134 | #define EE_ADDR_SENSOR_MODE 36 //4BYTES Type sensors capture 135 | #define EE_ADDR_NUMBER_UPDATES 40 //4BYTES Number of updates before posting 136 | #define EE_ADDR_NUMBER_READ_MEASURE 44 //4BYTES Number of updates before posting 137 | #define EE_ADDR_NUMBER_WRITE_MEASURE 48 //4BYTES Number of updates before posting 138 | #define EE_ADDR_NUMBER_NETS 52 //4BYTES Number of networks in the memory 139 | #define EE_ADDR_APIKEY 56 //32BYTES Apikey of the device 140 | #define EE_ADDR_MAC 100 //32BYTES MAC of the device 141 | 142 | // SCK WIFI SETTINGS Parameters 143 | #define DEFAULT_ADDR_SSID 150 //160 BYTES 144 | #define DEFAULT_ADDR_PASS 310 //160 BYTES 145 | #define DEFAULT_ADDR_AUTH 470 //160 BYTES 146 | #define DEFAULT_ADDR_ANTENNA 630 //160 BYTES 147 | 148 | 149 | /* 150 | 151 | External EEPROM Memory Addresses 152 | 153 | */ 154 | 155 | // SCK DATA SPACE (Sensor readings can be stored here to do batch updates) 156 | #define DEFAULT_ADDR_MEASURES 0 157 | 158 | 159 | /* 160 | 161 | MICS PARAMETERS - Gas Sensor Addresses and Defaults 162 | 163 | */ 164 | 165 | #define MICS_5525 0x00 166 | #define MICS_2710 0x01 167 | 168 | #define RES 256 // Digital pot. resolution 169 | #define P1 100 //Digital potentiometer resistance 100Kohm 170 | 171 | #define Rc0 10. //Ohm. Average current resistance for sensor MICS_5525/MICS_5524 172 | 173 | #if F_CPU == 8000000 174 | #define Rc1 39. //Ohm. Average current resistance for sensor MICS_2714 175 | #else 176 | #define Rc1 10. //Ohm. Average current resistance for sensor MICS_2710 177 | #endif 178 | 179 | #if F_CPU == 8000000 180 | #define VMIC0 2734. 181 | #define VMIC1 2734. 182 | #else 183 | #define VMIC0 5000. 184 | #define VMIC1 2500. 185 | #endif 186 | 187 | #define reference 2560. 188 | #define second 1000 189 | #define minute 60000 190 | 191 | /* 192 | 193 | BATTERY PARAMETERS - Battery sensing calibration parameters 194 | 195 | */ 196 | 197 | #if F_CPU == 8000000 198 | #define VAL_MAX_BATTERY 4200 199 | #define VAL_MIN_BATTERY 3000 200 | #else 201 | #define VAL_MAX_BATTERY 4050 202 | #define VAL_MIN_BATTERY 3000 203 | #endif 204 | 205 | 206 | #define DHTLIB_INVALID_VALUE -999 207 | 208 | #define OFFLINE 0 //No connect to server 209 | #define NOWIFI 1 //No connect arduino to wifi module 210 | #define NORMAL 2 //Nomal mode o real time 211 | #define ECONOMIC 3 //Economic mode, sensor gas active one time for hour 212 | 213 | #define SENSORS 9 //Numbers of sensors in the board 214 | 215 | #define buffer_length 32 216 | static char buffer[buffer_length]; 217 | 218 | // Basic Server Posts to the SmartCitizen Platform - EndPoint: http://data.smartcitizen.me/add 219 | static char* WEB[8]={ 220 | "data.smartcitizen.me", 221 | "PUT /add HTTP/1.1\n", 222 | "Host: data.smartcitizen.me \n", 223 | "User-Agent: SmartCitizen \n", 224 | "X-SmartCitizenMacADDR: ", 225 | "X-SmartCitizenApiKey: ", 226 | "X-SmartCitizenVersion: ", 227 | "X-SmartCitizenData: "}; 228 | 229 | // Time server request - EndPoint: http://data.smartcitizen.me/datetime 230 | static char* WEBTIME[3]={ 231 | /*Servidor de tiempo*/ 232 | "GET /datetime HTTP/1.1\n", 233 | "Host: data.smartcitizen.me \n", 234 | "User-Agent: SmartCitizen \n\n" 235 | }; 236 | 237 | // Data JSON structure 238 | static char* SERVER[11]={ 239 | "{\"temp\":\"", 240 | "\",\"hum\":\"", 241 | "\",\"light\":\"", 242 | "\",\"bat\":\"", 243 | "\",\"panel\":\"", 244 | "\",\"co\":\"", 245 | "\",\"no2\":\"", 246 | "\",\"noise\":\"", 247 | "\",\"nets\":\"", 248 | "\",\"timestamp\":\"", 249 | "\"}" 250 | }; 251 | 252 | static char* SENSOR[10]={ 253 | "Temperature: ", 254 | "Humidity: ", 255 | "Light: ", 256 | "Battery: ", 257 | "Solar Panel: ", 258 | "Carbon Monxide: ", 259 | "Nitrogen Dioxide: ", 260 | "Noise: ", 261 | "Wifi Spots: ", 262 | "UTC: " 263 | }; 264 | 265 | static char* UNITS[9]={ 266 | #if F_CPU == 8000000 267 | " C RAW", 268 | " % RAW", 269 | #else 270 | " C", 271 | " %", 272 | #endif 273 | #if F_CPU == 8000000 274 | " lx", 275 | #else 276 | " %", 277 | #endif 278 | " %", 279 | " mV", 280 | " kOhm", 281 | " kOhm", 282 | " mV", 283 | "", 284 | }; 285 | -------------------------------------------------------------------------------- /sck_beta_v0_9/SCKAmbient.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | SCKAmbient.h 4 | Supports the sensor reading and calibration functions. 5 | 6 | - Sensors supported (sensors use on board custom peripherials): 7 | 8 | - TEMP / HUM (DHT22 and HPP828E031) 9 | - NOISE 10 | - LIGHT (LDR and BH1730FVC) 11 | - CO (MICS5525 and MICS4514) 12 | - NO2 (MiCS2710 and MICS4514) 13 | 14 | */ 15 | 16 | 17 | /* 18 | 19 | SENSOR Contants and Defaults 20 | 21 | */ 22 | 23 | #ifndef __SCKAMBIENT_H__ 24 | #define __SCKAMBIENT_H__ 25 | 26 | #include 27 | 28 | #define TIME_BUFFER_SIZE 20 29 | 30 | class SCKAmbient { 31 | public: 32 | void begin(); 33 | void ini(); 34 | void execute(boolean instant); 35 | void writeGAIN(long value); 36 | float readGAIN(); 37 | void GasSensor(boolean active); 38 | void getMICS(); 39 | unsigned long getCO(); 40 | unsigned long getNO2(); 41 | 42 | void getSHT21(); 43 | boolean getDHT22(); 44 | #if F_CPU == 8000000 45 | uint32_t getTemperature(); 46 | uint32_t getHumidity(); 47 | #else 48 | int getTemperature(); 49 | int getHumidity(); 50 | #endif 51 | 52 | void readADXL(byte address, int num, byte buff[]); 53 | uint16_t getLight(); 54 | unsigned int getNoise(); 55 | 56 | void txDebug(); 57 | boolean debug_state(); 58 | 59 | void serialRequests(); 60 | private: 61 | void writeVH(byte device, long voltage ); 62 | float readVH(byte device); 63 | void writeRL(byte device, long resistor); 64 | float readRL(byte device); 65 | void writeRGAIN(byte device, long resistor); 66 | float readRGAIN(byte device); 67 | void getVcc(); 68 | void heat(byte device, int current); 69 | float readRs(byte device); 70 | float readMICS(byte device); 71 | void writeADXL(byte address, byte val); 72 | void averageADXL(); 73 | void updateSensors(byte mode); 74 | uint16_t readSHT21(uint8_t type); 75 | boolean DhtRead(uint8_t pin); 76 | int addData(byte inByte); 77 | boolean printNetWorks(unsigned int address_eeprom, boolean endLine); 78 | void addNetWork(unsigned int address_eeprom, char* text); 79 | }; 80 | #endif 81 | -------------------------------------------------------------------------------- /sck_beta_v0_9/SCKBase.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | SCKBase.cpp 4 | Supports core and data management functions (Power, WiFi, SD storage, RTClock and EEPROM storage) 5 | 6 | - Modules supported: 7 | 8 | - WIFI (Microchip RN131 (WiFly)) 9 | - RTC (DS1339U and DS1307Z) 10 | - EEPROM (24LC256) 11 | - POWER MANAGEMENT IC's 12 | 13 | */ 14 | 15 | #include "Constants.h" 16 | #include "SCKBase.h" 17 | #include 18 | #include 19 | 20 | #define debugBASE false 21 | 22 | 23 | 24 | void SCKBase::begin() { 25 | Wire.begin(); 26 | TWBR = ((F_CPU / TWI_FREQ) - 16) / 2; 27 | Serial.begin(115200); 28 | Serial1.begin(9600); 29 | pinMode(IO0, OUTPUT); //VH_MICS5525 30 | pinMode(IO1, OUTPUT); //VH_MICS2710 31 | pinMode(IO2, OUTPUT); //MICS2710_HIGH_IMPEDANCE 32 | pinMode(AWAKE, OUTPUT); 33 | pinMode(MOSI, OUTPUT); 34 | pinMode(SCK, OUTPUT); 35 | pinMode(FACTORY, OUTPUT); 36 | pinMode(CONTROL, INPUT); 37 | digitalWrite(AWAKE, LOW); 38 | digitalWrite(FACTORY, LOW); 39 | } 40 | 41 | void SCKBase::config(){ 42 | eepromCheck(); 43 | timer1Initialize(); 44 | } 45 | 46 | void SCKBase::eepromCheck() { 47 | //do a clearmemory only if needed 48 | digitalWrite(AWAKE, HIGH); 49 | boolean doClearMemory = false; 50 | char temp[17]; 51 | strncpy(temp, MAC(), 18); 52 | while (compareData(temp, "-1")){ 53 | #if debugBASE 54 | Serial.println(F("Can't get MAC from Wifly!!!")); 55 | #endif 56 | strncpy(temp, MAC(), 18); 57 | } 58 | if (!compareData(temp, readData(EE_ADDR_MAC, 0, INTERNAL))) doClearMemory = true; 59 | uint32_t intTemp; 60 | intTemp = readData(EE_ADDR_SENSOR_MODE, INTERNAL); 61 | if (intTemp < 0 || intTemp > 3) doClearMemory = true; 62 | intTemp = readData(EE_ADDR_TIME_UPDATE, INTERNAL); 63 | if (intTemp < MIN_TIME_UPDATE || intTemp > MAX_TIME_UPDATE) doClearMemory = true; 64 | intTemp = readData(EE_ADDR_NUMBER_UPDATES, INTERNAL); 65 | if (intTemp < DEFAULT_MIN_UPDATES || intTemp > POST_MAX) doClearMemory = true; 66 | if (doClearMemory) clearmemory(); 67 | 68 | //if there are hardcoded networks write them without clearing memory 69 | //so the user can add more networks after hardcoded one's 70 | #if (networks > 0) 71 | intTemp = readData(EE_ADDR_NUMBER_NETS, INTERNAL); 72 | if (intTemp < networks || intTemp > 5) writeData(EE_ADDR_NUMBER_NETS, networks, INTERNAL); 73 | for (byte i=0; iRES) data=RES; 146 | Wire.beginTransmission(deviceaddress); 147 | address=(address<<4)|bitRead(data, 8) ; 148 | Wire.write(address); 149 | Wire.write(lowByte(data)); 150 | Wire.endTransmission(); 151 | delay(4); 152 | } 153 | 154 | int SCKBase::readMCP(int deviceaddress, uint16_t address ) { 155 | byte rdata = 0xFF; 156 | int data = 0x0000; 157 | Wire.beginTransmission(deviceaddress); 158 | address=(address<<4)|B00001100; 159 | Wire.write(address); 160 | Wire.endTransmission(); 161 | Wire.requestFrom(deviceaddress,2); 162 | unsigned long time = millis(); 163 | while (!Wire.available()) if ((millis() - time)>500) return 0x00; 164 | rdata = Wire.read(); 165 | data=rdata<<8; 166 | while (!Wire.available()); 167 | rdata = Wire.read(); 168 | data=data|rdata; 169 | return data; 170 | } 171 | 172 | #if F_CPU == 8000000 173 | #define MCP3 0x2D // Direction of the mcp3 Ajust the battary charge 174 | float SCKBase::readCharge() { 175 | float resistor = kr*readMCP(MCP3, 0x00)/1000; 176 | float current = 1000./(2+((resistor * 10)/(resistor + 10))); 177 | #if debugBASE 178 | Serial.print("Resistor : "); 179 | Serial.print(resistor); 180 | Serial.print(" kOhm, "); 181 | Serial.print("Current : "); 182 | Serial.print(current); 183 | Serial.println(" mA"); 184 | #endif 185 | return(current); 186 | } 187 | 188 | void SCKBase::writeCharge(int current) { 189 | if (current < 100) current = 100; 190 | else if (current > 500) current = 500; 191 | float Rp = (1000./current)-2; 192 | float resistor = Rp*10/(10-Rp); 193 | writeMCP(MCP3, 0x00, (uint8_t)(resistor*1000/kr)); 194 | #if debugBASE 195 | Serial.print("Rc : "); 196 | Serial.print(Rp + 2); 197 | Serial.print(" kOhm, "); 198 | Serial.print("Rpot : "); 199 | Serial.print(resistor); 200 | Serial.print(" kOhm, "); 201 | Serial.print("Current : "); 202 | Serial.print(current); 203 | Serial.println(" mA"); 204 | #endif 205 | } 206 | #endif 207 | 208 | void SCKBase::writeEEPROM(uint16_t eeaddress, uint8_t data) { 209 | uint8_t retry = 0; 210 | while ((readEEPROM(eeaddress)!=data)&&(retry<10)) 211 | { 212 | Wire.beginTransmission(E2PROM); 213 | Wire.write((byte)(eeaddress >> 8)); // MSB 214 | Wire.write((byte)(eeaddress & 0xFF)); // LSB 215 | Wire.write(data); 216 | Wire.endTransmission(); 217 | delay(6); 218 | retry++; 219 | } 220 | } 221 | 222 | byte SCKBase::readEEPROM(uint16_t eeaddress) { 223 | byte rdata = 0xFF; 224 | Wire.beginTransmission(E2PROM); 225 | Wire.write((byte)(eeaddress >> 8)); // MSB 226 | Wire.write((byte)(eeaddress & 0xFF)); // LSB 227 | Wire.endTransmission(); 228 | Wire.requestFrom(E2PROM,1); 229 | while (!Wire.available()); 230 | rdata = Wire.read(); 231 | return rdata; 232 | } 233 | 234 | void SCKBase::writeData(uint32_t eeaddress, long data, uint8_t location) 235 | { 236 | for (int i =0; i<4; i++) 237 | { 238 | if (location == EXTERNAL) writeEEPROM(eeaddress + (3 -i) , data>>(i*8)); 239 | else EEPROM.write(eeaddress + (3 -i), data>>(i*8)); 240 | } 241 | 242 | } 243 | 244 | void SCKBase::writeData(uint32_t eeaddress, uint16_t pos, char* text, uint8_t location) 245 | { 246 | uint16_t eeaddressfree = eeaddress + buffer_length * pos; 247 | if (location == EXTERNAL) 248 | { 249 | for (uint16_t i = eeaddressfree; i< (eeaddressfree + buffer_length); i++) writeEEPROM(i, 0x00); 250 | for (uint16_t i = eeaddressfree; text[i - eeaddressfree]!= 0x00; i++) writeEEPROM(i, text[i - eeaddressfree]); 251 | } 252 | else 253 | { 254 | 255 | for (uint16_t i = eeaddressfree; i< (eeaddressfree + buffer_length); i++) EEPROM.write(i, 0x00); 256 | for (uint16_t i = eeaddressfree; text[i - eeaddressfree]!= 0x00; i++) 257 | { 258 | if (eeaddressfree>=DEFAULT_ADDR_SSID) if (text[i - eeaddressfree]==' ') text[i - eeaddressfree]='$'; 259 | EEPROM.write(i, text[i - eeaddressfree]); 260 | } 261 | } 262 | } 263 | 264 | uint32_t SCKBase::readData(uint16_t eeaddress, uint8_t location) 265 | { 266 | uint32_t data = 0; 267 | for (int i =0; i<4; i++) 268 | { 269 | if (location == EXTERNAL) data = data + (uint32_t)((uint32_t)readEEPROM(eeaddress + i)<<((3-i)*8)); 270 | else data = data + (uint32_t)((uint32_t)EEPROM.read(eeaddress + i)<<((3-i)*8)); 271 | } 272 | return data; 273 | } 274 | 275 | char* SCKBase::readData(uint16_t eeaddress, uint16_t pos, uint8_t location) 276 | { 277 | eeaddress = eeaddress + buffer_length * pos; 278 | uint16_t i; 279 | if (location == EXTERNAL) 280 | { 281 | uint8_t temp = readEEPROM(eeaddress); 282 | for ( i = eeaddress; ((temp!= 0x00)&&(temp<0x7E)&&(temp>0x1F)&&((i - eeaddress)0x1F)&&((i - eeaddress)500) return false; 309 | Wire.read(); 310 | return true; 311 | } 312 | 313 | boolean SCKBase::RTCadjust(char *time) { 314 | byte rtc[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 315 | byte count = 0x00; 316 | byte data_count=0; 317 | while (time[count]!=0x00) 318 | { 319 | if(time[count] == '-') data_count++; 320 | else if(time[count] == ' ') data_count++; 321 | else if(time[count] == ':') data_count++; 322 | else if ((time[count] >= '0')&&(time[count] <= '9')) 323 | { 324 | rtc[data_count] =(rtc[data_count]<<4)|(0x0F&time[count]); 325 | } 326 | else break; 327 | count++; 328 | } 329 | if (data_count == 5) 330 | { 331 | #if F_CPU == 8000000 332 | Wire.beginTransmission(RTC_ADDRESS); 333 | Wire.write((int)0); 334 | Wire.write(rtc[5]); 335 | Wire.write(rtc[4]); 336 | Wire.write(rtc[3]); 337 | Wire.write(0x00); 338 | Wire.write(rtc[2]); 339 | Wire.write(rtc[1]); 340 | Wire.write(rtc[0]); 341 | Wire.endTransmission(); 342 | delay(4); 343 | Wire.beginTransmission(RTC_ADDRESS); 344 | Wire.write(0x0E); //Address 345 | Wire.write(0x00); //Value 346 | Wire.endTransmission(); 347 | #else 348 | Wire.beginTransmission(RTC_ADDRESS); 349 | Wire.write((int)0); 350 | Wire.write(rtc[5]); 351 | Wire.write(rtc[4]); 352 | Wire.write(rtc[3]); 353 | Wire.write(0x00); 354 | Wire.write(rtc[2]); 355 | Wire.write(rtc[1]); 356 | Wire.write(rtc[0]); 357 | Wire.write((int)0); 358 | Wire.endTransmission(); 359 | return true; 360 | #endif 361 | return true; 362 | } 363 | return false; 364 | } 365 | 366 | boolean SCKBase::RTCtime(char *time) { 367 | Wire.beginTransmission(RTC_ADDRESS); 368 | Wire.write((int)0); 369 | Wire.endTransmission(); 370 | Wire.requestFrom(RTC_ADDRESS, 7); 371 | uint8_t seconds = (Wire.read() & 0x7F); 372 | uint8_t minutes = Wire.read(); 373 | uint8_t hours = Wire.read(); 374 | Wire.read(); 375 | uint8_t day = Wire.read(); 376 | uint8_t month = Wire.read(); 377 | uint8_t year = Wire.read(); 378 | time[0] = '2'; 379 | time[1] = '0'; 380 | time[2] = (year>>4) + '0'; 381 | time[3] = (year&0x0F) + '0'; 382 | time[4] = '-'; 383 | time[5] = (month>>4) + '0'; 384 | time[6] = (month&0x0F) + '0'; 385 | time[7] = '-'; 386 | time[8] = (day>>4) + '0'; 387 | time[9] = (day&0x0F) + '0'; 388 | time[10] = ' '; 389 | time[11] = (hours>>4) + '0'; 390 | time[12] = (hours&0x0F) + '0'; 391 | time[13] = ':'; 392 | time[14] = (minutes>>4) + '0'; 393 | time[15] = (minutes&0x0F) + '0'; 394 | time[16] = ':'; 395 | time[17] = (seconds>>4) + '0'; 396 | time[18] = (seconds&0x0F) + '0'; 397 | time[19] = 0x00; 398 | return true; 399 | } 400 | 401 | boolean SCKBase::RTCisValid(char *time) { 402 | RTCtime(time); 403 | //If year is 2016 we consider rtc data to ba a valid date (without update RTC starts in year 2000) 404 | if (time[0] == '2' && time[1] == '0' && time[2] == '1' && time[3] == '6') return true; 405 | return false; 406 | } 407 | 408 | uint16_t SCKBase::getPanel(float Vref){ 409 | #if F_CPU == 8000000 410 | uint16_t value = 11*average(PANEL)*Vref/1023.; 411 | if (value > 500) value = value + 120; //Voltage protection diode 412 | else value = 0; 413 | #else 414 | uint16_t value = 3*average(PANEL)*Vref/1023.; 415 | if (value > 500) value = value + 750; //Voltage protection diode 416 | else value = 0; 417 | #endif 418 | #if debugBASE 419 | Serial.print("Panel = "); 420 | Serial.print(value); 421 | Serial.println(" mV"); 422 | #endif 423 | return value; 424 | } 425 | 426 | const uint16_t batTable[] = { 427 | 3078, 428 | 3364, 429 | 3468, 430 | 3540, 431 | 3600, 432 | 3641, 433 | 3682, 434 | 3701, 435 | 3710, 436 | 3716, 437 | 3716, 438 | 3716, 439 | 3720, 440 | 3714, 441 | 3720, 442 | 3725, 443 | 3732, 444 | 3742, 445 | 3739, 446 | 3744, 447 | 3744, 448 | 3754, 449 | 3760, 450 | 3762, 451 | 3770, 452 | 3768, 453 | 3774, 454 | 3774, 455 | 3774, 456 | 3779, 457 | 3784, 458 | 3790, 459 | 3788, 460 | 3794, 461 | 3798, 462 | 3798, 463 | 3804, 464 | 3809, 465 | 3809, 466 | 3812, 467 | 3817, 468 | 3817, 469 | 3822, 470 | 3823, 471 | 3828, 472 | 3828, 473 | 3828, 474 | 3833, 475 | 3838, 476 | 3838, 477 | 3842, 478 | 3847, 479 | 3852, 480 | 3859, 481 | 3858, 482 | 3864, 483 | 3862, 484 | 3869, 485 | 3877, 486 | 3877, 487 | 3883, 488 | 3888, 489 | 3894, 490 | 3898, 491 | 3902, 492 | 3906, 493 | 3912, 494 | 3923, 495 | 3926, 496 | 3936, 497 | 3942, 498 | 3946, 499 | 3960, 500 | 3972, 501 | 3979, 502 | 3982, 503 | 3991, 504 | 3997, 505 | 4002, 506 | 4002, 507 | 4012, 508 | 4018, 509 | 4028, 510 | 4043, 511 | 4057, 512 | 4074, 513 | 4084, 514 | 4094, 515 | 4098, 516 | 4098, 517 | 4109, 518 | 4115, 519 | 4123, 520 | 4134, 521 | 4142, 522 | 4153, 523 | 4158, 524 | 4170, 525 | 4180, 526 | 4188 527 | }; 528 | 529 | uint16_t SCKBase::getBattery(float Vref) { 530 | uint16_t temp = average(BAT); 531 | #if F_CPU == 8000000 532 | float voltage = Vref*temp/1023.; 533 | voltage = voltage + (voltage/180)*100; 534 | #else 535 | float voltage = Vref*temp/1023.; 536 | #endif 537 | uint16_t percent = 1000; 538 | for(uint16_t i = 0; i < 100; i++) { 539 | if(voltage < batTable[i]) { 540 | percent = i * 10; 541 | break; 542 | } 543 | } 544 | if(percent < 10) percent = 10; 545 | #if debugBASE 546 | Serial.print("Vbat: "); 547 | Serial.print(voltage); 548 | Serial.print(" mV, "); 549 | Serial.print("Battery level: "); 550 | Serial.print(percent/10); 551 | Serial.println(" %"); 552 | #endif 553 | return percent; 554 | } 555 | 556 | boolean SCKBase::findInResponse(const char *toMatch, 557 | unsigned int timeOut = 1000) { 558 | int byteRead; 559 | 560 | unsigned long timeOutTarget; // in milliseconds 561 | 562 | for (unsigned int offset = 0; offset < strlen(toMatch); offset++) { 563 | timeOutTarget = millis() + timeOut; // Doesn't handle timer wrapping 564 | while (!Serial1.available()) { 565 | // Wait, with optional time out. 566 | if (timeOut > 0) { 567 | if (millis() > timeOutTarget) { 568 | return false; 569 | } 570 | } 571 | delay(1); // This seems to improve reliability slightly 572 | } 573 | byteRead = Serial1.read(); 574 | //Serial.print((char)byteRead); 575 | delay(1); // Removing logging may affect timing slightly 576 | 577 | if (byteRead != toMatch[offset]) { 578 | offset = 0; 579 | // Ignore character read if it's not a match for the start of the string 580 | if (byteRead != toMatch[offset]) { 581 | offset = -1; 582 | } 583 | continue; 584 | } 585 | } 586 | 587 | return true; 588 | } 589 | 590 | void SCKBase::skipRemainderOfResponse(unsigned int timeOut) { 591 | unsigned long time = millis(); 592 | while (((millis()-time) // Specify the channel to create network 737 | sendCommand(F("set wlan ssid "), true); // Set up network broadcast SSID 738 | sendCommand(ssid); 739 | 740 | buffer[6] = 0x00; 741 | sendCommand(F("set opt device_id "), true); // Set up network broadcast SSID 742 | sendCommand(ssid); 743 | 744 | sendCommand(F("set ip dhcp 4")); // Enable DHCP server 745 | sendCommand(F("set ip address 1.2.3.4")); // Specify the IP address 746 | sendCommand(F("set ip net 255.255.255.0")); // Specify the subnet mask 747 | sendCommand(F("set ip gateway 1.2.3.4")); // Specify the gateway 748 | sendCommand(F("save"), false, "Storing in config"); // Store settings 749 | sendCommand(F("reboot"), false, "*READY*"); // Reboot the module in AP mode 750 | } 751 | } 752 | 753 | boolean SCKBase::ready() 754 | { 755 | if(!enterCommandMode()) 756 | { 757 | repair(); 758 | return(false); 759 | } 760 | else 761 | { 762 | Serial1.println(F("join")); 763 | if (findInResponse("Associated!", 8000)) 764 | { 765 | skipRemainderOfResponse(3000); 766 | exitCommandMode(); 767 | return(true); 768 | } 769 | } 770 | 771 | } 772 | 773 | boolean connected = false; 774 | 775 | boolean SCKBase::open(const char *addr, int port) { 776 | 777 | if (connected) { 778 | close(); 779 | } 780 | if (enterCommandMode()) 781 | { 782 | sendCommand(F("open "), true); 783 | sendCommand(addr, true); 784 | Serial1.print(F(" ")); 785 | Serial1.print(port); 786 | if (sendCommand("", false, "*OPEN*")) 787 | { 788 | connected = true; 789 | return true; 790 | } 791 | else return false; 792 | } 793 | enterCommandMode(); 794 | return false; 795 | } 796 | 797 | boolean SCKBase::close() { 798 | if (!connected) { 799 | return true; 800 | } 801 | if (sendCommand(F("close"), false, "*CLOS*")) { 802 | connected = false; 803 | return true; 804 | } 805 | connected = false; 806 | return false; 807 | } 808 | 809 | #define MAC_ADDRESS_BUFFER_SIZE 18 // "FF:FF:FF:FF:FF:FF\0" 810 | 811 | char* SCKBase::MAC() { 812 | if (enterCommandMode()) 813 | { 814 | if (sendCommand(F("get mac"), false, "Mac Addr=")) 815 | { 816 | char newChar; 817 | byte offset = 0; 818 | 819 | while (offset < MAC_ADDRESS_BUFFER_SIZE) { 820 | if (Serial1.available()) 821 | { 822 | newChar = Serial1.read(); 823 | if ((newChar == '\n')||(newChar < '0')) { 824 | buffer[offset] = '\x00'; 825 | return buffer; 826 | } 827 | else if (newChar != -1) { 828 | buffer[offset] = newChar; 829 | offset++; 830 | } 831 | } 832 | } 833 | buffer[MAC_ADDRESS_BUFFER_SIZE-1] = '\x00'; 834 | exitCommandMode(); 835 | } 836 | } 837 | return "-1"; 838 | } 839 | 840 | char* SCKBase::id() { 841 | char* temp = MAC(); 842 | byte len = strlen(temp); 843 | byte j = 4; 844 | buffer[0] = 'S'; 845 | buffer[1] = 'C'; 846 | buffer[2] = 'K'; 847 | buffer[3] = '_'; 848 | for(byte i=12; i 0) 894 | { 895 | if (ver < WIFLY_LATEST_VERSION) 896 | { 897 | byte state = 1; 898 | if(update()); //Wifly Updated. 899 | else state = 2; //Update Fail. 900 | reset(); 901 | return state; 902 | } 903 | else return 0; //WiFly up to date. 904 | } 905 | else return -1; //Error reading the wifi version. 906 | } 907 | 908 | int SCKBase::getWiFlyVersion() { 909 | if (enterCommandMode()) 910 | { 911 | if (sendCommand(F("ver"), false, "wifly-GSX Ver")) 912 | { 913 | char newChar; 914 | byte offset = 0; 915 | boolean prevWasNumber = false; 916 | while (offset < 3) { 917 | if (Serial1.available()) 918 | { 919 | newChar = Serial1.read(); 920 | if ((newChar != -1 && isdigit(newChar)) || newChar == '.') { 921 | if (newChar != '.') { 922 | buffer[offset] = newChar; 923 | offset++; 924 | } 925 | prevWasNumber = true; 926 | } 927 | else { 928 | if (prevWasNumber){ 929 | break; 930 | } 931 | prevWasNumber = false; 932 | } 933 | } 934 | } 935 | exitCommandMode(); 936 | buffer[offset] = 0x00; 937 | return atoi(buffer); 938 | } 939 | return 0; 940 | } 941 | return 0; 942 | } 943 | 944 | 945 | boolean SCKBase::update() { 946 | if (enterCommandMode()) 947 | { 948 | sendCommand(F(DEFAULT_WIFLY_FIRMWARE)); 949 | delay(1000); 950 | if (findInResponse("FTP OK.", 60000)) 951 | { 952 | return true; 953 | } 954 | } 955 | else return false; 956 | } 957 | 958 | uint32_t baud[7]={ 959 | 2400, 4800, 9600, 19200, 38400, 57600, 115200}; 960 | 961 | void SCKBase::repair() 962 | { 963 | if(!enterCommandMode()) 964 | { 965 | boolean repair = true; 966 | for (int i=6; ((i>=0)&&repair); i--) 967 | { 968 | Serial1.begin(baud[i]); 969 | if(enterCommandMode()) 970 | { 971 | reset(); 972 | repair = false; 973 | } 974 | Serial1.begin(9600); 975 | } 976 | } 977 | } 978 | 979 | /*TIMER*/ 980 | 981 | #define RESOLUTION 65536 // Timer1 is 16 bit 982 | unsigned int pwmPeriod; 983 | unsigned char clockSelectBits; 984 | char oldSREG; // To hold Status 985 | 986 | void SCKBase::timer1SetPeriod(long microseconds) // AR modified for atomic access 987 | { 988 | 989 | long cycles = (F_CPU / 2000000) * microseconds; // the counter runs backwards after TOP, interrupt is at BOTTOM so divide microseconds by 2 990 | if(cycles < RESOLUTION) clockSelectBits = _BV(CS10); // no prescale, full xtal 991 | else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11); // prescale by /8 992 | else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11) | _BV(CS10); // prescale by /64 993 | else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12); // prescale by /256 994 | else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12) | _BV(CS10); // prescale by /1024 995 | else cycles = RESOLUTION - 1, clockSelectBits = _BV(CS12) | _BV(CS10); // request was out of bounds, set as maximum 996 | 997 | oldSREG = SREG; 998 | cli(); // Disable interrupts for 16 bit register access 999 | ICR1 = pwmPeriod = cycles; // ICR1 is TOP in p & f correct pwm mode 1000 | SREG = oldSREG; 1001 | 1002 | TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12)); 1003 | TCCR1B |= clockSelectBits; // reset clock select register, and starts the clock 1004 | } 1005 | 1006 | void SCKBase::timer1Initialize() 1007 | { 1008 | TCCR1A = 0; // clear control register A 1009 | TCCR1B = _BV(WGM13); // set mode 8: phase and frequency correct pwm, stop the timer 1010 | timer1SetPeriod(1500); 1011 | TIMSK1 = _BV(TOIE1); 1012 | } 1013 | 1014 | void SCKBase::timer1Stop() 1015 | { 1016 | TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12)); // clears all clock selects bits 1017 | TIMSK1 &= ~(_BV(TOIE1)); 1018 | 1019 | } 1020 | 1021 | 1022 | 1023 | 1024 | 1025 | 1026 | 1027 | 1028 | 1029 | 1030 | 1031 | 1032 | -------------------------------------------------------------------------------- /sck_beta_v0_9/SCKBase.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | SCKBase.h 4 | Supports core and data management functions (Power, WiFi, SD storage, RTClock and EEPROM storage) 5 | 6 | - Modules supported: 7 | 8 | - WIFI (Microchip RN131 (WiFly)) 9 | - RTC (DS1339U and DS1307Z) 10 | - EEPROM (24LC256) 11 | - POWER MANAGEMENT IC's 12 | 13 | */ 14 | 15 | #ifndef __SCKBASE_H__ 16 | #define __SCKBASE_H__ 17 | 18 | #include 19 | 20 | class SCKBase { 21 | public: 22 | void begin(); 23 | void config(); 24 | void eepromCheck(); 25 | void clearmemory(); 26 | float average(int anaPin); 27 | boolean checkText(char* text, char* text1); 28 | boolean compareData(char* text, char* text1); 29 | void writeMCP(byte deviceaddress, byte address, int data ); 30 | int readMCP(int deviceaddress, uint16_t address ); 31 | float readCharge(); 32 | void writeCharge(int current); 33 | void writeEEPROM(uint16_t eeaddress, uint8_t data); 34 | byte readEEPROM(uint16_t eeaddress); 35 | void writeData(uint32_t eeaddress, long data, uint8_t location); 36 | void writeData(uint32_t eeaddress, uint16_t pos, char* text, uint8_t location); 37 | char* readData(uint16_t eeaddress, uint16_t pos, uint8_t location); 38 | uint32_t readData(uint16_t eeaddress, uint8_t location); 39 | 40 | uint16_t getPanel(float Vref); 41 | uint16_t getBattery(float Vref); 42 | 43 | /*RTC commands*/ 44 | boolean checkRTC(); 45 | boolean RTCadjust(char *time); 46 | boolean RTCtime(char *time); 47 | boolean RTCisValid(char *time); 48 | 49 | /*Wifi commands*/ 50 | boolean findInResponse(const char *toMatch, 51 | unsigned int timeOut); 52 | void skipRemainderOfResponse(unsigned int timeOut); 53 | boolean sendCommand(const __FlashStringHelper *command, 54 | boolean isMultipartCommand, 55 | const char *expectedResponse); 56 | boolean sendCommand(const char *command, 57 | boolean isMultipartCommand, 58 | const char *expectedResponse); 59 | boolean enterCommandMode(); 60 | boolean sleep(); 61 | boolean reset(); 62 | boolean exitCommandMode(); 63 | boolean connect(); 64 | void APmode(char* ssid); 65 | boolean ready(); 66 | boolean open(const char *addr, int port); 67 | boolean close(); 68 | char* MAC(); 69 | char* id(); 70 | uint32_t scan(); 71 | int checkWiFly(); 72 | int getWiFlyVersion(); 73 | boolean update(); 74 | void repair(); 75 | 76 | /*Timer commands*/ 77 | void timer1SetPeriod(long microseconds); 78 | void timer1Initialize(); 79 | void timer1Stop(); 80 | private: 81 | 82 | }; 83 | #endif 84 | -------------------------------------------------------------------------------- /sck_beta_v0_9/SCKServer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | SCKServer.cpp 4 | 5 | */ 6 | 7 | 8 | #include "Constants.h" 9 | #include "SCKServer.h" 10 | #include "SCKBase.h" 11 | #include "SCKAmbient.h" 12 | #include 13 | #include 14 | 15 | #define debugServer false 16 | 17 | SCKBase base__; 18 | SCKServer server__; 19 | SCKAmbient ambient__; 20 | 21 | #define TIME_BUFFER_SIZE 20 22 | 23 | boolean SCKServer::time(char *time_) { 24 | boolean ok=false; 25 | uint8_t count = 0; 26 | byte retry=0; 27 | while ((retry<5)&&(!ok)) 28 | { 29 | retry++; 30 | if (base__.enterCommandMode()) 31 | { 32 | if (base__.open(WEB[0], 80)) 33 | { 34 | for(byte i = 0; i<3; i++) Serial1.print(WEBTIME[i]); //Requests to the server time 35 | if (base__.findInResponse("UTC:", 2000)) 36 | { 37 | char newChar; 38 | byte offset = 0; 39 | unsigned long time = millis(); 40 | while (offset < TIME_BUFFER_SIZE) { 41 | if (Serial1.available()) 42 | { 43 | newChar = Serial1.read(); 44 | time = millis(); 45 | if (newChar == '#') { 46 | ok = true; 47 | time_[offset] = '\x00'; 48 | break; 49 | } 50 | else if (newChar != -1) { 51 | if (newChar==',') 52 | { 53 | if (count<2) time_[offset]='-'; 54 | else if (count>2) time_[offset]=':'; 55 | else time_[offset]=' '; 56 | count++; 57 | } 58 | else time_[offset] = newChar; 59 | offset++; 60 | } 61 | } 62 | else if((millis()-time)>1000) 63 | { 64 | ok = false; 65 | break; 66 | } 67 | } 68 | } 69 | else { 70 | #if debugServer 71 | Serial.println("FAIL:("); 72 | #endif 73 | } 74 | base__.close(); 75 | } 76 | } 77 | } 78 | if (!ok) 79 | { 80 | time_[0] = '#'; 81 | time_[1] = 0x00; 82 | } 83 | base__.exitCommandMode(); 84 | return ok; 85 | } 86 | 87 | boolean SCKServer::RTCupdate(char *time_){ 88 | byte retry = 0; 89 | if (base__.checkRTC()){ 90 | if (time(time_)) { 91 | while (retry<5) { 92 | retry++; 93 | if(base__.RTCadjust(time_)) { 94 | return true; 95 | } 96 | } 97 | } 98 | } 99 | return false; 100 | } 101 | 102 | void SCKServer::json_update(uint16_t updates, long *value, char *time, boolean isMultipart) 103 | { 104 | #if debugServer 105 | Serial.print(F("[")); 106 | #endif 107 | Serial1.print(F("[")); 108 | for (int i = 0; i< updates;i++) 109 | { 110 | readFIFO(); 111 | if ((i< (updates - 1)) || (isMultipart)) 112 | { 113 | Serial1.print(F(",")); 114 | #if debugServer 115 | Serial.print(F(",")); 116 | #endif 117 | } 118 | } 119 | 120 | if (isMultipart) 121 | { 122 | byte i; 123 | for (i = 0; i<9; i++) 124 | { 125 | Serial1.print(SERVER[i]); 126 | Serial1.print(value[i]); 127 | } 128 | Serial1.print(SERVER[i]); 129 | Serial1.print(time); 130 | Serial1.print(SERVER[i+1]); 131 | Serial1.println(F("]")); 132 | Serial1.println(); 133 | 134 | #if debugServer 135 | for (i = 0; i<9; i++) 136 | { 137 | Serial.print(SERVER[i]); 138 | Serial.print(value[i]); 139 | } 140 | Serial.print(SERVER[i]); 141 | Serial.print(time); 142 | Serial.print(SERVER[i+1]); 143 | #endif 144 | } 145 | Serial1.println(F("]")); 146 | Serial1.println(); 147 | #if debugServer 148 | Serial.println(F("]")); 149 | #endif 150 | } 151 | 152 | void SCKServer::addFIFO(long *value, char *time) 153 | { 154 | uint16_t updates = (base__.readData(EE_ADDR_NUMBER_WRITE_MEASURE, INTERNAL)-base__.readData(EE_ADDR_NUMBER_READ_MEASURE, INTERNAL))/((SENSORS)*4 + TIME_BUFFER_SIZE); 155 | if (updates < MAX_MEMORY) 156 | { 157 | int eeaddress = base__.readData(EE_ADDR_NUMBER_WRITE_MEASURE, INTERNAL); 158 | int i = 0; 159 | for (i = 0; i<9; i++) 160 | { 161 | base__.writeData(eeaddress + i*4, value[i], EXTERNAL); 162 | } 163 | base__.writeData(eeaddress + i*4, 0, time, EXTERNAL); 164 | eeaddress = eeaddress + (SENSORS)*4 + TIME_BUFFER_SIZE; 165 | base__.writeData(EE_ADDR_NUMBER_WRITE_MEASURE, eeaddress, INTERNAL); 166 | } 167 | else 168 | { 169 | #if debugEnabled 170 | if (!ambient__.debug_state()) Serial.println(F("Memory limit exceeded!!")); 171 | #endif 172 | } 173 | } 174 | 175 | void SCKServer::readFIFO() 176 | { 177 | int i = 0; 178 | int eeaddress = base__.readData(EE_ADDR_NUMBER_READ_MEASURE, INTERNAL); 179 | for (i = 0; i<9; i++) 180 | { 181 | Serial1.print(SERVER[i]); 182 | Serial1.print(base__.readData(eeaddress + i*4, EXTERNAL)); //SENSORS 183 | } 184 | Serial1.print(SERVER[i]); 185 | Serial1.print(base__.readData(eeaddress + i*4, 0, EXTERNAL)); //TIME 186 | Serial1.print(SERVER[i+1]); 187 | 188 | #if debugServer 189 | for (i = 0; i<9; i++) 190 | { 191 | Serial.print(SERVER[i]); 192 | Serial.print(base__.readData(eeaddress + i*4, EXTERNAL)); //SENSORS 193 | } 194 | Serial.print(SERVER[i]); 195 | Serial.print(base__.readData(eeaddress + i*4, 0, EXTERNAL)); //TIME 196 | Serial.print(SERVER[i+1]); 197 | #endif 198 | 199 | eeaddress = eeaddress + (SENSORS)*4 + TIME_BUFFER_SIZE; 200 | if (eeaddress == base__.readData(EE_ADDR_NUMBER_WRITE_MEASURE, INTERNAL)) 201 | { 202 | base__.writeData(EE_ADDR_NUMBER_WRITE_MEASURE, 0, INTERNAL); 203 | base__.writeData(EE_ADDR_NUMBER_READ_MEASURE, 0, INTERNAL); 204 | } 205 | else base__.writeData(EE_ADDR_NUMBER_READ_MEASURE, eeaddress, INTERNAL); 206 | } 207 | 208 | #define numbers_retry 5 209 | 210 | boolean SCKServer::update(long *value, char *time_) 211 | { 212 | value[8] = base__.scan(); //Wifi Nets 213 | byte retry = 0; 214 | if (time(time_)) //Update server time 215 | { 216 | if (base__.checkRTC()) 217 | { 218 | while (!base__.RTCadjust(time_)&&(retry= numbers_retry) return false; 245 | } 246 | } 247 | for (byte i = 1; i<5; i++) Serial1.print(WEB[i]); 248 | Serial1.println(base__.readData(EE_ADDR_MAC, 0, INTERNAL)); //MAC ADDRESS 249 | Serial1.print(WEB[5]); 250 | Serial1.println(base__.readData(EE_ADDR_APIKEY, 0, INTERNAL)); //Apikey 251 | Serial1.print(WEB[6]); 252 | Serial1.println(FirmWare); //Firmware version 253 | Serial1.print(WEB[7]); 254 | return true; 255 | } 256 | 257 | 258 | void SCKServer::send(boolean sleep, boolean *wait_moment, long *value, char *time, boolean instant) { 259 | *wait_moment = true; 260 | if (base__.checkRTC()) base__.RTCtime(time); 261 | char tmpTime[19]; 262 | strncpy(tmpTime, time, 20); 263 | uint16_t updates = (base__.readData(EE_ADDR_NUMBER_WRITE_MEASURE, INTERNAL)-base__.readData(EE_ADDR_NUMBER_READ_MEASURE, INTERNAL))/((SENSORS)*4 + TIME_BUFFER_SIZE); 264 | uint16_t NumUpdates = base__.readData(EE_ADDR_NUMBER_UPDATES, INTERNAL); // Number of readings before batch update 265 | if (updates>=(NumUpdates - 1) || instant) 266 | { 267 | if (sleep) 268 | { 269 | #if debugEnabled 270 | if (!ambient__.debug_state()) Serial.println(F("SCK Waking up...")); 271 | #endif 272 | digitalWrite(AWAKE, HIGH); 273 | } 274 | if (base__.connect()) //Wifi connect 275 | { 276 | #if debugEnabled 277 | if (!ambient__.debug_state()) Serial.println(F("SCK Connected to Wi-Fi!!")); 278 | #endif 279 | if (update(value, time)) //Update time and nets 280 | { 281 | #if debugEnabled 282 | if (!ambient__.debug_state()) 283 | { 284 | Serial.print(F("updates = ")); 285 | Serial.println(updates + 1); 286 | } 287 | #endif 288 | int num_post = updates; 289 | int cycles = cycles = updates/POST_MAX;; 290 | if (updates > POST_MAX) 291 | { 292 | for (int i=0; i 12 | 13 | class SCKServer { 14 | public: 15 | boolean time(char *time); 16 | void json_update(uint16_t updates, long *value, char *time, boolean isMultipart); 17 | void send(boolean sleep, boolean *wait_moment, long *value, char *time, boolean instant); 18 | boolean update(long *value, char *time_); 19 | boolean connect(); 20 | void addFIFO(long *value, char *time); 21 | void readFIFO(); 22 | boolean RTCupdate(char *time); 23 | private: 24 | 25 | }; 26 | #endif 27 | -------------------------------------------------------------------------------- /sck_beta_v0_9/TemperatureDecoupler.h: -------------------------------------------------------------------------------- 1 | /* 2 | TemperatureDecoupler.h 3 | SmartCitizen 4 | 5 | Created by Oriol Ferrer Mesià on 03/06/13. 6 | */ 7 | 8 | #ifndef SmartCitizen_TemperatureDecoupler_h 9 | #define SmartCitizen_TemperatureDecoupler_h 10 | 11 | #define BATTERY_HEATUP_MAX 11 12 | #define BATTERY_CHARGE_THRESHOLD 980 13 | #include 14 | #include "AccumulatorFilter.h" 15 | 16 | 17 | class TemperatureDecoupler{ 18 | 19 | public: 20 | 21 | void setup(){ 22 | _prevBattery = 0; 23 | filter.setup(0.3); 24 | } 25 | 26 | void update( uint16_t battery ){ 27 | 28 | //Serial.println( "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #" ); 29 | 30 | bool charging = false; 31 | bool doNothing = false; 32 | if (battery == _prevBattery){ 33 | //doNothing; 34 | if ( battery > BATTERY_CHARGE_THRESHOLD ){ 35 | charging = true; 36 | //Serial.println( "Battery same val > 980! charging!"); 37 | }else{ 38 | charging = false; 39 | //Serial.println( "Battery same val < 980! NOT charging!"); 40 | } 41 | }else{ 42 | if ( battery > _prevBattery || battery > BATTERY_CHARGE_THRESHOLD ){ //battery is charging! 43 | //Serial.println( "Battery charging!"); 44 | charging = true; 45 | }else{ //battery is being drained 46 | //Serial.println( "Battery dis-charging!"); 47 | charging = false; 48 | } 49 | } 50 | 51 | if (!doNothing){ 52 | if(charging) 53 | filter.goUp(); 54 | else 55 | filter.goDown(); 56 | } 57 | 58 | //Serial.print(F("battery: ")); Serial.println( battery ); 59 | //Serial.print(F("_prevBattery: ")); Serial.println( _prevBattery ); 60 | //Serial.print(F("filter: ")); Serial.println( filter.getVal() ); 61 | 62 | //Serial.println( "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #" ); 63 | //store last bat reading for future comparing 64 | _prevBattery = battery; 65 | lastChargingState = charging; 66 | } 67 | 68 | short int getCompensation(){ 69 | return (short int) (filter.getVal() * BATTERY_HEATUP_MAX); 70 | } 71 | 72 | short int _prevBattery; 73 | AccumulatorFilter filter; 74 | bool lastChargingState; //true == up, false == down 75 | 76 | }; 77 | 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /sck_beta_v0_9/sck_beta_v0_9.ino: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Smart Citizen Kit 4 | Ambient Board Beta Firmware v. 0.9.4 5 | 6 | http://smartcitizen.me/ 7 | 8 | 9 | Compatible: 10 | 11 | Smart Citizen Kit v.1.0 (Goteo) (ATMEGA32U4 @ 16Mhz - Arduino Leonardo profile) 12 | Smart Citizen Kit v.1.1 (Kickstarter) (ATMEGA32U4 @ 8Mhz - Lylipad Arduino USB) 13 | 14 | Structure: 15 | 16 | sck_beta_v0_9.ino - Core Runtime. 17 | 18 | SCKAmbient.h - Supports the sensor reading and calibration functions. 19 | SCKBase.h - Supports the data management functions (WiFi, RTClock and EEPROM storage) 20 | SCKServer.h - Supports data publishing to the SmartCitizen Platform over WiFi. 21 | 22 | Constants.h - Defines pins configuration and other static parameters. 23 | AccumulatorFilter.h - Used for battery temperature decoupling in Smart Citizen Kit v.1.0 24 | TemperatureDecoupler.h - Used for battery temperature decoupling in Smart Citizen Kit v.1.0 25 | 26 | Check REAMDE.md for more information. 27 | 28 | */ 29 | 30 | #include 31 | #include 32 | #include "SCKAmbient.h" 33 | 34 | SCKAmbient ambient; 35 | 36 | void setup() { 37 | ambient.begin(); 38 | ambient.ini(); 39 | ambient.execute(true); 40 | } 41 | 42 | void loop() { 43 | ambient.execute(false); 44 | } 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /utilities/README.md: -------------------------------------------------------------------------------- 1 | Utilities 2 | ================= 3 | 4 | #### This are firmwares to perform repair and update tasks on the Smart Citizen Kit WiFi Module. 5 | 6 | ##### WiFly - Microchip RN131 Wi-Fi Module 7 | 8 | * Most of this functionailities are included directly on the core firmware. 9 | * The aim of the utilities is to perform advanced tasks for repairing damaged WiFly modules. 10 | 11 | Documentation in process. Visit the [forum](http://forum.smartcitizen.me) for more information. 12 | -------------------------------------------------------------------------------- /utilities/SCK_check/SCK_check.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "SCKlibs.h" 4 | 5 | sck sck; 6 | void setup() { 7 | sck.begin(); 8 | delay(5000); 9 | Serial.println("Trying to connect."); 10 | if (!sck.repair()) sck.recovery(); 11 | else Serial.println("Device detected."); 12 | Serial.print("Firmware version: "); 13 | char *Version = sck.getWiFlyVersion(1000); 14 | Serial.println(Version); 15 | int state = sck.checkWiFlyVersion(Version); 16 | if (state==1) Serial.println("Wifi device is ok :)"); 17 | else if (state==-1) Serial.println("Wifi device is corrupted :("); 18 | else if ((state)==0) if (!sck.webAppRepair())Serial.println("Wifi device is corrupted :("); 19 | Serial.println(F("Want to test the EEPROM? (y/n)")); 20 | while (!Serial.available()); 21 | byte inByte = Serial.read(); 22 | if (inByte =='y') 23 | { 24 | if (sck.checkEEPROM()) Serial.println("EEPROM is OK"); 25 | else Serial.println("EEPROM fail :("); 26 | } 27 | else if (inByte !='n') Serial.println("Request invalid."); 28 | if (sck.checkRTC()) Serial.println("RTC is OK"); 29 | else Serial.println("RTC fail, RTC battery check"); 30 | Serial.print("Panel: "); Serial.print(sck.getPanel()); Serial.println("mV"); 31 | Serial.print("Battery: "); Serial.print(sck.getBattery()); Serial.println("%"); 32 | Serial.print("Speed charge: "); Serial.print(sck.readCharge()); Serial.println("mA"); 33 | } 34 | 35 | void loop() { 36 | if (Serial.available()) 37 | { 38 | int inByte = Serial.read(); 39 | Serial1.write(inByte); 40 | } 41 | if (Serial1.available()) { 42 | int inByte = Serial1.read(); 43 | Serial.write(inByte); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /utilities/SCK_check/SCKlibs.cpp: -------------------------------------------------------------------------------- 1 | #include "SCKlibs.h" 2 | #include 3 | #include 4 | 5 | 6 | #define WIFLY_LATEST_VERSION 441 7 | #define DEFAULT_WIFLY_FIRMWARE "ftp update wifly3-441.img" 8 | #define DEFAULT_WIFLY_FTP_UPDATE "set ftp address 198.175.253.161" 9 | 10 | #define AWAKE 4 //Despertar WIFI 11 | #define PANEL A8 //Entrada panel 12 | #define BAT A7 //Entrada bateria 13 | 14 | #define IO0 5 //MICS5525_HEATHER 15 | #define IO1 13 //MICS2710_HEATHER 16 | #define IO2 9 //MICS2710_ALTAIMPEDANCIA 17 | #define IO3 10 //MICS2710_ALTAIMPEDANCIA 18 | #define FACTORY 7 //factory RESET/AP RN131 19 | #define CONTROL 12 //Control Mode 20 | 21 | #define S0 A4 //MICS_5525 22 | #define S1 A5 //MICS_2710 23 | #define S2 A2 //SENS_5525 24 | #define S3 A3 //SENS_2710 25 | #define S4 A0 //MICRO 26 | #define S5 A1 //LDR 27 | 28 | #define OPEN "0" 29 | #define WEP "1" 30 | #define WPA1 "2" 31 | #define WPA2 "4" 32 | #define WEP64 "8" 33 | 34 | #define INT_ANT "0" //EXT_ANT 35 | #define EXT_ANT "1" //EXT_ANT 36 | 37 | char* mySSID = "Red"; 38 | char* myPassword = "Pass"; 39 | char* wifiEncript = WPA2; 40 | char* antenna = INT_ANT; //EXT_ANT 41 | 42 | #define buffer_length 32 43 | static char buffer[buffer_length]; 44 | 45 | boolean sck::checkEEPROM() { 46 | boolean ok = true; 47 | for (int i=0; i<32000; i++) 48 | { 49 | writeEEPROM(i, 'x'); 50 | Serial.print("."); 51 | if ((i%100) == 0) 52 | { 53 | Serial.println(); 54 | Serial.print(i/100); 55 | } 56 | if (readEEPROM(i)!= 'x') 57 | { 58 | ok = false; 59 | break; 60 | } 61 | } 62 | Serial.println(); 63 | return ok; 64 | } 65 | #define TWI_FREQ 400000L //Frecuencia bus I2C 66 | 67 | void sck::begin() { 68 | Serial.begin(9600); 69 | Serial1.begin(9600); 70 | Wire.begin(); 71 | TWBR = ((F_CPU / TWI_FREQ) - 16) / 2; 72 | if (EEPROM.read(0)>=2) EEPROM.write(0, 0); 73 | pinMode(IO0, OUTPUT); //VH_MICS5525 74 | pinMode(IO1, OUTPUT); //VH_MICS2710 75 | pinMode(IO2, OUTPUT); //MICS2710_ALTAIMPEDANCIA 76 | pinMode(AWAKE, OUTPUT); 77 | pinMode(MOSI, OUTPUT); 78 | pinMode(SCK, OUTPUT); 79 | pinMode(FACTORY, OUTPUT); 80 | pinMode(CONTROL, INPUT); 81 | digitalWrite(AWAKE, HIGH); 82 | // digitalWrite(FACTORY, LOW); 83 | digitalWrite(FACTORY, HIGH); 84 | } 85 | 86 | boolean sck::findInResponse(const char *toMatch, 87 | unsigned int timeOut = 1000) { 88 | int byteRead; 89 | 90 | unsigned long timeOutTarget; // in milliseconds 91 | 92 | for (unsigned int offset = 0; offset < strlen(toMatch); offset++) { 93 | timeOutTarget = millis() + timeOut; // Doesn't handle timer wrapping 94 | while (!Serial1.available()) { 95 | // Wait, with optional time out. 96 | if (timeOut > 0) { 97 | if (millis() > timeOutTarget) { 98 | return false; 99 | } 100 | } 101 | delay(1); // This seems to improve reliability slightly 102 | } 103 | byteRead = Serial1.read(); 104 | //Serial.print((char)byteRead); 105 | delay(1); // Removing logging may affect timing slightly 106 | 107 | if (byteRead != toMatch[offset]) { 108 | offset = 0; 109 | // Ignore character read if it's not a match for the start of the string 110 | if (byteRead != toMatch[offset]) { 111 | offset = -1; 112 | } 113 | continue; 114 | } 115 | } 116 | 117 | return true; 118 | } 119 | 120 | void sck::recovery() 121 | { 122 | if (EEPROM.read(0) == 0) 123 | { 124 | Serial.println(F("Reseting...")); 125 | digitalWrite(FACTORY, HIGH); 126 | delay(1000); 127 | digitalWrite(FACTORY, LOW); 128 | delay(1000); 129 | digitalWrite(FACTORY, HIGH); 130 | delay(1000); 131 | digitalWrite(FACTORY, LOW); 132 | delay(1000); 133 | digitalWrite(FACTORY, HIGH); 134 | delay(1000); 135 | digitalWrite(FACTORY, LOW); 136 | delay(1000); 137 | digitalWrite(FACTORY, HIGH); 138 | delay(1000); 139 | digitalWrite(FACTORY, LOW); 140 | delay(1000); 141 | digitalWrite(FACTORY, HIGH); 142 | delay(1000); 143 | digitalWrite(FACTORY, LOW); 144 | delay(1000); 145 | Serial.println("Please, turn off the board."); 146 | EEPROM.write(0,1); 147 | while(true); 148 | } 149 | else EEPROM.write(0,2); 150 | } 151 | 152 | void sck::skipRemainderOfResponse(unsigned int timeOut) { 153 | unsigned long time = millis(); 154 | while (((millis()-time)=0)&&(!repair)); i--) 280 | { 281 | // Serial1.begin(baud[i]); 282 | // Serial.println(baud[i]); 283 | if(enterCommandMode()) 284 | { 285 | reset(); 286 | repair = true; 287 | } 288 | Serial1.begin(9600); 289 | } 290 | } 291 | else repair = true; 292 | return repair; 293 | } 294 | 295 | boolean sck::ready() 296 | { 297 | if(!enterCommandMode()) 298 | { 299 | repair(); 300 | } 301 | if (enterCommandMode()) 302 | { 303 | Serial1.println(F("join")); 304 | if (findInResponse("Associated!", 8000)) 305 | { 306 | skipRemainderOfResponse(3000); 307 | exitCommandMode(); 308 | return(true); 309 | } 310 | } 311 | else return(false); 312 | } 313 | 314 | char* itoa(int32_t number) 315 | { 316 | byte count = 0; 317 | uint32_t temp; 318 | if (number < 0) {temp = number*(-1); count++;} 319 | while ((temp/10)!=0) 320 | { 321 | temp = temp/10; 322 | count++; 323 | } 324 | int i; 325 | if (number < 0) {temp = number*(-1);} 326 | else temp = number; 327 | for (i = count; i>=0; i--) 328 | { 329 | buffer[i] = temp%10 + '0'; 330 | temp = temp/10; 331 | } 332 | if (number < 0) {buffer[0] = '-';} 333 | buffer[count + 1] = 0x00; 334 | return buffer; 335 | } 336 | 337 | 338 | char* sck::getWiFlyVersion(unsigned long timeOut) { 339 | Serial1.println(); 340 | Serial1.println(); 341 | char newChar = '<'; 342 | byte offset = 0; 343 | unsigned long time = millis(); 344 | while (((millis()-time)') break; 356 | } 357 | } 358 | skipRemainderOfResponse(1000); 359 | 360 | if (newChar=='>') 361 | { 362 | buffer[offset] = 0x00; 363 | return buffer; 364 | } 365 | else return "0"; 366 | } 367 | 368 | int sck::checkWiFlyVersion(char *text) { 369 | if (text[0]=='0') 370 | { 371 | Serial.println(F("Error reading version.")); 372 | return -1; 373 | } 374 | else if (text[0]<'4') Serial.println(F("Old version, please update.")); 375 | else if ((text[0]=='4')&&(text[2]=='0')) Serial.println(F("Warning version, please update.")); 376 | else if ((text[0]=='4')&&(text[2]=='4')) Serial.println(F("WiFly up to date.")); 377 | else if (text[0]=='W') 378 | { 379 | Serial.println(F("Started as web_app")); 380 | return 0; 381 | } 382 | return 1; 383 | } 384 | 385 | boolean sck::webAppRepair() { 386 | if (enterCommandMode()) 387 | { 388 | Serial1.println(F("boot image 2")); 389 | if (findInResponse("= OK", 8000)) 390 | { 391 | skipRemainderOfResponse(3000); 392 | Serial1.println(F("save")); 393 | skipRemainderOfResponse(3000); 394 | Serial1.println(F("reboot")); 395 | skipRemainderOfResponse(3000); 396 | enterCommandMode(); 397 | Serial.print("Firmware version: "); 398 | char *Version = getWiFlyVersion(1000); 399 | Serial.println(Version); 400 | int state = checkWiFlyVersion(Version); 401 | if (state==1) Serial.print("Wifi device is ok :)"); 402 | return(true); 403 | } 404 | } 405 | else return(false); 406 | } 407 | 408 | #define E2PROM 0x50 // Direcion de la EEPROM 409 | 410 | void sck::writeEEPROM(uint16_t eeaddress, uint8_t data) { 411 | uint8_t retry = 0; 412 | while ((readEEPROM(eeaddress)!=data)&&(retry<10)) 413 | { 414 | Wire.beginTransmission(E2PROM); 415 | Wire.write((byte)(eeaddress >> 8)); // MSB 416 | Wire.write((byte)(eeaddress & 0xFF)); // LSB 417 | Wire.write(data); 418 | Wire.endTransmission(); 419 | delay(6); 420 | retry++; 421 | } 422 | } 423 | 424 | byte sck::readEEPROM(uint16_t eeaddress) { 425 | byte rdata = 0xFF; 426 | Wire.beginTransmission(E2PROM); 427 | Wire.write((byte)(eeaddress >> 8)); // MSB 428 | Wire.write((byte)(eeaddress & 0xFF)); // LSB 429 | Wire.endTransmission(); 430 | Wire.requestFrom(E2PROM,1); 431 | while (!Wire.available()); 432 | rdata = Wire.read(); 433 | return rdata; 434 | } 435 | 436 | #define RTC_ADDRESS 0x68 // Direcion de la RTC 437 | 438 | boolean sck::checkRTC() { 439 | Wire.beginTransmission(RTC_ADDRESS); 440 | Wire.write(0x00); //Address 441 | Wire.endTransmission(); 442 | delay(4); 443 | Wire.requestFrom(RTC_ADDRESS,1); 444 | unsigned long time = millis(); 445 | while (!Wire.available()) if ((millis() - time)>500) return false; 446 | Wire.read(); 447 | return true; 448 | } 449 | 450 | float average(int anaPin) { 451 | int lecturas = 100; 452 | long total = 0; 453 | float average = 0; 454 | for(int i=0; i 500) value = value + 120; //Tension del diodo de proteccion 478 | else value = 0; 479 | #else 480 | uint16_t value = 3*average(PANEL)*Vref/1023.; 481 | if (value > 500) value = value + 750; //Tension del diodo de proteccion 482 | else value = 0; 483 | #endif 484 | return value; 485 | } 486 | 487 | float sck::getBattery() { 488 | uint16_t temp = average(BAT); 489 | #if F_CPU == 8000000 490 | float voltage = Vref*temp/1023.; 491 | voltage = voltage + (voltage/180)*100; 492 | #else 493 | float voltage = Vref*temp/1023.; 494 | #endif 495 | temp = map(voltage, VAL_MIN_BATTERY, VAL_MAX_BATTERY, 0, 1000); 496 | if (temp>1000) temp=1000; 497 | if (temp<0) temp=0; 498 | return temp/10.; 499 | } 500 | 501 | #define RES 256 //Resolucion de los potenciometros digitales 502 | 503 | #if F_CPU == 8000000 504 | #define R1 12 //Kohm 505 | #else 506 | #define R1 82 //Kohm 507 | #endif 508 | 509 | #define P1 100 //Kohm 510 | 511 | float kr= ((float)P1*1000)/RES; //Constante de conversion a resistencia de potenciometrosen ohmios 512 | 513 | void writeMCP(byte deviceaddress, byte address, int data ) { 514 | if (data>RES) data=RES; 515 | Wire.beginTransmission(deviceaddress); 516 | address=(address<<4)|bitRead(data, 8) ; 517 | Wire.write(address); 518 | Wire.write(lowByte(data)); 519 | Wire.endTransmission(); 520 | delay(4); 521 | } 522 | 523 | int readMCP(int deviceaddress, uint16_t address ) { 524 | byte rdata = 0xFF; 525 | int data = 0x0000; 526 | Wire.beginTransmission(deviceaddress); 527 | address=(address<<4)|B00001100; 528 | Wire.write(address); 529 | Wire.endTransmission(); 530 | Wire.requestFrom(deviceaddress,2); 531 | unsigned long time = millis(); 532 | while (!Wire.available()) if ((millis() - time)>500) return 0x00; 533 | rdata = Wire.read(); 534 | data=rdata<<8; 535 | while (!Wire.available()); 536 | rdata = Wire.read(); 537 | data=data|rdata; 538 | return data; 539 | } 540 | 541 | #if F_CPU == 8000000 542 | #define MCP3 0x2D // Direcion del mcp3 Ajuste carga bateria 543 | float sck::readCharge() { 544 | float resistor = kr*readMCP(MCP3, 0x00)/1000; 545 | float current = 1000./(2+((resistor * 10)/(resistor + 10))); 546 | return(current); 547 | } 548 | #else 549 | float SCKBase::readCharge() { 550 | return(500); 551 | } 552 | #endif 553 | 554 | -------------------------------------------------------------------------------- /utilities/SCK_check/SCKlibs.h: -------------------------------------------------------------------------------- 1 | #ifndef __SCKLIBS_H__ 2 | #define __SCKLIBS_H__ 3 | 4 | #include 5 | 6 | #define TIME_BUFFER_SIZE 20 7 | 8 | class sck { 9 | public: 10 | boolean checkEEPROM(); 11 | void begin(); 12 | boolean findInResponse(const char *toMatch, 13 | unsigned int timeOut); 14 | void recovery(); 15 | void skipRemainderOfResponse(unsigned int timeOut); 16 | boolean sendCommand(const __FlashStringHelper *command, 17 | boolean isMultipartCommand, 18 | const char *expectedResponse); 19 | boolean sendCommand(const char *command, 20 | boolean isMultipartCommand, 21 | const char *expectedResponse); 22 | boolean enterCommandMode(); 23 | boolean reset(); 24 | boolean exitCommandMode(); 25 | boolean connect(); 26 | boolean repair(); 27 | boolean ready(); 28 | char* getWiFlyVersion(unsigned long timeOut); 29 | int checkWiFlyVersion(char *text); 30 | boolean webAppRepair(); 31 | void writeEEPROM(uint16_t eeaddress, uint8_t data); 32 | byte readEEPROM(uint16_t eeaddress); 33 | boolean checkRTC(); 34 | uint16_t getPanel(); 35 | float getBattery(); 36 | float readCharge(); 37 | private: 38 | 39 | }; 40 | #endif 41 | -------------------------------------------------------------------------------- /utilities/SCK_testing/SCKtester: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | """ 3 | Script for testing new SCK kits. 4 | """ 5 | version = 0.2 6 | 7 | import serial, sys, glob, shutil, tempfile, urllib, urllib2, json, zipfile, os, time, subprocess 8 | 9 | SSID = "mySSID" 10 | PHRASE = "myPASSWORD" 11 | 12 | 13 | class SCK: 14 | def __init__(self): 15 | # self.baud = 115200 16 | self.baud = 9600 17 | self.timeout = 20 18 | self.port = False 19 | self.mac = False 20 | self.talkWiflyFirmware = "wifly/wifly.ino" 21 | self.maxRetries = 5 22 | self.connected = False 23 | self.wiflyVersion = 0 24 | self.ssid = SSID 25 | self.phrase = PHRASE 26 | self.associated = False 27 | self.ip = False 28 | self.inoFile = False 29 | self.firmwareDir = "firmware" 30 | self.tmpZip = os.path.join(self.firmwareDir, "tmp.zip") 31 | self.logFileName = "testingLog.csv" 32 | self.usePort = False 33 | def _retry(self, command): 34 | retry = 0 35 | while retry < myKit.maxRetries: 36 | myPrint(".") 37 | retry = retry + 1 38 | if command: return True 39 | return False 40 | def _uploadWifliConsole(self): 41 | out = subprocess.Popen(['arduino', '--upload', self.talkWiflyFirmware, '--board', 'arduino:avr:LilyPadUSB', '--port', self.port, '--preserve-temp-files'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) 42 | status = out.wait() 43 | if status == 0: return True 44 | else:return False 45 | def _W_getWiflyVersion(self): 46 | self._W_sendWiflyCommand("$$$") 47 | self._W_sendWiflyCommand("\r\n") 48 | self._W_sendWiflyCommand("exit\r\n", "EXIT", 2) 49 | self._W_sendWiflyCommand("$$$") 50 | response = self._W_sendWiflyCommand("\r\n", "> ", 2) 51 | if "<4.41>" in response[1]: 52 | self.wiflyVersion = 4.41 53 | return True 54 | elif "<4.75>" in response[1]: 55 | self.wiflyVersion = 4.75 56 | return True 57 | else: 58 | return False 59 | def _W_wiflyJoin(self): 60 | self._W_sendWiflyCommand("$$$") 61 | self._W_sendWiflyCommand("\r\n") 62 | self._W_sendWiflyCommand("set wlan join 1\r\n", "AOK", 1) 63 | self._W_sendWiflyCommand("set ip dhcp 1\r\n", "AOK", 1) 64 | self._W_sendWiflyCommand("set ip proto 10\r\n", "AOK", 1) 65 | self._W_sendWiflyCommand("set wlan auth 4\r\n", "AOK", 1) 66 | self._W_sendWiflyCommand("set wlan ssid ") 67 | self._W_sendWiflyCommand(self.ssid) 68 | self._W_sendWiflyCommand("\r\n", "AOK", 3) 69 | self._W_sendWiflyCommand("set wlan phrase ") 70 | self._W_sendWiflyCommand(self.phrase) 71 | self._W_sendWiflyCommand("\r\n", "AOK", 3) 72 | self._W_sendWiflyCommand("set wlan ext_antenna 0\r\n", "AOK", 1) 73 | self._W_sendWiflyCommand("save\r\n", "Storing in config", 5) 74 | response = self._W_sendWiflyCommand("reboot\r\n", "Listen on", 15) 75 | if response[0]: 76 | self.associated = True 77 | self.ip = response[1].split("IP=")[1].split(":")[0] 78 | return True 79 | else: 80 | return False 81 | def _W_updateWifly(self): 82 | self._W_sendWiflyCommand("$$$") 83 | self._W_sendWiflyCommand("\r\n") 84 | updateResponse = self._W_sendWiflyCommand("ftp update wifly3-475.img\r\n", "FTP OK", 60) 85 | self._W_sendWiflyCommand("reboot\r\n", "READY", 10) 86 | return updateResponse[0] 87 | def _W_sendWiflyCommand(self, command, expectedResponse=False, timeout=0.3): 88 | self.serial.write(command) 89 | response = "" 90 | startTime = time.time() 91 | while time.time() - startTime < timeout: 92 | response = response + self.serial.read_all() 93 | if isinstance(expectedResponse, basestring) and expectedResponse in response: 94 | return [True, response] 95 | return [False, response] 96 | def _connectSerial(self): 97 | portList = serialPorts() 98 | if self.port not in portList: 99 | if len(portList) == 1: 100 | print "Changing serial port to: " + bcolors.OKBLUE + portList[0] + bcolors.ENDC 101 | self.port = portList[0] 102 | else: 103 | self.port = False 104 | while not self.port: 105 | self.port = serialPorts()[0] 106 | try: 107 | self.serial = serial.Serial(self.port, self.baud) 108 | self.connected = True 109 | return True 110 | except serial.SerialException: 111 | print bcolors.FAIL + "Can't open Serial Port!!" + bcolors.ENDC 112 | self.connected = False 113 | sys.exit() 114 | def _downloadFirmware(self): 115 | if os.path.exists(myKit.firmwareDir) and len(os.listdir(myKit.firmwareDir)) > 0: 116 | self.inoFile = os.path.join(os.path.join(os.path.join(myKit.firmwareDir, os.listdir(myKit.firmwareDir)[0]), 'sck_beta_v0_9'), 'sck_beta_v0_9.ino') 117 | if os.path.exists(self.inoFile): 118 | return True 119 | else: 120 | if not os.path.exists(myKit.firmwareDir): os.makedirs(myKit.firmwareDir) 121 | myPrint(" downloading...") 122 | zipUrl = "https://github.com/fablabbcn/Smart-Citizen-Kit/archive/master.zip" 123 | downloadedZip = urllib.urlretrieve(zipUrl, myKit.tmpZip)[0] 124 | zipfile.ZipFile(downloadedZip).extractall(myKit.firmwareDir) 125 | os.remove(myKit.tmpZip) 126 | self.inoFile = os.path.join(os.path.join(os.path.join(myKit.firmwareDir, os.listdir(myKit.firmwareDir)[0]), 'sck_beta_v0_9'), 'sck_beta_v0_9.ino') 127 | if os.path.exists(self.inoFile): 128 | return True 129 | else: 130 | return False 131 | def _uploadFirmware(self): 132 | out = subprocess.Popen(['arduino', '--upload', self.inoFile, '--board', 'arduino:avr:LilyPadUSB', '--port', self.port, '--preserve-temp-files'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) 133 | status = out.wait() 134 | if status == 0: return True 135 | else: return False 136 | def _sendCommand(self, command, expectedResponse=False, timeout=0.3): 137 | self.serial.write(command) 138 | response = "" 139 | startTime = time.time() 140 | while time.time() - startTime < timeout: 141 | response = response + self.serial.read_all() 142 | #exception for post data 143 | if "post data" in command: 144 | time.sleep(0.05) 145 | if isinstance(expectedResponse, basestring) and expectedResponse in response: 146 | return [True, response] 147 | else: 148 | if isinstance(expectedResponse, basestring) and expectedResponse in response: 149 | return [True, response] 150 | return [False, response] 151 | def _update(self): 152 | response = self._sendCommand("get all\r\n", "|60|1|", 2) 153 | if response[0]: 154 | r = response[1].split("|") 155 | self.version = r[1] 156 | self.mac = r[2] 157 | self.nets = r[3] 158 | self.hardcodedNets = r[4] 159 | self.timeUpdate = r[5] 160 | self.posts = r[6] 161 | else: 162 | return False 163 | response = self._sendCommand("post data\r\n", "UTC:", 45) 164 | if response[0]: 165 | self.temperature = int(response[1].split("Temperature: ")[1].split(" ")[0]) 166 | self.humidity = int(response[1].split("Humidity: ")[1].split(" ")[0]) 167 | self.light = float(response[1].split("Light: ")[1].split(" ")[0]) 168 | self.battery = float(response[1].split("Battery: ")[1].split(" ")[0]) 169 | self.solarPanel = float(response[1].split("Panel: ")[1].split(" ")[0]) 170 | self.co = float(response[1].split("Monxide: ")[1].split(" ")[0]) 171 | self.no2 = float(response[1].split("Dioxide: ")[1].split(" ")[0]) 172 | self.noise = float(response[1].split("Noise: ")[1].split(" ")[0]) 173 | self.wifiSpots = int(response[1].split("Spots: ")[1].split("\r\n")[0]) 174 | self.utc = response[1].split("UTC: ")[1].split("\r\n")[0] 175 | return True 176 | else: 177 | return False 178 | def _evaluate(self): 179 | if self.wiflyVersion < 4.75: return "ERROR: wifly ver" 180 | if not self.ip or self.ip == "0.0.0.0": return "ERROR: no ip" 181 | if self.temperature > 40000 or self.temperature < 0: return "ERROR: temp sensor" 182 | if self.humidity > 100000 or self.humidity < 0: return "ERROR: humidity sensor" 183 | if self.light > 1000 or self.light < 0: return "ERROR: light sensor" 184 | if self.co > 10000 or self.co < 0: return "ERROR: CO sensor" 185 | if self.no2 > 10000 or self.no2 < 0: return "ERROR: NO2 sensor" 186 | if self.noise > 10000 or self.noise < 0: return "ERROR: noise sensor" 187 | return "PASSED" 188 | def _log(self): 189 | headers = "mac_address,firmware_version,wifly_version,temperature,humidity,light,battery,solar_panel,CO,NO2,noise,passed,comment\n" 190 | toLog = [self.mac, self.version, self.wiflyVersion, self.temperature, self.humidity, self.light, self.battery, self.solarPanel, self.co, self.no2, self.noise] 191 | result = self._evaluate() 192 | 193 | 194 | if not os.path.exists(myKit.logFileName): 195 | try: 196 | myFile = open(myKit.logFileName, 'w') 197 | except: 198 | print bcolors.FAIL + "can't create log file!!!, bye!" + bcolors.ENDC 199 | sys.exit() 200 | myFile.write(headers) 201 | else: 202 | try: 203 | myFile = open(myKit.logFileName, 'a') 204 | except: 205 | print bcolors.FAIL + "can't create log file!!!, bye!" + bcolors.ENDC 206 | sys.exit() 207 | for d in toLog: 208 | myFile.write(str(d) + ",") 209 | print headers.split(",")[toLog.index(d)] + ": " + bcolors.OKBLUE + str(d) + bcolors.ENDC 210 | if result == "PASSED": 211 | myFile.write("1") 212 | else: 213 | myFile.write("0") 214 | myFile.write("," + result) 215 | myFile.write("\n") 216 | myFile.close() 217 | return result 218 | 219 | def myPrint(text): 220 | sys.stdout.write(str(text)) 221 | sys.stdout.flush() 222 | def serialPorts(): 223 | """Lists serial ports 224 | 225 | :raises EnvironmentError: 226 | On unsupported or unknown platforms 227 | :returns: 228 | A list of available serial ports 229 | """ 230 | if sys.platform.startswith('win'): 231 | ports = ['COM' + str(i + 1) for i in range(256)] 232 | 233 | elif sys.platform.startswith('linux') or sys.platform.startswith('cygwin'): 234 | # this is to exclude your current terminal "/dev/tty" 235 | ports = glob.glob('/dev/tty[A-Za-z]*') 236 | 237 | elif sys.platform.startswith('darwin'): 238 | ports = glob.glob('/dev/tty.*') 239 | 240 | else: 241 | raise EnvironmentError('Unsupported platform') 242 | 243 | result = [] 244 | 245 | #TODO validar que quien responde es un SCK 246 | for port in ports: 247 | try: 248 | s = serial.Serial(port) 249 | s.close() 250 | result.append(port) 251 | except (OSError, serial.SerialException): 252 | pass 253 | return result 254 | def selectPort(ports): 255 | if len(ports) == 1: 256 | print "\nOnly one serial port found, using it! (" + bcolors.OKBLUE + ports[0] + bcolors.ENDC + ")" 257 | return ports[0] 258 | if len(ports) > 0: 259 | print "\nSelect a serial port from the list:\n" 260 | for p in ports: 261 | print "\t" + str(ports.index(p) + 1) + ". " + p 262 | 263 | i = raw_input("\n[" + ports[0] + "]: ") 264 | 265 | try: 266 | val = int(i) 267 | except: 268 | if i == "": val = 1 269 | else: val = -1 270 | 271 | if val-1 >= len(ports) or val-1 < 0: 272 | print "\n*** please input the port number! ***" 273 | return False 274 | else: 275 | return ports[val -1] 276 | else: 277 | print bcolors.FAIL + "No serial port available, bye!" + bcolors.ENDC 278 | sys.exit() 279 | def wiflySetup(): 280 | myPrint("Uploading firmware for wifly setup...") 281 | if myKit._retry(myKit._uploadWifliConsole()): 282 | print bcolors.OKGREEN + " OK" + bcolors.ENDC 283 | else: 284 | print bcolors.FAIL + " can't upload firmware, bye!" + bcolors.ENDC 285 | sys.exit() 286 | 287 | time.sleep(1) 288 | myKit._connectSerial() 289 | 290 | myPrint("Checking Wifly version...") 291 | if myKit._retry(myKit._W_getWiflyVersion()): 292 | if myKit.wiflyVersion < 4.75: 293 | myPrint(" " + bcolors.FAIL + str(myKit.wiflyVersion) + bcolors.ENDC) 294 | print " upgrade needed!!!" 295 | else: 296 | print " " + bcolors.OKGREEN + str(myKit.wiflyVersion) + bcolors.ENDC 297 | else: 298 | print bcolors.FAIL + " can't talk with wifly module (try resetting your SCK), bye!" + bcolors.ENDC 299 | sys.exit() 300 | 301 | myPrint("Conecting to network " + bcolors.OKBLUE + myKit.ssid + bcolors.ENDC + "...") 302 | if myKit._retry(myKit._W_wiflyJoin()): 303 | print bcolors.OKGREEN + " OK" + bcolors.ENDC + " (" + bcolors.OKBLUE + myKit.ip + bcolors.ENDC + ")" 304 | else: 305 | print bcolors.FAIL + " cant'connect to network, bye!" + bcolors.ENDC 306 | sys.exit() 307 | 308 | if myKit.wiflyVersion < 4.75: 309 | myPrint("Upgrading wifly version...") 310 | if myKit._retry(myKit._W_updateWifly()) and myKit._W_getWiflyVersion() and myKit.wiflyVersion == 4.75: 311 | print bcolors.OKGREEN + " OK" + bcolors.ENDC 312 | else: 313 | print bcolors.FAIL + " Upgrade failed, please try again, bye!" + bcolors.ENDC 314 | sys.exit() 315 | 316 | #return to factory settings 317 | myPrint("Reseting wifly module...") 318 | myKit._W_sendWiflyCommand("$$$") 319 | myKit._W_sendWiflyCommand("\r\n") 320 | myKit._W_sendWiflyCommand("factory RESET\r\n", "Set Factory Defaults", 1) 321 | myKit._W_sendWiflyCommand("save\r\n", "Storing in config", 1) 322 | response = myKit._W_sendWiflyCommand("reboot\r\n", "*READY*", 15) 323 | if response[0]: 324 | print bcolors.OKGREEN + " OK" + bcolors.ENDC 325 | return True 326 | def installFirmware(): 327 | if not myKit.inoFile: 328 | myPrint("Looking for latest SCK firmware...") 329 | if myKit._downloadFirmware(): 330 | print bcolors.OKGREEN + " OK" + bcolors.ENDC 331 | else: 332 | print bcolors.FAIL + " download failed, bye!" + bcolors.ENDC 333 | sys.exit() 334 | myPrint("Uploading latest firmware...") 335 | if myKit._uploadFirmware(): 336 | print bcolors.OKGREEN + " OK" + bcolors.ENDC 337 | else: 338 | print bcolors.FAIL + " ERROR, reset your kit and try again, bye!" + bcolors.ENDC 339 | sys.exit() 340 | return True 341 | 342 | class bcolors: 343 | OKBLUE = '\033[36m' 344 | OKGREEN = '\033[92m' 345 | WARNING = '\033[93m' 346 | FAIL = '\033[91m' 347 | ENDC = '\033[0m' 348 | BOLD = '\033[1m' 349 | UNDERLINE = '\033[4m' 350 | 351 | if __name__ == '__main__': 352 | 353 | myKit = SCK() 354 | 355 | benchStart = time.time() 356 | 357 | if len(sys.argv) > 1: 358 | if sys.argv[1] == "-p": 359 | myKit.usePort = True 360 | else: 361 | print 362 | print "Usage: SCKtester.py [OPTION]" 363 | print 364 | print " -p If there is only one serial port, don't ask, use it" 365 | print 366 | sys.exit() 367 | 368 | print "\n------------------------------------------" 369 | print "| " + bcolors.BOLD + "Smartcitizen Kit tester Script ver " + str(version) + bcolors.ENDC + " |" 370 | print "------------------------------------------" 371 | 372 | #seleccion de puerto 373 | while not myKit.port: 374 | myKit.port = selectPort(serialPorts()) 375 | 376 | 377 | if wiflySetup(): 378 | if installFirmware(): 379 | time.sleep(5) 380 | if myKit._connectSerial(): 381 | time.sleep(0.5) 382 | myPrint("Reading sensors...") 383 | if myKit._retry(myKit._update()): 384 | print bcolors.OKGREEN + " OK\n" + bcolors.ENDC 385 | result = myKit._log() 386 | if result == "PASSED": 387 | print "\nTesting " + bcolors.OKGREEN + result + bcolors.ENDC + "\n" 388 | else: 389 | print bcolors.FAIL + "\n" + result + bcolors.ENDC + "\n" 390 | else: 391 | print bcolors.FAIL + "can't read sensors! bye!" + bcolors.ENDC 392 | sys.exit() 393 | myPrint("Last task: clearing nets and eeprom memory...") 394 | myKit._sendCommand("clear nets\r\n") 395 | myKit._sendCommand("clear memory\r\n") 396 | myKit._sendCommand("get all\r\n", "|60|1|", 25) 397 | print bcolors.OKGREEN + " OK" + bcolors.ENDC 398 | print "Testing has took " + bcolors.OKBLUE + str(int(time.time()-benchStart)) + bcolors.ENDC + " seconds." 399 | print "Bye!\n" 400 | -------------------------------------------------------------------------------- /utilities/SCK_testing/readme.md: -------------------------------------------------------------------------------- 1 | Smartcitizen Kit testing script 2 | ================= 3 | 4 | 5 | #### A python script to test and update Smartcitizen kits 6 | 7 | ##### It's a command line utility aimed to check the different parts of a kit and apply available updates in the most possible automated way. 8 | 9 | * Checks wifly firmware version and installs available updates. 10 | * Installs the latest available firmware from github (after first installation if you want to refresh the firmware, delete the folder named *"firmware"* before running the script again) 11 | * Takes readings from sensors and checks if values are inside an acceptable range (*work in progress*). 12 | * Creates a csv file with the results of the tests with one entry per tested kit. 13 | 14 | ------ 15 | ##### Using the script 16 | 17 | * This script requires a working installation of [python](https://www.python.org/) and [Arduino IDE](https://www.arduino.cc/en/Main/Software) and a working Internet connection with wi-fi access. 18 | * Download this folder to your computer, edit your network settings on line 9-10, connect your kit to the USB port and run the script with `python SCKtester`. 19 | * If you only have the kit connected to your computer and only one serial port is available, you can skip port selection with the *-p* option: `python SCKtester -p` 20 | 21 | ------ 22 | ##### Screenshot 23 | ![Screenshot](shot.png) -------------------------------------------------------------------------------- /utilities/SCK_testing/shot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fablabbcn/smartcitizen-kit-10/5d343f7c37d714c69dcb57fa3f7c47099750bee6/utilities/SCK_testing/shot.png -------------------------------------------------------------------------------- /utilities/SCK_testing/wifly/wifly.ino: -------------------------------------------------------------------------------- 1 | 2 | 3 | void setup() { 4 | Serial.begin(9600); 5 | Serial1.begin(9600); 6 | 7 | pinMode(4, OUTPUT); //despierta al wifly 8 | digitalWrite(4, LOW); 9 | 10 | pinMode(7, OUTPUT); //factory RESET/AP RN131 11 | digitalWrite(7, LOW); 12 | 13 | pinMode(MOSI, OUTPUT); 14 | pinMode(SCK, OUTPUT); 15 | } 16 | 17 | void loop() { 18 | if (Serial.available()) 19 | { 20 | int inByte = Serial.read(); 21 | Serial1.write(inByte); 22 | } 23 | if (Serial1.available()) { 24 | int inByte = Serial1.read(); 25 | Serial.write(inByte); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /utilities/Wifly_Rescue/SCKBase.ino: -------------------------------------------------------------------------------- 1 | 2 | #define AWAKE 4 //Despertar WIFI 3 | #define PANEL A8 //Entrada panel 4 | #define BAT A7 //Entrada bateria 5 | 6 | #define IO0 5 //MICS5525_HEATHER 7 | #define IO1 13 //MICS2710_HEATHER 8 | #define IO2 9 //MICS2710_ALTAIMPEDANCIA 9 | #define IO3 10 //MICS2710_ALTAIMPEDANCIA 10 | #define FACTORY 7 //factory RESET/AP RN131 11 | #define CONTROL 12 //Control Mode 12 | 13 | #define S0 A4 //MICS_5525 14 | #define S1 A5 //MICS_2710 15 | #define S2 A2 //SENS_5525 16 | #define S3 A3 //SENS_2710 17 | #define S4 A0 //MICRO 18 | #define S5 A1 //LDR 19 | 20 | #define OPEN "0" 21 | #define WEP "1" 22 | #define WPA1 "2" 23 | #define WPA2 "4" 24 | #define WEP64 "8" 25 | 26 | #define INT_ANT "0" //EXT_ANT 27 | #define EXT_ANT "1" //EXT_ANT 28 | 29 | char* mySSID = "Red"; 30 | char* myPassword = "Pass"; 31 | char* wifiEncript = WPA2; 32 | char* antenna = INT_ANT; //EXT_ANT 33 | 34 | 35 | boolean connected; 36 | 37 | #define buffer_length 32 38 | static char buffer[buffer_length]; 39 | 40 | void sckBegin() { 41 | Serial.begin(115200); 42 | Serial1.begin(9600); 43 | pinMode(IO0, OUTPUT); //VH_MICS5525 44 | pinMode(IO1, OUTPUT); //VH_MICS2710 45 | pinMode(IO2, OUTPUT); //MICS2710_ALTAIMPEDANCIA 46 | pinMode(AWAKE, OUTPUT); 47 | pinMode(MOSI, OUTPUT); 48 | pinMode(SCK, OUTPUT); 49 | pinMode(FACTORY, OUTPUT); 50 | pinMode(CONTROL, INPUT); 51 | digitalWrite(AWAKE, LOW); 52 | digitalWrite(FACTORY, HIGH); 53 | // digitalWrite(FACTORY, LOW); 54 | } 55 | 56 | boolean sckFindInResponse(const char *toMatch, 57 | unsigned int timeOut = 1000) { 58 | int byteRead; 59 | 60 | unsigned long timeOutTarget; // in milliseconds 61 | 62 | for (unsigned int offset = 0; offset < strlen(toMatch); offset++) { 63 | timeOutTarget = millis() + timeOut; // Doesn't handle timer wrapping 64 | while (!Serial1.available()) { 65 | // Wait, with optional time out. 66 | if (timeOut > 0) { 67 | if (millis() > timeOutTarget) { 68 | return false; 69 | } 70 | } 71 | delay(1); // This seems to improve reliability slightly 72 | } 73 | byteRead = Serial1.read(); 74 | //Serial.print((char)byteRead); 75 | delay(1); // Removing logging may affect timing slightly 76 | 77 | if (byteRead != toMatch[offset]) { 78 | offset = 0; 79 | // Ignore character read if it's not a match for the start of the string 80 | if (byteRead != toMatch[offset]) { 81 | offset = -1; 82 | } 83 | continue; 84 | } 85 | } 86 | 87 | return true; 88 | } 89 | 90 | void sckRecovery() 91 | { 92 | Serial.println(F("Reseting...")); 93 | digitalWrite(FACTORY, HIGH); 94 | delay(1000); 95 | digitalWrite(FACTORY, LOW); 96 | delay(1000); 97 | digitalWrite(FACTORY, HIGH); 98 | delay(1000); 99 | digitalWrite(FACTORY, LOW); 100 | delay(1000); 101 | digitalWrite(FACTORY, HIGH); 102 | delay(1000); 103 | digitalWrite(FACTORY, LOW); 104 | delay(1000); 105 | digitalWrite(FACTORY, HIGH); 106 | delay(1000); 107 | digitalWrite(FACTORY, LOW); 108 | delay(1000); 109 | digitalWrite(FACTORY, HIGH); 110 | delay(1000); 111 | digitalWrite(FACTORY, LOW); 112 | delay(1000); 113 | Serial1.println(); 114 | sckFindInResponse("=0)&&repair); i--) 256 | { 257 | Serial1.begin(baud[i]); 258 | Serial.println(baud[i]); 259 | if(sckEnterCommandMode()) 260 | { 261 | sckReset(); 262 | repair = false; 263 | } 264 | Serial1.begin(9600); 265 | } 266 | } 267 | } 268 | 269 | boolean sckReady() 270 | { 271 | if(!sckEnterCommandMode()) 272 | { 273 | sckRepair(); 274 | } 275 | if (sckEnterCommandMode()) 276 | { 277 | Serial1.println(F("join")); 278 | if (sckFindInResponse("Associated!", 8000)) 279 | { 280 | sckSkipRemainderOfResponse(3000); 281 | sckExitCommandMode(); 282 | return(true); 283 | } 284 | } 285 | else return(false); 286 | } 287 | 288 | char* itoa(int32_t number) 289 | { 290 | byte count = 0; 291 | uint32_t temp; 292 | if (number < 0) {temp = number*(-1); count++;} 293 | while ((temp/10)!=0) 294 | { 295 | temp = temp/10; 296 | count++; 297 | } 298 | int i; 299 | if (number < 0) {temp = number*(-1);} 300 | else temp = number; 301 | for (i = count; i>=0; i--) 302 | { 303 | buffer[i] = temp%10 + '0'; 304 | temp = temp/10; 305 | } 306 | if (number < 0) {buffer[0] = '-';} 307 | buffer[count + 1] = 0x00; 308 | return buffer; 309 | } 310 | 311 | 312 | 313 | -------------------------------------------------------------------------------- /utilities/Wifly_Rescue/Wifly_Rescue.ino: -------------------------------------------------------------------------------- 1 | void setup() { 2 | sckBegin(); 3 | delay(5000); 4 | sckRecovery(); 5 | } 6 | 7 | void loop() { 8 | if (Serial.available()) 9 | { 10 | int inByte = Serial.read(); 11 | Serial1.write(inByte); 12 | } 13 | if (Serial1.available()) { 14 | int inByte = Serial1.read(); 15 | Serial.write(inByte); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /utilities/Wifly_Update/SCKBase.ino: -------------------------------------------------------------------------------- 1 | 2 | #define AWAKE 4 //Despertar WIFI 3 | #define PANEL A8 //Entrada panel 4 | #define BAT A7 //Entrada bateria 5 | 6 | #define IO0 5 //MICS5525_HEATHER 7 | #define IO1 13 //MICS2710_HEATHER 8 | #define IO2 9 //MICS2710_ALTAIMPEDANCIA 9 | #define IO3 10 //MICS2710_ALTAIMPEDANCIA 10 | #define FACTORY 7 //factory RESET/AP RN131 11 | #define CONTROL 12 //Control Mode 12 | 13 | #define S0 A4 //MICS_5525 14 | #define S1 A5 //MICS_2710 15 | #define S2 A2 //SENS_5525 16 | #define S3 A3 //SENS_2710 17 | #define S4 A0 //MICRO 18 | #define S5 A1 //LDR 19 | 20 | #define OPEN "0" 21 | #define WEP "1" 22 | #define WPA1 "2" 23 | #define WPA2 "4" 24 | #define WEP64 "8" 25 | 26 | #define INT_ANT "0" //EXT_ANT 27 | #define EXT_ANT "1" //EXT_ANT 28 | 29 | //char* mySSID = "Red"; 30 | //char* myPassword = "Pass"; 31 | char* mySSID = "Mi$Red"; 32 | char* myPassword = "FINALFANTASY"; 33 | char* wifiEncript = WPA2; 34 | char* antenna = INT_ANT; //EXT_ANT 35 | 36 | 37 | boolean connected; 38 | 39 | #define buffer_length 32 40 | static char buffer[buffer_length]; 41 | 42 | void sckBegin() { 43 | Serial.begin(115200); 44 | Serial1.begin(9600); 45 | pinMode(IO0, OUTPUT); //VH_MICS5525 46 | pinMode(IO1, OUTPUT); //VH_MICS2710 47 | pinMode(IO2, OUTPUT); //MICS2710_ALTAIMPEDANCIA 48 | pinMode(AWAKE, OUTPUT); 49 | pinMode(MOSI, OUTPUT); 50 | pinMode(SCK, OUTPUT); 51 | pinMode(FACTORY, OUTPUT); 52 | pinMode(CONTROL, INPUT); 53 | digitalWrite(AWAKE, LOW); 54 | digitalWrite(FACTORY, LOW); 55 | sckExitCommandMode(); 56 | } 57 | 58 | boolean sckFindInResponse(const char *toMatch, 59 | unsigned int timeOut = 1000) { 60 | int byteRead; 61 | 62 | unsigned long timeOutTarget; // in milliseconds 63 | 64 | for (unsigned int offset = 0; offset < strlen(toMatch); offset++) { 65 | timeOutTarget = millis() + timeOut; // Doesn't handle timer wrapping 66 | while (!Serial1.available()) { 67 | // Wait, with optional time out. 68 | if (timeOut > 0) { 69 | if (millis() > timeOutTarget) { 70 | return false; 71 | } 72 | } 73 | delay(1); // This seems to improve reliability slightly 74 | } 75 | byteRead = Serial1.read(); 76 | //Serial.print((char)byteRead); 77 | delay(1); // Removing logging may affect timing slightly 78 | 79 | if (byteRead != toMatch[offset]) { 80 | offset = 0; 81 | // Ignore character read if it's not a match for the start of the string 82 | if (byteRead != toMatch[offset]) { 83 | offset = -1; 84 | } 85 | continue; 86 | } 87 | } 88 | 89 | return true; 90 | } 91 | 92 | void sckRecovery() 93 | { 94 | Serial.println("Reseting..."); 95 | digitalWrite(FACTORY, HIGH); 96 | delay(1000); 97 | digitalWrite(FACTORY, LOW); 98 | delay(1000); 99 | digitalWrite(FACTORY, HIGH); 100 | delay(1000); 101 | digitalWrite(FACTORY, LOW); 102 | delay(1000); 103 | digitalWrite(FACTORY, HIGH); 104 | delay(1000); 105 | digitalWrite(FACTORY, LOW); 106 | delay(1000); 107 | digitalWrite(FACTORY, HIGH); 108 | delay(1000); 109 | digitalWrite(FACTORY, LOW); 110 | delay(1000); 111 | digitalWrite(FACTORY, HIGH); 112 | delay(1000); 113 | digitalWrite(FACTORY, LOW); 114 | delay(1000); 115 | Serial1.println(); 116 | sckFindInResponse("=0)&&repair); i--) 271 | { 272 | Serial1.begin(baud[i]); 273 | Serial.println(baud[i]); 274 | if(sckEnterCommandMode()) 275 | { 276 | sckReset(); 277 | repair = false; 278 | } 279 | Serial1.begin(9600); 280 | } 281 | } 282 | } 283 | 284 | boolean sckReady() 285 | { 286 | if(!sckEnterCommandMode()) 287 | { 288 | sckRepair(); 289 | } 290 | if (sckEnterCommandMode()) 291 | { 292 | Serial1.println(F("join")); 293 | if (sckFindInResponse("Associated!", 8000)) 294 | { 295 | sckSkipRemainderOfResponse(3000); 296 | sckExitCommandMode(); 297 | return(true); 298 | } 299 | } 300 | else return(false); 301 | } 302 | 303 | char* itoa(int32_t number) 304 | { 305 | byte count = 0; 306 | uint32_t temp; 307 | if (number < 0) {temp = number*(-1); count++;} 308 | while ((temp/10)!=0) 309 | { 310 | temp = temp/10; 311 | count++; 312 | } 313 | int i; 314 | if (number < 0) {temp = number*(-1);} 315 | else temp = number; 316 | for (i = count; i>=0; i--) 317 | { 318 | buffer[i] = temp%10 + '0'; 319 | temp = temp/10; 320 | } 321 | if (number < 0) {buffer[0] = '-';} 322 | buffer[count + 1] = 0x00; 323 | return buffer; 324 | } 325 | 326 | 327 | 328 | -------------------------------------------------------------------------------- /utilities/Wifly_Update/Wifly_Update.ino: -------------------------------------------------------------------------------- 1 | void setup() { 2 | sckBegin(); 3 | delay(5000); 4 | sckConnect(); 5 | sckExitCommandMode(); 6 | sckEnterCommandMode(); 7 | } 8 | 9 | void loop() { 10 | if (!digitalRead(12)) 11 | { 12 | if (sckConnect()) 13 | { 14 | Serial.println("connected!!"); 15 | sckExitCommandMode(); 16 | sckEnterCommandMode(); 17 | Serial.println("Updating..."); 18 | if (sckUpdate()) Serial.println("Update OK"); 19 | else Serial.println("Update FAIL"); 20 | sckReset(); 21 | } 22 | else Serial.println("Connection Fail :("); 23 | } 24 | 25 | if (Serial.available()) 26 | { 27 | int inByte = Serial.read(); 28 | Serial1.write(inByte); 29 | } 30 | if (Serial1.available()) { 31 | int inByte = Serial1.read(); 32 | Serial.write(inByte); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /utilities/wifly_terminal/SCKBase.ino: -------------------------------------------------------------------------------- 1 | 2 | #define AWAKE 4 //Despertar WIFI 3 | #define PANEL A8 //Entrada panel 4 | #define BAT A7 //Entrada bateria 5 | 6 | #define IO0 5 //MICS5525_HEATHER 7 | #define IO1 13 //MICS2710_HEATHER 8 | #define IO2 9 //MICS2710_ALTAIMPEDANCIA 9 | #define IO3 10 //MICS2710_ALTAIMPEDANCIA 10 | #define FACTORY 7 //factory RESET/AP RN131 11 | #define CONTROL 12 //Control Mode 12 | 13 | #define S0 A4 //MICS_5525 14 | #define S1 A5 //MICS_2710 15 | #define S2 A2 //SENS_5525 16 | #define S3 A3 //SENS_2710 17 | #define S4 A0 //MICRO 18 | #define S5 A1 //LDR 19 | 20 | #define OPEN "0" 21 | #define WEP "1" 22 | #define WPA1 "2" 23 | #define WPA2 "4" 24 | #define WEP64 "8" 25 | 26 | #define INT_ANT "0" //EXT_ANT 27 | #define EXT_ANT "1" //EXT_ANT 28 | 29 | char* mySSID = "Red"; 30 | char* myPassword = "Pass"; 31 | char* wifiEncript = WPA2; 32 | char* antenna = INT_ANT; //EXT_ANT 33 | 34 | 35 | boolean connected; 36 | 37 | #define buffer_length 32 38 | static char buffer[buffer_length]; 39 | 40 | void sckBegin() { 41 | Serial.begin(115200); 42 | Serial1.begin(9600); 43 | pinMode(IO0, OUTPUT); //VH_MICS5525 44 | pinMode(IO1, OUTPUT); //VH_MICS2710 45 | pinMode(IO2, OUTPUT); //MICS2710_ALTAIMPEDANCIA 46 | pinMode(AWAKE, OUTPUT); 47 | pinMode(MOSI, OUTPUT); 48 | pinMode(SCK, OUTPUT); 49 | pinMode(FACTORY, OUTPUT); 50 | pinMode(CONTROL, INPUT); 51 | digitalWrite(AWAKE, LOW); 52 | digitalWrite(FACTORY, LOW); 53 | } 54 | 55 | boolean sckFindInResponse(const char *toMatch, 56 | unsigned int timeOut = 1000) { 57 | int byteRead; 58 | 59 | unsigned long timeOutTarget; // in milliseconds 60 | 61 | for (unsigned int offset = 0; offset < strlen(toMatch); offset++) { 62 | timeOutTarget = millis() + timeOut; // Doesn't handle timer wrapping 63 | while (!Serial1.available()) { 64 | // Wait, with optional time out. 65 | if (timeOut > 0) { 66 | if (millis() > timeOutTarget) { 67 | return false; 68 | } 69 | } 70 | delay(1); // This seems to improve reliability slightly 71 | } 72 | byteRead = Serial1.read(); 73 | //Serial.print((char)byteRead); 74 | delay(1); // Removing logging may affect timing slightly 75 | 76 | if (byteRead != toMatch[offset]) { 77 | offset = 0; 78 | // Ignore character read if it's not a match for the start of the string 79 | if (byteRead != toMatch[offset]) { 80 | offset = -1; 81 | } 82 | continue; 83 | } 84 | } 85 | 86 | return true; 87 | } 88 | 89 | void sckRecovery() 90 | { 91 | Serial.println("Reseting..."); 92 | digitalWrite(FACTORY, HIGH); 93 | delay(1000); 94 | digitalWrite(FACTORY, LOW); 95 | delay(1000); 96 | digitalWrite(FACTORY, HIGH); 97 | delay(1000); 98 | digitalWrite(FACTORY, LOW); 99 | delay(1000); 100 | digitalWrite(FACTORY, HIGH); 101 | delay(1000); 102 | digitalWrite(FACTORY, LOW); 103 | delay(1000); 104 | digitalWrite(FACTORY, HIGH); 105 | delay(1000); 106 | digitalWrite(FACTORY, LOW); 107 | delay(1000); 108 | digitalWrite(FACTORY, HIGH); 109 | delay(1000); 110 | digitalWrite(FACTORY, LOW); 111 | delay(1000); 112 | Serial1.println(); 113 | sckFindInResponse("=0)&&repair); i--) 268 | { 269 | Serial1.begin(baud[i]); 270 | Serial.println(baud[i]); 271 | if(sckEnterCommandMode()) 272 | { 273 | sckReset(); 274 | repair = false; 275 | } 276 | Serial1.begin(9600); 277 | } 278 | } 279 | } 280 | 281 | boolean sckReady() 282 | { 283 | if(!sckEnterCommandMode()) 284 | { 285 | sckRepair(); 286 | } 287 | if (sckEnterCommandMode()) 288 | { 289 | Serial1.println(F("join")); 290 | if (sckFindInResponse("Associated!", 8000)) 291 | { 292 | sckSkipRemainderOfResponse(3000); 293 | sckExitCommandMode(); 294 | return(true); 295 | } 296 | } 297 | else return(false); 298 | } 299 | 300 | char* itoa(int32_t number) 301 | { 302 | byte count = 0; 303 | uint32_t temp; 304 | if (number < 0) {temp = number*(-1); count++;} 305 | while ((temp/10)!=0) 306 | { 307 | temp = temp/10; 308 | count++; 309 | } 310 | int i; 311 | if (number < 0) {temp = number*(-1);} 312 | else temp = number; 313 | for (i = count; i>=0; i--) 314 | { 315 | buffer[i] = temp%10 + '0'; 316 | temp = temp/10; 317 | } 318 | if (number < 0) {buffer[0] = '-';} 319 | buffer[count + 1] = 0x00; 320 | return buffer; 321 | } 322 | 323 | 324 | 325 | -------------------------------------------------------------------------------- /utilities/wifly_terminal/wifly_terminal.ino: -------------------------------------------------------------------------------- 1 | void setup() { 2 | sckBegin(); 3 | sckRepair(); 4 | //sckConnect(); 5 | sckEnterCommandMode(); 6 | } 7 | 8 | void loop() { 9 | if (Serial.available()) 10 | { 11 | int inByte = Serial.read(); 12 | Serial1.write(inByte); 13 | } 14 | if (Serial1.available()) { 15 | int inByte = Serial1.read(); 16 | Serial.write(inByte); 17 | } 18 | } 19 | --------------------------------------------------------------------------------